Skip to content

fix: corrected framing survey + marginal camera-nudge sweep (7 examples)#109

Merged
TMHSDigital merged 9 commits into
mainfrom
fix/framing-survey-marginal-sweep
Jul 22, 2026
Merged

fix: corrected framing survey + marginal camera-nudge sweep (7 examples)#109
TMHSDigital merged 9 commits into
mainfrom
fix/framing-survey-marginal-sweep

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Corrected framing survey + floor sanity-check + mechanical marginal sweep

Follow-up to #107/#108. Three parts: fix the survey's scene resolution and re-measure everything, sanity-check the 0.02 margin floor against the calibration set, then camera-nudge only the genuinely marginal cases into the band and wire check_framing into them as the acceptance gate. Recomposition cases deferred to the ROADMAP worklist.

Part 1 — the survey bug and its fix

Bug: the #107 survey measured each example against bpy.context.scene after main() returned. Any example that stills from a non-context scene was measured against the wrong scene. vse-cut-list renders its hero from a dedicated Bay scene via bpy.ops.render.render(..., scene=sc.name) — it was reported "unsurveyable" when it was actually mis-surveyed.

Fix: the corrected survey registers a persistent bpy.app.handlers.render_pre handler (persistent because examples call read_factory_settings, which clears plain handlers), records every (scene, camera) render each example issues, and measures the last render — the gallery still. A shipped helper bug fell out of the same root cause: _matte_render rendered the active scene, so a passed non-context scene would have been matte-measured wrong too. gallery_framing._matte_render now renders the scene it was handed (same scene= idiom vse-cut-list uses); both current callers measure unchanged (0.803/0.733 on 5.1.2 and 4.5.11).

Old vs corrected table (silhouette, union-of-renderables): all 38 examples re-measured; 37 of 38 identical to the old table (they render from the context scene). The one change:

example old corrected note
vse-cut-list unsurveyable (context scene had no camera) fill 0.772x/1.000y, margins L0.113 R0.116 B0.000 T0.000, touch bottom+top measured against the wrong scene before; genuinely out of band — monitor top cropped, desk bleeding bottom

World/atmosphere example (sky-texture-sun-elevation) measures identically (0.369x/0.489y) — the #108 artifact classification stands. No previously-measured classification changed.

Part 2 — floor decision: keep 0.02

Calibration evidence (corrected survey): armature-bend min margin 0.039, bmesh-gear min 0.033; damped-track-aim sits at 0.0 but is a documented deviation (#108), not an enforcing reference. Across the accepted in-band corpus the tightest margin anywhere is 0.028 (shape-key-blend, gn-instance-grid). The enforcing reference standard clears the floor by ≥ 65 %, the corpus by ≥ 40 %, and nothing accepted lives in the 0.013–0.019 gap — 0.02 cleanly separates accepted work from curve-bevel-arc's 0.012 near-contact. Unlike damped-track-aim (which tripped the fill rule by design), no reference member trips the margin floor, so the floor stands. MARGIN_MIN stays 0.02; no constant change, no re-floored survey needed.

Part 3 — mechanical sweep (7 examples, camera-only)

Per-example before → after (corrected-survey numbers → gated render numbers, 5.1.2; 4.5.11 identical unless noted):

example before after nudge
curve-bevel-arc R margin 0.012; fill 0.784x/0.683y fill 0.738x/0.633y, margins L0.219 R0.044 B0.083 T0.283 cam (2.4,-3.4,1.7)→(2.55,-3.62,1.78)
driver-wave fill 0.969x over; margins 0.016 0.869x/0.333y, L/R 0.066 cam y -13.5→-15.0
shader-node-group fill 0.969x over; margins 0.016 0.869x/0.650y, L/R 0.066 cam y -7.8→-8.7
swatch-grid fill 0.944y over 0.769x/0.878y, L/R 0.116 B/T 0.061 ortho_scale 7.8→8.4
png-exr-alpha touch B 0.000 0.725x/0.628y, B 0.028 aim z 1.65→1.38 (a pull-back overshot under-band; pitch only)
gp-lineart-contour fill 0.978y over; touch B 0.463x/0.867y, B 0.044 cam (3.4,-4.2,2.4)→(3.95,-4.9,2.62)
vse-cut-list fill 1.000y; touch B+T 0.506x/0.850y, B 0.067 T 0.083 BayCam (2.0,-5.2,1.72)→(3.05,-7.9,2.0), aim z 1.28→1.20

All seven are wired to check_framing (exit 10, before the beauty render) as the acceptance gate. No check code or closed forms changed: swatch-grid's verify_png third/half cell sampling tolerates the new ortho_scale (confirmed distinct_regions=6 at both the default and the exact smoke invocation --engine cycles --samples 8 --width 640, both versions); every other example's printed check values are unchanged. vse-cut-list was the most-broken (frame-filling before), so its composition change is the largest — still camera-only; anything needing recomposition was deferred.

Deferred to the ROADMAP recomposition worklist: depsgraph-export (0.984x, cube amputated), vertex-weight-limit (0.247x/0.861y, off-center, base cropped), text-version-stamp (0.663 max, dead lower third), triangulate-tangents (0.334x/0.661y, 2×-class move-in). ROADMAP updated accordingly.

Falsification (each new gate proven to fail, then restored)

curve-bevel-arc lens 65 → margins FAIL, exit 10. driver-wave lens 55 → fill 0.994, exit 10. shader-node-group lens 72 → fill 1.000, exit 10. swatch-grid ortho_scale 6.5 → fill 1.000, exit 10. png-exr-alpha lens 64 → fill 0.916, exit 10. gp-lineart-contour lens 62 → fill 1.000, exit 10. vse-cut-list lens 66 → fill 1.000, exit 10. All: no artifact written on violation; all restored (diff-verified).

Contact sheets (Pass 5)

Each pairs the candidate with the pinned set (armature-bend 70.8, damped-track-aim 44.5, bmesh-gear 77.7 mean luminance; reading order TL→BR, candidate last):

  • curve-bevel-arc — 48.6 ✓ in range
  • driver-wave — 55.7 ✓ in range
  • shader-node-group — 89.2, above range: its lighter studio variant (0.055 floor vs 0.03 house) predates this camera-only pass — flagged as information, not altered here
  • swatch-grid — 82.1, marginally above range (bright swatches by design; pre-existing)
  • png-exr-alpha — 68.2 ✓ in range
  • gp-lineart-contour — 47.7 ✓ in range
  • vse-cut-list — 54.3 ✓ in range; subject presence lower than calibration but in family with the bay/monitor examples

Per-criterion verdicts: stage darkness, wedge warmth, saturation, and thumbnail legibility ✓ for all seven (no lighting or material touched); subject fill now band-consistent for all seven.

Visual-pass log (per touched example)

  • Pass 1 (full size + helper numbers): one nudge iteration each except png-exr-alpha (2 — first pull-back overshot under-band), gp-lineart-contour (2 — first stop landed y at exactly 0.900, on the ceiling), vse-cut-list (3 — desk's near corner needed distance and aim drop). All final renders reviewed at full size; compositions preserved.
  • Pass 2 (thumbnail, 400 px): all seven read instantly; vse-cut-list is the weakest but legible and in family.
  • Pass 3 (100 % edge crops): no clipping, no blown highlights, no visible helpers on any of the seven.
  • Pass 4 (Playwright, full-page captures per the scroll-anchoring note): gallery index at 1280 and 390 + all seven detail pages — new heroes, teaches, witnesses, and the new framing-gate README line all render correctly; generated HTML read character by character (img alts complete, no truncation artifacts).
  • Pass 5: sheets above.

Runtime

  • Check-only (the smoke invocations) for all touched examples, both binaries: exit 0; timings sub-second to ~2.6 s (vse-cut-list --check-pixels renders tiny frames as before) — unchanged code paths.
  • swatch-grid's smoke step already renders; the gate adds two 320×180 8-sample mattes (~2 s) to that one existing render step. All other smoke steps are check-only and untouched.
  • Local binaries: .scratch/blender-5.1.2-windows-x64/blender.exe (reports Blender 5.1.2), .scratch/blender-4.5.11-windows-x64/blender.exe (reports Blender 4.5.11 LTS). CI floats within series (per CLAUDE.md); its jobs may run a newer 4.5.x point release.

Live-run vs inspection-only

  • Live run (5.1.2): corrected 38-example survey, all seven nudge renders + gate, all seven falsification probes, webp conversion, contact sheets, gallery regen, Playwright captures.
  • Live run (4.5.11): all seven render paths + check-only; swatch smoke-style render; framing numbers identical unless noted (gp-lineart 0.469x vs 0.463x — GP stroke rasterization; inside band).
  • Inspection only: that the corrected survey's union-of-renderables fill approximates per-example hero fill (placards are small); that CI smoke runtimes track local timings.

_matte_render called bpy.ops.render.render(write_still=True) bare, which
renders the ACTIVE context scene — silently wrong for any example that
stills from a non-context scene (vse-cut-list renders its gallery hero
from a dedicated Bay scene via the operator's scene= kwarg). The matte
now renders the scene it was handed, matching that idiom. Both current
callers use the context scene and measure unchanged (0.803/0.733 on
5.1.2 and 4.5.11); the corrected survey that exposed this now captures
each example's rendered scene via a persistent render_pre handler and
re-measured all 38 examples against the scene and camera each actually
renders from.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
Right cap sat 0.012 from the right edge, under the 0.02 floor. Camera
moves from (2.4,-3.4,1.7) to (2.55,-3.62,1.78) — a pure pull-back, no
restage — landing fill 0.738x/0.633y with margins L0.219 R0.044 B0.083
T0.283. The render path now calls gallery_framing.check_framing before
the beauty render (exit 10); check code and closed forms untouched
(eval_verts=1044, eval_faces=1028, x_span=3.292 all print unchanged).
Gate falsified at lens 65 (margins FAIL, exit 10, no artifact) and
restored. Identical framing numbers on 4.5.11.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
Sixteen-column skyline over-filled the frame at 0.969x with side margins
0.016. Camera pulls back from (0,-13.5,2.0) to (0,-15.0,2.0) — pure
distance, no restage — landing fill 0.869x/0.333y with margins L0.066
R0.066 B0.367 T0.300. Render path gated with check_framing (exit 10);
check values unchanged (driven_range 0.404..2.399, flushed_to_original).
Gate falsified at lens 55 (fill 0.994 FAIL, exit 10) and restored.
Identical numbers on 4.5.11.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
Sphere pair over-filled the frame at 0.969x with side margins 0.016.
Camera pulls back from (0,-7.8,2.6) to (0,-8.7,2.6) — pure distance, no
restage — landing fill 0.869x/0.650y with margins L0.066 R0.066 B0.256
T0.094. Render path gated with check_framing (exit 10); check values
unchanged (group users=2, distinct instance tints). Gate falsified at
lens 72 (fill 1.000 FAIL, exit 10) and restored. Identical numbers on
4.5.11.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
The ortho grid over-filled vertically at 0.944y. ortho_scale 7.8 -> 8.4
(height 4.39 -> 4.73 for the 4.14-unit grid) lands fill 0.769x/0.878y
with margins L0.116 R0.116 B0.061 T0.061. verify_png's third/half
cell-center sampling tolerates the scale change — distinct_regions=6
and max_pixel=1.000 confirmed at 1280 default and at the smoke
invocation (640, cycles, 8 samples) on 5.1.2 and 4.5.11. Render path
gated with check_framing (exit 10); falsified at ortho_scale 6.5
(fill 1.000 FAIL, exit 10) and restored.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
The shared display plinth touched the bottom frame edge (margin 0.000).
A pull-back first overshot (fill 0.672 under-band), so the fix is an aim
drop instead: aim z 1.65 -> 1.38 at unchanged camera distance pitches
the composition up, landing fill 0.725x/0.628y with margins L0.122
R0.056 B0.028 T0.150 — distance and composition otherwise untouched.
Render path gated with check_framing (exit 10); falsified at lens 64
(fill 0.916 FAIL, exit 10) and restored. Identical numbers on 4.5.11.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
The neon vessel over-filled vertically at 0.978y with its base cropped
by the bottom edge. Camera pulls back from (3.4,-4.2,2.4) to
(3.95,-4.9,2.62) — pure distance, no restage — landing fill
0.463x/0.867y with margins L0.272 R0.266 B0.044 T0.089 (an intermediate
stop landed y at exactly 0.900, on the band ceiling, so the pull-back
goes one step further for cross-version slack). Render path gated with
check_framing (exit 10); check values unchanged (strokes=10, points=34,
restore recovers both). Gate falsified at lens 62 (fill 1.000 FAIL,
exit 10) and restored. 4.5.11 matches (0.469x/0.867y).

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
The corrected survey (render_pre capture) measured this hero for the
first time: the monitor top was cropped and the desk bled the bottom
edge (fill 1.000y, touch B+T) — the #107 survey had read bpy.context.scene,
which is the cut-list scene, not the Bay the still renders from. BayCam
pulls back from (2.0,-5.2,1.72) to (3.05,-7.9,2.0) with aim z 1.28 ->
1.20, landing fill 0.506x/0.850y with margins L0.247 R0.247 B0.067
T0.083. This was the most-broken of the seven (frame-filling before),
so the composition change is correspondingly larger; the bezel, stand,
desk, and on-screen cut list are all fully in frame now. The gate runs
on the Bay scene (the helper's scene-targeted matte from the previous
commit), falsified at lens 66 (fill 1.000 FAIL, exit 10) and restored.
check and --check-pixels both exit 0 on 5.1.2 and 4.5.11 with identical
pixel witnesses.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
The corrected survey plus the marginal sweep leaves four examples that
need real reframing rather than a camera nudge: depsgraph-export (cube
amputated), vertex-weight-limit (off-center, base cropped),
text-version-stamp (dead lower third), triangulate-tangents (2x-class
move-in). The seven marginal cases are marked swept and gated;
deviations and the sky-texture artifact stay as documented in #108.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 22, 2026
@TMHSDigital
TMHSDigital merged commit 7fd594e into main Jul 22, 2026
9 checks passed
@TMHSDigital
TMHSDigital deleted the fix/framing-survey-marginal-sweep branch July 22, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant