luckiest-co 1.0.53 → 1.0.55

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.
Files changed (29) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/package.json +1 -1
  4. package/skills/video-studio/ATTRIBUTION.md +1 -1
  5. package/skills/video-studio/CHANGELOG.md +10 -0
  6. package/skills/video-studio/SKILL.md +3 -3
  7. package/skills/video-studio/references/audio.md +9 -0
  8. package/skills/video-studio/references/lessons.md +11 -0
  9. package/skills/video-studio-cards/ATTRIBUTION.md +1 -1
  10. package/skills/video-studio-cuts/ATTRIBUTION.md +1 -1
  11. package/skills/video-studio-cuts/CHANGELOG.md +8 -0
  12. package/skills/video-studio-cuts/SKILL.md +15 -5
  13. package/skills/video-studio-cuts/scripts/find-cut-candidates.mjs +45 -5
  14. package/skills/video-studio-cuts/scripts/find-cut-candidates.test.mjs +43 -0
  15. package/skills/video-studio-reel/ATTRIBUTION.md +1 -1
  16. package/skills/video-studio-script/CHANGELOG.md +5 -0
  17. package/skills/video-studio-script/SKILL.md +12 -3
  18. package/skills/video-studio-talk/ATTRIBUTION.md +1 -1
  19. package/skills/video-studio-talk/CHANGELOG.md +9 -0
  20. package/skills/video-studio-talk/SKILL.md +27 -6
  21. package/skills/video-studio-talk/references/house-reel.md +114 -0
  22. package/skills/youtube-planner/ATTRIBUTION.md +9 -3
  23. package/skills/youtube-planner/CHANGELOG.md +11 -0
  24. package/skills/youtube-planner/SKILL.md +89 -23
  25. package/skills/youtube-planner/references/plan-template.md +9 -5
  26. package/skills/youtube-planner/references/stages.md +20 -11
  27. package/skills/youtube-planner/scripts/floor_ceiling.py +71 -1
  28. package/skills/youtube-planner/scripts/pairing.py +121 -0
  29. package/skills/youtube-planner/scripts/retention.py +142 -0
@@ -9,7 +9,7 @@
9
9
  "name": "luckiest",
10
10
  "source": "./",
11
11
  "description": "Plan, go, finish, plus bundled free Luckiest skills that work in Claude Code, web chat, and Cowork.",
12
- "version": "0.1.52",
12
+ "version": "0.1.54",
13
13
  "author": { "name": "Luckiest" }
14
14
  }
15
15
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luckiest",
3
3
  "description": "Plan, go, finish. Guided planning, progress dashboards, and your luckiest.co tribe inside Claude Code.",
4
- "version": "0.1.52",
4
+ "version": "0.1.54",
5
5
  "author": { "name": "Luckiest" }
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luckiest-co",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "description": "Luckiest for Claude Code: plan, go, finish. Your luckiest.co skills and tribe, inside Claude.",
5
5
  "bin": {
6
6
  "luckiest-co": "./bin/install.js"
@@ -10,7 +10,7 @@ projects. Upstream license texts are kept beside this file.
10
10
  | **diagram-design** by Cathryn Lavery | MIT | Brand extraction from a website and the restraint rules (accent on one or two elements, low density) | `LICENSE-diagram-design` |
11
11
  | **Kenney** sound effects (`kenney.nl`) | CC0 | `assets/sfx/` | Public domain, credit given here |
12
12
  | **skills** by Emil Kowalski (`emilkowalski/skills`) | MIT | Motion and taste rules, the review posture, and the motion vocabulary, rewritten for video in the `luckiest-video-studio-motion` sub-skill | `luckiest-video-studio-motion/LICENSE-emil` |
13
- | **HyperFrames student kit** by Nate Herk and contributors (`hyperframes-student-kit`) | MIT for the original kit; the Student Kit Use Permission for its pipeline skills, style library, templates, and editing tools | Rewritten rules and ported scripts in the `luckiest-video-studio-cuts`, `-talk`, and `-reel` sub-skills | `LICENSE-student-kit`, `LICENSE-student-kit-pipeline` |
13
+ | **Herk Edit Kit** (formerly the HyperFrames student kit, `nateherkai/herk-edit-kit`) by Nate Herk and contributors, commit 10511e5a | MIT for the original kit; the Student Kit Use Permission for its pipeline skills, style library, templates, and editing tools | Rewritten rules and ported scripts in the `luckiest-video-studio-cuts`, `-talk`, and `-reel` sub-skills, and the editing-playbook rules (phrase-boundary cuts, house reel style, short-form checks, narration leveling) rewritten in our own words in cuts, talk, script, `references/audio.md`, and `references/lessons.md` | `LICENSE-student-kit`, `LICENSE-student-kit-pipeline` |
14
14
  | **Motion OS** by Jason Lee (`jasonlee-breadcrumb/motion-os`) | MIT | The review player in the `luckiest-video-studio-review` sub-skill (`editor/index.html`, `editor/serve.mjs`) and the `reel.json` format; see that sub-skill's `ATTRIBUTION.md` | `luckiest-video-studio-review/LICENSE-motion-os` |
15
15
  | **motionmaxxing** by Tejas Makwana (`Tejashmakwana/motionmaxxing`, FinalMotion, finalmotion.video), commit 8c8ec0f2 | Apache-2.0 | The beat contract, render-gate posture and `NOTE.md` review note, the `endhold`, `blankframes` and `hud` gate thresholds in `scripts/qa.mjs`, the no-crossfade transition table, and the sound-arc numbers in `references/audio.md`. Rewritten in our own words; no code, runtime, media, studies or `library/` rows are copied | `LICENSE-motionmaxxing` |
16
16
  | **mg-styles-15** by Vincentwei1021 (`vincentwei1021/mg-styles-15`) | MIT | The 15 motion-design styles in `references/styles/` (palettes, signature features, beat seeds), the shared craft checklist, and the two-round jury review rubric. Translated and rewritten for HyperFrames; no films, audio code, samples or fonts are copied | `LICENSE-mg-styles-15` |
@@ -1,5 +1,15 @@
1
1
  # Changelog — luckiest-video-studio
2
2
 
3
+ ## 1.20.0 — 2026-10-27
4
+ - `references/audio.md`: level every voice line then limit only peaks, re-transcribe
5
+ narration before render, one beat grid for the whole timeline, measure loudness on
6
+ the encoded stereo file.
7
+ - `references/lessons.md`: transforms over `top`/`left`, real footage over dim UI
8
+ panels, and a new "Notes become rules" section.
9
+ - Sub-skills cuts 1.2.0, talk 1.4.0, script 1.4.0. The HyperFrames student kit is now
10
+ Herk Edit Kit (`nateherkai/herk-edit-kit`), recorded in `upstreams.json` at 10511e5a.
11
+ - Fixed the stale `installedSemver` in `check_updates` (was 1.18.0).
12
+
3
13
  ## 1.19.0 — 2026-10-15
4
14
 
5
15
  - New motion-design style card `product-flight` (Continuous Product Flight): one camera flight around one hero object, speed ramps between stops on downbeats, side captions, glass callouts with pointer lines, one procedural VFX peak. Distilled from the approved PSA slab film and its review corrections. Offered for collectible and single premium product reveals. 39 styles.
@@ -4,7 +4,7 @@ description: "Make product launch videos, product demos with motion design betwe
4
4
  license: See ATTRIBUTION.md
5
5
  allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
6
6
  metadata:
7
- version: "1.19.0"
7
+ version: "1.20.0"
8
8
  listing_id: luckiest-video-studio
9
9
  author: luckiest
10
10
  ---
@@ -19,13 +19,13 @@ an MP4.
19
19
  ## Staying current
20
20
 
21
21
  On activation, call the Luckiest MCP `check_updates` tool with
22
- `{ listingId: "aff888e4-9ee9-4f73-af08-74d5d09d3c10", installedSemver: "1.18.0" }`. If it returns
22
+ `{ listingId: "aff888e4-9ee9-4f73-af08-74d5d09d3c10", installedSemver: "1.20.0" }`. If it returns
23
23
  `upToDate: false`, surface the `notice` to the user once, then continue. Do nothing
24
24
  further if `upToDate: true`. Never block on this check; if the tool is unavailable,
25
25
  proceed.
26
26
 
27
27
  When the skill's work is done, call the Luckiest MCP `report_usage` tool once with
28
- `{ listing_id: "luckiest-video-studio", skill_version: "1.19.0", matched: true, success: <true if the skill completed, false otherwise> }`.
28
+ `{ listing_id: "luckiest-video-studio", skill_version: "1.20.0", matched: true, success: <true if the skill completed, false otherwise> }`.
29
29
  Metadata only, never prompt text. Never block on it; if the tool is unavailable,
30
30
  skip silently.
31
31
 
@@ -227,6 +227,15 @@ The bundled library has no whooshes or risers. Source them with HyperFrames
227
227
  text holds on screen.
228
228
  - **Duck under the voice.** With narration, the music sits about 9 dB lower while
229
229
  a line plays (80 ms down, 300 ms back up).
230
+ - **Level every voice line to the same loudness, then limit only the peaks.**
231
+ Scaling a whole line down to fit its loudest peak leaves that line several dB
232
+ quieter than the rest.
233
+ - **Re-transcribe the narration against the script before every render**, and
234
+ never fade the last spoken word.
235
+ - **Put the whole timeline on one beat grid** so picture, music, and SFX move
236
+ together when a line changes. Never hard-code the time a word should land.
237
+ - **Measure the delivered file.** Loudness and true peak come from the encoded
238
+ stereo MP4, not the WAV; a mono file reads about 3 dB lower.
230
239
  - **Normalize SFX to a -3 dBFS peak** before the gain ladder, so gains mean the
231
240
  same thing for every file.
232
241
  - **Grid at 30fps:** 120 BPM is exactly 15 frames per beat, so cuts land on whole
@@ -42,3 +42,14 @@ that layout does not cover.
42
42
  two renders on one machine starve each other and time out.
43
43
  - **Use absolute paths in background commands.** A background shell does not keep
44
44
  your working directory.
45
+ - **Animate transforms (x, y, scale), not `top` or `left`.**
46
+ - **Dim UI panels and waveforms lose viewers.** Put real footage in those scenes.
47
+
48
+ ## Notes become rules
49
+
50
+ The edits get better only if a note never has to be given twice. When the user
51
+ gives a note on a draft ("I can't read that caption", "that shot doesn't move"),
52
+ fix the edit, then offer to write the note into the skill as a rule, a check, or
53
+ a script change: this file for build traps, the sub-skill's reference for style
54
+ and editing rules. Record the note and the resulting rule together. Fixing only
55
+ the current video is half the job.
@@ -3,7 +3,7 @@
3
3
  `luckiest-video-studio-cards` is a Luckiest sub-skill of `luckiest-video-studio`.
4
4
  Its two card packs, blueprint, scene templates, and the `build-registry.mjs` and
5
5
  `new-pack.mjs` scripts come from the style library and style templates of the
6
- **HyperFrames student kit** by Nate Herk and contributors. The kit is MIT; its
6
+ **Herk Edit Kit** (formerly the HyperFrames student kit, `nateherkai/herk-edit-kit`) by Nate Herk and contributors. The kit is MIT; its
7
7
  style library and templates carry the Student Kit Use Permission. Both texts are
8
8
  kept in `luckiest-video-studio/LICENSE-student-kit` and
9
9
  `LICENSE-student-kit-pipeline`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  `luckiest-video-studio-cuts` is a Luckiest sub-skill of `luckiest-video-studio`.
4
4
  It is built from the `cut-silences` and `cut-mistakes` skills of the
5
- **HyperFrames student kit** by Nate Herk and
5
+ **Herk Edit Kit** (formerly the HyperFrames student kit, `nateherkai/herk-edit-kit`) by Nate Herk and
6
6
  contributors. The kit is MIT; its pipeline skills and editing tools carry the
7
7
  Student Kit Use Permission. Both texts are kept in
8
8
  `luckiest-video-studio/LICENSE-student-kit` and `LICENSE-student-kit-pipeline`.
@@ -1,5 +1,13 @@
1
1
  # Changelog: luckiest-video-studio-cuts
2
2
 
3
+ ## 1.2.0 (2026-10-27)
4
+ - Cut between phrases, never inside one: `find-cut-candidates.mjs` proposes a
5
+ `filler` (um, uh) cut only with 0.1 s of silence on both sides, and drops a
6
+ stutter or retake whose edge sits in continuous speech to `review`
7
+ (`insidePhrase`). Covers word decay: transcripts end words 40 to 80 ms early.
8
+ - New `find-cut-candidates.test.mjs`.
9
+ - From the Herk Edit Kit editing playbook, in our own words.
10
+
3
11
  ## 1.1.0 (2026-10-07)
4
12
  - Step 4 reviews the silence cut in the review player from
5
13
  `luckiest-video-studio-review`: `scripts/build-cuts-reel.mjs` writes
@@ -14,7 +14,7 @@ user-invocable: false
14
14
  license: MIT. See ATTRIBUTION.md
15
15
  allowed-tools: Bash, Read, Write, Glob, AskUserQuestion
16
16
  metadata:
17
- version: "1.1.0"
17
+ version: "1.2.0"
18
18
  listing_id: luckiest-video-studio-cuts
19
19
  author: luckiest
20
20
  ---
@@ -28,11 +28,11 @@ decides. Nothing here changes the words that stay.
28
28
  ## Staying current
29
29
 
30
30
  On activation, call the Luckiest MCP `check_updates` tool with
31
- `{ listingId: "luckiest-video-studio-cuts", installedSemver: "1.1.0" }`. If
31
+ `{ listingId: "luckiest-video-studio-cuts", installedSemver: "1.2.0" }`. If
32
32
  `upToDate: false`, surface the `notice` once and continue. Never block on it.
33
33
 
34
34
  When done, call `report_usage` once with
35
- `{ listing_id: "luckiest-video-studio-cuts", skill_version: "1.1.0", matched: true, success: <true|false> }`.
35
+ `{ listing_id: "luckiest-video-studio-cuts", skill_version: "1.2.0", matched: true, success: <true|false> }`.
36
36
  Metadata only. Skip silently if unavailable.
37
37
 
38
38
  ## Standing rules
@@ -79,8 +79,18 @@ a readable `raw.silence-decisions.md`. Drop `--apply` for a plan without a rende
79
79
  node <skill-dir>/scripts/find-cut-candidates.mjs \
80
80
  <run-dir>/footage/raw.silence-transcript.json --out-dir <run-dir>/footage
81
81
  ```
82
- Types: `stutter` (a word said twice), `retake` (a near-duplicate line),
83
- `false_start` (a short phrase abandoned and restarted).
82
+ Types: `filler` (um, uh), `stutter` (a word said twice), `retake` (a
83
+ near-duplicate line), `false_start` (a short phrase abandoned and restarted).
84
+
85
+ **Cut between phrases, never inside one.** A phrase is what is said in one
86
+ breath. A cut edge needs at least 0.1 s of silence on its side: transcripts end
87
+ words 40 to 80 ms before the sound dies, so a tighter edge clips the
88
+ neighbouring word, and padding it with silence makes that word sound muted. A
89
+ filler that runs straight into the next word stays (`recommend: "keep"`).
90
+ Retakes join only where both sides are silent; otherwise play one take whole.
91
+ Candidates flagged `insidePhrase` drop to `review`. Fewer cuts, all between
92
+ phrases, beat a tighter cut that clips words. Keep natural beats (after a
93
+ comma, after "First,") and never speed the voice up.
84
94
  2. Read every candidate in context. Emphasis ("never, never"), a repeated word
85
95
  before a question ("the point is, is this"), and lists look like stutters but
86
96
  are not. Present each one with your recommendation and collect the user's
@@ -62,23 +62,60 @@ let cid = 0;
62
62
  const ctx = (i, before = 6, after = 6) =>
63
63
  displayText(words.slice(Math.max(0, i - before), Math.min(words.length, i + after)));
64
64
 
65
+ // Cut between phrases, never inside one. Transcripts end words 40-80 ms before
66
+ // the sound decays, so a cut edge needs at least this much silence on its side or
67
+ // it clips the neighbouring word. Words in one breath run ~0.04-0.1 s apart.
68
+ const PHRASE_GAP = 0.1;
69
+ // Silence on each side of removed words first..last (word indexes).
70
+ function edgeGaps(first, last) {
71
+ return {
72
+ before: first > 0 ? words[first].start - words[first - 1].end : Infinity,
73
+ after: last < words.length - 1 ? words[last + 1].start - words[last].end : Infinity,
74
+ };
75
+ }
76
+ function insidePhrase(first, last) {
77
+ const g = edgeGaps(first, last);
78
+ return g.before < PHRASE_GAP || g.after < PHRASE_GAP;
79
+ }
80
+ const INSIDE_NOTE = "inside a phrase: cutting clips the words around it";
81
+
82
+ // ---- 0) fillers: cut only with silence on both sides ----
83
+ const FILLERS = new Set(["um", "uh", "erm", "er", "ah", "hmm", "mm"]);
84
+ for (let i = 0; i < words.length; i++) {
85
+ if (!FILLERS.has(words[i].token)) continue;
86
+ const inside = insidePhrase(i, i);
87
+ candidates.push({
88
+ id: `c${String(++cid).padStart(3, "0")}`,
89
+ type: "filler",
90
+ confidence: inside ? "low" : "high",
91
+ recommend: inside ? "keep" : "cut",
92
+ cut: { start: Number(words[i].start.toFixed(3)), end: Number((words[i + 1]?.start ?? words[i].end).toFixed(3)) },
93
+ removes: words[i].text,
94
+ context: ctx(i),
95
+ note: inside ? INSIDE_NOTE : "filler between phrases",
96
+ });
97
+ }
98
+
65
99
  // ---- 1) stutters / immediate repeats ----
66
100
  for (let i = 1; i < words.length; i++) {
67
101
  const a = words[i - 1], b = words[i];
68
102
  if (!b.token || b.token.length < 1) continue;
69
103
  const closeGap = b.start - a.end < 0.5;
70
104
  if (a.token === b.token && closeGap) {
105
+ // The repeat itself is the join; only the silence before the first copy matters.
106
+ const inside = edgeGaps(i - 1, i - 1).before < PHRASE_GAP;
71
107
  candidates.push({
72
108
  id: `c${String(++cid).padStart(3, "0")}`,
73
109
  type: "stutter",
74
- confidence: "high",
75
- recommend: "cut",
110
+ confidence: inside ? "medium" : "high",
111
+ recommend: inside ? "review" : "cut",
112
+ ...(inside && { insidePhrase: true }),
76
113
  // remove the first utterance, keep the second
77
114
  cut: { start: Number(a.start.toFixed(3)), end: Number(b.start.toFixed(3)) },
78
115
  removes: a.text,
79
116
  keeps: b.text,
80
117
  context: ctx(i),
81
- note: `repeated "${a.token}"`,
118
+ note: `repeated "${a.token}"${inside ? `; ${INSIDE_NOTE}` : ""}`,
82
119
  });
83
120
  }
84
121
  }
@@ -120,18 +157,21 @@ for (let i = 0; i < segments.length; i++) {
120
157
  const firstLen = segments[i].end - segments[i].start;
121
158
  // A short first take that restarts soon after reads as a false start.
122
159
  const isFalseStart = sameOpening && firstLen < 6 && segments[j].start - segments[i].end < 12;
160
+ // Join two takes only where both sides are silent; otherwise play one take whole.
161
+ const inside = insidePhrase(segments[i].wordStart, segments[j].wordStart - 1);
123
162
  candidates.push({
124
163
  id: `c${String(++cid).padStart(3, "0")}`,
125
164
  type: isFalseStart ? "false_start" : "retake",
126
165
  confidence: score >= 0.45 ? "high" : score >= 0.34 ? "medium" : "low",
127
- recommend: score >= 0.34 ? "cut" : "review",
166
+ recommend: score >= 0.34 && !inside ? "cut" : "review",
167
+ ...(inside && { insidePhrase: true }),
128
168
  score: Number(score.toFixed(3)),
129
169
  // default: remove the earlier take up to the start of the cleaner restart
130
170
  cut: { start: Number(segments[i].start.toFixed(3)), end: Number(segments[j].start.toFixed(3)) },
131
171
  removes: segments[i].text,
132
172
  keeps: segments[j].text,
133
173
  gapBetween: Number((segments[j].start - segments[i].end).toFixed(2)),
134
- note: `seg ${segments[i].id} ~ seg ${segments[j].id} (jaccard ${score.toFixed(2)}${sameOpening ? ", same opening" : ""})`,
174
+ note: `seg ${segments[i].id} ~ seg ${segments[j].id} (jaccard ${score.toFixed(2)}${sameOpening ? ", same opening" : ""})${inside ? `; ${INSIDE_NOTE}` : ""}`,
135
175
  });
136
176
  }
137
177
  }
@@ -0,0 +1,43 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { execFileSync } from "node:child_process";
4
+ import { mkdtempSync, writeFileSync, readFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+
8
+ const script = new URL("./find-cut-candidates.mjs", import.meta.url).pathname;
9
+
10
+ function run(words) {
11
+ const dir = mkdtempSync(join(tmpdir(), "cuts-"));
12
+ const file = join(dir, "clip.json");
13
+ writeFileSync(file, JSON.stringify(words));
14
+ execFileSync(process.execPath, [script, file, "--out-dir", dir]);
15
+ return JSON.parse(readFileSync(join(dir, "clip.cut-candidates.json"), "utf8")).candidates;
16
+ }
17
+ // Words from [text, start, end] tuples.
18
+ const w = (rows) => rows.map(([text, start, end]) => ({ text, start, end }));
19
+
20
+ test("a filler with silence on both sides is cut", () => {
21
+ const [c] = run(w([["So", 0, 0.3], ["um", 0.6, 0.8], ["here", 1.1, 1.4], ["it", 1.45, 1.6], ["is.", 1.65, 1.9]]));
22
+ assert.equal(c.type, "filler");
23
+ assert.equal(c.recommend, "cut");
24
+ });
25
+
26
+ test("a filler run into the next word stays", () => {
27
+ const [c] = run(w([["So", 0, 0.3], ["um", 0.33, 0.5], ["here", 0.52, 0.8], ["it", 0.85, 1], ["is.", 1.05, 1.3]]));
28
+ assert.equal(c.type, "filler");
29
+ assert.equal(c.recommend, "keep");
30
+ });
31
+
32
+ test("a stutter at a phrase start is still cut", () => {
33
+ const [c] = run(w([["Ready.", 0, 0.4], ["The", 0.9, 1], ["the", 1.05, 1.2], ["plan", 1.25, 1.6], ["works.", 1.65, 2]]));
34
+ assert.equal(c.type, "stutter");
35
+ assert.equal(c.recommend, "cut");
36
+ });
37
+
38
+ test("a stutter inside one breath goes to review", () => {
39
+ const [c] = run(w([["First,", 0, 0.3], ["the", 0.33, 0.45], ["the", 0.48, 0.6], ["plan", 0.63, 1], ["works.", 1.05, 1.4]]));
40
+ assert.equal(c.type, "stutter");
41
+ assert.equal(c.recommend, "review");
42
+ assert.equal(c.insidePhrase, true);
43
+ });
@@ -1,7 +1,7 @@
1
1
  # Attribution
2
2
 
3
3
  `luckiest-video-studio-reel` is a Luckiest sub-skill of `luckiest-video-studio`.
4
- It is rewritten from the `motion-showreel` skill of the **HyperFrames student kit**
4
+ It is rewritten from the `motion-showreel` skill of the **Herk Edit Kit** (formerly the HyperFrames student kit, `nateherkai/herk-edit-kit`)
5
5
  by Nate Herk and contributors, and ports that skill's `beatgrid.mjs`,
6
6
  `splice-music.mjs`, and `mix.mjs`. The kit is MIT; its pipeline skills carry the
7
7
  Student Kit Use Permission. Both texts are kept in
@@ -1,5 +1,10 @@
1
1
  # Changelog — luckiest-video-studio-script
2
2
 
3
+ ## 1.4.0 — 2026-10-27
4
+ - Narrated explainers end on the thesis line, never put a narrator over a real
5
+ person talking, and re-transcribe the narration against `script.md` before
6
+ every render. From the Herk Edit Kit editing playbook.
7
+
3
8
  ## 1.3.0 — 2026-10-12
4
9
 
5
10
  - Word budgets for short films (28 to 38 words per 15 s, 60 to 80 per 30 s) and slower sign-offs.
@@ -15,7 +15,7 @@ user-invocable: true
15
15
  license: MIT. See ATTRIBUTION.md
16
16
  allowed-tools: Read, Write, Glob, Grep, AskUserQuestion
17
17
  metadata:
18
- version: "1.3.0"
18
+ version: "1.4.0"
19
19
  listing_id: luckiest-video-studio-script
20
20
  author: luckiest
21
21
  ---
@@ -29,11 +29,11 @@ one picture.
29
29
  ## Staying current
30
30
 
31
31
  On activation, call the Luckiest MCP `check_updates` tool with
32
- `{ listingId: "luckiest-video-studio-script", installedSemver: "1.3.0" }`. If
32
+ `{ listingId: "luckiest-video-studio-script", installedSemver: "1.4.0" }`. If
33
33
  `upToDate: false`, surface the `notice` once and continue. Never block on it.
34
34
 
35
35
  When done, call `report_usage` once with
36
- `{ listing_id: "luckiest-video-studio-script", skill_version: "1.3.0", matched: true, success: <true|false> }`.
36
+ `{ listing_id: "luckiest-video-studio-script", skill_version: "1.4.0", matched: true, success: <true|false> }`.
37
37
  Metadata only, never prompt text. Skip silently if unavailable.
38
38
 
39
39
  ## Standing rules
@@ -178,6 +178,15 @@ the script is the narration text. On-screen words land 0 to 2 frames before
178
178
  they are heard (up to 5 for names), and a transition starts 3 to 6 frames
179
179
  before its line ends.
180
180
 
181
+ For a narrated explainer:
182
+
183
+ - End on the thesis line, spoken in the decay of the last music hit, then the logo.
184
+ - Never play the narrator over footage of a real person talking. Viewers hear
185
+ that person speaking in the narrator's voice.
186
+ - After the voice is generated, re-transcribe the full narration and compare it
187
+ to `script.md` before every render. A dropped or swapped word is caught here or
188
+ not at all.
189
+
181
190
  The storyboard review can edit a line. When it does, write the new line back to
182
191
  `script.md` too, recount its words and seconds, and re-check the word budget, so
183
192
  the narration and the storyboard never drift apart.
@@ -2,7 +2,7 @@
2
2
 
3
3
  `luckiest-video-studio-talk` is a Luckiest sub-skill of `luckiest-video-studio`.
4
4
  It is rewritten from the `short-form-edit`, `hyperframes-video-beats`, and
5
- `video-storytelling` skills of the **HyperFrames student kit** by Nate Herk and
5
+ `video-storytelling` skills of the **Herk Edit Kit** (formerly the HyperFrames student kit, `nateherkai/herk-edit-kit`) by Nate Herk and
6
6
  contributors, and ports that kit's `validate-plan.mjs` and `validate-footage.mjs`.
7
7
  The kit is MIT; its pipeline skills carry the Student Kit Use Permission. Both
8
8
  texts are kept in `luckiest-video-studio/LICENSE-student-kit` and
@@ -1,5 +1,14 @@
1
1
  # Changelog: luckiest-video-studio-talk
2
2
 
3
+ ## 1.4.0 — 2026-10-27
4
+ - New `references/house-reel.md`: the default reel style when the user gives none
5
+ (pacing, layouts, story order, B-roll order, captions, sound, raw reel and
6
+ long-to-Short variants), and the note-becomes-a-rule loop.
7
+ - Step 4 inspection adds the mouth-free first 2.5 s, 10-frame strips across cuts,
8
+ caption contrast on real pixels, lip sync against the raw, re-transcribing the
9
+ final render, loudness on the encoded stereo file, and how to treat AI watch tests.
10
+ - From the Herk Edit Kit editing playbook, in our own words.
11
+
3
12
  ## 1.3.0 — 2026-10-05
4
13
  - Follows `art-direction.json` and runs the director's score loop when installed.
5
14
 
@@ -15,7 +15,7 @@ user-invocable: false
15
15
  license: MIT. See ATTRIBUTION.md
16
16
  allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
17
17
  metadata:
18
- version: "1.3.0"
18
+ version: "1.4.0"
19
19
  listing_id: luckiest-video-studio-talk
20
20
  author: luckiest
21
21
  ---
@@ -29,11 +29,11 @@ word and earns its place, or it is cut.
29
29
  ## Staying current
30
30
 
31
31
  On activation, call the Luckiest MCP `check_updates` tool with
32
- `{ listingId: "luckiest-video-studio-talk", installedSemver: "1.3.0" }`. If
32
+ `{ listingId: "luckiest-video-studio-talk", installedSemver: "1.4.0" }`. If
33
33
  `upToDate: false`, surface the `notice` once and continue. Never block on it.
34
34
 
35
35
  When done, call `report_usage` once with
36
- `{ listing_id: "luckiest-video-studio-talk", skill_version: "1.3.0", matched: true, success: <true|false> }`.
36
+ `{ listing_id: "luckiest-video-studio-talk", skill_version: "1.4.0", matched: true, success: <true|false> }`.
37
37
  Metadata only. Skip silently if unavailable.
38
38
 
39
39
  ## Standing rules
@@ -59,6 +59,9 @@ Ask once if the brief does not say:
59
59
 
60
60
  - **Short** (9:16, 1080x1920, 10 to 60 s): hook in the first three seconds, dense
61
61
  rhythm, captions on. Read [references/short-form.md](references/short-form.md).
62
+ When the user gives no style, use
63
+ [references/house-reel.md](references/house-reel.md) as the default: pacing,
64
+ layouts, story order, B-roll order, captions, and sound. The brief wins.
62
65
  - **Long** (16:9, 1920x1080, minutes): the speaker stays on screen with lower
63
66
  thirds, and occasional full-frame takeovers carry the big ideas. Read
64
67
  [references/long-form.md](references/long-form.md).
@@ -155,13 +158,31 @@ the coordinator's Step 4, up to v3.
155
158
  Pass `--tokens <file>` to `tokens` when the video locks its own values. Gates do
156
159
  not replace looking. Then inspect:
157
160
 
158
- - the first encoded frame and the first three seconds, frame by frame
159
- - a contiguous strip across every transition (`ffmpeg ... tile=6x7`); single hero
160
- frames miss pops, freezes, and two moves that should be one
161
+ - the first encoded frame and the first 2.5 s, frame by frame, plus the first
162
+ frame of every face shot: nothing over the mouth or chin, since the first
163
+ second is when a viewer decides the person is real
164
+ - a contiguous strip across every cut and transition, 10 frames each side
165
+ (`ffmpeg ... tile=6x7`); single hero frames miss one-frame empty panels,
166
+ captions flashing over the wrong shot, pops, and freezes
167
+ - caption contrast against the actual pixels behind each caption, not the
168
+ design color; never white on light
161
169
  - every hero frame at full size and at phone size: face clear, text inside the
162
170
  safe area, nothing within 60 px of an edge
171
+ - lip sync: cut frames compared against the raw clip. A matching frame count
172
+ does not prove the right frames were picked. Select exact frames in one pass;
173
+ encoding segments separately and concatenating drifts sync by about a frame
174
+ - every word whole: transcribe `final.mp4` again and compare the words at every
175
+ cut with `clean.json`. Speech-to-text can guess a clipped word correctly while
176
+ a listener hears it broken, so also listen across the joins when you can
177
+ - loudness and true peak measured on the encoded stereo delivery
178
+ (`ffmpeg -i final.mp4 -af ebur128=peak=true -f null -`), not the WAV
163
179
  - sound across every join: no clipped word tails, voice above the music
164
180
 
181
+ An AI watch test (a video model watching the render) can list candidate
182
+ problems, but it is noisy and invents effects. Check each complaint on real
183
+ frames before acting. "Would this viewer finish, and where would they stop?"
184
+ is more useful than a 1 to 10 score. The user's own viewing is the final gate.
185
+
165
186
  Write `talk/VERIFY.md` with what was checked, how (watched, listened, or signal
166
187
  analysis only), and what is still open. Never claim a viewing or listening pass
167
188
  the runtime could not do.
@@ -0,0 +1,114 @@
1
+ # House reel style (9:16 talking head)
2
+
3
+ The default for a short talking-head reel when the user gives no style. The
4
+ user's brief wins on every line. The numbers are starting points measured on
5
+ reels that held attention, not law. Where this file and `short-form.md` disagree,
6
+ this file wins for reels built in this style.
7
+
8
+ ## Pacing
9
+
10
+ - Speech starts within 0.1 s. The file ends right after the last word. No intro
11
+ or outro card.
12
+ - No dead air: pauses between phrases stay under about 0.2 s. Natural beats after
13
+ a comma or a list marker ("First,") run 0.2 to 0.4 s and stay. Tightness comes
14
+ from removing dead air between phrases, never from speeding the voice up.
15
+ - Shots average 1.1 to 1.4 s, none over about 2.8 s. The first cut lands at 0.6
16
+ to 1.0 s, on the first charged word.
17
+ - Each item in a spoken list gets its own shot.
18
+
19
+ ## Layouts (1080x1920, every change is a hard cut)
20
+
21
+ | Layout | What | Share of the reel |
22
+ |---|---|---|
23
+ | Split | B-roll on top (y 0 to 880), speaker below | 30 to 42% |
24
+ | Full B-roll | Footage fills the frame | 50 to 55% |
25
+ | Punch-in | Tight shot of the speaker for pivots, emphasis, and the CTA | 5 to 15% |
26
+
27
+ The speaker is on screen about 45% of the time and never gone for more than about
28
+ 3.5 s. The first frame is a split with the topic's tool or brand on top.
29
+
30
+ ## Story
31
+
32
+ 1. Hook in the first 3 s: a claim or command that names the tool or person.
33
+ 2. One line of credibility or context.
34
+ 3. If there is a list, show every item early, blurred, as an open loop.
35
+ 4. Each item: a section card, a one-line definition, two or three literal
36
+ visuals, a punch-in on the key line.
37
+ 5. A resolution that calls back to the hook visual.
38
+ 6. CTA: show the resource first, then a punch-in with the comment keyword. Never
39
+ assemble a CTA the speaker did not say.
40
+
41
+ A raw recording caps the edit: a clip with no hook and no CTA stays weak however
42
+ well it is cut. If the user can still record, suggest scripting the hook first.
43
+
44
+ ## B-roll: every shot moves
45
+
46
+ Video beats images. Preference order:
47
+
48
+ 1. Real footage of the thing named: the product's demo, the person's talk, the
49
+ user's own long-form video.
50
+ 2. A real screen recording, zoomed into the part being talked about, with a
51
+ visible cursor.
52
+ 3. An animated UI mock (typing, rows ticking, a counter climbing), labeled as an
53
+ example.
54
+ 4. AI video the user supplies. Concrete metaphors work; generic "person at a
55
+ computer" reads as stock. Use only the first continuous seconds (models often
56
+ cut to a new angle near 2.5 to 3 s) and keep screens small, since generated
57
+ text turns to gibberish. Consecutive shots of one person must match.
58
+ 5. Highlight crops of a real page under 1 s, on tool names, prices, badges.
59
+
60
+ Every shot gets a slow push-in. An AI still image used as B-roll is a build
61
+ error; a still is only a first frame for AI video. A whole web page shrunk to
62
+ phone size is unreadable: crop to the phrase and highlight it on the spoken word.
63
+ Small UI floating in empty space is the fastest tell of an AI edit; zoom UI until
64
+ it fills its panel. Never click "Accept" on cookie or terms dialogs while
65
+ capturing. Never invent numbers or results to decorate a claim.
66
+
67
+ ## Captions
68
+
69
+ - 1 to 3 words per chunk, split on phrase boundaries. They hard-swap with no pop
70
+ animation and appear 2 frames before the first word.
71
+ - The display face from `brand.json`, heavy weight, all caps, about 62 to 64 px.
72
+ An accent face on 5 to 20% of chunks for soft words, never two in a row.
73
+ - Color on 25 to 45% of chunks, whole chunk only: a warning color for the wrong
74
+ way or a loss, the accent for the concept, a positive color for the payoff.
75
+ - One look for the whole reel: every caption in the same dark box with a thin
76
+ light edge, so it reads on black, white, and footage alike. Mixing boxed and
77
+ bare captions looks cheap. Never white on light.
78
+ - Position: on the seam in a split, on the shirt in a punch-in, and in a clear
79
+ zone on shots full of text to read. Captions never blink out on those shots;
80
+ they move.
81
+ - Never over the mouth or chin, least of all in the first second. A caption that
82
+ runs across a cut moves to the new shot's spot on the cut frame.
83
+
84
+ ## Music and sound
85
+
86
+ - Music by mood: a darker, confident beat for claims and news, a chill groove for
87
+ methods. The bed sits about 11 dB under the voice (9 to 14 dB), ducks under
88
+ speech, and is often quieter for the first 1 to 2 s.
89
+ - Sound effects follow visible actions, not every cut: a soft air whoosh on a real
90
+ spatial move, a damped tap when a logo lands, a dry click for small UI, paper
91
+ for documents, one short warm tone for a check, a dry stop for an X. No laser
92
+ zaps, pitch-drop plops, sci-fi chirps, or a whoosh on every cut.
93
+ - Vary the files for repeated items so a list does not sound like a loop.
94
+ - Master near -14 LUFS, true peak at or below -1.5 dBTP, measured on the encoded
95
+ stereo file (a mono file reads 3 dB lower). Never fade the last spoken word.
96
+
97
+ ## Variants
98
+
99
+ **Raw reel (lighter):** no B-roll, no music. Cut retakes, stutters, and dead air
100
+ only, keeping the last clean take. One word on screen at a time, small, lower
101
+ middle, synced to the exact word. When the speaker points while naming a tool,
102
+ pop its real logo where they point with a quiet tap.
103
+
104
+ **Short from a long-form video:** screen recording on top, face cam below,
105
+ word-highlight captions on the seam. The value or claim in the first 3 s, then
106
+ proofs in the long-form's order, ending on a complete takeaway. Every number on
107
+ screen must be explainable from what the Short showed. Name things before using
108
+ them. Keep labels below the top 130 px.
109
+
110
+ ## Notes become rules
111
+
112
+ When the user gives a note on a draft ("I can't read that caption"), fix the
113
+ edit, then offer to write the note into this file or the relevant skill as a
114
+ rule, a check, or a script change, so the next edit starts from it.
@@ -14,9 +14,15 @@ our own words. No text or code was copied from the sources below.
14
14
  loops chained through the video): from Kallaway Marketing's public Facebook
15
15
  reel on storytelling loops
16
16
  (https://www.facebook.com/reel/4034613460177150, viewed 2026-10-16).
17
- - Ranking a video by its views over its own channel's median, and linting the
18
- title and thumbnail as one pairing: ideas from Jakeschincariol/youtube-agent-skill
19
- (MIT, https://github.com/Jakeschincariol/youtube-agent-skill).
17
+ - Ranking a video by its views over its own channel's median (skipping channels
18
+ with too few videos), linting the title and thumbnail as one pairing, the
19
+ query test, reading a retention export as hook leak, cliffs, and slide, the
20
+ opening-line rules, on-screen notes per beat, chapter rules and short section
21
+ names, Short candidates with new first lines, comment triage, an audit that
22
+ ends in one fix, and a voice file: ideas from Jakeschincariol/youtube-agent-skill
23
+ (MIT, https://github.com/Jakeschincariol/youtube-agent-skill, reviewed at
24
+ commit a2feb21). `pairing.py`, `retention.py`, and the `--channel` mode are
25
+ our own code.
20
26
  - Comments as a satisfaction readout: an idea from
21
27
  ScrapeCreators/social-media-research-skills (MIT,
22
28
  https://github.com/ScrapeCreators/social-media-research-skills).
@@ -1,5 +1,16 @@
1
1
  # Changelog — luckiest-youtube-planner
2
2
 
3
+ ## 1.2.0 — 2026-10-27
4
+
5
+ - `scripts/pairing.py` lints a title and its thumbnail text as one pairing: desktop and mobile cuts, repeated words, thumbnail word count, all-caps, vague adjectives, nothing specific, filler up front. Packaging now writes 10 titles, shows the top 3, and adds a query test (3 searches whose words the title and first description lines must contain).
6
+ - `floor_ceiling.py --channel` (repeatable) ranks videos by their multiple over their own channel's median and skips channels with fewer than 4 counted videos.
7
+ - `scripts/retention.py` reads a Studio retention export: hook leak in the first 30 seconds with bands, the steepest cliffs with the words spoken there (`--transcript`), and the slide across the middle.
8
+ - Hook: rules for the opening lines (confirm the title, one promise, specific beats big, show the promised thing within 20 seconds, no intro or subscribe ask before 0:45), and 3 versions with the best 2 shown.
9
+ - Body: `[ON SCREEN]` on every beat, section names of 5 words or fewer that become valid chapters, a runtime at 150 wpm, and 3 Short candidates with new first lines.
10
+ - Readout: comment triage into questions, corrections, praise, and bait, a pin suggestion, and a flop report that ends in one change, 3 things to keep, and what not to change yet.
11
+ - Reads `voice.md` before writing spoken lines when the user has one.
12
+ - Ideas from Jakeschincariol/youtube-agent-skill (MIT), in our own words and code.
13
+
3
14
  ## 1.1.0 — 2026-10-16
4
15
 
5
16
  - Body stage runs each section as a story loop: stakes, open question, turn, and reopen, with the next loop starting before the last one ends. The rubric and per-beat fixes are in stages.md.