From d412dcc3d2d01204a6f686ac0220ba8886d10886 Mon Sep 17 00:00:00 2001 From: zhanglinghao Date: Fri, 2 Oct 2026 03:16:49 +0800 Subject: [PATCH 1/4] Blender swatch scenes, and a 29th style: tabletop-miniature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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// 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 --- AGENTS.md | 2 +- CHANGELOG.md | 37 ++ CLAUDE.md | 2 +- README.md | 26 +- README.zh-CN.md | 26 +- bin/vh | 9 +- engines/README.md | 5 +- engines/blender.md | 32 +- styles/README.md | 15 +- styles/_swatch/README.md | 47 +- styles/_swatch/blender_prep.py | 87 ++++ styles/_swatch/blender_render.py | 159 ++++++ styles/_swatch/custom_sfx.py | 49 ++ styles/_swatch/determinism.sh | 56 +- styles/_swatch/foley.mjs | 13 +- styles/_swatch/render.sh | 159 ++++-- styles/gallery.jpg | Bin 1036552 -> 1064326 bytes styles/gallery.mp4 | Bin 6986715 -> 7184399 bytes styles/tabletop-miniature/STYLE.md | 116 +++++ styles/tabletop-miniature/events.json | 15 + styles/tabletop-miniature/media/poster.jpg | Bin 0 -> 71309 bytes styles/tabletop-miniature/media/swatch.mp4 | Bin 0 -> 1136737 bytes styles/tabletop-miniature/score.json | 34 ++ styles/tabletop-miniature/sfx/bird.wav | Bin 0 -> 40364 bytes styles/tabletop-miniature/sfx/felt_land_a.wav | Bin 0 -> 15404 bytes styles/tabletop-miniature/sfx/felt_land_b.wav | Bin 0 -> 15404 bytes styles/tabletop-miniature/sfx/felt_land_c.wav | Bin 0 -> 15404 bytes styles/tabletop-miniature/sfx/lamp_off.wav | Bin 0 -> 19244 bytes styles/tabletop-miniature/sfx/lamp_on.wav | Bin 0 -> 19244 bytes styles/tabletop-miniature/sfx/thread_tug.wav | Bin 0 -> 17324 bytes styles/tabletop-miniature/swatch.py | 491 ++++++++++++++++++ styles/tabletop-miniature/tokens.json | 68 +++ tools/ci.sh | 15 +- 33 files changed, 1363 insertions(+), 100 deletions(-) create mode 100644 styles/_swatch/blender_prep.py create mode 100644 styles/_swatch/blender_render.py create mode 100644 styles/tabletop-miniature/STYLE.md create mode 100644 styles/tabletop-miniature/events.json create mode 100644 styles/tabletop-miniature/media/poster.jpg create mode 100644 styles/tabletop-miniature/media/swatch.mp4 create mode 100644 styles/tabletop-miniature/score.json create mode 100644 styles/tabletop-miniature/sfx/bird.wav create mode 100644 styles/tabletop-miniature/sfx/felt_land_a.wav create mode 100644 styles/tabletop-miniature/sfx/felt_land_b.wav create mode 100644 styles/tabletop-miniature/sfx/felt_land_c.wav create mode 100644 styles/tabletop-miniature/sfx/lamp_off.wav create mode 100644 styles/tabletop-miniature/sfx/lamp_on.wav create mode 100644 styles/tabletop-miniature/sfx/thread_tug.wav create mode 100644 styles/tabletop-miniature/swatch.py create mode 100644 styles/tabletop-miniature/tokens.json diff --git a/AGENTS.md b/AGENTS.md index 5c7a089..7369d11 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -112,7 +112,7 @@ effort 管 agent 自己查得多细,导演模式管人拍板哪些事,两个 | 3 分钟以上的长片,或靠故事、谜题推进的片子(角色短片、长讲解) | 主类型文档,加上 `playbook/09-narrative.md`(骨架、节拍表、张力曲线、换挡) | 按主类型 | — | | 要发短视频平台:开头钩子、标题、封面 | `playbook/10-hooks-and-packaging.md`,加上主类型文档 | 按主类型 | — | | 要写有篇章、有主题的配乐(MV、介绍片和发布片、45 s 以上靠音乐撑起结构的片子、`studio` 档位,或者人要亲自定主题和 BGM) | `playbook/11-composition.md`;`score.json` 的写法见 `playbook/04-audio.md` | `bin/vh music` | — | -| 3D 场景、着色器短片(Three.js) | 暂无专门的类型文档:以 `03-product-promo.md` 的运动规则为准,加上 `playbook/08-vfx-and-motion-sources.md`(一镜到底、特效预设栈、子帧运动模糊)。要路径追踪的光影(玻璃、皮肤、体积光)、物理模拟或真实景深时,读 `engines/blender.md`(实验性:维护者的 Mac 没装 Blender,没验证过,渲染时间先渲 5 帧校准) | HyperFrames + Three.js 层;重光影的镜头用 Blender | `showcase/04-intro-film/`、`cases/opus55-gallery.md` 的 3D 一节和第 6 节(Austerlitz 长片深读) | +| 3D 场景、着色器短片(Three.js) | 暂无专门的类型文档:以 `03-product-promo.md` 的运动规则为准,加上 `playbook/08-vfx-and-motion-sources.md`(一镜到底、特效预设栈、子帧运动模糊)。要路径追踪的光影(玻璃、皮肤、体积光)、物理模拟或真实景深时,读 `engines/blender.md`(部分验证:风格样片 `tabletop-miniature` 已用 Blender 5.2.2 渲染,项目用的命令还有几条没跑过;渲染时间先渲 3–5 帧校准) | HyperFrames + Three.js 层;重光影的镜头用 Blender | `showcase/04-intro-film/`、`cases/opus55-gallery.md` 的 3D 一节和第 6 节(Austerlitz 长片深读) | | 想要某种风格、参考某部名作,或者不想每支片子都一个口味 | `styles/README.md`,再读选中预设的 `styles//STYLE.md` | 随主引擎 | 每个预设的 `media/swatch.mp4`,总览 `styles/gallery.jpg` | | 想知道某种镜头怎么动(开场、字卡、转场、卡点、收尾),或想要"专业的节奏" | `recipes/README.md`,再读 `recipes/sequences/` 里合适的骨架 | 随主引擎 | `cases/promo-video-shotcraft.md` | diff --git a/CHANGELOG.md b/CHANGELOG.md index f8e43ba..25253b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ ## Unreleased +**Style swatches can be Blender scenes; a 29th style, tabletop-miniature (桌面微缩剧场)** +- Why: every swatch is drawn on a canvas, and none looks like a lit, physical set. Taking apart a community film (Kevin Ngo's piano short, made with Python and rendered in Blender) gave a stop-motion miniature grammar whose look rests on path-traced light and real depth of field, so the swatch renderer needed a Blender path. Blender 5.2.2 is now installed on the maintainer's Mac. +- `styles/_swatch/`: a style folder with `swatch.py` instead of `swatch.js` renders in Blender (Cycles). `blender_render.py` runs the scene's `build(env)` once per process and `apply(t, env)` before every frame, setting properties directly (no keyframes, no handlers, so no motion blur, which suits stop-motion). It writes PNG frames, and `render.sh` encodes them into the same 1080p BT.709 `hf.mp4` the HyperFrames path makes, so the frame checks, music, foley, mix, `bin/vh qa`, encode, poster and contact sheet are shared. New `render.sh` options for Blender scenes: `--frames 149,90,12` (with `--png`: only those frames, in that order) and `--stamp`. +- Final renders use Cycles on the CPU. Measured on an M3 Max: the same frame rendered twice is pixel-identical on the CPU, but not on Metal (92 dB) or EEVEE (85 dB), and this pipeline's CRF-to-size loop amplifies small differences. `--draft` uses the GPU. tabletop-miniature: about 15 s per frame on the CPU at 32 spp + OIDN (64 spp looked the same side by side), about 1.6 s on Metal. +- Safety, following `engines/blender.md`: `blender_prep.py scan` reads `swatch.py` as a syntax tree before anything runs it, allowing only `bpy bmesh mathutils math colorsys json sys` and no `eval exec compile __import__ open`, .blend saving or loading, `execfile`, `app.handlers`, `app.timers` or `sys.modules`, so `random` and `time` are excluded too. Blender then runs under `env -i` (no API keys), with its HOME and TMPDIR in `out//.blender/`, and on macOS under `sandbox-exec`: no network, writes only to `out//` plus the per-user cache and temp folders. Metal needs those two folders: with the cache denied it recompiles shaders on every frame (13 s instead of 2 s), and with the temp folder denied Blender aborts when a scene needs new kernels. The `--python-exit-code 1` runs are started with job control off, so the watchdog's process-group kill reaches them; with it on, the Blenders landed in their own groups. +- Fonts: a scene's `FONTS` are fontconfig patterns; `blender_prep.py fonts` resolves them with `fc-match` to the same system fonts `fonts.css` uses. Blender loads only face 0 of a `.ttc`, so another face (Songti SC Bold is face 1) is written out with fontTools to `out//fonts/`, a local cache that is never committed. +- `determinism.sh` on a Blender scene re-renders 12 frames spread over the clip, last to first, in 3 fresh Blender processes and compares them pixel by pixel with the final render's frames (`out//frames/`, used when their `inputs.txt` checksum still matches the scene). It earned its place on the first final render: with `render.use_persistent_data` on, Cycles on the CPU rendered the teacup black on frames 27–44 of the in-order render and grey when those frames were rendered alone, and the check failed on frame 30 (24.5 dB). The renderer now keeps persistent data off (per-frame time barely changed, 15–19 s). `foley.mjs` reads `FOLEY` from `swatch.py` (after the scan). `bin/vh style` skips the HyperFrames install for a Blender scene. +- Licence (the maintainer's decision, 2026-10-01): files that import bpy are GPL-3.0-or-later with an SPDX header, as Blender asks of published bpy scripts: `styles/_swatch/blender_render.py` and `styles/tabletop-miniature/swatch.py`. The rest of the repo stays MIT. Both READMEs' licence sections and `engines/blender.md` ("许可证") say so. `tools/ci.sh` runs the scan on every `styles/*/swatch.py` and fails a `.py` that imports bpy without the header. +- The style (`styles/tabletop-miniature/`): + - Learned from Aardman's *A Grand Day Out* (1989), Laika's *Coraline* (2009), Olivo Barbieri's tilt-shift *Site Specific* series and the piano film. + - The grammar: + - a real-scale tabletop, with a geometric puppet that acts with its gait and two bead eyes; + - only practical light, whose colour and angle carry time; + - the camera at the puppet's eye height, f/4.5, so only a few millimetres are sharp; + - puppets on twos with a hand-placed jitter, camera and lights on ones, no motion blur; + - one acoustic instrument, with each action a note. + - The swatch: the camera starts tight on a sleeping felt puck. The desk lamp clicks on, the puck wakes, and the camera pulls back as a playbill card is lowered on two threads. The puck walks to three wooden blocks and hops up them: 大纲 is raw wood, 分镜 is half-dipped in red, 初版 is all red, so the paint is the progress. The lamp goes off on the last downbeat, the morning comes through the window, and the puck falls asleep. The puppet is on ones while the camera follows it: on twos it stepped back 8–16 px on every odd frame. + - The score is one upright piano: the low register pedalled underneath, a note on each takeoff and a dry high note on each landing, and a V7 chord held through the dark until dawn resolves it. Seven foley sounds are synthesized in `custom_sfx.py`: lamp switch on and off, felt on wood ×3, the thread pulled tight, a bird. + - Its layout was checked frame by frame with a pinhole projection before rendering: the hanging card clears the highest hop by 20 px. + - Four rounds of independent "harsh motion director" review on fresh contexts, with the worst three issues fixed between rounds. Lowest score 6, 7, 7, 7. + - Round 4: hook 8, phone 8, motion 7, variety 8, polish 7, accuracy 8, sync 9. Its three issues were fixed afterwards and not reviewed again: + - the last hop moved to ones (it had 3 air drawings on twos); + - a cool moonlight fill and a dark window frame were added, because the blackout had pure-black blocks while the frame glowed; + - a half-lid and a nod come before sleep. +- `engines/blender.md` changes from "experimental, never run" to "partly verified". The first-smoke items that were run are written back as 【实测 5.2.2】: + - render repeatability by device; + - speeds; + - what `sandbox-exec` must allow; + - the `.ttc` face limit; + - Mix-node socket identifiers; + - dynamic `view_transform` enums; + - stdout buffering in background mode; + - job control. + + `engines/README.md` and `CLAUDE.md` (and `AGENTS.md`) now point to the working swatch path. +- Docs: `styles/README.md` (table row, sound row, how to add a Blender style), `styles/_swatch/README.md` ("Blender 场景"), both READMEs (29 styles). The gallery is rebuilt with the new poster and clip. + **Sound refresh: every film on the new SFX engine, a transition family per style, plucked parts on the modelled voices** - Why: the maintainer heard the same page-turn sound in every film, and the same one on every cut within a film ("切换音效都是一模一样的有审美疲劳,同一个片子同一个切换页音效一样可能也不是很好"). #39 built the variants and the new transitions; this applies them and renders everything again. - **28 swatches, a transition family each**, chosen by style and shaped to the move (`dur` ≈ the move's length, `dir` with the motion, `pan_from` / `pan_to` where the screen direction is clear, smaller moves shorter and higher); variants stay unpinned. paper: blueprint, cutout-jazz, guochao-festive (one slide per door), isotype, risograph (every roller), silhouette-papercut, watercolor-pastoral (the brush stroke). air: archival-pan-zoom, bubble-chart-story, editorial-data, ink-wash, symmetry-pastel (curtains), watercolor-pastoral (the gusts). whip: bouncy-flat-2d, halftone-comic, neon-step-print, pixel-16bit, swiss-grid-type, symmetry-pastel (the whip pan). swoosh_tonal: clockwork-map (the rings), dunhuang-mural (the two flying figures, from the edges to the axis), fui-hud, monumental-scifi, pixel-16bit (the mosaic), product-keynote. tape: crt-terminal (a stop into the dot), scratched-type (the end), synthwave-outrun (a rewind through the tracking noise). Whoosh and swish_rev stay where they fit, shaped. dark-math and shadow-puppet keep no transition. Where a transition falls inside the gallery reel's clip (1.9–3.4 s), neighbouring swatches use different families. diff --git a/CLAUDE.md b/CLAUDE.md index f50ee17..c507fae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -109,7 +109,7 @@ effort 管 agent 自己查得多细,导演模式管人拍板哪些事,两个 | 3 分钟以上的长片,或靠故事、谜题推进的片子(角色短片、长讲解) | 主类型文档,加上 `playbook/09-narrative.md`(骨架、节拍表、张力曲线、换挡) | 按主类型 | — | | 要发短视频平台:开头钩子、标题、封面 | `playbook/10-hooks-and-packaging.md`,加上主类型文档 | 按主类型 | — | | 要写有篇章、有主题的配乐(MV、介绍片和发布片、45 s 以上靠音乐撑起结构的片子、`studio` 档位,或者人要亲自定主题和 BGM) | `playbook/11-composition.md`;`score.json` 的写法见 `playbook/04-audio.md` | `bin/vh music` | — | -| 3D 场景、着色器短片(Three.js) | 暂无专门的类型文档:以 `03-product-promo.md` 的运动规则为准,加上 `playbook/08-vfx-and-motion-sources.md`(一镜到底、特效预设栈、子帧运动模糊)。要路径追踪的光影(玻璃、皮肤、体积光)、物理模拟或真实景深时,读 `engines/blender.md`(实验性:维护者的 Mac 没装 Blender,没验证过,渲染时间先渲 5 帧校准) | HyperFrames + Three.js 层;重光影的镜头用 Blender | `showcase/04-intro-film/`、`cases/opus55-gallery.md` 的 3D 一节和第 6 节(Austerlitz 长片深读) | +| 3D 场景、着色器短片(Three.js) | 暂无专门的类型文档:以 `03-product-promo.md` 的运动规则为准,加上 `playbook/08-vfx-and-motion-sources.md`(一镜到底、特效预设栈、子帧运动模糊)。要路径追踪的光影(玻璃、皮肤、体积光)、物理模拟或真实景深时,读 `engines/blender.md`(部分验证:风格样片 `tabletop-miniature` 已用 Blender 5.2.2 渲染,项目用的命令还有几条没跑过;渲染时间先渲 3–5 帧校准) | HyperFrames + Three.js 层;重光影的镜头用 Blender | `showcase/04-intro-film/`、`cases/opus55-gallery.md` 的 3D 一节和第 6 节(Austerlitz 长片深读) | | 想要某种风格、参考某部名作,或者不想每支片子都一个口味 | `styles/README.md`,再读选中预设的 `styles//STYLE.md` | 随主引擎 | 每个预设的 `media/swatch.mp4`,总览 `styles/gallery.jpg` | | 想知道某种镜头怎么动(开场、字卡、转场、卡点、收尾),或想要"专业的节奏" | `recipes/README.md`,再读 `recipes/sequences/` 里合适的骨架 | 随主引擎 | `cases/promo-video-shotcraft.md` | diff --git a/README.md b/README.md index 3a14b16..39ffa9f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Coding agents like Claude Code and Codex can make videos by writing programs. This makes them do it reliably.** -Explainers, science shorts, product films, music videos, data stories, paper talks, hand-drawn shorts, meme edits and edits of your own footage: 9 video types (09 experimental), 28 styles, one workflow. +Explainers, science shorts, product films, music videos, data stories, paper talks, hand-drawn shorts, meme edits and edits of your own footage: 9 video types (09 experimental), 29 styles, one workflow. **English** · [中文](README.zh-CN.md) · [Wiki](https://github.com/ZLHad/OpenVideoHarness/wiki) @@ -12,7 +12,7 @@ Explainers, science shorts, product films, music videos, data stories, paper tal ![Agents](https://img.shields.io/badge/agents-Claude%20Code%20%7C%20Codex-orange) ![Engines](https://img.shields.io/badge/engines-HyperFrames%20%7C%20Remotion%20%7C%20Manim%20%7C%20p5.brush-blue) ![Voice](https://img.shields.io/badge/voice-Qwen3--TTS%20zh%20%7C%20en-purple) -![Styles](https://img.shields.io/badge/styles-28-green) +![Styles](https://img.shields.io/badge/styles-29-green) OpenVideoHarness intro film @@ -32,7 +32,7 @@ OpenVideoHarness is that craft, written as docs and tools an agent can follow: - **A method for each kind of video.** Say "make a science short" or "make a launch film", and it reads the workflow for that type: which engine, which steps, what looks good, what is off limits. - **It stops and asks you three times.** At the outline, the storyboard and the first draft, it waits for your go-ahead. Direction gets settled while changes are still cheap. For a quick try, switch to the `quick` level and it just renders. -- **More than one taste.** 28 styles learned from famous work, each with a real rendered sample, offered to you before anything is built. +- **More than one taste.** 29 styles learned from famous work, each with a real rendered sample, offered to you before anything is built. - **It checks its own work.** An agent can't watch video or hear sound, so it looks at rendered frames, measures the mix, and fixes things until a checklist passes. A reviewer who didn't make the film then scores it. - **Sound included.** Chinese and English voiceover (a local open-source model), bilingual subtitles, music and sound effects written as code, mixing and a final audio check. @@ -95,8 +95,8 @@ The five films below were made by an agent **reading only this repo's docs**. Cl 04 · Intro film (one-take 3D) (HyperFrames + Three.js · 81 s · 1920×1080)
The repo's own product film, one continuous 3D take.
Request, as revised at gate ①: “一镜到底 动画动效 音乐动态字等风格 叙事感 科幻感大片感” (one continuous shot, kinetic type on music, a narrative arc, a sci-fi blockbuster feel)
Suggested workflow (studio effort, --effort studio):
bin/vh new promo intro-film --style monumental-scifi
one-take 3D: playbook/08; bin/vh sfx place, sheet, check
Sound: a code-composed cinematic score (D minor, 90 BPM) and 97 sound effects; zh/en soft subtitle tracks -The 28 style samples, all showing the same content
▶ the reel, with sound (42 s) -28 styles, one reel (5-second samples)
The same content in 28 styles learned from famous work.
Start from one:
bin/vh new promo launch-film --style cutout-jazz
bin/vh style list shows all 28; details in styles/README.md
Sound: one score per sample (bin/vh music, mix … profile=swatch) +The 29 style samples, all showing the same content
▶ the reel, with sound (42 s) +29 styles, one reel (5-second samples)
The same content in 29 styles learned from famous work.
Start from one:
bin/vh new promo launch-film --style cutout-jazz
bin/vh style list shows all 29; details in styles/README.md
Sound: one score per sample (bin/vh music, mix … profile=swatch) @@ -117,26 +117,26 @@ The GIFs are compressed, silent previews. Films you make with it are welcome in -## 28 styles, not one taste +## 29 styles, not one taste AI-made videos drift toward one look: dark background, glow, glass cards, busy animated UI. Unless you say otherwise, that's where an agent goes. -So we studied famous work and wrote down 28 styles in [`styles/`](styles/), grouped into film titles, brand and launch, data and explainers, illustration and print, Chinese aesthetics, and retro tech. The sources include: -- **film and title design**: Saul Bass's titles, *Se7en*, *Blade Runner 2049*, Wes Anderson's symmetry, Wong Kar-wai's step-printing; +So we studied famous work and wrote down 29 styles in [`styles/`](styles/), grouped into film titles, brand and launch, data and explainers, illustration and print, Chinese aesthetics, and retro tech. The sources include: +- **film and title design**: Saul Bass's titles, *Se7en*, *Blade Runner 2049*, Wes Anderson's symmetry, Wong Kar-wai's step-printing, Aardman's and Laika's stop-motion miniatures; - **design**: the Swiss grid, 3Blue1Brown, New York Times data graphics, Otto Neurath's Isotype pictograms; - **animation and print**: the halftone dots of *Spider-Verse*, 16-bit Super Nintendo pixel art; - **Chinese aesthetics**: ink wash (水墨), Dunhuang murals, shadow puppetry and guochao. Each style is written as instructions an agent can follow: colors and fonts, composition, how things move, how scenes change, what it sounds like, and which clichés to avoid. -**Every style comes with a real 5-second sample rendered by this repo**, each with its own code-written music. All 28 samples show exactly the same content, so the only difference is the style: +**Every style comes with a real 5-second sample rendered by this repo**, each with its own code-written music. All 29 samples show exactly the same content, so the only difference is the style: -The 28 style samples, all showing the same content +The 29 style samples, all showing the same content Watch them back to back, each with its own sound, in [`styles/gallery.mp4`](styles/gallery.mp4). To use one: ```bash -bin/vh style list # see all 28 +bin/vh style list # see all 29 bin/vh new promo launch-film --style cutout-jazz # start a project from a style ``` @@ -338,7 +338,7 @@ OpenVideoHarness/ ├── video-types/ workflows for the 9 video types (09 experimental) ├── playbook/ shared know-how 00–11: pipeline, checks, motion, sound, effects, narrative, hooks and covers, composition ├── templates/ files each new project fills in: brief, storyboard, style, review, decisions, notes, lessons, checklist; script, character and packaging when needed -├── styles/ 28 styles, each with a sample; _swatch/ renders the samples +├── styles/ 29 styles, each with a sample; _swatch/ renders the samples ├── recipes/ shot recipes: how a shot moves (frames, critical values, pitfalls) + pacing skeletons for whole films ├── cases/ 12 case studies + curated community work + a 3D long-form deep-dive ├── showcase/ films made with this repo (source + final + process notes) @@ -398,7 +398,7 @@ This is an independent project, not affiliated with Anthropic, HeyGen, Remotion, ## License -Original content is [MIT](LICENSE). The bundled ClaudeAnimationBase is also MIT (© John Heibel). Some files in `recipes/` are modified from Apache-2.0 projects (video-shotcraft, HyperFrames): their upstream parts stay under Apache-2.0, and [`recipes/NOTICE.md`](recipes/NOTICE.md) lists them. Reference repos keep their own licenses. +Original content is [MIT](LICENSE). The bundled ClaudeAnimationBase is also MIT (© John Heibel). Some files in `recipes/` are modified from Apache-2.0 projects (video-shotcraft, HyperFrames): their upstream parts stay under Apache-2.0, and [`recipes/NOTICE.md`](recipes/NOTICE.md) lists them. Files that call Blender's Python API (`import bpy`: `styles/_swatch/blender_render.py` and the Blender style scenes such as `styles/tabletop-miniature/swatch.py`) are GPL-3.0-or-later, as Blender asks of published bpy scripts; each carries an SPDX header (see [`engines/blender.md`](engines/blender.md), "许可证"). Reference repos keep their own licenses. ## Citation diff --git a/README.zh-CN.md b/README.zh-CN.md index 34804e4..c06e215 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@ **让 Claude Code、Codex 这类写代码的 AI,用写程序的方式做视频,而且做得稳。** -科普、讲解、产品片、MV、数据、论文、手绘、梗图快剪、真人素材剪辑:9 类视频(09 实验中),28 种风格,一套流程。 +科普、讲解、产品片、MV、数据、论文、手绘、梗图快剪、真人素材剪辑:9 类视频(09 实验中),29 种风格,一套流程。 [English](README.md) · **中文** · [Wiki](https://github.com/ZLHad/OpenVideoHarness/wiki) @@ -12,7 +12,7 @@ ![Agents](https://img.shields.io/badge/agents-Claude%20Code%20%7C%20Codex-orange) ![Engines](https://img.shields.io/badge/engines-HyperFrames%20%7C%20Remotion%20%7C%20Manim%20%7C%20p5.brush-blue) ![Voice](https://img.shields.io/badge/voice-Qwen3--TTS%20zh%20%7C%20en-purple) -![Styles](https://img.shields.io/badge/styles-28-green) +![Styles](https://img.shields.io/badge/styles-29-green) OpenVideoHarness 介绍片 @@ -32,7 +32,7 @@ OpenVideoHarness 就是这套行规,写成了 AI 能照着执行的文档和 - **按片子类型给做法**:你说"做个科普"或"做个发布片",它就去读那一类的工作流:用哪个引擎、分几步、什么算好看、什么不许做。 - **三个节点停下来问你**:大纲、分镜、初版,每到一处都等你点头再往下做。方向在最便宜的时候定下来。只想快速试一版时,可以切到"快出"档,直接出片。 -- **不止一种口味**:28 个从名作里学来的风格,每个都附一段真渲的样片,开工前让你挑。 +- **不止一种口味**:29 个从名作里学来的风格,每个都附一段真渲的样片,开工前让你挑。 - **自己检查自己**:AI 看不了视频,也听不了声音。所以让它看渲染出来的帧、测混音的数据,照着清单改到合格;整片还要交给一个没参与制作的 reviewer 打分。 - **声音一起管**:中英配音(本地开源模型)、双语字幕、用代码写配乐和音效、混音和质检。 @@ -95,8 +95,8 @@ cd ~/OpenVideoHarness && claude 04 · 介绍片(一镜到底 3D)(HyperFrames + Three.js · 81 秒 · 1920×1080)
本仓库自己的产品片,一个连续的 3D 长镜头。
提示词(关卡 ① 时改的方向):“一镜到底 动画动效 音乐动态字等风格 叙事感 科幻感大片感”
建议工作流(精品档,--effort studio):
bin/vh new promo intro-film --style monumental-scifi
一镜到底 3D 见 playbook/08;bin/vh sfx place、sheet、check
声音:代码写的电影感配乐(D 小调,90 BPM)和 97 个音效;中英软字幕轨 -28 种风格的样片,内容完全相同
▶ 带声音的连播(42 秒) -28 种风格,连播(每段 5 秒)
同一段内容,换 28 种从名作里学来的风格。
从一种开始:
bin/vh new promo launch-film --style cutout-jazz
bin/vh style list 列出全部 28 种,详见 styles/README.md
声音:每段样片一首配乐(bin/vh music,mix … profile=swatch) +29 种风格的样片,内容完全相同
▶ 带声音的连播(42 秒) +29 种风格,连播(每段 5 秒)
同一段内容,换 29 种从名作里学来的风格。
从一种开始:
bin/vh new promo launch-film --style cutout-jazz
bin/vh style list 列出全部 29 种,详见 styles/README.md
声音:每段样片一首配乐(bin/vh music,mix … profile=swatch) @@ -117,26 +117,26 @@ GIF 是压缩过的无声预览。你做出来的片子也欢迎 PR 进 `showcas -## 28 种风格,不止一种口味 +## 29 种风格,不止一种口味 AI 做的视频很容易长成一个样子:暗底、发光、玻璃卡片、满屏动态 UI。你不说,它就往这个方向走。 -所以我们从名作里学了 28 种风格,放在 [`styles/`](styles/),分成六类:电影片头、品牌发布、数据讲解、插画印刷、中国美学、复古科技。学习对象包括: -- **电影和片头**:Saul Bass 的片头、《七宗罪》、《银翼杀手 2049》、韦斯·安德森的对称构图、王家卫的抽帧; +所以我们从名作里学了 29 种风格,放在 [`styles/`](styles/),分成六类:电影片头、品牌发布、数据讲解、插画印刷、中国美学、复古科技。学习对象包括: +- **电影和片头**:Saul Bass 的片头、《七宗罪》、《银翼杀手 2049》、韦斯·安德森的对称构图、王家卫的抽帧、Aardman 和 Laika 的定格微缩; - **设计**:瑞士网格、3Blue1Brown、《纽约时报》的数据图、纽拉特的图形统计(Isotype); - **动画和印刷**:《蜘蛛侠:平行宇宙》的网点、超级任天堂的 16 位像素; - **中国美学**:水墨、敦煌、皮影、国潮。 每种风格都写成一份 AI 能照着做的说明:用什么颜色和字体、怎么构图、东西怎么动、怎么转场、配什么声音、哪些俗套不许碰。 -**每种风格都用本仓库真渲了一段 5 秒样片**,配乐也是各自用代码写的。28 段样片的内容一模一样,差别只在风格: +**每种风格都用本仓库真渲了一段 5 秒样片**,配乐也是各自用代码写的。29 段样片的内容一模一样,差别只在风格: -28 种风格的样片,内容完全相同 +29 种风格的样片,内容完全相同 连着看的版本在 [`styles/gallery.mp4`](styles/gallery.mp4),每段带着自己的声音。用法: ```bash -bin/vh style list # 看 28 种风格 +bin/vh style list # 看 29 种风格 bin/vh new promo launch-film --style cutout-jazz # 建项目时直接带上一种风格 ``` @@ -386,7 +386,7 @@ OpenVideoHarness/ ├── video-types/ 9 类视频的工作流(09 实验中) ├── playbook/ 通用知识 00–11:流程、自查、运动设计、声音、特效、叙事、钩子与封面、作曲等 ├── templates/ 每个新项目要填的文件:需求、分镜、风格、审阅、决定、笔记、经验、清单;按需再加旁白稿、角色、标题封面 -├── styles/ 28 种风格,各带样片;_swatch/ 是样片渲染器 +├── styles/ 29 种风格,各带样片;_swatch/ 是样片渲染器 ├── recipes/ 镜头配方:一镜怎么动(帧数、命门、坑)+ 整支片子的节奏骨架 ├── cases/ 12 个案例拆解 + 社区作品精选 + 一支 3D 长片深读 ├── showcase/ 本仓库自己做的片子(源码 + 成片 + 过程记录) @@ -446,7 +446,7 @@ OpenVideoHarness/ ## 许可 -原创内容采用 [MIT](LICENSE) 许可。自带的 ClaudeAnimationBase 也是 MIT(© John Heibel)。`recipes/` 里有些文件改编自 Apache-2.0 的项目(video-shotcraft、HyperFrames),来自上游的部分仍按 Apache-2.0,清单见 [`recipes/NOTICE.md`](recipes/NOTICE.md)。参考仓库遵循各自的许可证。 +原创内容采用 [MIT](LICENSE) 许可。自带的 ClaudeAnimationBase 也是 MIT(© John Heibel)。`recipes/` 里有些文件改编自 Apache-2.0 的项目(video-shotcraft、HyperFrames),来自上游的部分仍按 Apache-2.0,清单见 [`recipes/NOTICE.md`](recipes/NOTICE.md)。调用 Blender Python API 的文件(`import bpy`:`styles/_swatch/blender_render.py` 和 `styles/tabletop-miniature/swatch.py` 这类 Blender 风格场景)按 GPL-3.0-or-later 分发,这是 Blender 对公开发布的 bpy 脚本的要求;每个文件头都有 SPDX 标注(见 [`engines/blender.md`](engines/blender.md) 的"许可证")。参考仓库遵循各自的许可证。 ## 引用 diff --git a/bin/vh b/bin/vh index e1970d4..0b02ea8 100755 --- a/bin/vh +++ b/bin/vh @@ -364,7 +364,10 @@ cmd_cover_preview() { [ $# -gt 0 ] || { echo "usage: bin/vh cover-preview /{STYLE.md,tokens.json,swatch.js,media/}; renderer in styles/_swatch @@ -381,7 +384,7 @@ for d in sorted(pathlib.Path(sys.argv[1]).iterdir()): PY ;; gallery) shift; uv run -q --no-project --with pillow python "$sw/gallery.py" "$@" ;; - check) shift; swatch_deps; "$sw/determinism.sh" "$@" ;; + check) shift; swatch_deps "${1:-}"; "$sw/determinism.sh" "$@" ;; compare) shift; [ $# -gt 0 ] || { echo "usage: bin/vh style compare a,b,c [--frame t] [--out file.png]"; exit 1; } uv run -q --no-project --with pillow python "$ROOT/tools/style_compare.py" "$@" ;; apply) shift; [ $# -eq 2 ] || { echo "usage: bin/vh style apply (bin/vh style list shows the presets)"; exit 1; } @@ -390,7 +393,7 @@ PY [ -f "$dir/BRIEF.md" ] && [ -f "$dir/STYLE.md" ] || { echo "$(rel "$dir") has no BRIEF.md and STYLE.md: not a bin/vh project"; exit 1; } attach_style "$dir" "$1" echo "$c_ok styles/$1 attached to $(rel "$dir") (STYLE_PRESET.md, style.tokens.json, its prompt block in BRIEF.md)" ;; - *) swatch_deps; exec "$sw/render.sh" "$@" ;; + *) swatch_deps "$1"; exec "$sw/render.sh" "$@" ;; esac } diff --git a/engines/README.md b/engines/README.md index ee662bc..f24fdd2 100644 --- a/engines/README.md +++ b/engines/README.md @@ -134,12 +134,13 @@ uv run manim -qh --fps 30 scene.py MyScene # 成片:1080p30(-qh 默认 - 写代码前先读 `references/repos/3brown1blue/src/three_b1b/skill/SKILL.md` 里的 Gotchas。 - 注意 CE 和 ManimGL 的 API 不能混用,参考 `references/repos/3brown1blue/src/three_b1b/skill/rules/manimgl-differences.md`。 -## Blender,未安装,按需使用(实验性) +## Blender,按需使用(部分验证) -完整指南:[`blender.md`](blender.md)。**实验性:维护者的 Mac 没有装 Blender,指南没有验证过;渲染时间先渲 5 帧校准。** +完整指南:[`blender.md`](blender.md)。**部分验证:维护者的 Mac 装了 Blender 5.2.2,风格样片 `tabletop-miniature` 用它渲染(`styles/_swatch/README.md` 的"Blender 场景");指南里项目用的两段式命令有几条还没跑过。渲染时间先渲 3–5 帧校准。** - 安装:`brew install --cask blender`,也可以从官网下载。指南钉在 5.2 LTS(5.0 起只支持 Apple Silicon,Python API 有破坏性改动)。 - 渲染用脚本方式,保证结果可复现,分两段:`blender -b --factory-startup --python build.py -- …` 生成 `scene.blend`,再 `blender -b scene.blend … -a` 渲 PNG 序列。同时固定随机种子,并烘焙好模拟缓存。 +- 能跑的样板:`styles/_swatch/blender_render.py`(逐帧 `apply(t)` 再渲,正式版走 CPU 求逐像素相同)、`blender_prep.py`(渲染前的静态检查和字体解析)和 `render.sh` 里的 `bl_run`(`env -i` 加 `sandbox-exec`)。调用 bpy 的文件按 GPL-3.0-or-later 分发(见指南的"许可证")。 - 官方的 MCP server 和社区的 `ahujasid/mcp-for-blender` 都会直接执行 LLM 生成的 Python,没有任何防护。**默认不用**:要用先问用户,放在虚拟机或单独的 macOS 用户下;没有沙箱,就不要让 LLM 生成的 bpy 代码经过它们执行。管线里跑 agent 写的脚本,加静态检查、`sandbox-exec` 和 `env -i`(见指南的"安全"一节)。 ## 生成式视频(fal 等),按需使用 diff --git a/engines/blender.md b/engines/blender.md index c289576..afad264 100644 --- a/engines/blender.md +++ b/engines/blender.md @@ -1,8 +1,8 @@ # Blender 引擎指南(实验性) -> **实验性(experimental, not yet verified on this machine):维护者的 Mac(M3 Max)没有装 Blender**,下面所有 Blender 命令、API 和数字都来自官方文档、release notes 和 issue,没有跑过。ffmpeg、色彩、alpha、EXR 和 `sandbox-exec` 相关的结论在维护者的 Mac 上跑过,标【实测】。**渲染时间先渲 5 帧校准,把结果写进 BRIEF**(见"渲染时间")。 +> **部分验证(partly verified)**:2026-10-01 维护者的 Mac(M3 Max,macOS 15)装上了 Blender 5.2.2 LTS,风格库的 `tabletop-miniature` 样片(`styles/_swatch/` 的 Blender 场景)是在它上面做的。"首次冒烟"里做过的几项已经写回本文,标【实测 5.2.2】;没做的几项和其余的 Blender 命令、API 和数字仍来自官方文档、release notes 和 issue。ffmpeg、色彩、alpha、EXR 和 `sandbox-exec` 相关的结论标【实测】。**渲染时间先渲 3–5 帧校准,把结果写进 BRIEF**(见"渲染时间")。 > -> 标记:【实测】在维护者的 Mac(macOS 15,ffmpeg 8.0.1)上跑过;【二手】只读到搜索摘要或第三方转述,没能打开原文;【推测】没有证据的推断。引用编号 `[n]` 见文末"来源"。`bin/vh` 里还没有 Blender 的子命令,下文都是直接调用 `blender`。首次装上 Blender 之后,先做"首次冒烟"里的几项,把结果写回本文,再去掉这段警告。 +> 标记:【实测】在维护者的 Mac(macOS 15,ffmpeg 8.0.1)上跑过;【实测 5.2.2】用 Blender 5.2.2 跑过;【二手】只读到搜索摘要或第三方转述,没能打开原文;【推测】没有证据的推断。引用编号 `[n]` 见文末"来源"。`bin/vh` 里没有项目用的 Blender 子命令,下文都是直接调用 `blender`;风格样片走 `bin/vh style `,做法见 `styles/_swatch/README.md` 的"Blender 场景",那里的 `blender_render.py` 是一个能跑的逐帧渲染器。 ## 要点 @@ -13,7 +13,7 @@ 5. **纯函数**:时间线用我们自己的缓动、样条和节拍函数,逐帧采样成关键帧;不用 Python handler,不靠实时模拟。 6. **合成与颜色**:默认交 PNG(straight alpha,视图变换已烘进去);EXR 是 scene-linear,进 ffmpeg 要显式 `-apply_trc iec61966_2_1`;最后一步 H.264 要写 BT.709 矩阵和四个标签,否则饱和色偏 20 个色阶左右。 7. **安全**:官方 MCP 自己警告,它会直接执行 LLM 生成的代码,没有任何防护 [16]。**没有沙箱,就不要让 LLM 生成的 bpy 代码经过任何 MCP 执行**;管线里跑 agent 写的脚本同理。 -8. **许可**:输出归自己,但公开发布的、调用 bpy 的脚本要以 GPL 兼容协议发布 [17]。仓库是 MIT,这里的做法**维护者待定**(见"许可证")。 +8. **许可**:输出归自己,但公开发布的、调用 bpy 的脚本要以 GPL 兼容协议发布 [17]。本仓库的做法(维护者 2026-10-01 决定):import bpy 的文件标 `SPDX-License-Identifier: GPL-3.0-or-later`,按 GPL 分发,其余仍是 MIT(见"许可证")。 ## 什么时候用 Blender @@ -236,7 +236,7 @@ sandbox-exec -f vh_blender.sb env -i PATH="$PATH" HOME="$PWD/blender/out/.home" Blender 自己需要写的位置(着色器缓存、用户配置目录)和 `env -i` 下还缺的环境变量都还没验证【未实测】,首次冒烟时按报错补白名单。沙箱不是安全边界的终点:`(allow default)` 只挡了网络和写入,读取 `~/.ssh`、`~/.zsh_secrets` 这类文件仍然放行(验证过)。要更严,在 profile 的 `(allow default)` 之后加一行拒读,例如 `(deny file-read* (subpath "/Users//.ssh") (literal "/Users//.zsh_secrets"))`(路径写绝对路径;实测读被拒,python 照常运行)。 -## 许可证(维护者待定) +## 许可证(2026-10-01 已定:选项 (2)) 以下是官方原文的要点,不是法律意见;许可页和 FAQ 的原文 2026-10-01 对着页面核对过 [17]。 @@ -249,7 +249,7 @@ Blender 自己需要写的位置(着色器缓存、用户配置目录)和 `e | 官方 MCP、`bpy` PyPI 包 | 元数据都标 GPL-3.0 [16][18] | 只读参考 | | 素材 | 各自许可:Poly Haven 等为 CC0,Poly Pizza 多为 CC-BY,Sketchfab 逐件不同 [16] | 一律记素材台账 | -**维护者待定**:本仓库是 MIT。`engines/blender/` 下如果放调用 bpy 的脚本,许可怎么写,有三个选项:(1) 仓库里不放 `import bpy` 的文件,`build.py` 由 agent 在项目目录里生成(`projects/` 不入库),仓库只放不 import bpy 的封装和模板 JSON;(2) `import bpy` 的文件标 `SPDX-License-Identifier: GPL-3.0-or-later`,在 `ACKNOWLEDGMENTS.md` 里说明,这部分文件按 GPL 分发;(3) 保持 MIT,承担 FAQ 字面要求和 MIT 之间的差距。**决定之前按 (1) 做**:仓库里不放 `import bpy` 的文件,本指南也只有流程、伪代码和 API 名称。Blender 的名称和 logo 受单独的商标政策约束,片子里出现 Blender 界面截图前先看一眼 [17]。 +本仓库是 MIT。调用 bpy 的脚本放进仓库时,许可怎么写,原有三个选项:(1) 仓库里不放 `import bpy` 的文件,`build.py` 由 agent 在项目目录里生成(`projects/` 不入库),仓库只放不 import bpy 的封装和模板 JSON;(2) `import bpy` 的文件标 `SPDX-License-Identifier: GPL-3.0-or-later`,这部分文件按 GPL 分发;(3) 保持 MIT,承担 FAQ 字面要求和 MIT 之间的差距。**维护者 2026-10-01 选了 (2)**:现在仓库里 import bpy 的文件是 `styles/_swatch/blender_render.py` 和 `styles/tabletop-miniature/swatch.py`,文件头都有 SPDX 标注,`README.md` 的 License 一节写明了;不 import bpy 的封装(`blender_prep.py`、`render.sh`)仍是 MIT。以后加 import bpy 的文件,照样标。项目里 agent 生成的 `build.py` 在 `projects/` 下,不入库,不受影响。Blender 的名称和 logo 受单独的商标政策约束,片子里出现 Blender 界面截图前先看一眼 [17]。 ## 流程与验证 @@ -277,14 +277,26 @@ Blender 自己需要写的位置(着色器缓存、用户配置目录)和 `e ## 首次冒烟(装上 Blender 之后) +2026-10-01 用 5.2.2(Homebrew cask,M3 Max)做过的【实测 5.2.2】: + +- **同一帧、同一设置、新进程渲两次**(一个简单场景:木纹桌面、一个方块、一行中文、两盏灯,1920×1080,64 spp + OIDN):CPU 上的 Cycles 逐像素相同;Metal 上的 Cycles 不同,PSNR 92 dB;EEVEE 不同,85 dB。都在 45 dB 线以上,但只有 CPU 能做到逐像素相同。风格样片的正式版因此走 CPU;草稿走 Metal。 +- **乱序、多进程**:`tabletop-miniature` 的 12 帧倒序分给 3 个新进程重渲,和整片按顺序渲出来的同一帧比(`styles/_swatch/determinism.sh`),结果见 `styles/_swatch/README.md`。 +- **速度**:上面那个简单场景每帧 CPU 21 s、Metal 4.5 s、EEVEE 1.1 s(含启动)。`tabletop-miniature`(约 70 个物体、文字、景深、4 盏灯)CPU 64 spp 每帧 32–43 s,32 spp 每帧 15–19 s,两者并排放大看不出差别;Metal 20 spp 每帧约 1.6 s。 +- **`sandbox-exec` 套 Blender**:只放行输出目录时,Metal 不能写着色器缓存,每帧都重编(2 s 变成 13 s);场景需要新内核时 Blender 直接 abort(`Abort trap: 6`)。再放行 `getconf DARWIN_USER_CACHE_DIR` 和 `DARWIN_USER_TEMP_DIR` 两个本用户目录后正常,日志里仍有几行无害的 "Error creating directory"。`env -i` 只带 `PATH`、`LANG`,`HOME` 和 `TMPDIR` 指进输出目录,Blender 照常运行,Cycles 的内核缓存写到 `$HOME/.cache/cycles`。 +- **字体**:`bpy.data.fonts.load()` 只读 .ttc 的第一个字形:`Songti.ttc` 读出 Songti SC Black,`Hiragino Sans GB.ttc` 读出 W3。要别的字重,先把那一面写成单独的字体文件(`styles/_swatch/blender_prep.py` 用 fontTools 做)。 +- **API**:5.2 里新建的材质和世界自带节点树,再设 `use_nodes` 会报 DeprecationWarning(6.0 删除);Mix 节点有三组同名输入(float、vector、color 都叫 "A"),要按 identifier 取(`A_Color`、`Factor_Float`、`Result_Color`);`view_transform` 和 `look` 是动态枚举,`bl_rna` 里查不到选项,直接设、失败再退(`AgX` 和 `AgX - Medium High Contrast` 都可用);后台模式下 `stdout` 是块缓冲,Cycles 的进度行不会实时进日志,渲染器要自己 `print(..., flush=True)`,否则看门狗会以为卡住了。 +- **persistent data 会留下跨帧状态**:一个进程里按顺序逐帧 `apply(t)` 再 `bpy.ops.render.render()`,开着 `render.use_persistent_data` 时,CPU 上的 Cycles 在一段帧里把一个物体(茶杯)渲成全黑,单独渲同一帧是正常的;乱序重渲 12 帧,有 1 帧对不上(24.5 dB)。关掉以后每帧时间几乎不变。逐帧改属性再渲的流程不要开它,开了就要做乱序比对。 +- **job control**:在 `set -m` 打开的 shell 里把 Blender 放到后台,它会进另一个进程组,看门狗按组杀不到它;在起 Blender 的子 shell 里先 `set +m`。 + +还没做的: + 1. 5.2 上 EEVEE 命令行渲 300 帧,看内存曲线(#125333 的后续)。 -2. Cycles Metal 的确定性:`-f N` 对 `-a`、单进程对多进程、重启前后;自适应采样开、关各一组。 +2. Cycles Metal 的确定性:`-f N` 对 `-a`、单进程对多进程、重启前后;自适应采样开、关各一组(CPU 的乱序一致见上)。 3. OIDN 开、关的静态区域闪烁。 4. 刚体烘焙缓存乱序渲染是否一致。 -5. `sandbox-exec` 套 Blender 本体:着色器缓存和用户配置目录要补哪些写目录。 -6. HyperFrames 的 `