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
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- UV atlas pack witness — lightmap/unique UV island packing with non-overlap + utilization closed forms (deferred behind hygiene/origin; overlaps `uv-layer-grid` / `triangulate-tangents` / `gltf-export-roundtrip` UV arc)
- Attribute domain witness: writing a POINT-domain color attribute and reading it as if it were CORNER (or vice versa) silently shears colors across shared verts — companion to `color-attribute-wheel`

- Gallery framing defect worklist (from the #107 survey; restage + re-render into the 0.70–0.90 band with all margins ≥ 0.02, then wire `examples/gallery_framing.py`'s `check_framing`): **depsgraph-export** (fill 0.984x over; left cube clipped by left+bottom edges), **driver-wave** (0.969x over; side margins 0.016), **shader-node-group** (0.969x over; side margins 0.016), **swatch-grid** (0.944y over, marginal), **gp-lineart-contour** (0.978y over; glass base cropped at bottom edge), **png-exr-alpha** (display plinth touches bottom edge, minor), **vertex-weight-limit** (base cropped at bottom edge; x-fill 0.247 with dead space), **text-version-stamp** (max fill 0.663 under; dead lower third), **triangulate-tangents** (0.334x/0.661y under; dead space both sides), **curve-bevel-arc** (right cap margin 0.012 < 0.02, marginal). Triaged as documented deviations instead (README `Framing deviation` notes, no restage): damped-track-aim (radiating composition, calibration member) and wave-displace (edge-to-edge field); sky-texture-sun-elevation is a measurement artifact (world-contract subject — report-only if wired); vse-cut-list is in scope via its `Bay` scene/camera pair.
- Gallery framing recomposition worklist (corrected survey after the survey scene-capture fix; these need real reframing, not a camera nudge — the seven marginal cases were swept mechanically and wired to `check_framing`): **depsgraph-export** (fill 0.984x over; left cube amputated by left+bottom edges — unclipping it changes the composition substantially), **vertex-weight-limit** (fill 0.247x/0.861y; base cropped at bottom edge, off-center with dead space left), **text-version-stamp** (max fill 0.663 under; dead lower third — needs vertical rebalance), **triangulate-tangents** (fill 0.334x/0.661y under; buckler small in a large stage, needs a 2x-class move-in). Already handled: the seven marginal cases (curve-bevel-arc, png-exr-alpha, swatch-grid, driver-wave, shader-node-group, gp-lineart-contour, vse-cut-list) were camera-nudged into the band and gated; deviations documented in #108 (damped-track-aim, wave-displace); sky-texture-sun-elevation is a measurement artifact (world subject — report-only if wired).

## Future (uncommitted)

Expand Down
Binary file modified docs/gallery/assets/curve-bevel-arc-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gallery/assets/driver-wave-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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.
Binary file modified docs/gallery/assets/png-exr-alpha-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gallery/assets/shader-node-group-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gallery/assets/swatch-grid-hero.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gallery/assets/vse-cut-list-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.
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.
Binary file modified docs/gallery/contact-sheets/png-exr-alpha-contact-sheet.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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gallery/contact-sheets/vse-cut-list-contact-sheet.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 24 additions & 5 deletions docs/gallery/curve-bevel-arc/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ <h2>Run</h2>
blender --background --python curve_bevel_arc.py -- --output arc.png
blender --background --python curve_bevel_arc.py -- --output arc.png --engine cycles</code></pre>
<p>It exits non-zero on failure (wrong point count, bevel, caps, topology, or span). The <code>blender-smoke</code> workflow runs the check on Blender 4.5 LTS and 5.1.</p>
<p>The <code>--output</code> render path additionally measures framing against the Layer 1 band via <code>examples/gallery_framing.py</code> (exit 10 on violation) before writing the still.</p>
</section>
<section class="detail-section src">
<h2>Source</h2>
Expand All @@ -219,6 +220,11 @@ <h2>Source</h2>
&quot;&quot;&quot;</span>
<span class="k">import</span> bpy, bmesh, sys, os, math, argparse

<span class="c"># Shared Layer 1 framing measurement (render path only) — see gallery_framing.py</span>
sys.path.insert(<span class="n">0</span>, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
sys.dont_write_bytecode = <span class="k">True</span> <span class="c"># keep examples/__pycache__ out of the repo tree</span>
<span class="k">import</span> gallery_framing

N_POINTS = <span class="n">8</span>
RADIUS = <span class="n">1.5</span>
BEVEL = <span class="n">0.15</span>
Expand Down Expand Up @@ -383,7 +389,7 @@ <h2>Source</h2>
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
cam_data.lens = <span class="n">50.0</span>
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
cam.location = (<span class="n">2.4</span>, -<span class="n">3.4</span>, <span class="n">1.7</span>)
cam.location = (<span class="n">2.55</span>, -<span class="n">3.62</span>, <span class="n">1.78</span>)
scene.collection.objects.link(cam)
scene.camera = cam
track = cam.constraints.new(<span class="s">&#x27;TRACK_TO&#x27;</span>)
Expand All @@ -405,8 +411,21 @@ <h2>Source</h2>
scene.render.filepath = path
<span class="c"># AgX would wash the rose tube toward salmon (docs/VISUAL-STYLE.md)</span>
scene.view_settings.view_transform = <span class="s">&#x27;Standard&#x27;</span>
<span class="c"># Layer 1 framing gate (silhouette matte) — exit 10 on violation, before</span>
<span class="c"># the beauty render so a defective composition ships no artifact.</span>
fcode = gallery_framing.check_framing(
scene, cam,
hero=[obj],
elements=[obj],
stage=[floor, wall],
)
<span class="k">if</span> fcode:
<span class="k">return</span> fcode
bpy.ops.render.render(write_still=<span class="k">True</span>)
<span class="k">return</span> os.path.exists(path) <span class="k">and</span> os.path.getsize(path) &gt; <span class="n">0</span>
<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>):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">11</span>
<span class="k">return</span> <span class="n">0</span>


<span class="k">def</span> main():
Expand All @@ -423,9 +442,9 @@ <h2>Source</h2>
<span class="k">return</span> code

<span class="k">if</span> args.output:
<span class="k">if</span> <span class="k">not</span> render_still(obj, os.path.abspath(args.output), args.engine):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">11</span>
rcode = render_still(obj, os.path.abspath(args.output), args.engine)
<span class="k">if</span> rcode:
<span class="k">return</span> rcode
print(<span class="s">f&quot;</span><span class="s">rendered still </span>{args.output}<span class="s">&quot;</span>)

print(<span class="s">&quot;curve-bevel-arc OK&quot;</span>)
Expand Down
29 changes: 24 additions & 5 deletions docs/gallery/driver-wave/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ <h2>Run</h2>
blender --background --python driver_wave.py -- --output driver.png
blender --background --python driver_wave.py -- --output driver.png --engine cycles</code></pre>
<p>It exits non-zero on failure (driven value wrong, or the flush-back disagreed). The <code>blender-smoke</code> workflow runs the check on Blender 4.5 LTS and 5.1.</p>
<p>The <code>--output</code> render path additionally measures framing against the Layer 1 band via <code>examples/gallery_framing.py</code> (exit 10 on violation) before writing the still.</p>
</section>
<section class="detail-section src">
<h2>Source</h2>
Expand All @@ -219,6 +220,11 @@ <h2>Source</h2>
&quot;&quot;&quot;</span>
<span class="k">import</span> bpy, bmesh, sys, os, math, argparse

<span class="c"># Shared Layer 1 framing measurement (render path only) — see gallery_framing.py</span>
sys.path.insert(<span class="n">0</span>, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
sys.dont_write_bytecode = <span class="k">True</span> <span class="c"># keep examples/__pycache__ out of the repo tree</span>
<span class="k">import</span> gallery_framing

COUNT = <span class="n">16</span>
SPACING = <span class="n">0.72</span>
BASE = <span class="n">0.28</span>
Expand Down Expand Up @@ -347,7 +353,7 @@ <h2>Source</h2>
<span class="c"># the frame with a small margin -- the skyline must not clip</span>
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>); cam_data.lens = <span class="n">42.0</span>
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
cam.location = (<span class="n">0.0</span>, -<span class="n">13.5</span>, <span class="n">2.0</span>)
cam.location = (<span class="n">0.0</span>, -<span class="n">15.0</span>, <span class="n">2.0</span>)
cam.rotation_euler = (math.radians(<span class="n">86</span>), <span class="n">0.0</span>, <span class="n">0.0</span>)
scene.collection.objects.link(cam)
scene.camera = cam
Expand All @@ -366,8 +372,21 @@ <h2>Source</h2>
scene.render.filepath = path
<span class="c"># AgX would wash the orange columns toward tan (docs/VISUAL-STYLE.md)</span>
scene.view_settings.view_transform = <span class="s">&#x27;Standard&#x27;</span>
<span class="c"># Layer 1 framing gate (silhouette matte) — exit 10 on violation, before</span>
<span class="c"># the beauty render so a defective composition ships no artifact.</span>
fcode = gallery_framing.check_framing(
scene, cam,
hero=list(objs),
elements=list(objs),
stage=[floor, wall],
)
<span class="k">if</span> fcode:
<span class="k">return</span> fcode
bpy.ops.render.render(write_still=<span class="k">True</span>)
<span class="k">return</span> os.path.exists(path) <span class="k">and</span> os.path.getsize(path) &gt; <span class="n">0</span>
<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>):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">6</span>
<span class="k">return</span> <span class="n">0</span>


<span class="k">def</span> main():
Expand All @@ -384,9 +403,9 @@ <h2>Source</h2>
<span class="k">return</span> code

<span class="k">if</span> args.output:
<span class="k">if</span> <span class="k">not</span> render_still(objs, os.path.abspath(args.output), args.engine):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">6</span>
rcode = render_still(objs, os.path.abspath(args.output), args.engine)
<span class="k">if</span> rcode:
<span class="k">return</span> rcode
print(<span class="s">f&quot;</span><span class="s">rendered still </span>{args.output}<span class="s">&quot;</span>)

print(<span class="s">&quot;driver-wave OK&quot;</span>)
Expand Down
35 changes: 30 additions & 5 deletions docs/gallery/gp-lineart-contour/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ <h2>Run</h2>
# Also render the gallery still:
blender --background --python gp_lineart_contour.py -- --output lineart.png</code></pre>
<p>It exits non-zero on failure. The <code>blender-smoke</code> workflow runs the check on Blender 4.5 LTS and 5.1.</p>
<p>The <code>--output</code> render path additionally measures framing against the Layer 1 band via <code>examples/gallery_framing.py</code> (exit 10 on violation) before writing the still.</p>
</section>
<section class="detail-section src">
<h2>Source</h2>
Expand Down Expand Up @@ -227,6 +228,11 @@ <h2>Source</h2>
blender --background --python gp_lineart_contour.py -- --output l.png
&quot;&quot;&quot;</span>
<span class="k">import</span> bpy, bmesh, sys, os, math, argparse

<span class="c"># Shared Layer 1 framing measurement (render path only) — see gallery_framing.py</span>
sys.path.insert(<span class="n">0</span>, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
sys.dont_write_bytecode = <span class="k">True</span> <span class="c"># keep examples/__pycache__ out of the repo tree</span>
<span class="k">import</span> gallery_framing
<span class="k">from</span> mathutils <span class="k">import</span> Matrix

<span class="c"># Faceted crystal (octahedron-ish) — enough silhouette edges to read at thumbnail</span>
Expand Down Expand Up @@ -353,7 +359,7 @@ <h2>Source</h2>
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
cam_data.lens = <span class="n">50.0</span>
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
cam.location = (<span class="n">3.4</span>, -<span class="n">4.2</span>, <span class="n">2.4</span>)
cam.location = (<span class="n">3.95</span>, -<span class="n">4.9</span>, <span class="n">2.62</span>)
sc.collection.objects.link(cam)
sc.camera = cam
aim = bpy.data.objects.new(<span class="s">&quot;Aim&quot;</span>, <span class="k">None</span>)
Expand Down Expand Up @@ -571,8 +577,27 @@ <h2>Source</h2>
sc.render.image_settings.file_format = <span class="s">&quot;PNG&quot;</span>
sc.render.filepath = path
sc.view_settings.view_transform = <span class="s">&quot;Standard&quot;</span>
<span class="c"># Layer 1 framing gate (silhouette matte) — exit 10 on violation, before</span>
<span class="c"># the beauty render so a defective composition ships no artifact. The two</span>
<span class="c"># renderable subjects are the crystal source mesh and the GP stroke object.</span>
stage = [o <span class="k">for</span> o <span class="k">in</span> sc.objects <span class="k">if</span> o.name <span class="k">in</span> {<span class="s">&quot;Floor&quot;</span>, <span class="s">&quot;Wall&quot;</span>}]
hero = [
o <span class="k">for</span> o <span class="k">in</span> sc.objects
<span class="k">if</span> o.type <span class="k">in</span> {<span class="s">&quot;MESH&quot;</span>, <span class="s">&quot;GREASEPENCIL&quot;</span>} <span class="k">and</span> o <span class="k">not</span> <span class="k">in</span> stage
]
fcode = gallery_framing.check_framing(
sc, sc.camera,
hero=hero,
elements=hero,
stage=stage,
)
<span class="k">if</span> fcode:
<span class="k">return</span> fcode
bpy.ops.render.render(write_still=<span class="k">True</span>)
<span class="k">return</span> os.path.exists(path) <span class="k">and</span> os.path.getsize(path) &gt; <span class="n">0</span>
<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>):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">8</span>
<span class="k">return</span> <span class="n">0</span>


<span class="k">def</span> build_scene():
Expand Down Expand Up @@ -604,9 +629,9 @@ <h2>Source</h2>
<span class="k">return</span> code

<span class="k">if</span> args.output:
<span class="k">if</span> <span class="k">not</span> render_still(sc, os.path.abspath(args.output), args.engine):
print(<span class="s">&quot;ERROR: render produced no file&quot;</span>, file=sys.stderr)
<span class="k">return</span> <span class="n">8</span>
rcode = render_still(sc, os.path.abspath(args.output), args.engine)
<span class="k">if</span> rcode:
<span class="k">return</span> rcode
print(<span class="s">f&quot;</span><span class="s">rendered still </span>{args.output}<span class="s">&quot;</span>)

print(<span class="s">&quot;gp-lineart-contour OK&quot;</span>)
Expand Down
Loading
Loading