Skip to content

Lessons from a long 4K canvas film: disk space, canvas density, 8-bit voice padding, a stale-mix warning in qa - #67

Merged
ZLHad merged 3 commits into
mainfrom
claude/icecube-lessons
Oct 6, 2026
Merged

ZLHad merged 3 commits into
mainfrom
claude/icecube-lessons

Conversation

@ZLHad

@ZLHad ZLHad commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Lessons from making a 457 s HyperFrames canvas film with narration (from its LESSONS.md), written into the docs without the film's own content.

What goes where

  • engines/README.md "出 4K": at 4K every capture is a screenshot (drawElement and Linux BeginFrame capture do not supersample), and 0.8.82's multi-worker screenshot capture stores every frame as a JPEG first, about 4 MB a frame. The render refuses to start when its estimate is over 90 % of the free space (57 GB needed, 53 GB free). HF_CAPTURE_PARALLEL_STREAM=true streams the frames into the encoder (13,710 frames, 4 workers, about 11 min on an M3 Max), or --workers 1; NODE_OPTIONS=--max-old-space-size=8192 is HyperFrames' own heap advice. The table gains: reset a canvas with setTransform(dpr, 0, 0, dpr, 0, 0), not (1, 0, 0, 1, 0, 0) or resetTransform(); a WebGL layer drawn into the canvas sizes its canvas and viewport by the same dpr.
  • tools/audio/qa.py: a STALE? warning (never a failure) at the top of the report and on the last line when an input was written more than 2 s after the mix (events.json, the beat map, --events, --voice, --timeline, --words, the inputs the stems' meta.json names; qa mix compares with meta.json), when an SFX event lands after the end of the mix, or when the narration ends after it. Why: bin/vh mix writes nothing when it stops on an error (a ding given a pitch), and qa then passed on the previous mix.wav.
  • tools/audio/README.md: t is a built-in's landing point (riser, swish_rev and tape end on it); which shaping keys each built-in takes (the signals take none, nor a variant); bin/vh mix writes nothing on an error; padding a voice with -f lavfi -i anullsrc and the concat filter quantises it to 8 bits, with the alternatives that were tested.
  • playbook/04-audio.md: --lead works without --beats (the clean way to start the narration later); the riser's landing point; the stale warning.

Item 6, the occlusion check as a bin/vh command, landed separately as bin/vh textcheck (ZLHad/OpenVideoHarness#68). After merging main, this PR no longer touches playbook/02-verification.md: its layer-2 line now describes the command, and the CHANGELOG keeps both entries.

Verified

  • HyperFrames 0.8.82 source (dist/cli.js): the disk estimate (frames × W × H × 4 / 8, refused above 90 % of the free space), the streaming gate (HF_CAPTURE_PARALLEL_STREAM; --workers 1 always streams), screenshot capture whenever DPR > 1, and the heap advisory. The film's 4K log: streaming, 4 workers, 10 min 45 s, 1,406.7 MB.
  • 8-bit padding reproduced with ffmpeg 8.0.1 on 16-bit, 24-bit and float sources: anullsrc + concat gives a max error of 1/128 with every quiet sample on the 1/128 grid, also with -c:a pcm_s24le and with aformat after concat; aformat=sample_fmts=s32 on each concat input, and adelay + apad, are bit-exact. bin/vh tts's gap files joined by the concat demuxer are bit-exact; bin/vh tts … say Tingting zh --lead 0.6 starts line 1 at 0.60 s with digital silence before it.
  • bin/vh mix with a ding + pitch exits 1 and writes nothing; bin/vh qa on the old mix passed silently before this change and warns now. Synthetic cases: fresh (silent); events newer by 1 s (silent, inside the slack), by 3 s and 10 min (warns); an event after the end (warns); narration past the end (warns); qa mix on old stems (warns at the top and bottom); exit codes unchanged. showcase/01's tools/build_audio.sh runs clean with no warning; touching its events.json afterwards makes qa warn.
  • Every swatch and showcase event list ends inside its film, so the late-event check stays quiet there.
  • tools/ci.sh --committed passes, also with VH_BASH=/bin/bash; shellcheck and pyflakes ran through the uv recipe. Re-run after merging main (with bin/vh textcheck: canvas text covered by the picture, too faint, or out of the frame #68's textcheck tests): passes.

Independent review (one reviewer, read-only): no logic bug in qa.py, the HyperFrames facts match cli.js, no false warnings in the swatch and showcase flows. Fixed from it: a riser written at the start of its build-up lands a whole dur early, not late; a playbook/04 sentence that read as an instruction to use anullsrc + concat; qa mix only compares input times with meta.json (docs now say so); the 8-bit case needs the silence first with its length set by d= or an atrim (silence last or an input -t stayed exact); the quiet-sample test needs a stretch that is not all zeros; temporary 4K frames go beside --output and are re-checked after 10 frames; the heap advice prints only for an automatic worker count; bitrate and render time vary with the picture, so the 135 s re-encode line is the intro film's; the --lead usage lines and an sfx.py docstring.

… voice padding, a stale-mix warning in qa

- engines/README "出 4K": at 4K every capture is a screenshot, and HyperFrames 0.8.82's
  multi-worker screenshot capture stores every frame as a JPEG first (about 4 MB a frame;
  it refuses to start when its estimate exceeds 90 % of the free space, as a 457 s film
  did). HF_CAPTURE_PARALLEL_STREAM=true streams the frames into the encoder, or use
  --workers 1. Canvas: reset the transform with setTransform(dpr, 0, 0, dpr, 0, 0), not
  (1, 0, 0, 1, 0, 0); a WebGL layer drawn into the canvas sizes by the same dpr.
- tools/audio/qa.py: warn, never fail, when the mix may be stale: an input written more
  than 2 s after it, an SFX event landing after its end, or narration ending after it.
  bin/vh mix writes nothing when it stops on an error (a ding given a pitch), and qa
  used to report on the previous mix.wav without a hint.
- tools/audio/README, playbook/04: t is a built-in's landing point (a riser ends on it);
  which shaping keys each built-in takes (the signals take none); padding a voice with
  -f lavfi -i anullsrc and the concat filter quantises it to 8 bits (reproduced with
  ffmpeg 8.0.1): use tts --lead, adelay and apad, numpy, or aformat=sample_fmts=s32 on
  every concat input.
- playbook/02: how to measure canvas text that is covered or low in contrast, which
  hyperframes check cannot see.
ZLHad added 2 commits October 7, 2026 01:42
# Conflicts:
#	CHANGELOG.md
#	playbook/02-verification.md
…oes 8-bit, 4K disk and cost notes

- A riser written at the start of its build-up lands a whole dur early (its peak on the
  build-up's start), not late: tools/audio/README and playbook/04.
- playbook/04: the padding sentence read as an instruction to use anullsrc + concat.
- qa mix only compares the inputs' times with meta.json; the late-event and narration
  checks run in full, scan and cues runs (docstring, README, CHANGELOG).
- The 8-bit padding happens with the silence first and its length set by d= or an
  atrim (ffmpeg 8.0.1); silence last or an input -t stayed exact. The quiet-sample test
  needs a stretch that is not all zeros.
- engines/README: temporary frames go beside --output, HyperFrames checks again after
  10 frames, a bigger disk is a third way; the heap advice only prints for an automatic
  worker count (4 fit the default heap); bitrate and render time vary with the picture,
  so the 135 s re-encode line is the intro film's; the identity transform is fine for
  clearing or pasting a device-sized layer.
- tts.py and bin/vh tts usage: --lead no longer nested under --beats; sfx.py: qa stops on
  a wrong shaping key only when one of its checks renders that event.
@ZLHad
ZLHad marked this pull request as ready for review October 6, 2026 18:29
@ZLHad
ZLHad enabled auto-merge (squash) October 6, 2026 18:29
@ZLHad
ZLHad merged commit 76eb5b3 into main Oct 6, 2026
2 checks passed
@ZLHad
ZLHad deleted the claude/icecube-lessons branch October 6, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant