luckiest-co 1.0.53 → 1.0.54
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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/video-studio/ATTRIBUTION.md +1 -1
- package/skills/video-studio/CHANGELOG.md +10 -0
- package/skills/video-studio/SKILL.md +3 -3
- package/skills/video-studio/references/audio.md +9 -0
- package/skills/video-studio/references/lessons.md +11 -0
- package/skills/video-studio-cards/ATTRIBUTION.md +1 -1
- package/skills/video-studio-cuts/ATTRIBUTION.md +1 -1
- package/skills/video-studio-cuts/CHANGELOG.md +8 -0
- package/skills/video-studio-cuts/SKILL.md +15 -5
- package/skills/video-studio-cuts/scripts/find-cut-candidates.mjs +45 -5
- package/skills/video-studio-cuts/scripts/find-cut-candidates.test.mjs +43 -0
- package/skills/video-studio-reel/ATTRIBUTION.md +1 -1
- package/skills/video-studio-script/CHANGELOG.md +5 -0
- package/skills/video-studio-script/SKILL.md +12 -3
- package/skills/video-studio-talk/ATTRIBUTION.md +1 -1
- package/skills/video-studio-talk/CHANGELOG.md +9 -0
- package/skills/video-studio-talk/SKILL.md +27 -6
- package/skills/video-studio-talk/references/house-reel.md +114 -0
package/package.json
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
159
|
-
|
|
160
|
-
|
|
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.
|