# How the Utility‑Model Structure‑Line‑Art Pipeline Combines SVG Parts and Overlays Callout Numbers

> Learn how the utility model structure line art pipeline creates editable SVG assemblies from part SVGs and overlays callout numbers with vision model anchors.

- Repository: [handsomestWei/patent-disclosure-skill](https://github.com/handsomestWei/patent-disclosure-skill)
- Tags: how-to-guide
- Published: 2026-09-02

---

**The utility‑model structure‑line‑art pipeline builds an editable SVG assembly from individual part SVGs, then overlays numbered callouts using persisted vision‑model anchors.**

The `handsomestWei/patent-disclosure-skill` repository implements a two‑stage pipeline for generating patent‑style technical illustrations. This article explains how the **structure line art pipeline** composes modular SVG parts and layers callout numbers on top—preserving full editability for utility model disclosures.

---

## Stage 1: Preparing and Composing Per‑Part SVGs

The first stage transforms source images into discrete, reusable SVG components. The entry point is [`structure_lineart_compose.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_compose.py), which orchestrates this decomposition.

### The Compose Schema

The pipeline reads a YAML configuration ([`structure_lineart_compose.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_compose.yaml)) that defines the assembly structure. Each part entry specifies:

- **`id`** – A unique token identifying the component
- **`source`** – One of three types: `crop`, `image`, or `placeholder`
- **`slot`** – Normalized coordinates (`x`, `y`, `w`, `h` as percentages) for placement

### Three Source Types for Part Generation

The `_write_part_svg()` function handles each source type differently:

| Source Type | Behavior | Use Case |
|-------------|----------|----------|
| **Crop** | Extracts a rectangular region from a source PNG/JPEG and converts it to SVG | Selecting regions from photographs or scans |
| **Image** | Embeds a pre‑generated PNG that scales to fit the slot | Reusing externally rendered part images |
| **Placeholder** | Draws a dashed rectangle when no visual source exists | Reserving space for unillustrated components |

### Building the Layered Assembly

The `render_view()` function in [`structure_lineart_compose.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_compose.py) iterates over resolved parts and computes absolute placement coordinates from slot percentages. Key implementation details:

- Child SVGs are stored under `…/parts/` and referenced via relative `<image>` elements
- Each part wraps in `<g id="part‑{token}" …>` groups, preserving original IDs for downstream identification
- No base‑64 embedding—keeping files lightweight and human‑editable
- Canvas dimensions derive from `_canvas_size()`, using either explicit settings or source image dimensions

The output is a single SVG where each part remains a separate, addressable layer.

---

## Stage 2: Generating Callout Metadata

Before overlaying numbers, the pipeline validates callout requirements and produces anchor data. This intermediary stage lives in [`structure_lineart_gate.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_gate.py).

### The Brief Schema Validation

[`structure_lineart_gate.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_gate.py) validates [`structure_lineart_brief.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_brief.yaml) against its schema. This brief specifies:

- **Visible part IDs** – Which components appear in each view
- **Callout mode** – `overlay` (numbers on image), `in_prompt` (numbers in generation prompt), or `contour_only` (silhouette without labels)
- **LLM prompt** – Instructions for rendering the raw line‑art "contour" pass

### Persisting Anchor Positions

After the contour pass completes, a vision model analyzes the output and writes normalized anchor coordinates to [`structure_callout_anchors.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_callout_anchors.yaml). These anchors define **where** each callout number should appear—separating positioning logic from the final rendering stage.

---

## Stage 3: Overlaying Callout Numbers

The final stage injects numbered leader lines into the composed SVG. [`structure_callout_overlay.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_callout_overlay.py) performs this merge.

### Loading and Positioning Anchors

For each view, the script:

1. Loads the base image—either the composed SVG from Stage 1 or an original raster fallback
2. Converts normalized anchor coordinates to absolute pixel positions via `_point()`
3. Computes both **anchor** (where the line touches the part) and **label** (where the number appears) positions

### Generating Callout Markup

The `callouts_markup()` function produces SVG elements for:

- Leader lines connecting parts to their labels
- Numeric labels with configurable styling (font size, line width)
- Optional circular backgrounds behind numbers

Style options are read from the pipeline configuration, allowing consistent patent‑office formatting.

### Injecting into the Document

The `inject_callouts()` function inserts generated markup between XML comment markers:

```xml
<!-- structure-callouts -->
[generated leader lines and numbers]
<!-- /structure-callouts -->

```

This insertion pattern enables:
- **Idempotent re‑runs** – Old callouts are replaced, not duplicated
- **Manual editing** – Human reviewers can adjust positions between comments
- **Tool interoperability** – Other processors can locate and modify callout regions

---

## Complete Pipeline Walkthrough

```python
from pathlib import Path
from tools.shared.structure_lineart_compose import load_data, render_view as compose_view
from tools.shared.structure_callout_overlay import load_data as load_manifest, render_view as overlay_view

# Stage 1: Compose parts into unified SVG

compose = load_data(Path("case/structure_lineart_compose.yaml"))
view = compose["views"][0]
composed_svg = compose_view(compose, view, Path("case"))

print(f"Composed SVG: {composed_svg}")

# Stage 3: Overlay callout numbers

manifest = load_data(Path("case/structure_callout_anchors.yaml"))
for view in manifest["views"]:
    final_svg = overlay_view(view, Path("case"))
    print(f"Final SVG with callouts: {final_svg}")

```

---

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`tools/shared/structure_lineart_compose.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/structure_lineart_compose.py) | Decomposes source images into per‑part SVGs and assembles the layered composition |
| [`tools/shared/structure_lineart_gate.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/structure_lineart_gate.py) | Validates briefs, generates contour jobs, and persists anchor metadata |
| [`tools/shared/structure_callout_overlay.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/tools/shared/structure_callout_overlay.py) | Reads anchors and injects numbered leader lines into the final SVG |
| [`references/schemas/structure_lineart_compose.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/structure_lineart_compose.schema.yaml) | Schema for part definitions and slot configurations |
| [`references/schemas/structure_lineart_brief.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/structure_lineart_brief.schema.yaml) | Schema for callout modes and view specifications |
| [`references/schemas/structure_callout_anchors.schema.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/references/schemas/structure_callout_anchors.schema.yaml) | Schema for vision‑model anchor coordinates |

---

## Summary

- **The structure line art pipeline separates composition from annotation**—parts assemble first, callouts apply second
- **SVG layering preserves editability**—relative `<image>` references keep files small and hand‑modifiable
- **Three source types** (`crop`, `image`, `placeholder`) handle diverse input conditions
- **Anchor persistence decouples vision processing from rendering**—enabling human review of AI‑generated positions
- **Comment‑delimited injection** makes callout updates safe and repeatable

---

## Frequently Asked Questions

### How does the pipeline handle missing part images?

When no visual source exists, [`structure_lineart_compose.py`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_compose.py) generates a **placeholder**—a dashed rectangle drawn by `_write_part_svg()`. This reserves slot space and maintains consistent part numbering without breaking the composition.

### Can I manually adjust callout positions after automated overlay?

Yes. The `inject_callouts()` function places all markup between `<!-- structure-callouts -->` and `<!-- /structure-callouts -->` comments. You can edit SVG coordinates within these boundaries; subsequent pipeline runs will replace only this delimited region.

### Why are child SVGs referenced rather than embedded?

The pipeline uses relative `<image>` elements pointing to `…/parts/` files instead of base‑64 encoding. This keeps the top‑level SVG editable in standard vector tools, enables part‑level version control, and reduces file sizes for complex assemblies.

### What callout modes are available for different patent requirements?

Three modes control annotation behavior: **`overlay`** draws numbers on the final image; **`in_prompt`** includes numbers during LLM generation (for integrated labels); **`contour_only`** produces silhouette illustrations without any numbering. Mode selection happens in [`structure_lineart_brief.yaml`](https://github.com/handsomestWei/patent-disclosure-skill/blob/main/structure_lineart_brief.yaml).