Docs/Skills and code/skill video-visual-production

.claude/skills/video-visual-production/references/troubleshooting.md

Markdown82 lines8.1 KBSkill: video-visual-production

What the file says about itself

Troubleshooting: Find the line you saw; do the fix. Never fix a failure by editing a rule, a threshold or a check script. If you believe a rule is wrong, tell the user which rule and why.

Troubleshooting

Find the line you saw; do the fix. Never fix a failure by editing a rule, a threshold or a check script. If you believe a rule is wrong, tell the user which rule and why.

Lint (beatsheet-lint.js, rule ids)

You seeMeaningFix
STRUCT ... does not follow / spans do not coverscene spans leave a gap or overlapmake each scene start at the previous scene's last word + 1; first at 0; last at the beat's last word
STRUCT ... cue X word N outside spana cue points at a word that is not in this scenepick a word index inside the scene's span (edit.js words a b)
STRUCT ... uses cue X which the scene does not definea text entry names a cue that is not in cuesadd the cue or change the text's cue (use enter for "from the start")
H1 ... class missing / unknown scene typeset class to E, D, M or T; use a type from scene-catalogue.md
H2 ledger id ... has no rowthe scene cites a fact not in ledger-<beat>.jsonadd the row (copy the claim, status and source from the script ledger) or remove the id
H2 class D scene with no ledger rowa data scene needs a ledger rowadd one
H3 ... asset ... has no recordthe asset was never fetchedrun the build (assets stage) or assets.js --sheet <sheet>
H3 ... without an on-screen source linean evidence scene needs a text entry with role: "source" and the scene must draw itadd it
H3 ... no allowed licenceCommons file is not CC0 / public domain / CC BY / CC BY-SA / GODLchoose another file
H4 ... not allowednews video, logo, face or stockremove it; use a typographic scene
H5 ledger row ... has status X[CHECK] or [V-search] facts may not be drawndo not draw it; tell the user
H8 "X" is on screen but N is not spokena number on screen the voice does not say in this sceneremove it, or if the voice said it earlier in the beat add recall_from: <word index>
H8 "N" is spoken but not shown on screenthe voice says a number the scene does not showadd a text entry with number: true on that word
T1 "..." is held X s, needs Y stext is on screen too brieflycue it on an earlier word, shorten it, or start the next scene later (start_shift_frames)
A3 sfx ... ms after / more than 3 sfx within 10 ssounds too close or too manyremove or move one (edit.js sfx-remove)
A4 sfx ... no role or event idadd role and event
Warning LABELa label has no word in the voice spanadd spoken_as (the spoken word) or recall_from
Warning SYNC ... interpolated word timethe cue word's time was estimated, not measuredaccept it, or choose a neighbouring measured word; tell the user
Warning L1, P3, A3 above 8 a minutepacing or densityoptional; mention to the user

Build stages

You seeCauseFix
canvas is not installedcd .claude/skills/video-visual-production/render && npm install
Node 22 or newer is neededuse Node 22+
missing input ...the audio, words or ledger path in the sheet is wrongfix the path (repo-relative)
FAILED bt2011...: anchor not found in page textthe article text does not contain your anchor wordsopen the page text (curl), copy the exact words; check the page did not move behind a paywall; if it still fails the scene is shown typeset and the build warns. Report that to the user
highlight phrase(s) not found on pagea highlight phrase is not on the page exactlycopy it exactly from the page text
Chrome did not expose a page targetChrome path or portset CHROME_PATH, close other Chrome windows started by the tool, retry
REFUSED ...: licence ... is not in the allowlistCommons licencepick another file
typeset: phrase not found in fallback textfallback_text lacks a highlight phrasemake the fallback the full passage
render.js ... Cannot read properties of undefineda scene prop is missingopen scene-catalogue.md for the type and compare
ffmpeg exitedffmpeg problem or disk fullcheck free space on C: (needs about 500 MB per beat)
mix says limiter cost about X dB with X over 4the voice is very peakytell the user; it still passes
build is slow (over 5 min)machine busy (6 GB RAM)close other programs; use --preview while authoring

Check (STATUS-video-<beat>.md)

Row failsMeaningFix
T2 text too smalla text box under the minimum sizeraise size in the scene's props or edit the scene function
T3 contrasttext colour against the sampled backgrounduse a lighter tone (ink or muted), not dim; avoid effects drawn behind text
T4 safe area / bottom 12%text too close to the edgemove it or shorten it; for a fixed layout, edit the scene function
T4 overlapping texttwo text boxes overlap at the end of the scenechange positions or remove one line
Q1 black / freeze / silenceundeclaredfind which scene (contact-sheet.png), fix its animation
Q3 no change at a cuttwo scenes look identical across a cutmake the scenes different or use fade
S2 a sound is off its eventthe contact offset in contacts.js differs from the animationalign the animation in scenes.js to the contact constant
A1 loudness / peakmix outside -14 LUFS +-1 or peak above -1 dBTPrerun the mix (mix.js); if it still fails tell the user
Q0 frame countthe cache holds a stale cliprebuild with --no-cache

Lessons from beats B2 to B9 (what failed, and where the fix belongs)

Most check failures were defects in a scene type, not in a beat. Fix them once in the scene code (the orchestrator does this; storyboard and review agents may not edit code), then every beat benefits.

What failedCauseFixed in
T4 text past the right or left edgea label wider than the room the scene left ittxt() in draw.js now keeps every text box inside the 96 px margins; race labels have 450 px; credits wrap
T3 contrast on red, dim or grey textthe dark red and the dim tone are too dark on the near-black groundC.lossText (lighter red) for red text; dim tones map to muted; a darker red on the cream calendar
Q1 black frames at the enda dark closing scene fades below the black threshold earlier than the last framesthe whole 0.6 s end fade is declared black in the timeline
Q3 "no change at a cut" on a scene that fades inthe first frames of a fade-in equal the previous scene's empty endthe check looks up to 12 frames past the cut
two series labels piled upboth end labels went above their pointshigher series above, lower below; series names in a legend row under the chart
a falling line crossing its own value labelthe label sat above a point the line arrives at from abovethe label goes below when the line falls into the point
a slot lock blocked every build for 30 minutesa killed build never released its lockthe lock records the owner's process id; a dead owner's lock is removed at once
alignment 63% on a 100 s beatWhisper dropped 85 words in one long passalign-beat.js retries with the large model, then cuts the beat into 30 s chunks at silences
ffmpeg could not cut the B3 WAVodd timestamps: input-side seek returns nothingdecode first, then trim (output-side -ss)
shell tools ate backslashes in generated codeheredocs and node -e stringswrite code with the Write or Edit tool; never patch regexes through the shell

What a storyboard should avoid so the checks pass first time: put a number only on the word that says it; keep texts short enough to hold for 1.2 s; use say for numbers the voice speaks in words; do not draw a figure the voice does not say, even a derived one (the 197-day clock in B9 was dropped for this reason: a waiver or a spoken number is needed); give every data scene a source line.

When you are stuck

Stop after two failed attempts at the same step. Write down: the command, the exact error, what you tried. Tell the user. Do not work around a gate, and do not claim the build passed.

Show the raw text
# Troubleshooting

Find the line you saw; do the fix. Never fix a failure by editing a rule, a threshold or a check script. If you believe a rule is wrong, tell the user which rule and why.

## Lint (`beatsheet-lint.js`, rule ids)

| You see | Meaning | Fix |
|---|---|---|
| `STRUCT ... does not follow` / `spans do not cover` | scene spans leave a gap or overlap | make each scene start at the previous scene's last word + 1; first at 0; last at the beat's last word |
| `STRUCT ... cue X word N outside span` | a cue points at a word that is not in this scene | pick a word index inside the scene's `span` (`edit.js words a b`) |
| `STRUCT ... uses cue X which the scene does not define` | a `text` entry names a cue that is not in `cues` | add the cue or change the text's `cue` (use `enter` for "from the start") |
| `H1 ... class missing` / `unknown scene type` | | set `class` to E, D, M or T; use a type from `scene-catalogue.md` |
| `H2 ledger id ... has no row` | the scene cites a fact not in `ledger-<beat>.json` | add the row (copy the claim, status and source from the script ledger) or remove the id |
| `H2 class D scene with no ledger row` | a data scene needs a ledger row | add one |
| `H3 ... asset ... has no record` | the asset was never fetched | run the build (assets stage) or `assets.js --sheet <sheet>` |
| `H3 ... without an on-screen source line` | an evidence scene needs a `text` entry with `role: "source"` and the scene must draw it | add it |
| `H3 ... no allowed licence` | Commons file is not CC0 / public domain / CC BY / CC BY-SA / GODL | choose another file |
| `H4 ... not allowed` | news video, logo, face or stock | remove it; use a typographic scene |
| `H5 ledger row ... has status X` | `[CHECK]` or `[V-search]` facts may not be drawn | do not draw it; tell the user |
| `H8 "X" is on screen but N is not spoken` | a number on screen the voice does not say in this scene | remove it, or if the voice said it earlier in the beat add `recall_from: <word index>` |
| `H8 "N" is spoken but not shown on screen` | the voice says a number the scene does not show | add a `text` entry with `number: true` on that word |
| `T1 "..." is held X s, needs Y s` | text is on screen too briefly | cue it on an earlier word, shorten it, or start the next scene later (`start_shift_frames`) |
| `A3 sfx ... ms after` / `more than 3 sfx within 10 s` | sounds too close or too many | remove or move one (`edit.js sfx-remove`) |
| `A4 sfx ... no role or event id` | | add `role` and `event` |
| Warning `LABEL` | a label has no word in the voice span | add `spoken_as` (the spoken word) or `recall_from` |
| Warning `SYNC ... interpolated word time` | the cue word's time was estimated, not measured | accept it, or choose a neighbouring measured word; tell the user |
| Warning `L1`, `P3`, `A3 above 8 a minute` | pacing or density | optional; mention to the user |

## Build stages

| You see | Cause | Fix |
|---|---|---|
| `canvas is not installed` | | `cd .claude/skills/video-visual-production/render && npm install` |
| `Node 22 or newer is needed` | | use Node 22+ |
| `missing input ...` | the audio, words or ledger path in the sheet is wrong | fix the path (repo-relative) |
| `FAILED bt2011...: anchor not found in page text` | the article text does not contain your anchor words | open the page text (`curl`), copy the exact words; check the page did not move behind a paywall; if it still fails the scene is shown **typeset** and the build warns. Report that to the user |
| `highlight phrase(s) not found on page` | a highlight phrase is not on the page exactly | copy it exactly from the page text |
| `Chrome did not expose a page target` | Chrome path or port | set `CHROME_PATH`, close other Chrome windows started by the tool, retry |
| `REFUSED ...: licence ... is not in the allowlist` | Commons licence | pick another file |
| `typeset: phrase not found in fallback text` | `fallback_text` lacks a highlight phrase | make the fallback the full passage |
| `render.js ... Cannot read properties of undefined` | a scene prop is missing | open `scene-catalogue.md` for the type and compare |
| `ffmpeg exited` | ffmpeg problem or disk full | check free space on C: (needs about 500 MB per beat) |
| mix says `limiter cost about X dB` with X over 4 | the voice is very peaky | tell the user; it still passes |
| build is slow (over 5 min) | machine busy (6 GB RAM) | close other programs; use `--preview` while authoring |

## Check (`STATUS-video-<beat>.md`)

| Row fails | Meaning | Fix |
|---|---|---|
| `T2` text too small | a text box under the minimum size | raise `size` in the scene's `props` or edit the scene function |
| `T3` contrast | text colour against the sampled background | use a lighter tone (`ink` or `muted`), not `dim`; avoid effects drawn behind text |
| `T4` safe area / bottom 12% | text too close to the edge | move it or shorten it; for a fixed layout, edit the scene function |
| `T4` overlapping text | two text boxes overlap at the end of the scene | change positions or remove one line |
| `Q1` black / freeze / silence | undeclared | find which scene (`contact-sheet.png`), fix its animation |
| `Q3` no change at a cut | two scenes look identical across a cut | make the scenes different or use `fade` |
| `S2` a sound is off its event | the contact offset in `contacts.js` differs from the animation | align the animation in `scenes.js` to the contact constant |
| `A1` loudness / peak | mix outside -14 LUFS +-1 or peak above -1 dBTP | rerun the mix (`mix.js`); if it still fails tell the user |
| `Q0 frame count` | the cache holds a stale clip | rebuild with `--no-cache` |

## Lessons from beats B2 to B9 (what failed, and where the fix belongs)

Most check failures were defects in a scene type, not in a beat. Fix them once in the scene code (the orchestrator does this; storyboard and review agents may not edit code), then every beat benefits.

| What failed | Cause | Fixed in |
|---|---|---|
| T4 text past the right or left edge | a label wider than the room the scene left it | `txt()` in `draw.js` now keeps every text box inside the 96 px margins; `race` labels have 450 px; credits wrap |
| T3 contrast on red, dim or grey text | the dark red and the dim tone are too dark on the near-black ground | `C.lossText` (lighter red) for red text; `dim` tones map to `muted`; a darker red on the cream calendar |
| Q1 black frames at the end | a dark closing scene fades below the black threshold earlier than the last frames | the whole 0.6 s end fade is declared black in the timeline |
| Q3 "no change at a cut" on a scene that fades in | the first frames of a fade-in equal the previous scene's empty end | the check looks up to 12 frames past the cut |
| two series labels piled up | both end labels went above their points | higher series above, lower below; series names in a legend row under the chart |
| a falling line crossing its own value label | the label sat above a point the line arrives at from above | the label goes below when the line falls into the point |
| a slot lock blocked every build for 30 minutes | a killed build never released its lock | the lock records the owner's process id; a dead owner's lock is removed at once |
| alignment 63% on a 100 s beat | Whisper dropped 85 words in one long pass | `align-beat.js` retries with the large model, then cuts the beat into 30 s chunks at silences |
| ffmpeg could not cut the B3 WAV | odd timestamps: input-side seek returns nothing | decode first, then trim (output-side `-ss`) |
| shell tools ate backslashes in generated code | heredocs and node -e strings | write code with the Write or Edit tool; never patch regexes through the shell |

What a storyboard should avoid so the checks pass first time: put a number only on the word that says it; keep texts short enough to hold for 1.2 s; use `say` for numbers the voice speaks in words; do not draw a figure the voice does not say, even a derived one (the 197-day clock in B9 was dropped for this reason: a waiver or a spoken number is needed); give every data scene a source line.

## When you are stuck

Stop after two failed attempts at the same step. Write down: the command, the exact error, what you tried. Tell the user. Do not work around a gate, and do not claim the build passed.

Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.