Skip to content

Commit 70fc770

Browse files
TMHSDigitalclaude
andcommitted
fix(gallery): describe each still in its alt text instead of the API it teaches
Every gallery image's alt was derived from `teaches`, which says what the code proves, not what the picture shows, and 29 of 79 card alts were cut at 160 characters. Detail-page, zoom and landing images said only "<name> render". - Each examples/ and showcase/ gallery.json entry gains an `alt`: one sentence written from the committed still (all 79, longest 135 chars). - build_gallery.py uses it for the card, the detail hero, the zoom image and the zoom button label, and fails the build on a missing or overlong alt. The teaches-derived card_alt/first_sentence helpers go. - The landing template uses it for both card grids. - CLAUDE.md, CONTRIBUTING.md and docs/new-example-prompt.md say new entries need one. Closes #213 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent e7a555d commit 70fc770

87 files changed

Lines changed: 426 additions & 377 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ example still carries a `tests/smoke/catalog.json` row and a falsifier.
122122
`examples/gallery.json` is the
123123
gallery's source of truth. When authoring a new gallery example, copy the anatomy of
124124
`examples/bmesh-gear/` (script structure, README shape, dark-studio render recipe) and
125-
wire all of: gallery.json entry, `.cursor-plugin/plugin.json` examples array (CI-gated),
125+
wire all of: gallery.json entry (with an `alt` sentence describing the still; the build fails without one), `.cursor-plugin/plugin.json` examples array (CI-gated),
126126
a `tests/smoke/catalog.json` row, a README gallery row, hero webp (1280×720) in
127127
`docs/gallery/assets/` + preview webp (1200×675), then run `python scripts/build_gallery.py`.
128128
A check-only example wires only the `.cursor-plugin/plugin.json` entry, the

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ budget conformance, never an API contract.
115115
**named** budget fails.
116116
2. List the directory in `.cursor-plugin/plugin.json` `"showcase"` and add a
117117
`tests/smoke/catalog.json` row. The runner takes opaque script paths.
118-
3. Add a `showcase/gallery.json` `pieces[]` entry, render a still, and run
119-
`python scripts/build_gallery.py`. Do not hand-edit `docs/gallery/` HTML.
118+
3. Add a `showcase/gallery.json` `pieces[]` entry, including an `alt`: one
119+
sentence saying what the still shows (the generator fails without it).
120+
Render a still, and run `python scripts/build_gallery.py`. Do not hand-edit `docs/gallery/` HTML.
120121
4. Update the README showcase-piece count. `validate-counts` checks it
121122
separately from the example total.
122123

‎docs/gallery/anvil/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>anvil</h1>
263263
<p>A procedural blacksmith anvil on a timber stump through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom anvil render">
267-
<img src="../assets/anvil-hero.webp" alt="anvil render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A black iron anvil mounted on a hooped timber stump.">
267+
<img src="../assets/anvil-hero.webp" alt="A black iron anvil mounted on a hooped timber stump." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the showcase piece itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Recomputed: 2988 tris, two materials with 1040 wood and 822 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.621×0.414×0.489 m, LOD ratios in band, convex collider 134 tris, hygiene 0, 16 grounded staves, hoop bite 0.003 m, foot-on-head gap 0.003 m, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-staves 16; --float-anvil 17; --round-band 18.</div>
@@ -1672,7 +1672,7 @@ <h2>Source</h2>
16721672
</main>
16731673
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
16741674
<button class="lightbox-close" type="button" autofocus>Close</button>
1675-
<img src="../assets/anvil-hero.webp" alt="anvil render, full size" />
1675+
<img src="../assets/anvil-hero.webp" alt="A black iron anvil mounted on a hooped timber stump." />
16761676
</dialog>
16771677
<footer>
16781678
<div class="statusbar">

‎docs/gallery/armature-bend/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>armature-bend</h1>
263263
<p>Rigging end to end in the data API — edit_bones chain construction, name-bound vertex groups with smoothstep blend zones, posing, and depsgraph evaluation — bending a tapered tube through rest, half, and full curl.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom armature-bend render">
267-
<img src="../assets/armature-bend-hero.webp" alt="armature-bend render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: Three tapered tubes, coral to amber to teal, standing straight, half curled and fully curled by an armature.">
267+
<img src="../assets/armature-bend-hero.webp" alt="Three tapered tubes, coral to amber to teal, standing straight, half curled and fully curled by an armature." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> edit_bones exists only in edit mode (empty in object mode), vertex groups bind to bones strictly by name, and the armature modifier is exactly linear blend skinning: every evaluated vertex must equal Σ wᵢ·(pose_bone.matrix @ bone.matrix_local.inverted()) @ rest, root ring pinned, tip deflected — a straight tube fails.</div>
@@ -631,7 +631,7 @@ <h2>Source</h2>
631631
</main>
632632
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
633633
<button class="lightbox-close" type="button" autofocus>Close</button>
634-
<img src="../assets/armature-bend-hero.webp" alt="armature-bend render, full size" />
634+
<img src="../assets/armature-bend-hero.webp" alt="Three tapered tubes, coral to amber to teal, standing straight, half curled and fully curled by an armature." />
635635
</dialog>
636636
<footer>
637637
<div class="statusbar">

‎docs/gallery/attribute-domain-shear/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>attribute-domain-shear</h1>
263263
<p>POINT vs CORNER color-attribute domains on a shared-vertex pinwheel: CORNER stays exact per face while a naive per-wedge POINT loop shears to the last write at the hub. Crisp petals versus a smeared swirl in one frame; the measured shear equals the palette closed form.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom attribute-domain-shear render">
267-
<img src="../assets/attribute-domain-shear-hero.webp" alt="attribute-domain-shear render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: Two octagonal rainbow-coloured caps labelled CORNER and POINT, last write wins, showing different colour blending.">
267+
<img src="../assets/attribute-domain-shear-hero.webp" alt="Two octagonal rainbow-coloured caps labelled CORNER and POINT, last write wins, showing different colour blending." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Authoring per-face colors into a POINT-domain attribute overwrites shared vertices once per neighbor; the last write wins and intended colors shear across every shared vertex.</div>
@@ -717,7 +717,7 @@ <h2>Source</h2>
717717
</main>
718718
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
719719
<button class="lightbox-close" type="button" autofocus>Close</button>
720-
<img src="../assets/attribute-domain-shear-hero.webp" alt="attribute-domain-shear render, full size" />
720+
<img src="../assets/attribute-domain-shear-hero.webp" alt="Two octagonal rainbow-coloured caps labelled CORNER and POINT, last write wins, showing different colour blending." />
721721
</dialog>
722722
<footer>
723723
<div class="statusbar">

‎docs/gallery/bake-normal-high-to-low/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>bake-normal-high-to-low</h1>
263263
<p>A collapse-decimated hatch plate receiving a Cycles cage-baked tangent normal map from a ribbed high-poly source</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom bake-normal-high-to-low render">
267-
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="bake-normal-high-to-low render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A baked tangent-space normal map shown as a lilac card beside a bronze plate wearing it, with a radial embossed pattern.">
267+
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="A baked tangent-space normal map shown as a lilac card beside a bronze plate wearing it, with a radial embossed pattern." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Statistical gates not byte-identity: detail frac 0.7211 / MAD 0.09356 vs flat 0.0000 / 0.00277; --flat-source exits 5; type=NORMAL not bake_type; RNA identical on 4.5.11, 5.1.2, 5.2.1</div>
@@ -835,7 +835,7 @@ <h2>Source</h2>
835835
</main>
836836
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
837837
<button class="lightbox-close" type="button" autofocus>Close</button>
838-
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="bake-normal-high-to-low render, full size" />
838+
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="A baked tangent-space normal map shown as a lilac card beside a bronze plate wearing it, with a radial embossed pattern." />
839839
</dialog>
840840
<footer>
841841
<div class="statusbar">

‎docs/gallery/bmesh-gear/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>bmesh-gear</h1>
263263
<p>A 14-tooth gear built entirely with bmesh — profile ring, face, extrude — with bm.free() in a try/finally, exactly as the ownership contract demands.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom bmesh-gear render">
267-
<img src="../assets/bmesh-gear-hero.webp" alt="bmesh-gear render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves.">
267+
<img src="../assets/bmesh-gear-hero.webp" alt="A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Parametric bmesh topology is exactly predictable: verts, edges, and faces match their closed forms, and every edge borders exactly two faces (watertight).</div>
@@ -526,7 +526,7 @@ <h2>Source</h2>
526526
</main>
527527
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
528528
<button class="lightbox-close" type="button" autofocus>Close</button>
529-
<img src="../assets/bmesh-gear-hero.webp" alt="bmesh-gear render, full size" />
529+
<img src="../assets/bmesh-gear-hero.webp" alt="A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves." />
530530
</dialog>
531531
<footer>
532532
<div class="statusbar">

‎docs/gallery/campfire/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>campfire</h1>
263263
<p>A procedural campfire through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom campfire render">
267-
<img src="../assets/campfire-hero.webp" alt="campfire render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A campfire of crossed logs in a teepee inside a ring of grey stone blocks.">
267+
<img src="../assets/campfire-hero.webp" alt="A campfire of crossed logs in a teepee inside a ring of grey stone blocks." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the showcase piece itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Recomputed: 2200 tris, three materials with 216 wood, 48 ash and 1304 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.807×0.808×0.404 m, LOD ratios in band, convex collider 198 tris, hygiene 0, 14 grounded bottom stones, teepee kiss 0.00001 m, course seat 0, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z/--short-stones 16; --float-logs 17; --gap-courses 18.</div>
@@ -1493,7 +1493,7 @@ <h2>Source</h2>
14931493
</main>
14941494
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
14951495
<button class="lightbox-close" type="button" autofocus>Close</button>
1496-
<img src="../assets/campfire-hero.webp" alt="campfire render, full size" />
1496+
<img src="../assets/campfire-hero.webp" alt="A campfire of crossed logs in a teepee inside a ring of grey stone blocks." />
14971497
</dialog>
14981498
<footer>
14991499
<div class="statusbar">

‎docs/gallery/car-mirror-symmetry/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>car-mirror-symmetry</h1>
263263
<p>A generic hatchback lofted as one half (14 stations, 9-point rings) and completed by the Mirror modifier, evaluated through the depsgraph. Wheels and lamps mirror about object origins parked on the symmetry plane.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom car-mirror-symmetry render">
267-
<img src="../assets/car-mirror-symmetry-hero.webp" alt="car-mirror-symmetry render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A red low-poly hatchback with white headlights, modelled as one mirrored half.">
267+
<img src="../assets/car-mirror-symmetry-hero.webp" alt="A red low-poly hatchback with white headlights, modelled as one mirrored half." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Mirror is a modifier, not applied data: the original keeps the authored half while the evaluated mesh is the welded, watertight, exactly symmetric whole.</div>
@@ -844,7 +844,7 @@ <h2>Source</h2>
844844
</main>
845845
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
846846
<button class="lightbox-close" type="button" autofocus>Close</button>
847-
<img src="../assets/car-mirror-symmetry-hero.webp" alt="car-mirror-symmetry render, full size" />
847+
<img src="../assets/car-mirror-symmetry-hero.webp" alt="A red low-poly hatchback with white headlights, modelled as one mirrored half." />
848848
</dialog>
849849
<footer>
850850
<div class="statusbar">

‎docs/gallery/cart/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ <h1>cart</h1>
263263
<p>A procedural two-wheel wooden cart through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
264264
</header>
265265
<main id="main">
266-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom cart render">
267-
<img src="../assets/cart-hero.webp" alt="cart render" width="1280" height="720" />
266+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A two-wheeled wooden cart with spoked wheels, an open box bed and long shafts resting on the floor.">
267+
<img src="../assets/cart-hero.webp" alt="A two-wheeled wooden cart with spoked wheels, an open box bed and long shafts resting on the floor." width="1280" height="720" />
268268
</button>
269269
<p class="zoom-hint">Rendered headless by the showcase piece itself — click to zoom.</p>
270270
<div class="callout"><span class="tag">witnesses</span> Recomputed: 2856 tris, two materials with metal and wood face floors, UVs in 0..1 with zero AABB overlap, outer AABB 1.539×0.749×0.640 m, LOD ratios in band, convex collider 154 tris, hygiene zero (loose, non-manifold, doubles, n-gons), zero coplanar cross-shell face pairs, both tyres grounded, tyre seat depth in band over 48 angular stations, the two wheels mirrored within 5e-5 m, grounded zmin, non-empty glTF. --flush-tyre exits 15 on the z-fight budget; --sink-tyre exits 18 on the tyre seat band; --float-wheel exits 16 on the named-support budget; --skew-wheel exits 19 on the wheel mirror; --skip-decimate exits 9 on the LOD1 ratio budget; --lift-z exits 16 on the grounded budget.</div>
@@ -1695,7 +1695,7 @@ <h2>Source</h2>
16951695
</main>
16961696
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
16971697
<button class="lightbox-close" type="button" autofocus>Close</button>
1698-
<img src="../assets/cart-hero.webp" alt="cart render, full size" />
1698+
<img src="../assets/cart-hero.webp" alt="A two-wheeled wooden cart with spoked wheels, an open box bed and long shafts resting on the floor." />
16991699
</dialog>
17001700
<footer>
17011701
<div class="statusbar">

0 commit comments

Comments
 (0)