Skip to content

Commit 8b3ed95

Browse files
TMHSDigitalclaude
andauthored
fix(gallery): describe each still in its alt text instead of the API it teaches (#221)
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 Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 1ed8c58 commit 8b3ed95

87 files changed

Lines changed: 585 additions & 536 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: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
<meta property="og:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/anvil-hero.webp" />
1717
<meta property="og:image:width" content="1280" />
1818
<meta property="og:image:height" content="720" />
19-
<meta property="og:image:alt" content="anvil: the showcase piece&#x27;s own headless render" />
19+
<meta property="og:image:alt" content="A black iron anvil mounted on a hooped timber stump." />
2020
<meta property="og:site_name" content="Blender Developer Tools" />
2121
<meta name="twitter:card" content="summary_large_image" />
2222
<meta name="twitter:title" content="anvil — Showcase — Blender Developer Tools" />
2323
<meta name="twitter:description" content="A procedural blacksmith anvil on a timber stump through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract." />
2424
<meta name="twitter:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/anvil-hero.webp" />
25-
<meta name="twitter:image:alt" content="anvil: the showcase piece&#x27;s own headless render" />
25+
<meta name="twitter:image:alt" content="A black iron anvil mounted on a hooped timber stump." />
2626
<style>
2727
/* fonts are deployed by the landing build (docs/fonts/) */
2828
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap;
@@ -268,8 +268,8 @@ <h1>anvil</h1>
268268
<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>
269269
</header>
270270
<main id="main">
271-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom anvil render">
272-
<img src="../assets/anvil-hero.webp" alt="anvil render" width="1280" height="720" />
271+
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: A black iron anvil mounted on a hooped timber stump.">
272+
<img src="../assets/anvil-hero.webp" alt="A black iron anvil mounted on a hooped timber stump." width="1280" height="720" />
273273
</button>
274274
<p class="zoom-hint">Rendered headless by the showcase piece itself — click to zoom.</p>
275275
<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>
@@ -1677,7 +1677,7 @@ <h2>Source</h2>
16771677
</main>
16781678
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
16791679
<button class="lightbox-close" type="button" autofocus>Close</button>
1680-
<img src="../assets/anvil-hero.webp" alt="anvil render, full size" />
1680+
<img src="../assets/anvil-hero.webp" alt="A black iron anvil mounted on a hooped timber stump." />
16811681
</dialog>
16821682
<footer>
16831683
<div class="statusbar">

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
<meta property="og:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/armature-bend-hero.webp" />
1717
<meta property="og:image:width" content="1280" />
1818
<meta property="og:image:height" content="720" />
19-
<meta property="og:image:alt" content="armature-bend: the example&#x27;s own headless render" />
19+
<meta property="og:image:alt" content="Three tapered tubes, coral to amber to teal, standing straight, half curled and fully curled by an armature." />
2020
<meta property="og:site_name" content="Blender Developer Tools" />
2121
<meta name="twitter:card" content="summary_large_image" />
2222
<meta name="twitter:title" content="armature-bend — Examples — Blender Developer Tools" />
2323
<meta name="twitter:description" content="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." />
2424
<meta name="twitter:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/armature-bend-hero.webp" />
25-
<meta name="twitter:image:alt" content="armature-bend: the example&#x27;s own headless render" />
25+
<meta name="twitter:image:alt" content="Three tapered tubes, coral to amber to teal, standing straight, half curled and fully curled by an armature." />
2626
<style>
2727
/* fonts are deployed by the landing build (docs/fonts/) */
2828
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap;
@@ -268,8 +268,8 @@ <h1>armature-bend</h1>
268268
<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>
269269
</header>
270270
<main id="main">
271-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom armature-bend render">
272-
<img src="../assets/armature-bend-hero.webp" alt="armature-bend render" width="1280" height="720" />
271+
<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.">
272+
<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" />
273273
</button>
274274
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
275275
<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>
@@ -636,7 +636,7 @@ <h2>Source</h2>
636636
</main>
637637
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
638638
<button class="lightbox-close" type="button" autofocus>Close</button>
639-
<img src="../assets/armature-bend-hero.webp" alt="armature-bend render, full size" />
639+
<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." />
640640
</dialog>
641641
<footer>
642642
<div class="statusbar">

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
<meta property="og:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/attribute-domain-shear-hero.webp" />
1717
<meta property="og:image:width" content="1280" />
1818
<meta property="og:image:height" content="720" />
19-
<meta property="og:image:alt" content="attribute-domain-shear: the example&#x27;s own headless render" />
19+
<meta property="og:image:alt" content="Two octagonal rainbow-coloured caps labelled CORNER and POINT, last write wins, showing different colour blending." />
2020
<meta property="og:site_name" content="Blender Developer Tools" />
2121
<meta name="twitter:card" content="summary_large_image" />
2222
<meta name="twitter:title" content="attribute-domain-shear — Examples — Blender Developer Tools" />
2323
<meta name="twitter:description" content="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." />
2424
<meta name="twitter:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/attribute-domain-shear-hero.webp" />
25-
<meta name="twitter:image:alt" content="attribute-domain-shear: the example&#x27;s own headless render" />
25+
<meta name="twitter:image:alt" content="Two octagonal rainbow-coloured caps labelled CORNER and POINT, last write wins, showing different colour blending." />
2626
<style>
2727
/* fonts are deployed by the landing build (docs/fonts/) */
2828
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap;
@@ -268,8 +268,8 @@ <h1>attribute-domain-shear</h1>
268268
<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>
269269
</header>
270270
<main id="main">
271-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom attribute-domain-shear render">
272-
<img src="../assets/attribute-domain-shear-hero.webp" alt="attribute-domain-shear render" width="1280" height="720" />
271+
<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.">
272+
<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" />
273273
</button>
274274
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
275275
<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>
@@ -722,7 +722,7 @@ <h2>Source</h2>
722722
</main>
723723
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
724724
<button class="lightbox-close" type="button" autofocus>Close</button>
725-
<img src="../assets/attribute-domain-shear-hero.webp" alt="attribute-domain-shear render, full size" />
725+
<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." />
726726
</dialog>
727727
<footer>
728728
<div class="statusbar">

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
<meta property="og:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/bake-normal-high-to-low-hero.webp" />
1717
<meta property="og:image:width" content="1280" />
1818
<meta property="og:image:height" content="720" />
19-
<meta property="og:image:alt" content="bake-normal-high-to-low: the example&#x27;s own headless render" />
19+
<meta property="og:image:alt" content="A baked tangent-space normal map shown as a lilac card beside a bronze plate wearing it, with a radial embossed pattern." />
2020
<meta property="og:site_name" content="Blender Developer Tools" />
2121
<meta name="twitter:card" content="summary_large_image" />
2222
<meta name="twitter:title" content="bake-normal-high-to-low — Examples — Blender Developer Tools" />
2323
<meta name="twitter:description" content="A collapse-decimated hatch plate receiving a Cycles cage-baked tangent normal map from a ribbed high-poly source" />
2424
<meta name="twitter:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/bake-normal-high-to-low-hero.webp" />
25-
<meta name="twitter:image:alt" content="bake-normal-high-to-low: the example&#x27;s own headless render" />
25+
<meta name="twitter:image:alt" content="A baked tangent-space normal map shown as a lilac card beside a bronze plate wearing it, with a radial embossed pattern." />
2626
<style>
2727
/* fonts are deployed by the landing build (docs/fonts/) */
2828
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap;
@@ -268,8 +268,8 @@ <h1>bake-normal-high-to-low</h1>
268268
<p>A collapse-decimated hatch plate receiving a Cycles cage-baked tangent normal map from a ribbed high-poly source</p>
269269
</header>
270270
<main id="main">
271-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom bake-normal-high-to-low render">
272-
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="bake-normal-high-to-low render" width="1280" height="720" />
271+
<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.">
272+
<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" />
273273
</button>
274274
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
275275
<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>
@@ -840,7 +840,7 @@ <h2>Source</h2>
840840
</main>
841841
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
842842
<button class="lightbox-close" type="button" autofocus>Close</button>
843-
<img src="../assets/bake-normal-high-to-low-hero.webp" alt="bake-normal-high-to-low render, full size" />
843+
<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." />
844844
</dialog>
845845
<footer>
846846
<div class="statusbar">

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
<meta property="og:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/bmesh-gear-hero.webp" />
1717
<meta property="og:image:width" content="1280" />
1818
<meta property="og:image:height" content="720" />
19-
<meta property="og:image:alt" content="bmesh-gear: the example&#x27;s own headless render" />
19+
<meta property="og:image:alt" content="A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves." />
2020
<meta property="og:site_name" content="Blender Developer Tools" />
2121
<meta name="twitter:card" content="summary_large_image" />
2222
<meta name="twitter:title" content="bmesh-gear — Examples — Blender Developer Tools" />
2323
<meta name="twitter:description" content="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." />
2424
<meta name="twitter:image" content="https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/bmesh-gear-hero.webp" />
25-
<meta name="twitter:image:alt" content="bmesh-gear: the example&#x27;s own headless render" />
25+
<meta name="twitter:image:alt" content="A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves." />
2626
<style>
2727
/* fonts are deployed by the landing build (docs/fonts/) */
2828
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap;
@@ -268,8 +268,8 @@ <h1>bmesh-gear</h1>
268268
<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>
269269
</header>
270270
<main id="main">
271-
<button class="detail-hero" id="heroZoom" type="button" aria-label="Zoom bmesh-gear render">
272-
<img src="../assets/bmesh-gear-hero.webp" alt="bmesh-gear render" width="1280" height="720" />
271+
<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.">
272+
<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" />
273273
</button>
274274
<p class="zoom-hint">Rendered headless by the example itself — click to zoom.</p>
275275
<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>
@@ -531,7 +531,7 @@ <h2>Source</h2>
531531
</main>
532532
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
533533
<button class="lightbox-close" type="button" autofocus>Close</button>
534-
<img src="../assets/bmesh-gear-hero.webp" alt="bmesh-gear render, full size" />
534+
<img src="../assets/bmesh-gear-hero.webp" alt="A gold fourteen-tooth gear lying at an angle, its face covered in concentric grooves." />
535535
</dialog>
536536
<footer>
537537
<div class="statusbar">

0 commit comments

Comments
 (0)