Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -809,17 +809,18 @@ round-trips through the raw `POINT` buffer.
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/gp-lineart-contour/"><img src="examples/gp-lineart-contour/preview.webp" alt="GP Line Art contour: a faceted teal crystal on a dark studio floor outlined in neon cyan Grease Pencil Line Art strokes, proving modifiers.new LINEART with source_object silhouette evaluation" /></a>
<a href="examples/gp-lineart-contour/"><img src="examples/gp-lineart-contour/preview.webp" alt="GP Line Art contour: a cel-shaded red-and-white lighthouse on a rocky islet with a keeper's cottage and rowboat, inked in bold black Grease Pencil Line Art strokes, proving modifiers.new LINEART with source_object evaluation" /></a>
</td>
<td valign="middle">

### [gp-lineart-contour](examples/gp-lineart-contour/)

Grease Pencil `LINEART` modifier contours via the depsgraph — not Freestyle and
not hand-drawn strokes. `source_object` is load-bearing (clear → 0 strokes);
contour+crease off → 0; restore recovers **10** strokes / **34** points on both
binaries. Stroke width: `thickness` exists on 4.5, `AttributeError` on 5.1 —
portable path is `radius`.
Grease Pencil `LINEART` modifier ink via the depsgraph on a cel-shaded
lighthouse diorama — not Freestyle and not hand-drawn strokes. `source_object`
is load-bearing (clear → 0 strokes); every edge type off → 0; the drawing is
**255** strokes / **1393** points on all three binaries, gated so dropping any
one edge type fails. Stroke width: `thickness` exists on 4.5, `AttributeError`
on 5.1 — portable path is `radius`.

</td>
</tr>
Expand Down
Binary file modified docs/gallery/assets/gp-lineart-contour-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
582 changes: 400 additions & 182 deletions docs/gallery/gp-lineart-contour/index.html

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/gallery/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -728,12 +728,12 @@ <h2><a href="sky-texture-sun-elevation/">sky-texture-sun-elevation</a></h2>
</article>
<article class="card" data-tags="grease-pencil line-art modifiers">
<a class="card-media" href="gp-lineart-contour/" tabindex="-1" aria-hidden="true">
<img src="assets/gp-lineart-contour-hero.webp" alt="A translucent teal crystal, a six-sided double pyramid set tip-down in a dark hex mount, its edges traced by cyan Line Art contour strokes." loading="lazy" decoding="async" />
<img src="assets/gp-lineart-contour-hero.webp" alt="A red-and-white lighthouse on a rocky islet with a keeper&#x27;s cottage and a rowboat, on a round blue sea with white wave crests, drawn like a comic panel in bold black Line Art ink." loading="lazy" decoding="async" />
</a>
<div class="card-body">
<h2><a href="gp-lineart-contour/">gp-lineart-contour</a></h2>
<p class="teaches">Grease Pencil LINEART modifier contours via the depsgraph on a faceted crystal. source_object is load-bearing (clear yields 0 strokes); contour+crease off yields 0; restore recovers 2 strokes / 12 points on 4.5.11, 5.1.2 and 5.2.1. Stroke width: thickness exists on 4.5, AttributeError on 5.1 — portable path is radius.</p>
<p class="witnesses"><span class="tag">witnesses</span> AI code still sets LINEART.thickness on 5.1 (AttributeError) or hand-draws strokes / enables Freestyle instead of modifiers.new(..., &#x27;LINEART&#x27;). Clearing source_object or leaving contour+crease off silently yields an empty drawing — the check proves both failure modes and recovery.</p>
<p class="teaches">Grease Pencil LINEART modifier ink via the depsgraph on a cel-shaded lighthouse diorama. source_object is load-bearing (clear yields 0 strokes); every edge type off yields 0; the drawing is 255 strokes / 1393 points on 4.5.11, 5.1.2 and 5.2.1, gated above the count left when any one of contour, crease, material-border or intersection edges is dropped. Stroke width: thickness exists on 4.5, AttributeError on 5.1 — portable path is radius.</p>
<p class="witnesses"><span class="tag">witnesses</span> AI code still sets LINEART.thickness on 5.1 (AttributeError) or hand-draws strokes / enables Freestyle instead of modifiers.new(..., &#x27;LINEART&#x27;). Clearing source_object or leaving every edge type off silently yields an empty drawing — the check proves both failure modes and recovery.</p>
<a class="card-link" href="gp-lineart-contour/">View example<span class="sr-only"> gp-lineart-contour</span> <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
Expand Down
6 changes: 3 additions & 3 deletions examples/gallery.json
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,9 @@
{
"name": "gp-lineart-contour",
"dir": "examples/gp-lineart-contour",
"teaches": "Grease Pencil LINEART modifier contours via the depsgraph on a faceted crystal. source_object is load-bearing (clear yields 0 strokes); contour+crease off yields 0; restore recovers 2 strokes / 12 points on 4.5.11, 5.1.2 and 5.2.1. Stroke width: thickness exists on 4.5, AttributeError on 5.1 — portable path is radius.",
"alt": "A translucent teal crystal, a six-sided double pyramid set tip-down in a dark hex mount, its edges traced by cyan Line Art contour strokes.",
"witnessesFix": "AI code still sets LINEART.thickness on 5.1 (AttributeError) or hand-draws strokes / enables Freestyle instead of modifiers.new(..., 'LINEART'). Clearing source_object or leaving contour+crease off silently yields an empty drawing — the check proves both failure modes and recovery.",
"teaches": "Grease Pencil LINEART modifier ink via the depsgraph on a cel-shaded lighthouse diorama. source_object is load-bearing (clear yields 0 strokes); every edge type off yields 0; the drawing is 255 strokes / 1393 points on 4.5.11, 5.1.2 and 5.2.1, gated above the count left when any one of contour, crease, material-border or intersection edges is dropped. Stroke width: thickness exists on 4.5, AttributeError on 5.1 — portable path is radius.",
"alt": "A red-and-white lighthouse on a rocky islet with a keeper's cottage and a rowboat, on a round blue sea with white wave crests, drawn like a comic panel in bold black Line Art ink.",
"witnessesFix": "AI code still sets LINEART.thickness on 5.1 (AttributeError) or hand-draws strokes / enables Freestyle instead of modifiers.new(..., 'LINEART'). Clearing source_object or leaving every edge type off silently yields an empty drawing — the check proves both failure modes and recovery.",
"hero": "docs/gallery/assets/gp-lineart-contour-hero.webp",
"preview": "examples/gp-lineart-contour/preview.webp",
"tags": [
Expand Down
60 changes: 37 additions & 23 deletions examples/gp-lineart-contour/README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,56 @@
# GP Line Art Contour

A runnable example that builds a faceted crystal, attaches a Grease Pencil
`LINEART` modifier with `source_type='OBJECT'`, and proves the contour contract
through the depsgraph — including the 4.5 → 5.1 stroke-width trap.
A runnable example that builds a lighthouse on a rocky islet — tower, gallery,
lantern room, keeper's cottage, a hauled-up rowboat and a diorama sea — as one
cel-shaded mesh, attaches a Grease Pencil `LINEART` modifier with
`source_type='OBJECT'`, and proves the contour contract through the depsgraph,
including the 4.5 → 5.1 stroke-width trap.

**What it witnesses:** the Line Art modifier contract AI-generated NPR code most
often gets wrong.

- **Contours are a modifier, not Freestyle and not hand-authored strokes.**
`modifiers.new(..., 'LINEART')` on a GPv3 object, with `target_layer` /
`target_material` set, evaluates silhouette edges into drawing strokes.
`target_material` set, evaluates the source mesh's edges into drawing strokes.
- **`source_object` is load-bearing.** Clearing it yields **0** evaluated
strokes (proven in the same check pass). Restoring it recovers the contour.
- **Edge-type flags matter.** A freshly added LINEART with `use_contour` and
`use_crease` both off emits **0** strokes; turning contour (+ crease) back on
recovers the silhouette (**2** strokes / **12** points on every binary for
this crystal + camera; Line Art chains the bipyramid's edges into long
strokes, so the count is low and the gates are lower bounds).
- **Stroke width renamed.** 4.5 exposes both `thickness` (legacy px, set to 45
strokes (proven in the same check pass). Restoring it recovers the drawing.
- **Edge-type flags matter.** A freshly added LINEART with every edge type off
(contour, crease, material borders, intersections, loose, edge marks) emits
**0** strokes. The configured modifier draws **255** strokes / **1393**
points on every binary, and the gates (**≥ 240** strokes, **≥ 1320** points)
sit above the count left when any *one* edge type is dropped — contour 234
strokes, crease 171 / 1099, material borders 247 / 1305, intersections
179 / 921 — so each is load-bearing: the band borders on the tower are
material-border ink, the waterline around each rock is intersection ink.
Rebuilding the modifier must recover exactly the first pass's counts.
- **Stroke width renamed.** 4.5 exposes both `thickness` (legacy px, set to 22
here) and `radius`; 5.1 removes `thickness` (`AttributeError`) and keeps
`radius` only (portable path: `mod.radius = 0.028`).
`radius` only (portable path: `mod.radius = 0.021`).
- **GPv3 address** matches `grease-pencil-rosette`: `grease_pencils_v3` on 4.5,
`grease_pencils` on 5.x.

**What each check catches on failure:** wrong GPv3 collection (exit 2),
`thickness` present/absent on the wrong side of 5.0 (exit 3), lost
`source_object` assignment (exit 4), contour too thin (exit 5), source clear
not zeroing strokes (exit 6), flags-off or restore failure (exit 7).
`source_object` assignment or `use_contour` (exit 4), drawing below the gates
(exit 5), source clear not zeroing strokes (exit 6), flags-off not zeroing
strokes or a rebuild not recovering the same counts (exit 7).

**Version witness:** stroke counts match on 4.5.11 LTS, 5.1.2 and 5.2.1 LTS
(2 strokes / 12 points). The divergence is `thickness` vs `radius`.
(255 strokes / 1393 points). The divergence is `thickness` vs `radius`.

**The still:** the crystal is a hexagonal bipyramid (an equator ring and two
apexes), set tip-down in a two-tier hex mount on the floor. The mount is
render staging, derived from the crystal's lowest evaluated vertex; it is built
after the check, so it never enters the Line Art counts. The still's camera
drops its aim and dollies in along the check camera's bearing, so the crystal
fills the frame with the mount's foot inside it.
**The still:** the check and the still share one camera, because Line Art is
view-dependent — the strokes the check counts are the strokes the still draws.
The mesh is shaded flat (three cel tones), so the black ink is what makes it
read as an inked illustration: clear `source_object` and the same render is a
flat, lineless low-poly model — no band borders, no waterline, no outlines.

### Stage deviation

Line Art is a non-photoreal contract: the hero's materials are cel-shaded
(Diffuse → Shader to RGB → constant ramp, emitted) instead of Principled, so
the ink reads against flat tone fields. The stage itself — floor, wall, world,
key, fill and warm wedge — is the default. The cel shading uses Shader to RGB,
which is EEVEE-only, so `--engine cycles` does not render the look.

## Run

Expand All @@ -63,9 +77,9 @@ against it. `10` is the shared framing helper.
| 2 | argparse / usage; also GPv3 collection address contract |
| 3 | LINEART `thickness` / `radius` trap for this Blender |
| 4 | LINEART type, source, or `use_contour` (`--no-contour` lands here) |
| 5 | Evaluated contour too thin |
| 5 | Evaluated drawing below the stroke/point gates |
| 6 | Cleared `source_object` still produced strokes |
| 7 | Contour+crease off still produced strokes, or restore failed |
| 7 | Every edge type off still produced strokes, or the rebuild did not recover the same counts |
| 8 | `--output` produced no file |
| 10 | Gallery framing violation |

Expand Down
Loading
Loading