hlassiege/darylpublic Fork
⑂ 24cadf2
Commits
⬇ Clone ▾
git clone https://git.rickub.com/hlassiege/daryl.git
git clone ssh://git@rickub.com/hlassiege/daryl.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

feat(music-bed): give each a-roll pause its own short cue

hlassiege committed 2026-11-10T14:51:30+01:00 Browse files
24cadf2 parent: ef15d3a
modified .claude/skills/music-bed/SKILL.md +7 -1
@@ -33,12 +33,18 @@ the voice loudness (≈ −24.6 LUFS on this channel), pauses ≥ 0.9 s, inserte
3333 titles, and a Whisper transcript **in timeline time** (`contexte.md` can be stale: don't trust its times).
3434
3535 Cut the video into sequences: cold open, intro, each part (part titles are 1.2 s `transition` motions),
36-conclusion. Inside a part, split again where the tone changes or where an inserted clip interrupts.
36+conclusion; each A-roll pause is a sequence of its own. Inside a part, split again where the tone changes or where an inserted clip interrupts.
3737
3838 ### 2. Decide what plays where
3939
4040 - **No music under inserted clips** that carry their own sound (politician quotes, TV excerpts, memes).
4141 The user likes it. Stop the bed right on the clip's first frame (0.3 s fade) and restart after.
42+- **A-roll pauses get a short cue of their own.** A pause (A-roll clip with `pause`, `montage/pause.mp4`)
43+ is a full-screen motion — usually a part title — during which the voice stops on purpose so the viewer
44+ breathes. Don't leave it silent and don't run the talking bed through it: end the previous bed on the
45+ pause's first frame (0.3 s fade), lay a short cue (a sting or a few bars, cut to the pause length + a tail
46+ of ≤ 0.5 s) at the bed's level or a few dB above (no voice to duck under), then start the next part's
47+ bed after it. The cue is the hinge between two parts: it closes one mood and opens the next.
4248 - **Every spoken passage gets music to its end.** A 15 s stretch of voice between two archives without
4349 music feels like a hole; a short teaser before a part title can get its own dedicated track.
4450 - **Silence is a choice:** keep it for a punchline right before an archive, not for whole passages.
@@ -33,12 +33,18 @@ the voice loudness (≈ −24.6 LUFS on this channel), pauses ≥ 0.9 s, inserte
33 titles, and a Whisper transcript **in timeline time** (`contexte.md` can be stale: don't trust its times).33 titles, and a Whisper transcript **in timeline time** (`contexte.md` can be stale: don't trust its times).
34 34
35 Cut the video into sequences: cold open, intro, each part (part titles are 1.2 s `transition` motions),35 Cut the video into sequences: cold open, intro, each part (part titles are 1.2 s `transition` motions),
36-conclusion. Inside a part, split again where the tone changes or where an inserted clip interrupts.36+conclusion; each A-roll pause is a sequence of its own. Inside a part, split again where the tone changes or where an inserted clip interrupts.
37 37
38 ### 2. Decide what plays where38 ### 2. Decide what plays where
39 39
40 - **No music under inserted clips** that carry their own sound (politician quotes, TV excerpts, memes).40 - **No music under inserted clips** that carry their own sound (politician quotes, TV excerpts, memes).
41 The user likes it. Stop the bed right on the clip's first frame (0.3 s fade) and restart after.41 The user likes it. Stop the bed right on the clip's first frame (0.3 s fade) and restart after.
42+- **A-roll pauses get a short cue of their own.** A pause (A-roll clip with `pause`, `montage/pause.mp4`)
43+ is a full-screen motion — usually a part title — during which the voice stops on purpose so the viewer
44+ breathes. Don't leave it silent and don't run the talking bed through it: end the previous bed on the
45+ pause's first frame (0.3 s fade), lay a short cue (a sting or a few bars, cut to the pause length + a tail
46+ of ≤ 0.5 s) at the bed's level or a few dB above (no voice to duck under), then start the next part's
47+ bed after it. The cue is the hinge between two parts: it closes one mood and opens the next.
42 - **Every spoken passage gets music to its end.** A 15 s stretch of voice between two archives without48 - **Every spoken passage gets music to its end.** A 15 s stretch of voice between two archives without
43 music feels like a hole; a short teaser before a part title can get its own dedicated track.49 music feels like a hole; a short teaser before a part title can get its own dedicated track.
44 - **Silence is a choice:** keep it for a punchline right before an archive, not for whole passages.50 - **Silence is a choice:** keep it for a punchline right before an archive, not for whole passages.
modified .claude/skills/music-bed/scripts/common.py +14 -0
@@ -47,6 +47,20 @@ def inserted_clips(tl: dict) -> list[dict]:
4747 return out
4848
4949
50+def pause_clips(tl: dict) -> list[dict]:
51+ """A-roll pauses: the voice stops (black, silence) under a full-screen motion (`pause` = its id), usually a
52+ part title. Not an inserted clip: each one gets its own short musical cue."""
53+ out, t = [], 0.0
54+ titles = {m["id"]: m["title"] for m in tl["motion"]}
55+ for c in tl["aroll"]:
56+ d = c["out"] - c["in"]
57+ if c.get("pause"):
58+ out.append({"id": c["id"], "motion": c["pause"], "title": titles.get(c["pause"], ""),
59+ "start": round(t, 3), "end": round(t + d, 3)})
60+ t += d
61+ return out
62+
63+
5064 def _ctx() -> ssl.SSLContext:
5165 ctx = ssl.create_default_context()
5266 ctx.check_hostname = False
@@ -47,6 +47,20 @@ def inserted_clips(tl: dict) -> list[dict]:
47 return out47 return out
48 48
49 49
50+def pause_clips(tl: dict) -> list[dict]:
51+ """A-roll pauses: the voice stops (black, silence) under a full-screen motion (`pause` = its id), usually a
52+ part title. Not an inserted clip: each one gets its own short musical cue."""
53+ out, t = [], 0.0
54+ titles = {m["id"]: m["title"] for m in tl["motion"]}
55+ for c in tl["aroll"]:
56+ d = c["out"] - c["in"]
57+ if c.get("pause"):
58+ out.append({"id": c["id"], "motion": c["pause"], "title": titles.get(c["pause"], ""),
59+ "start": round(t, 3), "end": round(t + d, 3)})
60+ t += d
61+ return out
62+
63+
50 def _ctx() -> ssl.SSLContext:64 def _ctx() -> ssl.SSLContext:
51 ctx = ssl.create_default_context()65 ctx = ssl.create_default_context()
52 ctx.check_hostname = False66 ctx.check_hostname = False
modified .claude/skills/music-bed/scripts/voice.py +4 -1
@@ -8,7 +8,7 @@ import re
88 import subprocess
99 import sys
1010
11-from common import inserted_clips, lufs, project_dir, timeline, total, work_dir
11+from common import inserted_clips, lufs, pause_clips, project_dir, timeline, total, work_dir
1212
1313
1414 def mix_aroll(pid: str, tl: dict, dest) -> None:
@@ -59,6 +59,9 @@ def main() -> None:
5959 print("inserted clips (no music under them):")
6060 for c in inserted_clips(tl):
6161 print(f" {c['start']:8.2f} -> {c['end']:8.2f} {c['src']}")
62+ print("A-roll pauses under a full-screen motion (a short cue each):")
63+ for c in pause_clips(tl):
64+ print(f" {c['start']:8.2f} -> {c['end']:8.2f} {c['motion']} {c['title'][:60]}")
6265 print("part titles (short motions):")
6366 for m in tl["motion"]:
6467 if m["kind"] == "transition" or m["dur"] <= 1.5:
@@ -8,7 +8,7 @@ import re
8 import subprocess8 import subprocess
9 import sys9 import sys
10 10
11-from common import inserted_clips, lufs, project_dir, timeline, total, work_dir11+from common import inserted_clips, lufs, pause_clips, project_dir, timeline, total, work_dir
12 12
13 13
14 def mix_aroll(pid: str, tl: dict, dest) -> None:14 def mix_aroll(pid: str, tl: dict, dest) -> None:
@@ -59,6 +59,9 @@ def main() -> None:
59 print("inserted clips (no music under them):")59 print("inserted clips (no music under them):")
60 for c in inserted_clips(tl):60 for c in inserted_clips(tl):
61 print(f" {c['start']:8.2f} -> {c['end']:8.2f} {c['src']}")61 print(f" {c['start']:8.2f} -> {c['end']:8.2f} {c['src']}")
62+ print("A-roll pauses under a full-screen motion (a short cue each):")
63+ for c in pause_clips(tl):
64+ print(f" {c['start']:8.2f} -> {c['end']:8.2f} {c['motion']} {c['title'][:60]}")
62 print("part titles (short motions):")65 print("part titles (short motions):")
63 for m in tl["motion"]:66 for m in tl["motion"]:
64 if m["kind"] == "transition" or m["dur"] <= 1.5:67 if m["kind"] == "transition" or m["dur"] <= 1.5: