explainer-video 0.0.0-stage → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +12 -0
- package/LICENSE +21 -0
- package/README.md +154 -2
- package/cordis.patch.yml +7 -0
- package/lib/index.js +35 -0
- package/package.json +56 -4
- package/plugin.json +13 -0
- package/skills/coursework-author/.synced-from +5 -0
- package/skills/coursework-author/SKILL.md +209 -0
- package/skills/craft-codeflow-flows/SKILL.md +116 -0
- package/skills/craft-codeflow-mine/SKILL.md +207 -0
- package/skills/craft-codeflow-plan/SKILL.md +65 -0
- package/skills/craft-codeflow-scene/SKILL.md +168 -0
- package/skills/craft-video-align/SKILL.md +109 -0
- package/skills/craft-video-assemble/SKILL.md +70 -0
- package/skills/craft-video-audio/SKILL.md +59 -0
- package/skills/craft-video-enrich/SKILL.md +46 -0
- package/skills/craft-video-plan/SKILL.md +57 -0
- package/skills/craft-video-publish/SKILL.md +79 -0
- package/skills/craft-video-render/SKILL.md +68 -0
- package/skills/craft-video-scene/SKILL.md +112 -0
- package/skills/craft-video-script/SKILL.md +80 -0
- package/skills/craft-video-thumbnail/SKILL.md +168 -0
- package/skills/explainer-video-from-codebase/FLOWS.md +577 -0
- package/skills/explainer-video-from-codebase/SKILL.md +698 -0
- package/skills/explainer-video-from-codebase/tools/apply-flows.mjs +531 -0
- package/skills/explainer-video-from-codebase/tools/approve-flows.mjs +56 -0
- package/skills/explainer-video-from-codebase/tools/codemap-md.mjs +116 -0
- package/skills/explainer-video-from-codebase/tools/config/dotenv.mjs +13 -0
- package/skills/explainer-video-from-codebase/tools/config/json.mjs +14 -0
- package/skills/explainer-video-from-codebase/tools/config/redact.mjs +16 -0
- package/skills/explainer-video-from-codebase/tools/config/toml-lite.mjs +13 -0
- package/skills/explainer-video-from-codebase/tools/config/yaml-lite.mjs +18 -0
- package/skills/explainer-video-from-codebase/tools/excerpt-check.mjs +186 -0
- package/skills/explainer-video-from-codebase/tools/excerpt.mjs +116 -0
- package/skills/explainer-video-from-codebase/tools/flow-diagram.mjs +168 -0
- package/skills/explainer-video-from-codebase/tools/flow-plan.mjs +129 -0
- package/skills/explainer-video-from-codebase/tools/flows-md.mjs +87 -0
- package/skills/explainer-video-from-codebase/tools/lang/c.mjs +684 -0
- package/skills/explainer-video-from-codebase/tools/lang/go.mjs +673 -0
- package/skills/explainer-video-from-codebase/tools/lang/python-config.mjs +143 -0
- package/skills/explainer-video-from-codebase/tools/lang/python-deps.mjs +62 -0
- package/skills/explainer-video-from-codebase/tools/lang/python-stdlib.mjs +24 -0
- package/skills/explainer-video-from-codebase/tools/lang/python.mjs +609 -0
- package/skills/explainer-video-from-codebase/tools/lang/typescript.mjs +963 -0
- package/skills/explainer-video-from-codebase/tools/lib/decompose.mjs +102 -0
- package/skills/explainer-video-from-codebase/tools/lib/groups.mjs +77 -0
- package/skills/explainer-video-from-codebase/tools/lib/observe-coverage.mjs +68 -0
- package/skills/explainer-video-from-codebase/tools/lib/observe-v8.mjs +232 -0
- package/skills/explainer-video-from-codebase/tools/lib/observe.mjs +162 -0
- package/skills/explainer-video-from-codebase/tools/lib/redact.mjs +28 -0
- package/skills/explainer-video-from-codebase/tools/lib/sandbox.mjs +97 -0
- package/skills/explainer-video-from-codebase/tools/lib/test-links.mjs +28 -0
- package/skills/explainer-video-from-codebase/tools/lib/toml.mjs +129 -0
- package/skills/explainer-video-from-codebase/tools/lib/trace-c.mjs +95 -0
- package/skills/explainer-video-from-codebase/tools/lib/trace-go.mjs +101 -0
- package/skills/explainer-video-from-codebase/tools/lib/trace-js.mjs +136 -0
- package/skills/explainer-video-from-codebase/tools/lib/tree-sitter.mjs +19 -0
- package/skills/explainer-video-from-codebase/tools/lib/walk.mjs +138 -0
- package/skills/explainer-video-from-codebase/tools/mine.mjs +409 -0
- package/skills/explainer-video-from-codebase/tools/propose.mjs +127 -0
- package/skills/explainer-video-from-codebase/tools/rank.mjs +119 -0
- package/skills/explainer-video-from-codebase/tools/ranking-md.mjs +76 -0
- package/skills/explainer-video-from-codebase/tools/rules/c-handlers.mjs +53 -0
- package/skills/explainer-video-from-codebase/tools/rules/celery-taskiq.mjs +48 -0
- package/skills/explainer-video-from-codebase/tools/rules/click-typer.mjs +6 -0
- package/skills/explainer-video-from-codebase/tools/rules/express.mjs +72 -0
- package/skills/explainer-video-from-codebase/tools/rules/fastapi.mjs +99 -0
- package/skills/explainer-video-from-codebase/tools/rules/go-http.mjs +173 -0
- package/skills/explainer-video-from-codebase/tools/rules/go-test.mjs +108 -0
- package/skills/explainer-video-from-codebase/tools/rules/grpc.mjs +57 -0
- package/skills/explainer-video-from-codebase/tools/rules/gtest.mjs +97 -0
- package/skills/explainer-video-from-codebase/tools/rules/haystack.mjs +55 -0
- package/skills/explainer-video-from-codebase/tools/rules/jest-vitest.mjs +100 -0
- package/skills/explainer-video-from-codebase/tools/rules/js-http-client.mjs +111 -0
- package/skills/explainer-video-from-codebase/tools/rules/nextjs.mjs +53 -0
- package/skills/explainer-video-from-codebase/tools/rules/process-spawn.mjs +49 -0
- package/skills/explainer-video-from-codebase/tools/rules/py-http-client.mjs +26 -0
- package/skills/explainer-video-from-codebase/tools/rules/pytest.mjs +107 -0
- package/skills/explainer-video-from-codebase/tools/rules/react-router.mjs +17 -0
- package/skills/explainer-video-from-codebase/tools/rules/registry.mjs +31 -0
- package/skills/explainer-video-from-codebase/tools/trace/c/fmtrace-sh +14 -0
- package/skills/explainer-video-from-codebase/tools/trace/js/fmtrace-net.cjs +33 -0
- package/skills/explainer-video-from-codebase/tools/trace/js/fmtrace-srcmap.cjs +41 -0
- package/skills/explainer-video-from-codebase/tools/trace/python/fmtrace_plugin.py +87 -0
- package/skills/explainer-video-from-codebase/tools/trace/python/sitecustomize.py +330 -0
- package/skills/explainer-video-from-codebase/tools/trace/sandbox/linux-bwrap.sh +73 -0
- package/skills/explainer-video-from-codebase/tools/trace/sandbox/macos-nonet.sb +41 -0
- package/skills/explainer-video-from-codebase/tools/trace.mjs +577 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-c.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-cpp.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-go.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-javascript.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-python.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/tree-sitter-typescript.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/LICENSES/web-tree-sitter.txt +21 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/MANIFEST.json +172 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-c.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-cpp.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-go.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-javascript.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-python.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-tsx.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/tree-sitter-typescript.wasm +0 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/web-tree-sitter.js +4081 -0
- package/skills/explainer-video-from-codebase/vendor/tree-sitter/web-tree-sitter.wasm +0 -0
- package/skills/explainer-video-from-coursework/ARCHITECTURE.md +61 -0
- package/skills/explainer-video-from-coursework/PIPELINE.md +369 -0
- package/skills/explainer-video-from-coursework/ROADMAP.md +727 -0
- package/skills/explainer-video-from-coursework/SERIES.md +243 -0
- package/skills/explainer-video-from-coursework/SETUP.md +105 -0
- package/skills/explainer-video-from-coursework/SKILL.md +998 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-chart.js +12 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-equation.js +10 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-hubspoke.js +7 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-loopflow.js +7 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-sequence.js +12 -0
- package/skills/explainer-video-from-coursework/scenes/_pt-timeline.js +11 -0
- package/skills/explainer-video-from-coursework/src/scene-code.html +127 -0
- package/skills/explainer-video-from-coursework/src/scene-code.js +379 -0
- package/skills/explainer-video-from-coursework/src/scene-core.js +1250 -0
- package/skills/explainer-video-from-coursework/src/scene-diagram.html +50 -0
- package/skills/explainer-video-from-coursework/src/scene-svg.html +50 -0
- package/skills/explainer-video-from-coursework/src/thumbnail.html +119 -0
- package/skills/explainer-video-from-coursework/src/timeline.js +297 -0
- package/skills/explainer-video-from-coursework/src/timing-chart.js +160 -0
- package/skills/explainer-video-from-coursework/tools/align.mjs +419 -0
- package/skills/explainer-video-from-coursework/tools/apply-enrichment.mjs +206 -0
- package/skills/explainer-video-from-coursework/tools/assemble.mjs +223 -0
- package/skills/explainer-video-from-coursework/tools/build-audio.mjs +234 -0
- package/skills/explainer-video-from-coursework/tools/chromium.mjs +73 -0
- package/skills/explainer-video-from-coursework/tools/debug-page.mjs +75 -0
- package/skills/explainer-video-from-coursework/tools/env.mjs +30 -0
- package/skills/explainer-video-from-coursework/tools/frame-dedup.mjs +131 -0
- package/skills/explainer-video-from-coursework/tools/key-source.mjs +151 -0
- package/skills/explainer-video-from-coursework/tools/model.mjs +21 -0
- package/skills/explainer-video-from-coursework/tools/naming.mjs +38 -0
- package/skills/explainer-video-from-coursework/tools/onset-audit.mjs +51 -0
- package/skills/explainer-video-from-coursework/tools/pacing-check.mjs +350 -0
- package/skills/explainer-video-from-coursework/tools/planner.mjs +616 -0
- package/skills/explainer-video-from-coursework/tools/publish.mjs +230 -0
- package/skills/explainer-video-from-coursework/tools/render.mjs +205 -0
- package/skills/explainer-video-from-coursework/tools/resolve-beats.mjs +239 -0
- package/skills/explainer-video-from-coursework/tools/script-check.mjs +174 -0
- package/skills/explainer-video-from-coursework/tools/stamp.mjs +71 -0
- package/skills/explainer-video-from-coursework/tools/thumbnail.mjs +224 -0
- package/skills/explainer-video-from-coursework/tools/timing-report.mjs +299 -0
- package/skills/explainer-video-from-coursework/tools/transcribe-gemini.mjs +96 -0
- package/skills/explainer-video-from-coursework/tools/tts-gemini.mjs +394 -0
- package/skills/explainer-video-from-coursework/tools/verify-audio.mjs +88 -0
- package/skills/explainer-video-from-coursework/tools/workdir.mjs +124 -0
- package/skills/explainer-video-from-coursework/vendor/plotly-basic.min.js +8 -0
- package/skills/explainer-video-from-coursework/vendor/plotly-basic.min.js.LICENSE.txt +16 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-video-script
|
|
3
|
+
description: Write and validate the spoken narration for one explainer-video. Stage 3 of explainer-video-from-coursework; run it alone to (re)write a video's script.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# craft-video-script — write the narration
|
|
7
|
+
|
|
8
|
+
> Part of the `explainer-video-from-coursework` pipeline — **stage 3 of 8**, the first
|
|
9
|
+
> per-video stage. Self-contained: it needs an enriched plan, not a full run.
|
|
10
|
+
>
|
|
11
|
+
> The pipeline's tools and scene hosts live in the sibling `explainer-video-from-coursework` skill: run them as `node ../explainer-video-from-coursework/tools/<tool>.mjs`, resolved against this skill's folder. Run from the **scratch root** — the directory holding `out/`, which Stage 0 fixes (default: beside your notes) — so every `out/<name>/…` path in this stage resolves.
|
|
12
|
+
|
|
13
|
+
> **Timing.** Bracket the stage with the stamp pair so the series accrues a per-video audit;
|
|
14
|
+
> `end` must run before the stage counts as done (see *Timing* in the main skill):
|
|
15
|
+
>
|
|
16
|
+
> ```bash
|
|
17
|
+
> node ../explainer-video-from-coursework/tools/stamp.mjs begin --out out/<name> --video <NN> --stage 3
|
|
18
|
+
> node ../explainer-video-from-coursework/tools/stamp.mjs end --out out/<name> --video <NN> --stage 3
|
|
19
|
+
> ```
|
|
20
|
+
|
|
21
|
+
**Prerequisites:** `out/<name>/plan.enriched.json` from the enrich stage.
|
|
22
|
+
|
|
23
|
+
The agent writes `out/<name>/scripts/<NN>-<slug>.json`, then validates:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
node ../explainer-video-from-coursework/tools/script-check.mjs --script out/<name>/scripts/<NN>-*.json \
|
|
27
|
+
--plan out/<name>/plan.enriched.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Done when:** the run exits **0** (`✓ script is valid`). An `UNCOVERED source
|
|
31
|
+
section` error — or any other error — means the script is incomplete.
|
|
32
|
+
|
|
33
|
+
**Script contract.**
|
|
34
|
+
|
|
35
|
+
- **Register** — a calm, methodical teacher who explains through story; each concept
|
|
36
|
+
opens as a concrete scenario, then unpacks step by step. No edge, no hot takes;
|
|
37
|
+
analogies welcome.
|
|
38
|
+
- **Granularity** — one segment per visual beat. Roughly 40–80 words; ≤130 words hard.
|
|
39
|
+
- **Per segment** — `key` (unique, short), `text` (spoken **verbatim**; no URLs,
|
|
40
|
+
markdown, or code), `style` (delivery direction), `visual` (a hint for the scene
|
|
41
|
+
stage), `covers` (the plan sections this segment narrates), and optional `pad` (hold
|
|
42
|
+
silence in seconds).
|
|
43
|
+
- **`covers`** — copy the exact section identity from `plan.enriched.json`
|
|
44
|
+
(`"src :: title @L<line>"`). Every assigned section must appear in some segment's
|
|
45
|
+
`covers`.
|
|
46
|
+
- **Budget** — target `planTargetMinutes`; stay within its 55%–125% band.
|
|
47
|
+
|
|
48
|
+
`videoIndex`, `title`, `form`, `planTargetMinutes`, `sources`, `artefacts` are copied
|
|
49
|
+
from the enriched plan's video; only `text`, `style`, `visual`, `covers` are authored.
|
|
50
|
+
|
|
51
|
+
<!-- sync:stage3-addendum -->
|
|
52
|
+
**Code-flow videos only.** A code-flow video's plan, `plan.json` or `plan.enriched.json`, carries
|
|
53
|
+
`"kind": "codebase"`, and its `forms` are `overview`, `flow` and `core`. A coursework plan has no `kind`; nothing
|
|
54
|
+
in this block applies to its videos.
|
|
55
|
+
|
|
56
|
+
A code video's narration is the reading time: a panel shows only the lines being narrated, each highlighted while
|
|
57
|
+
its sentence plays. The script for a code video adds these rules:
|
|
58
|
+
|
|
59
|
+
- **Open** on the concrete request, UI action or command that starts the flow.
|
|
60
|
+
- **One hop per segment.** Name identifiers in words; spoken text holds no code, no URLs and no markdown.
|
|
61
|
+
- **Narrate every line a panel will show**: the hop's narrated lines (`sectionSpans[].lines` in the plan, or the
|
|
62
|
+
lines you choose when that is `null`, at most 22), plus a cited test's def, call and assertion lines.
|
|
63
|
+
- **Branches.** Teach each `teach` branch in its own segment, naming its selector: the setting, flag or profile
|
|
64
|
+
that picks it.
|
|
65
|
+
- **Tests.** Describe a cited test by what it asserts. Call a hop "tested" or "pinned" only for a direct, unmocked
|
|
66
|
+
link, never for a `"strength": "reachable"` citation. For a traced run say "observed in the test suite", never
|
|
67
|
+
"in production".
|
|
68
|
+
- **Evals.** An eval hop that drives a production flow names that flow's video instead of re-narrating it.
|
|
69
|
+
- **Pause prompts** are rare and bounded, only for a block that must be read whole.
|
|
70
|
+
- The segment's text says "pause" out loud.
|
|
71
|
+
- It carries `"pause": {"dwell": <s>}`, with 0 < dwell ≤ 2 and `pad` equal to the dwell.
|
|
72
|
+
- A video has at most 3. `script-check` errors on a fourth, so split the video instead.
|
|
73
|
+
- **Secrets.** Never say a secret or a redacted value.
|
|
74
|
+
<!-- /sync:stage3-addendum -->
|
|
75
|
+
|
|
76
|
+
## Maintenance
|
|
77
|
+
|
|
78
|
+
> If you modify this file, or the user asks to change this stage, tell the user that the
|
|
79
|
+
> main `explainer-video-from-coursework` skill's **"Stage 3 — /script"** section must be
|
|
80
|
+
> reconciled to match, and name that section in your reply.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-video-thumbnail
|
|
3
|
+
description: Design the upload thumbnail for one video — a mildly tacky, attractive 1280x720 PNG with one clear hook over a still from the video's own scenes and, for a series, a "<playlist name>-Part X, <title>" label. Stage 6b of explainer-video-from-coursework.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# craft-video-thumbnail — the upload thumbnail
|
|
7
|
+
|
|
8
|
+
> Part of the `explainer-video-from-coursework` pipeline — **stage 6b of 8**, between
|
|
9
|
+
> publish (6) and render (7). It needs the final upload title (`title.txt`, from stage 6)
|
|
10
|
+
> and the stage-5 scenes, but not the finished MP4, so it runs before the expensive render.
|
|
11
|
+
>
|
|
12
|
+
> The pipeline's tools and scene hosts live in the sibling `explainer-video-from-coursework` skill: run them as `node ../explainer-video-from-coursework/tools/<tool>.mjs`, resolved against this skill's folder. Run from the **scratch root** — the directory holding `out/`, which Stage 0 fixes (default: beside your notes) — so every `out/<name>/…` path in this stage resolves.
|
|
13
|
+
|
|
14
|
+
> **Timing.** Bracket the stage with the stamp pair so the series accrues a per-video audit;
|
|
15
|
+
> `end` must run before the stage counts as done (see *Timing* in the main skill):
|
|
16
|
+
>
|
|
17
|
+
> ```bash
|
|
18
|
+
> node ../explainer-video-from-coursework/tools/stamp.mjs begin --out out/<name> --video <NN> --stage 6b
|
|
19
|
+
> node ../explainer-video-from-coursework/tools/stamp.mjs end --out out/<name> --video <NN> --stage 6b
|
|
20
|
+
> ```
|
|
21
|
+
|
|
22
|
+
**Prerequisites:** `--dest/<NN>-<slug>/title.txt` (stage 6), the video's stage-5 scenes and
|
|
23
|
+
`manifest.json`, `out/<name>/plan.enriched.json`, and the Stage 0 playlist answer; on the
|
|
24
|
+
machine, headless Chromium (see `SETUP.md`) and `ffmpeg` for the phone-size preview.
|
|
25
|
+
|
|
26
|
+
> A `headless Chromium not found` / `Playwright cache not found` failure means Chromium is
|
|
27
|
+
> absent — relay the `SETUP.md` step to the user and re-run.
|
|
28
|
+
|
|
29
|
+
The output is `--dest/<NN>-<slug>/thumbnail.png`, beside `title.txt`: a 1280x720 PNG of at
|
|
30
|
+
most 2,000,000 bytes, exactly what `upload_yt_video` picks up. The upload takes
|
|
31
|
+
`thumbnail.png`, `.jpg` or `.jpeg` from the video's folder, PNG or JPG only, refuses a file
|
|
32
|
+
over 2 MB and ignores `thumbnail.svg`. It is rendered from an HTML template by the
|
|
33
|
+
pipeline's own headless Chromium, never by a paid image-generation API.
|
|
34
|
+
|
|
35
|
+
### The brief
|
|
36
|
+
|
|
37
|
+
A viewer reads the thumbnail and the title together, in a fraction of a second, usually at
|
|
38
|
+
phone size. Every thumbnail follows the owner's brief:
|
|
39
|
+
|
|
40
|
+
- **Mildly tacky, attractive.** Loud on purpose: fat outlined type, a hard drop shadow, one
|
|
41
|
+
bright accent, a tilted sticker. But one hook and one visual, nothing else competing:
|
|
42
|
+
tacky is the energy, not clutter.
|
|
43
|
+
- **One clear hook.** At most 5 big words (32 characters) that make a viewer want the
|
|
44
|
+
answer: a tension, a surprise, a stake ("The bug nobody catches", "Your data is lying").
|
|
45
|
+
It **complements the upload title and never repeats it**: the title says what the video
|
|
46
|
+
is, the hook says why it is worth the click. Highlight the one word that carries the
|
|
47
|
+
punch. Never promise what the video does not deliver, the same rule as the title.
|
|
48
|
+
- **Sentence case.** Write the hook and the badge in sentence case: the first word capitalised,
|
|
49
|
+
the rest lower case except proper nouns, acronyms and product names ("Your data is lying",
|
|
50
|
+
"Why TypeScript lies"). The template renders text exactly as written, so never type them in
|
|
51
|
+
all capitals.
|
|
52
|
+
- **High contrast.** White type with a black stroke over a darkened wedge, and one accent
|
|
53
|
+
colour (default yellow `#FFD400`) picked to stand out against the still, not to match it.
|
|
54
|
+
- **A strong visual from the video itself.** A still rendered from one of this video's own
|
|
55
|
+
stage-5 scenes, at the beat that shows the idea at its most dramatic (the failure, the
|
|
56
|
+
reveal, the before and after), cropped with `focus` so its subject sits clear of the hook.
|
|
57
|
+
Never stock art, never a logo on its own.
|
|
58
|
+
- **Readable at small mobile size.** If the hook cannot be read in the 320x180 preview, it
|
|
59
|
+
is too long: cut words.
|
|
60
|
+
|
|
61
|
+
### The series label
|
|
62
|
+
|
|
63
|
+
When the video belongs to a series or an intended playlist, a band across the top reads
|
|
64
|
+
**`<playlist name>-Part X, <title>`**: the first link of chronology a new viewer sees.
|
|
65
|
+
|
|
66
|
+
- **The playlist name comes only from the user**: the Stage 0 answer. Never guess it, never
|
|
67
|
+
default it, never derive it from the notes or the repo. Pass `--standalone`, with no
|
|
68
|
+
label, only when the plan has one video or the user explicitly said there is no
|
|
69
|
+
playlist; a blank Stage 0 answer on a series is not that.
|
|
70
|
+
- **Unset for a series means ask.** With neither `--playlist` nor `--standalone`, a plan of
|
|
71
|
+
more than one video exits **3**. Ask the user whether the series is published as a
|
|
72
|
+
playlist and under what name, then re-run with `--playlist "<name>"` or `--standalone`.
|
|
73
|
+
- **Part X** is computed by the tool: the video's 1-based position in
|
|
74
|
+
`plan.enriched.json`'s `videos` list, its index after curation's skips and merges. It is
|
|
75
|
+
not the raw `videoIndex`, which keeps the gaps curation left.
|
|
76
|
+
- **The title** is the final upload title, read from `title.txt`.
|
|
77
|
+
|
|
78
|
+
### Pick the still
|
|
79
|
+
|
|
80
|
+
Choose the beat from the scenes you authored at stage 5, then render that instant:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
node ../explainer-video-from-coursework/tools/render.mjs --shots <t> --work out/<name>/<NN> \
|
|
84
|
+
--scene "src/scene-diagram.html?scene=<name>" --shot-dir out/<name>/<NN>/thumbnail
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`--shots` takes seconds of video time; pick one inside the segment's window in
|
|
88
|
+
`timeline.json`. Use the segment's own host (`scene-diagram`, `scene-svg` or `scene-code`).
|
|
89
|
+
|
|
90
|
+
### Write `thumbnail.json`
|
|
91
|
+
|
|
92
|
+
Write `out/<name>/<NN>/thumbnail.json`:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"hook": "The bug nobody catches",
|
|
97
|
+
"highlight": "nobody",
|
|
98
|
+
"still": "thumbnail/t000042.png",
|
|
99
|
+
"focus": { "x": 0.7, "y": 0.45, "zoom": 1.3 },
|
|
100
|
+
"accent": "#FFD400",
|
|
101
|
+
"badge": "8 min"
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- `hook` (required) — at most 5 words and 32 characters; it must not repeat the upload title.
|
|
106
|
+
- `highlight` (optional) — a word of the hook, or a list of them, drawn in the accent colour.
|
|
107
|
+
- `still` (required) — the PNG from the step above, relative to the work dir.
|
|
108
|
+
- `focus` (optional) — the still's point to keep in view, `x` and `y` as fractions (0–1),
|
|
109
|
+
and a `zoom` of 1–4. The hook sits on the left, so frame the subject to the right.
|
|
110
|
+
- `accent` (optional) — a hex colour for the highlight, the label band, the badge and the bar.
|
|
111
|
+
- `badge` (optional) — a short tilted sticker, 1–16 characters ("8 min", "Fixed"), in sentence case like the hook.
|
|
112
|
+
|
|
113
|
+
### Render and check
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
node ../explainer-video-from-coursework/tools/thumbnail.mjs --work out/<name>/<NN> \
|
|
117
|
+
--script out/<name>/scripts/<NN>-*.json --plan out/<name>/plan.enriched.json \
|
|
118
|
+
--dest <destination> [--playlist "<name>" | --standalone]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
It validates `thumbnail.json`, adds the series label, photographs `src/thumbnail.html` at
|
|
122
|
+
1280x720, checks the PNG and copies it into `--dest/<NN>-<slug>/`. It also writes
|
|
123
|
+
`out/<name>/<NN>/thumbnail.small.png`, a 320x180 copy for the phone-size look. It costs no
|
|
124
|
+
TTS and takes about a second, so iterate freely.
|
|
125
|
+
|
|
126
|
+
| Exit | Meaning |
|
|
127
|
+
|---|---|
|
|
128
|
+
| 0 | written: `thumbnail.png` in the work dir and in `--dest/<NN>-<slug>/` |
|
|
129
|
+
| 1 | a missing input or prerequisite: no `thumbnail.json`, no `title.txt` (run `/publish` first), a video not in the enriched plan, no Chromium |
|
|
130
|
+
| 2 | a check failed: the hook, the still, the crop, or the PNG (not 1280x720, not a PNG, over 2,000,000 bytes) |
|
|
131
|
+
| 3 | a series with no playlist decision: ask the user, never invent a name |
|
|
132
|
+
|
|
133
|
+
### Look at it
|
|
134
|
+
|
|
135
|
+
The tool checks the shape of the thumbnail, never its appeal. **Vision gate:** read
|
|
136
|
+
`thumbnail.png` as an image. If that fails, you are on a text-only model: ask the user
|
|
137
|
+
whether to switch to a vision model or to skip the visual check. Never "look" blind.
|
|
138
|
+
|
|
139
|
+
Read both `thumbnail.png` and `thumbnail.small.png`, and check:
|
|
140
|
+
|
|
141
|
+
- the hook reads in the small copy, and the highlighted word is the punch;
|
|
142
|
+
- the hook does not cover the still's subject (move `focus`, or pick another still);
|
|
143
|
+
- the label, when there is one, is whole and names the right part and title;
|
|
144
|
+
- nothing is clipped at an edge, and the accent stands out against the still;
|
|
145
|
+
- it is loud and a little tacky, and still one idea, not a collage.
|
|
146
|
+
|
|
147
|
+
**Done when:** `thumbnail` exits 0, `thumbnail.png` sits in `--dest/<NN>-<slug>/` beside
|
|
148
|
+
`title.txt`, and both PNGs have been looked at, or the user skipped the visual check.
|
|
149
|
+
|
|
150
|
+
<!-- sync:codeflow-thumbnail -->
|
|
151
|
+
**Code-flow videos only.** A code-flow video's plan, `plan.json` or `plan.enriched.json`, carries
|
|
152
|
+
`"kind": "codebase"`, and its `forms` are `overview`, `flow` and `core`. A coursework plan has no `kind`; nothing
|
|
153
|
+
in this block applies to its videos. A code-flow video adds these rules at stage 6b:
|
|
154
|
+
|
|
155
|
+
- **Hook.** Name the flow in the viewer's terms, such as what a request does, what breaks or what a command runs
|
|
156
|
+
("One click, three services"). Never use a module path, a file name or an identifier: `thumbnail` refuses a hook
|
|
157
|
+
word that is a path (`./x`, `dir/file.ext`, `a/b/c`), lowercase-first camelCase (`getUser`), snake_case, a dotted
|
|
158
|
+
module path (`pkg.mod.fn`), `::` or a call (`fn()`). Viewer words such as TypeScript, macOS, gRPC, I/O and CI/CD pass.
|
|
159
|
+
- **Still.** Take it from a diagram beat (the overview's system map, a flow's sequence, an eval's hand-off), never
|
|
160
|
+
from a code panel: a wall of code is unreadable texture at thumbnail size.
|
|
161
|
+
- **Secrets.** Never put a secret or a redacted value on the thumbnail.
|
|
162
|
+
<!-- /sync:codeflow-thumbnail -->
|
|
163
|
+
|
|
164
|
+
## Maintenance
|
|
165
|
+
|
|
166
|
+
> If you modify this file, or the user asks to change this stage, tell the user that the
|
|
167
|
+
> main `explainer-video-from-coursework` skill's **"Stage 6b — /thumbnail"** section must be
|
|
168
|
+
> reconciled to match, and name that section in your reply.
|