Repository navigation
Lessons from a long 4K canvas film: disk space, canvas density, 8-bit voice padding, a stale-mix warning in qa - #67
Merged
Merged
Conversation
… 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.
# 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
marked this pull request as ready for review
October 6, 2026 18:29
ZLHad
enabled auto-merge (squash)
October 6, 2026 18:29
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.
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=truestreams 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=8192is HyperFrames' own heap advice. The table gains: reset a canvas withsetTransform(dpr, 0, 0, dpr, 0, 0), not(1, 0, 0, 1, 0, 0)orresetTransform(); a WebGL layer drawn into the canvas sizes its canvas and viewport by the same dpr.tools/audio/qa.py: aSTALE?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 mixcompares with meta.json), when an SFX event lands after the end of the mix, or when the narration ends after it. Why:bin/vh mixwrites nothing when it stops on an error (adinggiven apitch), and qa then passed on the previous mix.wav.tools/audio/README.md:tis 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 avariant);bin/vh mixwrites nothing on an error; padding a voice with-f lavfi -i anullsrcand theconcatfilter quantises it to 8 bits, with the alternatives that were tested.playbook/04-audio.md:--leadworks 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/vhcommand, landed separately asbin/vh textcheck(ZLHad/OpenVideoHarness#68). After merging main, this PR no longer touchesplaybook/02-verification.md: its layer-2 line now describes the command, and the CHANGELOG keeps both entries.Verified
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 1always 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.-c:a pcm_s24leand withaformatafter concat;aformat=sample_fmts=s32on each concat input, andadelay+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.6starts line 1 at 0.60 s with digital silence before it.bin/vh mixwith ading+pitchexits 1 and writes nothing;bin/vh qaon 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 mixon old stems (warns at the top and bottom); exit codes unchanged.showcase/01'stools/build_audio.shruns clean with no warning; touching its events.json afterwards makes qa warn.tools/ci.sh --committedpasses, also withVH_BASH=/bin/bash; shellcheck and pyflakes ran through theuvrecipe. 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 matchcli.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 wholedurearly, not late; a playbook/04 sentence that read as an instruction to use anullsrc + concat;qa mixonly compares input times with meta.json (docs now say so); the 8-bit case needs the silence first with its length set byd=or anatrim(silence last or an input-tstayed exact); the quiet-sample test needs a stretch that is not all zeros; temporary 4K frames go beside--outputand 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--leadusage lines and an sfx.py docstring.