Repository navigation
macOS: bash 3.2, BSD tools, BT.709 tags with ffmpeg 7.1 and newer, LF checkouts (fixes #2) - #6
Merged
Merged
Conversation
Fixes #2. - hf-finish.sh: the preflight moves out of a heredoc inside $( ), which bash 3.2 (macOS's /bin/bash) scans as shell code, into scripts/hf-preflight.cjs, verbatim (same cues, messages and exit codes). The other heredocs inside $( ), in deliver.sh and render.sh, become shell functions called inside $( ). - hf-finish.sh: BSD wc's padded frame count is trimmed and compared as a number; colour codes are stripped with an ESC from printf (BSD sed has no \x1b). render-chunks.sh falls back to sysctl -n hw.ncpu. - BT.709: ffmpeg 7.1 and newer take the stream's colour tags from the frames, over -color_primaries/-color_trc. The hf-finish.sh encode, accumulate.py and the WebM in deliver.sh end their filters with setparams. accumulate.py's unlabelled raw pipe was also converted by an auto-inserted scaler (colours shifted); it now passes through bit-exact. With ffmpeg 6.1 the output is identical to before. - CI: a bash 3.2.57 job (bash -n of every script, the HyperFrames preflight under 3.2, a guard against heredocs inside $( )), node --check of the Node scripts, and a job that runs the new scripts/test/encode-tags.test.py. - Docs: finishing.md section 4, setup.md (requirements, troubleshooting, the stale date %N row removed), README contributing, CHANGELOG. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scripts row says 28 scripts now, names hf-preflight.cjs next to brand-svg.ts as an internal helper without --help, and lists the encode-tags test in scripts/test/. Part of #2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
core.autocrlf=true (the Git for Windows default) checked the scripts out with CRLF, and WSL's bash then stops at "set: pipefail: invalid option name". The index already holds LF everywhere, so renormalising changes no blob. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…affold - hf-preflight.cjs crashed with a TypeError on --help or without its environment; it now points at hf-finish.sh --help and exits 2. SKILL.md names it with brand-svg.ts as the scripts without --help. - docs/setup.md told projects to `cp -R "$SKILL/scripts/." scripts/`, which also copies the skill's tests (fixtures that break the rules on purpose) and caches. Both troubleshooting rows now link a new "Updating a project's scripts" section with new-film.sh's own tar copy. - scripts/test/scripts-docs.test.mjs: the --help contract, hf-preflight's exit 2, the docs naming the same helpers, and the refresh command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- macos-latest job: the real /bin/bash 3.2 parses every .sh and runs the HyperFrames preflight; new-film.sh scaffolds a HyperFrames project and the docs' refresh command runs with BSD sed and tar; encode-tags.test.py runs on Homebrew's ffmpeg (7.1+, where the setparams fix matters). Ubuntu's ffmpeg 6.1 passes the encodes with or without it. - The one-line grep for a heredoc inside $( ) missed `X=$(` followed by a heredoc on the next line and nested parens. scripts/test/bash32.test.py scans across lines (quotes, comments, heredoc bodies, arithmetic, nesting of $( ), backticks, <( ), >( )), with self-tests; it flags all four heredocs main had inside $( ). - check job: runs scripts-docs.test.mjs, and checks LF in the index, LF checkout attributes for scripts and binary attributes for media. - new-film.sh matches motion.js with [[:space:]] instead of \s. - CHANGELOG and README describe the guard as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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.
Fixes #2
Five commits on
main(bee5d78): the fix (d2532b3), the README's script count (080eec9), LF checkouts(bb26a14),
hf-preflight.cjs --helpand a safer script refresh for existing projects (d27fab7), and CI that teststhe fix on a real macOS runner (ea2e007).
Thanks to @gdorea for the precise report: all three problems were real, and the suggested fixes were right. This PR
applies them and the same fixes in the places the report did not reach.
The fixes from #2
hf-finish.sh. When bash 3.2 looks for the closing paren of a$( ), it scans thetext as shell code, heredoc bodies included. The quote characters in the preflight's JavaScript regexes (
["'])then open strings that never close. The preflight moves, verbatim, into
scripts/hf-preflight.cjs, andhf-finish.shrunsnode "$SCRIPT_DIR/hf-preflight.cjs". The three other heredocs inside$( )(deliver.sh×2,
render.sh×1) parse today only because their Python happens to have balanced quotes. They become shellfunctions called inside
$( ).wcpads its count.hf-finish.shtrims the count (tr -d '[:space:]') and compares it with-eq.those win over
-color_primaries/-color_trc.scalesets only the matrix and range on the frames, so theHyperFrames encode came out
bt709/None/None/tv.hf-finish.shnow ends its-vfwithsetparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv.accumulate.py(the encoder of every--blurmaster, for Remotion andHyperFrames). Its raw yuv pipe has no colour labels at all, so ffmpeg 7.1+ inserts its own scaler. That scaler
converts the planes from an assumed matrix to BT.709, so the colours shift (lossless test: PSNR Y 22.5 dB against
the source), and the file still has no primaries or transfer.
-vf setparams=...labels the planes instead: alossless encode now decodes to exactly the source planes.
deliver.sh --webmgets the same-vf setparams=...(it only labels; the master is BT.709 limited range).Without it, a master that lacks the tags passes that on to the WebM.
Smaller macOS fixes from the same pass:
hf-finish.shstrips colour codes from the HyperFrames logs with an ESC character built byprintf. BSDsedhasno
\x1b, so before this the codes stayed in.render-chunks.shfalls back tosysctl -n hw.ncpuwhen there is nonproc.new-film.shmatchesmotion.jswith[[:space:]]instead of\s, which is not portable to BSDgrep.docs/setup.mdloses a stale troubleshooting row aboutdate %N.render.shonly usesdate +%sand times thesharp pass with
python3.Later commits
.gitattributes). Withcore.autocrlf=true(the Git for Windows default) the scripts werechecked out with CRLF, and WSL's bash then stops at
set: pipefail: invalid option name. Every text file now checksout with LF, scripts are always text, and media files are marked binary. The index already held LF everywhere, so
no blob changes.
hf-preflight.cjs --help. Run on its own, the helper crashed with a TypeError. It now prints a pointer tohf-finish.sh --helpand exits 2.SKILL.md, the README anddocs/setup.mdname it, withbrand-svg.ts, as thescripts without a
--helpof their own.cp -R "$SKILL/scripts/." scripts/, which also copies the skill's own tests (fixtures that break the rules onpurpose) and Python caches into the project. A new
docs/setup.mdsection, "Updating a project's scripts", givesthe same
tarcopy thatnew-film.shuses, and both rows link to it.Changes
skills/cinetic/scripts/hf-preflight.cjs--help/ missing-environment answer (exit 2). It is.cjsbecause it usesrequire()and a project'spackage.jsoncould declare"type": "module"skills/cinetic/scripts/hf-finish.shwcfix; ESC forsed;setparamsin the encodeskills/cinetic/scripts/deliver.shprobe_masterandposter_matchfunctions;setparamsin the WebMskills/cinetic/scripts/render.shsubframe_spanfunctionskills/cinetic/scripts/accumulate.py-vf setparams=...on the encoder; the comment that said "no scale filter, so no hidden dither" (not true on new ffmpeg) now says what happens and whyskills/cinetic/scripts/render-chunks.shsysctlfallbackskills/cinetic/scripts/new-film.sh[[:space:]]instead of\sskills/cinetic/scripts/probe.pybt709failure hint mentionssetparamsskills/cinetic/scripts/test/encode-tags.test.py-color_primaries bt709also hassetparams. With ffmpeg: thehf-finish.shfilter string (read from the script) andaccumulate.py(8-bit and 10-bit) writebt709/bt709/bt709/tvskills/cinetic/scripts/test/bash32.test.py$( ), backticks,<( )or>( )(it follows quotes, comments, heredoc bodies, arithmetic and nesting), with self-tests. It replaces a one-linegit grepthat missedX=$(with the heredoc on the next line, and nested parensskills/cinetic/scripts/test/scripts-docs.test.mjs--help;hf-preflight.cjsexits 2 with its pointer; the docs name the same helpers;docs/setup.mdrefreshes scripts withnew-film.sh's own copy.gitattributes.github/workflows/ci.ymlcheckjob additions; newbash32,macosandencode-tagsjobs (below)references/finishing.md§4setparamsand a paragraph on why it is neededskills/cinetic/SKILL.mdhf-preflight.cjswithbrand-svg.tsas the scripts without--helpdocs/setup.mdbt709/None/None/tvprobe failure; "Updating a project's scripts"; the stale row removedREADME.md,CHANGELOG.mdhf-preflight.cjsis an internal helper without--help), the new tests in Contributing, a description of the bash 3.2 guard;[Unreleased]Fixed and AddedCI
The
macosjob has never run on GitHub: this PR's first CI run is its first run. Thebash32andencode-tagsjobs have not run on GitHub either. Their steps were run locally (see Verification).macOS (bash 3.2, BSD tools, current ffmpeg)job (macos-latest): the platform of macOS: hf-finish.sh fails with stock bash 3.2, frame-count check fails with BSD wc, bt709 probe fails with ffmpeg 7.1 #2 for real./bin/bashis no longer 3.2, and warns if Homebrew's ffmpeg is older than 7.1./bin/bash -non every tracked.sh.hf-finish.sh <starter> --export-cues, the same asnpm run cues) under/bin/bash.new-film.sh --engine hyperframesscaffolds a project (and must not copyscripts/test), then the refreshcommand from
docs/setup.mdruns with BSDtarand the project'shf-finish.shexports cues.encode-tags.test.pyon Homebrew's ffmpeg (7.1 or newer, where thesetparamsfix matters).bash 3.2 (macOS)job (Docker imagebash:3.2.57, on Ubuntu, seconds to run):bash32.test.pyover every tracked.sh; it names each heredoc it finds and the fix;bash -non every tracked.sh, run by bash 3.2;hf-finish.sh <starter> --export-cuesrun by bash 3.2 (node from Alpine'sapk). It must get through thepreflight and write valid cues. A fresh checkout has no starter fonts or
vendor/gsap.min.js, so a preflightthat gets through still exits 1 after writing the cues, and the step accepts that. A script bash 3.2 cannot parse
writes nothing.
BT.709 encode tagsjob: installsffmpegandpython3-numpyand runsencode-tags.test.py. Ubuntu's ffmpegis 6.1, which passes the encodes with or without
setparams, so here the static part is the real guard; the macOSjob runs the encode part on a current ffmpeg.
checkjob:node --checkforscripts/**/*.mjs|cjs(the.pyfiles already getpy_compile), runsscripts-docs.test.mjs, and checks line endings: LF in the index, LF checkout attributes for every script type,and binary attributes for media.
The container job pins the exact bash version and is fast; the macOS job also covers the BSD userland and a current
ffmpeg, which the container cannot.
Verification
Local: Windows 11 with Git Bash 5.2.37 and ffmpeg 8.0.1; WSL Ubuntu 24.04 with bash 5.2.21, node 22.23 and ffmpeg
6.1.1. No Mac and no bash 3.2 binary were available.
hf-finish.sh <starter> --export-cuesbefore and after the change, on the freshstarter (fonts missing, exit 1) and on a copy with stub font and vendor files (exit 0). The cues JSON, stderr and
exit codes are identical, and so is the
P_...line from running the preflight on its own. The CI step, simulatedwith WSL bash, prints
300 frames, 7 events, and its cues are byte-identical to the pre-change run.$( ).bash32.test.pyonmain's scripts reports all four:hf-finish.sh:82(the reportedfailure),
deliver.sh:105,deliver.sh:156andrender.sh:219. On this branch it reports none, and its 18self-tests pass: 8 cases it must flag (the macOS: hf-finish.sh fails with stock bash 3.2, frame-count check fails with BSD wc, bt709 probe fails with ffmpeg 7.1 #2 case,
$(with the heredoc on the next line, nested$( ),backticks,
<( ),>( ),$( )inside${...}, two heredocs in one substitution) and 10 it must not (atop-level heredoc, the fix itself, a here-string,
<<as a shift or inside quotes or comments,$#, and others).bash -npasses on every script with bash 5.2 (Git Bash and WSL). Whether bash 3.2 itself accepts the scripts isshown by the CI jobs.
hf-finish.shencode line on testsrc2 PNGs: beforebt709/None/None/tv, afterbt709/bt709/bt709/tv.accumulate.py8-bit and 10-bit: beforebt709/None/None/tv, afterbt709/bt709/bt709/tv.probe.pyfails theold files and passes the new ones.
accumulate.py's encoder arguments on raw yuv420p with-qp 0: before, the decoded planes differ from thesource (auto-inserted scaler, PSNR Y 22.5 dB); after, they are identical.
bt709/None/None/tv, afterbt709/bt709/bt709/tv. From a fullytagged master, the WebM decodes to the same md5 with or without
setparams.encode-tags.test.pyon the branch head: all pass. Onmain's scripts it fails 6 checks and exits 1.accumulate.py's output decodes toidentical md5 before and after (8-bit and 10-bit).
setparamschanges nothing on older ffmpeg.deliver.shsmoke test (WSL) on a tiny master with--poster-fromand--webm:probe_master,poster_match(its message and exit status reachMATCH) and the tagged WebM all work.scripts-docs.test.mjs16 of 16 checks pass;hf-preflight.cjs --helpprints its pointer andexits 2;
lint-film.test.mjsandpick.test.pypass (WSL).py_compileof every script andnode --checkof the.mjs/.cjs: ok. The workflow YAML parses (jobscheck,bash32,macos,encode-tags). Thebash32job'spreflight step, run with WSL bash in place of the container, passes; its scan step is
bash32.test.py(above).Notes for review
new-film.shcopiesscripts/into each project, so a film madewith 1.0.0 keeps the broken
hf-finish.sh. The troubleshooting rows link to "Updating a project's scripts" indocs/setup.md, which refreshes them with the scaffold's owntarcopy (without the skill's tests).macosjob is for. The BSDwc/sedfixes follow thereport and were tested with GNU tools on the same inputs.
render.sh,render-chunks.sh,deliver.sh --alphaand--variantsuse Remotion's bundled ffmpeg with
--color-space=bt709. If that ffmpeg is 7.1 or newer, they may show the samemissing tags.
render.shrunsprobe.pyon every master, so that would fail loudly. Worth checking on the nextreal render.
next: a test merge (git merge-tree) conflicts only inCHANGELOG.md([Unreleased]) andREADME.md, because both sides added lines; keep both. In the README, the Contributing test list gets both sides'tests, and the scripts row becomes 29 scripts (
nextaddstrack-info.py, this PR addshf-preflight.cjs).🤖 Generated with Claude Code