diff --git a/CHANGELOG.md b/CHANGELOG.md index a662bfc..911f75b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +**Lessons from a narrated film with 3D: one voice across a one-request take, labels sized from the start, text swaps and readouts, glass in Three.js** +- Why: the maintainer asked that the general lessons from a 2-minute narrated canvas + Three.js film go into the docs as short guidance. +- playbook/04: in a one-request gemini take (`--join all`) every line still carries its own style, so one line with a `[direction]` (often the opening) tends to sound different from the rest; for one voice in a single-narrator film, write one short overall style and no per-line directions (tools/audio/README's "整段合成" points there). When lines in one take run audibly fast and slow, an optional way to bring them closer line by line without synthesizing again, not to one exact pace (cuts refined from the waveform, so a first syllable the ASR placed late is not clipped; long pauses inside a line capped; per-line `atempo` part of the way towards one target pace; the take and the timeline written back, aligned again, captions redone), described, not a command yet: the film went from 4.7–6.7 to 5.6–6.1 CJK chars/s per line; the numbers are a reference, the ear decides. When transcription is unavailable (daily quota, API errors): the take is already on disk; `--resume` later, or take word times from a local whisper and align them with tts.py's `align_lines`, mapping digits back to a script that spells years out (一九五三). +- tools/audio/README: a 429 asking for under 90 s (or naming no delay) is retried like the per-minute limit, up to 5 times a call, so a spent daily quota can look hung; the old text said the daily quota always fails at once. +- playbook/03 §4: write readable labels at the floor from the first draft (44 px for `desktop`; one draft had about 40 at 24–40 px). Source, credit and asset lines go into the description unless a licence or the type doc wants them on screen, and then they are labels. +- playbook/02 layer 3: a strip at each text swap in one place (#17's old-out-before-new-in, unchanged; a reviewer found three that the author's own check missed) and at each rolling readout, whose resting values are checked against NOTES. +- Floors, said explicitly (CONTRIBUTING rule 7): TASTE_CHECKLIST #19 names a readout resting on an interpolated value as a fabricated number (the film's reviewer had judged it under #19); #6 and playbook/03 §4 count a shot's one-line headline as a 主标题, so it is held to 84 px (150 for `feed`), not 44. +- engines/README (Three.js): `RoomEnvironment` reflections drew a bright vertical strip down every glass object, and a full-turn `LatheGeometry` seam faces a +z camera by default; turn the seam away and give glass a fresnel rim shell instead of the environment map. The list's lead-in now says most of its pitfalls come from the intro film. + **`bin/vh tts … minimax`: MiniMax narration in one request, timed by its own subtitles** - Why: a film's narration was made with MiniMax T2A (`speech-2.8-hd`) through a project script. Sending the whole script in one request kept the voice from drifting between blocks, which the maintainer had heard and disliked with block-by-block synthesis, and the request's own subtitles gave every character's time without an ASR pass. This makes that a provider. - `minimax` posts to `https://api.minimax.io/v1/t2a_v2` (the China host `api.minimaxi.com` rejects international keys with 2049; `MINIMAX_BASE_URL` for a China-platform key). Key from `MINIMAX_TOKEN_PLAN_KEY` (Token Plan, spends its credits) first, then `MINIMAX_API_KEY` (pay-as-you-go); an error names the variable, never the key, with a hint for 1008 (no balance on that billing) and 1004/2049 (wrong host for the key). `MINIMAX_TTS_MODEL` / `_SPEED` / `_VOL` / `_PITCH` are recorded in `_run.json`, so `--resume` refuses a change; speed, volume and pitch are checked against the API's ranges before anything is deleted, and so is the 10,000-character limit of each request. `--instruct` / `[direction]` count only as one of MiniMax's nine emotion words; other text is ignored and that is said once. Default voices: zh `Chinese (Mandarin)_Reliable_Executive`, en `English_expressive_narrator`. diff --git a/engines/README.md b/engines/README.md index 7d43806..fb4e78a 100644 --- a/engines/README.md +++ b/engines/README.md @@ -152,7 +152,7 @@ window.__vh = { - **等宽字体的坑**:`ui-monospace, monospace` 能通过字体 lint,快照里看起来也是等宽,但 `hyperframes render` 渲染出来却是比例字体(showcase 00 在第一版全片都中了招)。要用 `@font-face` 显式声明,例如 `@font-face{font-family:"LF Mono";src:local("SF Mono"),local("Menlo")}`。**判断字体要看 mp4 渲染出的帧,不要看快照。**`check --snapshots` 只保存对比度检查用的 PNG,不能替代 `snapshot --at`。 - `snapshot` 在 tween 刚开始的那一刻,可能和最终渲染出的帧不一致。关键帧以渲染出的 mp4 为准,逐帧 strip 的做法见 `playbook/02-verification.md`。 - 完整样板:`showcase/02-short-leo-doppler/`(竖屏科普,单个 `index.html`)。 -- **HyperFrames 加 Three.js(3D 世界、一镜到底)的坑**,来自介绍片的制作: +- **HyperFrames 加 Three.js(3D 世界、一镜到底)的坑**,多数来自介绍片的制作: - 每一帧都用 `renderAt(t)` 从 t 算出摄像机和所有物体的状态。摄像机路线用按 t 参数化的样条,不用 Three.js 的动画时钟。关卡处可以用 stop 关键帧停站,但要叠一层低幅的手持漂移,镜头不要完全停死(原因见 `playbook/08-vfx-and-motion-sources.md` 的"一镜到底"一节)。 - `VideoTexture` 必须**每帧**设置 `texture.needsUpdate = true`,否则渲染出的屏幕是全黑的。视频按 t 去 seek,而且要等 seek 完成。 - `__hf.buildReady` 要在普通 `