Skip to content

Commit 60506e8

Browse files
TMHSDigitalclaude
andcommitted
fix(showcase): all 76 pieces run the asset-quality floors; lint enforces it
showcase/README.md makes check_asset_quality part of the asset gate, but 37 of 76 pieces never called it, including wheelbarrow and apothecary-shelf from the pinned asset-quality reference set, and 9 pieces added after the rule landed. - Each of the 37 now imports gallery_asset_quality and calls check_asset_quality right after its framing gate, with the hero and stage copied from that piece's own check_framing call. The helper's 11 is remapped to the piece's next free exit (20-26, computed from its README table and every int it already returns), and the README exit table gains that row. - tests/check_render_gates.py also fails any showcase/*/*.py that does not import gallery_asset_quality and call check_asset_quality. 76/76 pass; removing the call from sundial reports it. - examples/gallery_asset_quality.py: the report printed "aq_materials ... FAIL" when only the dominant-material share exceeded 0.75, while the gate (correctly) passed and printed aq_ok. Dominant share is a dropped floor (docs/VISUAL-STYLE.md § Asset quality, printed as information), so the line now marks the material count and labels the share informational-only. Gate behavior unchanged. - showcase/README.md names the lint; gallery pages regenerated for the inlined source. Proof (local, .scratch/blender-5.2.1-windows-x64, 5.2.1 LTS, EEVEE): each of the 37 rendered via its README --output command: 37/37 exit 0 with aq_ok (fence-kit's FenceWood@1.00 dominant share is the informational line above). No floor bound, so no model needed fixing and no exemption was recorded; the committed heroes are unchanged because the gates only run before the render. Closes #341 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent cf881a7 commit 60506e8

114 files changed

Lines changed: 765 additions & 157 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.

‎docs/gallery/anvil/index.html‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ <h2 id="run">Run<a class="anchor" href="#run" aria-label="Link to this section">
9898
<p>Smoke passes no flags.</p>
9999
<h2 id="exit-codes">Exit codes<a class="anchor" href="#exit-codes" aria-label="Link to this section">#</a></h2>
100100
<p>File-local. <code>9</code> is a valid check code. <code>10</code> is reserved for <code>gallery_framing.check_framing</code> on the <code>--output</code> path. <code>15</code>–<code>19</code> are the hygiene and joint-fit family.</p>
101-
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td>Mesh did not build / no UV layer</td></tr><tr><td>4</td><td>Base triangle count outside range</td></tr><tr><td>5</td><td>Material count ≠ 2 distinct slots, or a face-count floor missed</td></tr><tr><td>6</td><td>UVs outside 0..1</td></tr><tr><td>7</td><td>UV AABB overlap above tolerance</td></tr><tr><td>8</td><td>World AABB off declared outer size</td></tr><tr><td>9</td><td>LOD ratio band (<code>--skip-decimate</code> lands here)</td></tr><tr><td>10</td><td>Framing gate (render path only)</td></tr><tr><td>11</td><td>Collider triangle count above ceiling</td></tr><tr><td>12</td><td>Bake did not finish or image has no data</td></tr><tr><td>13</td><td>Export file missing or empty</td></tr><tr><td>14</td><td><code>--output</code> produced no file</td></tr><tr><td>15</td><td>Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight</td></tr><tr><td>16</td><td>Not grounded: bounding box <code>zmin</code> off 0, or a named stave floats</td></tr><tr><td>17</td><td>Joint fit: foot-on-head gap (<code>--float-anvil</code>)</td></tr><tr><td>18</td><td>Seat: hoop bite band (<code>--round-band</code>)</td></tr><tr><td>19</td><td>Body length or height off the stated real-world size, or waist form (<code>--round-waist</code>)</td></tr></tbody></table></div>
101+
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td>Mesh did not build / no UV layer</td></tr><tr><td>4</td><td>Base triangle count outside range</td></tr><tr><td>5</td><td>Material count ≠ 2 distinct slots, or a face-count floor missed</td></tr><tr><td>6</td><td>UVs outside 0..1</td></tr><tr><td>7</td><td>UV AABB overlap above tolerance</td></tr><tr><td>8</td><td>World AABB off declared outer size</td></tr><tr><td>9</td><td>LOD ratio band (<code>--skip-decimate</code> lands here)</td></tr><tr><td>10</td><td>Framing gate (render path only)</td></tr><tr><td>11</td><td>Collider triangle count above ceiling</td></tr><tr><td>12</td><td>Bake did not finish or image has no data</td></tr><tr><td>13</td><td>Export file missing or empty</td></tr><tr><td>14</td><td><code>--output</code> produced no file</td></tr><tr><td>15</td><td>Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight</td></tr><tr><td>16</td><td>Not grounded: bounding box <code>zmin</code> off 0, or a named stave floats</td></tr><tr><td>17</td><td>Joint fit: foot-on-head gap (<code>--float-anvil</code>)</td></tr><tr><td>18</td><td>Seat: hoop bite band (<code>--round-band</code>)</td></tr><tr><td>19</td><td>Body length or height off the stated real-world size, or waist form (<code>--round-waist</code>)</td></tr><tr><td>20</td><td>Gallery asset-quality violation (render path; the floors&#x27; 11 is remapped here)</td></tr></tbody></table></div>
102102
</section>
103103
<section class="detail-section src" id="source">
104104
<h2>Source</h2>
105105
<div class="src-meta">
106106
<code>showcase/anvil/anvil.py</code>
107-
<span>1717 lines &middot; <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/showcase/anvil/anvil.py">View on GitHub &rarr;</a></span>
107+
<span>1722 lines &middot; <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/showcase/anvil/anvil.py">View on GitHub &rarr;</a></span>
108108
</div>
109-
<div class="code" data-lines="1717">
109+
<div class="code" data-lines="1722">
110110
<pre class="gutter" aria-hidden="true">1
111111
2
112112
3
@@ -1823,7 +1823,12 @@ <h2>Source</h2>
18231823
1714
18241824
1715
18251825
1716
1826-
1717</pre><pre class="code-lines"><span class="s">&quot;&quot;&quot;Game-ready blacksmith anvil — a showcase piece, not an example.
1826+
1717
1827+
1718
1828+
1719
1829+
1720
1830+
1721
1831+
1722</pre><pre class="code-lines"><span class="s">&quot;&quot;&quot;Game-ready blacksmith anvil — a showcase piece, not an example.
18271832

18281833
Asserts budget conformance of a procedural London-pattern anvil on a
18291834
coopered timber stump (stave-chord hoops, sawn head, horn/face/heel
@@ -1869,6 +1874,7 @@ <h2>Source</h2>
18691874
sys.path.insert(<span class="n">0</span>, os.path.join(_REPO, <span class="s">&quot;examples&quot;</span>))
18701875
sys.dont_write_bytecode = <span class="k">True</span>
18711876
<span class="k">import</span> gallery_framing <span class="c"># noqa: E402</span>
1877+
<span class="k">import</span> gallery_asset_quality <span class="c"># noqa: E402</span>
18721878

18731879
N_STAVES = <span class="n">16</span>
18741880
STAVE_THICK = <span class="n">0.028</span>
@@ -3493,6 +3499,10 @@ <h2>Source</h2>
34933499
)
34943500
<span class="k">if</span> fcode:
34953501
<span class="k">return</span> fcode
3502+
<span class="c"># asset-quality floors (examples/gallery_asset_quality.py) return 11,</span>
3503+
<span class="c"># which this piece&#x27;s numbering already spends; remap at the call site</span>
3504+
<span class="k">if</span> gallery_asset_quality.check_asset_quality(scene, cam, [low], stage=[floor, wall]):
3505+
<span class="k">return</span> <span class="n">20</span>
34963506
bpy.ops.render.render(write_still=<span class="k">True</span>)
34973507
<span class="k">if</span> <span class="k">not</span> (os.path.exists(path) <span class="k">and</span> os.path.getsize(path) &gt; <span class="n">0</span>):
34983508
<span class="k">return</span> fail(<span class="s">&quot;render produced no file&quot;</span>, <span class="n">14</span>)

‎docs/gallery/apothecary-shelf/index.html‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ <h2 id="falsifiers">Falsifiers<a class="anchor" href="#falsifiers" aria-label="L
8888
<div class="table-wrap"><table><thead><tr><th scope="col">Flag</th><th scope="col">Target budget</th><th scope="col">Breaks</th><th scope="col">Exit</th></tr></thead><tbody><tr><td><code>--skip-decimate</code></td><td>LOD1 ratio</td><td>drops the DECIMATE modifiers, LOD1 ratio goes to 1.0000</td><td>9</td></tr><tr><td><code>--stray-vert</code></td><td>mesh hygiene</td><td>adds one loose vertex inside the carcass</td><td>15</td></tr><tr><td><code>--lift-z</code></td><td>grounded zmin</td><td>lifts the whole mesh 50 mm</td><td>16</td></tr><tr><td><code>--float-side</code></td><td>named sides</td><td>lifts the left side 5 mm; the right side still grounds the AABB</td><td>16</td></tr><tr><td><code>--short-shelves</code></td><td>dado bite</td><td>stops the three shelves 4 mm short of the sides; −4.0 mm</td><td>17</td></tr><tr><td><code>--pop-corks</code></td><td>closure bite</td><td>lifts every cork and lid 10 mm; −5.0 mm</td><td>17</td></tr><tr><td><code>--pull-knobs</code></td><td>knob bite</td><td>pulls every knob 8 mm out of its front; −4.0 mm</td><td>17</td></tr><tr><td><code>--float-jars</code></td><td>vessel seat</td><td>lifts every vessel 6 mm off its shelf; −5.0 to −4.2 mm</td><td>18</td></tr><tr><td><code>--lift-drawers</code></td><td>drawer seat</td><td>lifts the drawer fronts 3 mm; −1.0 mm</td><td>18</td></tr><tr><td><code>--float-labels</code></td><td>label seat</td><td>builds every label 1.1 mm off its body; −1.1 mm</td><td>18</td></tr><tr><td><code>--tall-flask</code></td><td>headroom</td><td>stretches the middle-shelf flask 1.20 into the shelf above; −5.5 mm</td><td>20</td></tr><tr><td><code>--crowd-jars</code></td><td>vessel overlaps</td><td>draws the bottom shelf&#x27;s jars to 0.55 of their spacing; 3 overlaps</td><td>21</td></tr><tr><td><code>--uniform-vessels</code></td><td>form spread</td><td>one radius and height for every vessel; 1.000 / 1.000</td><td>22</td></tr><tr><td><code>--sharp-rail</code></td><td>edge treatment</td><td>leaves the top rail unchamfered; 12 right-angle edges</td><td>23</td></tr></tbody></table></div>
8989
<h2 id="exit-codes">Exit codes<a class="anchor" href="#exit-codes" aria-label="Link to this section">#</a></h2>
9090
<p>File-local and sequential. <code>9</code> is a valid check code. <code>1</code> is the FATAL wrapper — a crash, never a named check. <code>19</code> (plumb and real-world size) is reserved across pieces and unused here.</p>
91-
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td>Mesh did not build, or has no UV layer</td></tr><tr><td>4</td><td>Base triangle count outside band</td></tr><tr><td>5</td><td>Material slots, or a material&#x27;s face floor</td></tr><tr><td>6</td><td>UVs outside 0..1</td></tr><tr><td>7</td><td>UV AABB overlap above tolerance</td></tr><tr><td>8</td><td>Outer AABB off declared size</td></tr><tr><td>9</td><td>LOD1 or LOD2 ratio outside band (<code>--skip-decimate</code>)</td></tr><tr><td>10</td><td>Framing gate (<code>examples/gallery_framing.py</code>, render path only)</td></tr><tr><td>11</td><td>Collider triangles above ceiling</td></tr><tr><td>12</td><td>Normal bake failed or produced no image data</td></tr><tr><td>13</td><td>glTF export missing or empty</td></tr><tr><td>14</td><td><code>--output</code> produced no file</td></tr><tr><td>15</td><td>Mesh hygiene (<code>--stray-vert</code>)</td></tr><tr><td>16</td><td>Grounded zmin, or a side floating (<code>--lift-z</code>, <code>--float-side</code>)</td></tr><tr><td>17</td><td>Dado, closure or knob bite (<code>--short-shelves</code>, <code>--pop-corks</code>, <code>--pull-knobs</code>)</td></tr><tr><td>18</td><td>Vessel, drawer or label seat (<code>--float-jars</code>, <code>--lift-drawers</code>, <code>--float-labels</code>)</td></tr><tr><td>20</td><td>Headroom under the member above (<code>--tall-flask</code>)</td></tr><tr><td>21</td><td>Vessels overlap each other or the carcass (<code>--crowd-jars</code>)</td></tr><tr><td>22</td><td>Form spread below floor (<code>--uniform-vessels</code>)</td></tr><tr><td>23</td><td>Right-angle wood edges (<code>--sharp-rail</code>)</td></tr></tbody></table></div>
91+
<div class="table-wrap"><table><thead><tr><th scope="col">Code</th><th scope="col">Meaning</th></tr></thead><tbody><tr><td>0</td><td>Success</td></tr><tr><td>1</td><td>Uncaught exception (FATAL wrapper)</td></tr><tr><td>2</td><td>argparse / usage</td></tr><tr><td>3</td><td>Mesh did not build, or has no UV layer</td></tr><tr><td>4</td><td>Base triangle count outside band</td></tr><tr><td>5</td><td>Material slots, or a material&#x27;s face floor</td></tr><tr><td>6</td><td>UVs outside 0..1</td></tr><tr><td>7</td><td>UV AABB overlap above tolerance</td></tr><tr><td>8</td><td>Outer AABB off declared size</td></tr><tr><td>9</td><td>LOD1 or LOD2 ratio outside band (<code>--skip-decimate</code>)</td></tr><tr><td>10</td><td>Framing gate (<code>examples/gallery_framing.py</code>, render path only)</td></tr><tr><td>11</td><td>Collider triangles above ceiling</td></tr><tr><td>12</td><td>Normal bake failed or produced no image data</td></tr><tr><td>13</td><td>glTF export missing or empty</td></tr><tr><td>14</td><td><code>--output</code> produced no file</td></tr><tr><td>15</td><td>Mesh hygiene (<code>--stray-vert</code>)</td></tr><tr><td>16</td><td>Grounded zmin, or a side floating (<code>--lift-z</code>, <code>--float-side</code>)</td></tr><tr><td>17</td><td>Dado, closure or knob bite (<code>--short-shelves</code>, <code>--pop-corks</code>, <code>--pull-knobs</code>)</td></tr><tr><td>18</td><td>Vessel, drawer or label seat (<code>--float-jars</code>, <code>--lift-drawers</code>, <code>--float-labels</code>)</td></tr><tr><td>20</td><td>Headroom under the member above (<code>--tall-flask</code>)</td></tr><tr><td>21</td><td>Vessels overlap each other or the carcass (<code>--crowd-jars</code>)</td></tr><tr><td>22</td><td>Form spread below floor (<code>--uniform-vessels</code>)</td></tr><tr><td>23</td><td>Right-angle wood edges (<code>--sharp-rail</code>)</td></tr><tr><td>24</td><td>Gallery asset-quality violation (render path; the floors&#x27; 11 is remapped here)</td></tr></tbody></table></div>
9292
<h2 id="run-it">Run it<a class="anchor" href="#run-it" aria-label="Link to this section">#</a></h2>
9393
<pre><code># Budget check, no render. ~4.5 s on 5.1 and 5.2.
9494
blender --background --python apothecary_shelf.py --
@@ -109,9 +109,9 @@ <h2 id="cross-version-measurements">Cross-version measurements<a class="anchor"
109109
<h2>Source</h2>
110110
<div class="src-meta">
111111
<code>showcase/apothecary-shelf/apothecary_shelf.py</code>
112-
<span>1639 lines &middot; <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/showcase/apothecary-shelf/apothecary_shelf.py">View on GitHub &rarr;</a></span>
112+
<span>1644 lines &middot; <a href="https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/showcase/apothecary-shelf/apothecary_shelf.py">View on GitHub &rarr;</a></span>
113113
</div>
114-
<div class="code" data-lines="1639">
114+
<div class="code" data-lines="1644">
115115
<pre class="gutter" aria-hidden="true">1
116116
2
117117
3
@@ -1750,7 +1750,12 @@ <h2>Source</h2>
17501750
1636
17511751
1637
17521752
1638
1753-
1639</pre><pre class="code-lines"><span class="s">&quot;&quot;&quot;Game-ready apothecary shelf — a showcase piece, not an example.
1753+
1639
1754+
1640
1755+
1641
1756+
1642
1757+
1643
1758+
1644</pre><pre class="code-lines"><span class="s">&quot;&quot;&quot;Game-ready apothecary shelf — a showcase piece, not an example.
17541759

17551760
Asserts budget conformance of a procedural apothecary shelf: a stained
17561761
carcass with housed shelves, gallery rails, a bank of three drawers and a
@@ -1805,6 +1810,7 @@ <h2>Source</h2>
18051810
sys.path.insert(<span class="n">0</span>, os.path.join(_REPO, <span class="s">&quot;examples&quot;</span>))
18061811
sys.dont_write_bytecode = <span class="k">True</span>
18071812
<span class="k">import</span> gallery_framing <span class="c"># noqa: E402</span>
1813+
<span class="k">import</span> gallery_asset_quality <span class="c"># noqa: E402</span>
18081814

18091815
<span class="c"># The carcass. X across, Y front (-) to back (+), Z up. Two full-height</span>
18101816
<span class="c"># sides carry everything; every cross member is housed into both of them.</span>
@@ -3328,6 +3334,10 @@ <h2>Source</h2>
33283334
fcode = gallery_framing.check_framing(scene, cam, hero=[low], elements=[low], stage=[floor, wall])
33293335
<span class="k">if</span> fcode:
33303336
<span class="k">return</span> fcode
3337+
<span class="c"># asset-quality floors (examples/gallery_asset_quality.py) return 11,</span>
3338+
<span class="c"># which this piece&#x27;s numbering already spends; remap at the call site</span>
3339+
<span class="k">if</span> gallery_asset_quality.check_asset_quality(scene, cam, [low], stage=[floor, wall]):
3340+
<span class="k">return</span> <span class="n">24</span>
33313341
bpy.ops.render.render(write_still=<span class="k">True</span>)
33323342
<span class="k">if</span> <span class="k">not</span> (os.path.exists(path) <span class="k">and</span> os.path.getsize(path) &gt; <span class="n">0</span>):
33333343
<span class="k">return</span> fail(<span class="s">&quot;render produced no file&quot;</span>, <span class="n">14</span>)

0 commit comments

Comments
 (0)