Blender swatch scenes, and a 29th style: tabletop-miniature - #42
Merged
Merged
Conversation
styles/_swatch renders a style folder that has swatch.py instead of swatch.js in Blender (Cycles): blender_render.py runs the scene's build(env) once and apply(t, env) before every frame, and render.sh turns the PNG frames into the same 1080p BT.709 hf.mp4 as the HyperFrames path, so the checks, music, foley, mix, qa, encode and poster are shared. Final renders use the CPU (pixel-identical run to run; Metal 92 dB, EEVEE 85 dB), drafts the GPU, with persistent data off (on, it carried state between frames: a black teacup that determinism.sh caught). Safety per engines/blender.md: blender_prep.py scans swatch.py as a syntax tree first (allow-listed imports, no eval/exec/open, .blend IO, handlers, timers), then Blender runs under env -i and, on macOS, sandbox-exec (no network; writes to out/<slug>/ and the per-user cache and temp folders that Metal needs). Fonts resolve through fc-match; a .ttc face Blender cannot load is written out to out/. determinism.sh re-renders 12 frames out of order in fresh processes against the final frames. Files that import bpy are GPL-3.0-or-later with an SPDX header (the maintainer's decision); CI checks the header and runs the scan. tabletop-miniature (桌面微缩剧场): stop-motion miniature on a real-scale desk, practical light as the clock, a felt puppet on twos (on ones while the camera follows and for the fastest hop), one piano with each action a note. Four rounds of independent review; engines/blender.md now records the first smoke results on Blender 5.2.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ture # Conflicts: # CHANGELOG.md
…ter STYLE.md Swatch (final render, determinism 12/12): - opening starts with the blocks out of frame; the card comes in after the pull-back - the small hop is a crouch, rise, apex and fall; the puck flinches at the lamp-off - the camera cranes up and swings round the set for the payoff, drifts through the dark and hands over to the dawn at the same speed - stitched eyes lie on the round face; the moon sits higher so its desk glint falls below the frame; brighter moon fill Safety, after the code review: - the scan refuses underscore names and attributes and strings with __, getattr and friends, and bpy that loads, saves or runs anything; it is a lint, the sandbox is the boundary - sandbox: no lsopen or Apple events; writes only to out/<slug>/ and Blender's cache subfolder; final (CPU) renders cannot read the home folder (Metal crashes with that rule, so drafts keep it off) - foley.mjs scans and sandboxes its read of FOLEY; CI checks the GPL header by AST - the render stamp includes the Blender version and is taken before rendering; a failing worker stops the others; Blender's stall limit is 300 s STYLE.md: the taste sections are defaults with reasons, not prohibitions.
…ture # Conflicts: # AGENTS.md # CHANGELOG.md # CLAUDE.md
…ender's real path for the sandbox From the code review's re-check of #42: - bl_run execs sandbox-exec (or Blender), so the pid bl_render kills is Blender, not a subshell around it; a stub run leaves nothing behind - the home read-deny's allow rule resolves Blender's real path and allows only its .app bundle or install folder; a folder that holds the home folder is refused - the sandbox profile lives in a temp folder outside out/<slug>/, and on macOS Blender does not start without it - foley.mjs shows the scan's findings and runs the interpreter it resolved, with its install readable (pyenv, uv under home) - the scan refuses `import json as x` and `import sys as x` - determinism.sh stamps a fresh full render before rendering; CI reads paths by line
…d on any exit; dotted json/sys aliases - bl_profile runs in the parent before run_watched; cleanup() removes its temp folder, so a timeout or Ctrl-C leaves nothing in TMPDIR (stub runs: failure and timeout both leave no Blender and no folder) - the scan flags `import json.decoder as d` too - styles/_swatch/README.md: how the Blender allow path is chosen, the Homebrew wrapper case, where the profile lives
ZLHad
marked this pull request as ready for review
October 2, 2026 05:08
ZLHad
added a commit
that referenced
this pull request
Oct 4, 2026
- Style swatches can be Blender scenes (swatch.py): build(env) once, apply(t, env) per frame, Cycles on the CPU for final renders (pixel-identical across runs), Metal for drafts. The frames feed the same hf.mp4, checks, music, foley, mix, qa, encode and poster as the HyperFrames path. - Safety in three layers: an AST scan (a lint), env -i, and on macOS a sandbox-exec profile (no network, no URL or Apple-event hand-off, writes only to out/<slug>/ and Blender's cache folder; final renders cannot read the home folder). Drafts on Metal cannot take the home read-deny (Metal crashes), so they keep it off. Linux has no sandbox. - determinism.sh for Blender scenes: 12 frames, last to first, in 3 fresh processes, against the final render's frames, using a stamp taken before rendering. It caught a real bug (persistent data drew the teacup black on frames 27-44). - A 29th style, tabletop-miniature (桌面微缩剧场): stop-motion miniature on a real-scale desk, one upright piano, seven synthesized foley sounds. Seven independent review rounds; shipped at hook 8, phone 8, motion 8, variety 7, polish 8, accuracy 9, sync 8, with the open points in styles/README.md. - STYLE.md writes taste as defaults with reasons; the floors stay hard. - Files that import bpy are GPL-3.0-or-later with an SPDX header (the maintainer's decision); CI checks it. engines/blender.md is now "partly verified".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
swatch.pyinstead ofswatch.jsrenders in Blender 5.2 (Cycles) throughstyles/_swatch/render.sh.hf.mp4the HyperFrames path makes, so the frame checks, music, foley, mix,bin/vh qa, encode, poster and sheet are all shared.blender_render.py(runs inside Blender:build(env)once,apply(t, env)per frame),blender_prep.py(a static check of the scene and font resolution), and Blender branches inrender.sh,determinism.sh,foley.mjsandbin/vh style.tabletop-miniature(桌面微缩剧场): stop-motion miniature on a real-scale tabletop.engines/blender.mdgoes from "experimental, never run" to "partly verified", with the first-smoke results measured on Blender 5.2.2.Licence
As decided in the session, files that import bpy are GPL-3.0-or-later with an SPDX header:
styles/_swatch/blender_render.pyandstyles/tabletop-miniature/swatch.py. Everything else stays MIT. Both READMEs' licence sections andengines/blender.mdrecord this.tools/ci.shfails a.pythat imports bpy without the header, and runs the static check on everystyles/*/swatch.py.Safety (following engines/blender.md)
Three layers. The third is the boundary; the first is a lint.
blender_prep.py scanreadsswatch.pyas a syntax tree before anything runs it.bpy bmesh mathutils math colorsys json sys, which rules outrandomandtimetoo. Ofjsononlydumps/loads, ofsysonlyargv._, and strings containing__, are refused. That closes the dunder routes the code review found (bpy.utils._os,x.__dict__["__import__"]).eval exec compile open getattr setattr type dir globals vars, and bpy that loads, saves or runs anything (.blend files, text blocks, drivers,bpy.utils,save_render, handlers, timers).foley.mjsruns the same scan before it readsFOLEY, and on macOS reads it inside a sandbox of its own.env -i, so no API keys reach it. Its HOME and TMPDIR are inout/<slug>/.blender/.sandbox-exec), measured on Blender 5.2.2:out/<slug>/and Blender's own subfolder of the per-user cache. Metal keeps compiled shaders there; with it denied, every frame recompiles (13 s instead of 2 s). The temp folder is not needed.~/Library/Fonts. Frame 90 rendered under that rule is pixel-identical to the frame rendered without it.-[_MTLDevice recordBinaryArchiveUsage:]) loading cached kernels when home is unreadable, even with~/Libraryallowed. Drafts stay offline and write only to the git-ignoredout/.Determinism
determinism.shre-renders 12 frames spread over the clip, last to first, in 3 fresh Blender processes. It compares them pixel by pixel with the final in-order render. The final render's frames are reused when the stamp in theirinputs.txt(a checksum of the scene) still matches.render.use_persistent_datamade Cycles on the CPU draw the teacup black on frames 27–44 of the in-order render; those frames rendered alone were grey. Frame 30 failed at 24.5 dB.How it was checked
CI:
tools/ci.sh --committedpasses on the merge with main (Case study: five community films, concept before style #43–Research note 06: concept-first against floors only; two self-checks for quick #46), under both bash 5 and macOS bash 3.2. Shellcheck 0.11 and pyflakes are clean.Swatch render:
swatch.mp4is 1.14 MB andposter.jpg67 KB, both under the caps.determinism.sh: 12/12 frames pixel-identical (last to first, 3 fresh processes).Layout: checked frame by frame with a pinhole projection that matches the Blender camera, before rendering. The hanging card clears the highest hop by 20 px; text stays inside the safe area through every camera move (title text x ≥ 239, y ≥ 105); the end frame's blocks sit above the action-safe line.
Gallery: rebuilt with 29 styles (jpg 1.06 MB, mp4 7.2 MB).
Review: seven rounds of independent "harsh motion director" review on fresh contexts. The lowest score was 6, then 7 in every round; no round had all seven dimensions at 8. Scores are hook, phone, motion, variety, polish, accuracy, sync.
Round 7's open points, written into
styles/README.mdand the CHANGELOG:STYLE.md (the maintainer asked not to write the rules too rigidly): the taste sections describe what the swatch does, why, and when to do otherwise; "禁止项" became "容易翻车的地方", each with its cost. The floors stay hard: frames are pure functions of t, type size, sandbox and key isolation, no digital silence, licences.
Not in this PR
open, so the renderer would have to pass it in throughenv. This matters for music: a note map for pictures driven note by note #41's note map: a Blender scene driven note by note would need that.engines/blender.mdstill lists first-smoke items not run: the EEVEE 300-frame memory test, OIDN flicker on/off, rigid-body cache order, HyperFrames video alpha, PNG metadata, and the two-stage-acommand lines.