kaizen-agent 1.47.0 → 1.49.0

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 (184) hide show
  1. package/README.md +111 -84
  2. package/cli/build-web.ts +4 -2
  3. package/cli/hermes.ts +65 -0
  4. package/cli/install.ts +24 -10
  5. package/cli/localsend.test.ts +84 -0
  6. package/cli/localsend.ts +131 -0
  7. package/cli/notes.test.ts +6 -4
  8. package/cli/settings.ts +1 -0
  9. package/cli/state.test.ts +37 -0
  10. package/cli/state.ts +35 -20
  11. package/cli/video.test.ts +479 -0
  12. package/cli/video.ts +507 -0
  13. package/cli/web.ts +127 -1
  14. package/cli/worktree.test.ts +3 -1
  15. package/package.json +1 -1
  16. package/skills/kaizen/config.default.yml +4 -0
  17. package/skills/media/kaizen-book/SKILL.md +107 -0
  18. package/skills/media/kaizen-book/assets/reader.html +440 -0
  19. package/skills/media/kaizen-book/assets/styles.json +45 -0
  20. package/skills/media/kaizen-book/examples/book.json +14 -0
  21. package/skills/media/kaizen-book/examples/images/reach.svg +1 -0
  22. package/skills/media/kaizen-book/examples/manuscript.md +127 -0
  23. package/skills/media/kaizen-book/references/interview.md +85 -0
  24. package/skills/media/kaizen-book/references/proofread.md +47 -0
  25. package/skills/media/kaizen-book/references/writing.md +53 -0
  26. package/skills/media/kaizen-book/scripts/build_book.py +279 -0
  27. package/skills/media/kaizen-book/scripts/check.sh +10 -0
  28. package/skills/media/kaizen-book/scripts/check_book.py +128 -0
  29. package/skills/media/kaizen-book/scripts/deploy.py +58 -0
  30. package/skills/media/kaizen-book/scripts/pdf.mjs +99 -0
  31. package/skills/media/kaizen-book/scripts/setup.sh +9 -0
  32. package/skills/media/kaizen-book/scripts/verify.mjs +95 -0
  33. package/skills/{story-deck → media/kaizen-deck}/SKILL.md +1 -1
  34. package/skills/{story-deck → media/kaizen-deck}/scripts/check.sh +1 -1
  35. package/skills/{story-deck → media/kaizen-deck}/scripts/install_fonts.py +2 -2
  36. package/skills/media/kaizen-video/SKILL.md +112 -0
  37. package/skills/media/kaizen-video/assets/CREDITS.txt +16 -0
  38. package/skills/media/kaizen-video/assets/film-fonts/Fraunces.ttf +0 -0
  39. package/skills/media/kaizen-video/assets/film-fonts/Inter.ttf +0 -0
  40. package/skills/media/kaizen-video/assets/film-fonts/PlayfairDisplay-Italic.ttf +0 -0
  41. package/skills/media/kaizen-video/assets/film-fonts/PlayfairDisplay.ttf +0 -0
  42. package/skills/media/kaizen-video/assets/fonts/Fredoka.ttf +0 -0
  43. package/skills/media/kaizen-video/assets/fonts/Montserrat.ttf +0 -0
  44. package/skills/media/kaizen-video/assets/fonts/SpecialElite.ttf +0 -0
  45. package/skills/media/kaizen-video/assets/music/investigations.mp3 +0 -0
  46. package/skills/media/kaizen-video/assets/music/lights.mp3 +0 -0
  47. package/skills/media/kaizen-video/assets/music/sunny.mp3 +0 -0
  48. package/skills/media/kaizen-video/examples/config.json +152 -0
  49. package/skills/media/kaizen-video/examples/sample-film/README.md +10 -0
  50. package/skills/media/kaizen-video/examples/sample-film/film.json +63 -0
  51. package/skills/media/kaizen-video/film.html +246 -0
  52. package/skills/media/kaizen-video/hyperframes.json +12 -0
  53. package/skills/media/kaizen-video/presets/educational-warning/CREDITS.txt +3 -0
  54. package/skills/media/kaizen-video/presets/educational-warning/README.md +26 -0
  55. package/skills/media/kaizen-video/presets/educational-warning/assets/sfx/ending.wav +0 -0
  56. package/skills/media/kaizen-video/presets/educational-warning/assets/sfx/reveal.wav +0 -0
  57. package/skills/media/kaizen-video/presets/educational-warning/assets/sfx/shutter.wav +0 -0
  58. package/skills/media/kaizen-video/presets/educational-warning/assets/sfx/stamp.wav +0 -0
  59. package/skills/media/kaizen-video/presets/educational-warning/index.html +236 -0
  60. package/skills/media/kaizen-video/presets/educational-warning/package.json +10 -0
  61. package/skills/media/kaizen-video/presets/film-cinematic-drama/CREDITS.txt +1 -0
  62. package/skills/media/kaizen-video/presets/film-cinematic-drama/README.md +2 -0
  63. package/skills/media/kaizen-video/presets/film-cinematic-drama/style.json +39 -0
  64. package/skills/media/kaizen-video/presets/film-fun-energetic/CREDITS.txt +1 -0
  65. package/skills/media/kaizen-video/presets/film-fun-energetic/README.md +2 -0
  66. package/skills/media/kaizen-video/presets/film-fun-energetic/style.json +39 -0
  67. package/skills/media/kaizen-video/presets/film-promo-booth/CREDITS.txt +1 -0
  68. package/skills/media/kaizen-video/presets/film-promo-booth/README.md +2 -0
  69. package/skills/media/kaizen-video/presets/film-promo-booth/style.json +39 -0
  70. package/skills/media/kaizen-video/presets/film-viral-social/CREDITS.txt +1 -0
  71. package/skills/media/kaizen-video/presets/film-viral-social/README.md +2 -0
  72. package/skills/media/kaizen-video/presets/film-viral-social/style.json +39 -0
  73. package/skills/media/kaizen-video/presets/tiktok-cheerful/CREDITS.txt +3 -0
  74. package/skills/media/kaizen-video/presets/tiktok-cheerful/README.md +35 -0
  75. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/boing.wav +0 -0
  76. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/chime.wav +0 -0
  77. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/ding.wav +0 -0
  78. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/ending.wav +0 -0
  79. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/pop.wav +0 -0
  80. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/reveal.wav +0 -0
  81. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/shutter.wav +0 -0
  82. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/stamp.wav +0 -0
  83. package/skills/media/kaizen-video/presets/tiktok-cheerful/assets/sfx/whoosh.wav +0 -0
  84. package/skills/media/kaizen-video/presets/tiktok-cheerful/index.html +260 -0
  85. package/skills/media/kaizen-video/presets/tiktok-cheerful/package.json +10 -0
  86. package/skills/media/kaizen-video/presets/tiktok-explainer/CREDITS.txt +3 -0
  87. package/skills/media/kaizen-video/presets/tiktok-explainer/README.md +52 -0
  88. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/fonts/InstrumentSerif.ttf +0 -0
  89. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/fonts/SpaceMono.ttf +0 -0
  90. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/boing.wav +0 -0
  91. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/ding.wav +0 -0
  92. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/ending.wav +0 -0
  93. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/pop.wav +0 -0
  94. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/reveal.wav +0 -0
  95. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/shutter.wav +0 -0
  96. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/stamp.wav +0 -0
  97. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/tick.wav +0 -0
  98. package/skills/media/kaizen-video/presets/tiktok-explainer/assets/sfx/whoosh.wav +0 -0
  99. package/skills/media/kaizen-video/presets/tiktok-explainer/index.html +272 -0
  100. package/skills/media/kaizen-video/presets/tiktok-explainer/package.json +10 -0
  101. package/skills/media/kaizen-video/presets/tiktok-mystery/CREDITS.txt +12 -0
  102. package/skills/media/kaizen-video/presets/tiktok-mystery/README.md +51 -0
  103. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/clock.wav +0 -0
  104. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/ding.wav +0 -0
  105. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/ending.wav +0 -0
  106. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/heart.wav +0 -0
  107. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/projector.wav +0 -0
  108. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/reveal.wav +0 -0
  109. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/shutter.wav +0 -0
  110. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/stamp.wav +0 -0
  111. package/skills/media/kaizen-video/presets/tiktok-mystery/assets/sfx/whoosh.wav +0 -0
  112. package/skills/media/kaizen-video/presets/tiktok-mystery/index.html +260 -0
  113. package/skills/media/kaizen-video/presets/tiktok-mystery/package.json +10 -0
  114. package/skills/media/kaizen-video/presets/tiktok-scam-alert/CREDITS.txt +8 -0
  115. package/skills/media/kaizen-video/presets/tiktok-scam-alert/README.md +24 -0
  116. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/clock.wav +0 -0
  117. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/ding.wav +0 -0
  118. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/ending.wav +0 -0
  119. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/heart.wav +0 -0
  120. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/reveal.wav +0 -0
  121. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/shutter.wav +0 -0
  122. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/stamp.wav +0 -0
  123. package/skills/media/kaizen-video/presets/tiktok-scam-alert/assets/sfx/whoosh.wav +0 -0
  124. package/skills/media/kaizen-video/presets/tiktok-scam-alert/index.html +266 -0
  125. package/skills/media/kaizen-video/presets/tiktok-scam-alert/package.json +10 -0
  126. package/skills/media/kaizen-video/references/presets.md +76 -0
  127. package/skills/{story-video → media/kaizen-video}/references/production.md +2 -2
  128. package/skills/{story-video → media/kaizen-video}/references/revisions.md +9 -9
  129. package/skills/media/kaizen-video/scripts/__pycache__/intake.cpython-314.pyc +0 -0
  130. package/skills/media/kaizen-video/scripts/__pycache__/make_film.cpython-314.pyc +0 -0
  131. package/skills/media/kaizen-video/scripts/__pycache__/make_tiktok.cpython-314.pyc +0 -0
  132. package/skills/media/kaizen-video/scripts/__pycache__/render_cut.cpython-314.pyc +0 -0
  133. package/skills/media/kaizen-video/scripts/__pycache__/sfx.cpython-314.pyc +0 -0
  134. package/skills/media/kaizen-video/scripts/__pycache__/srt.cpython-314.pyc +0 -0
  135. package/skills/media/kaizen-video/scripts/__pycache__/transcribe.cpython-314.pyc +0 -0
  136. package/skills/media/kaizen-video/scripts/__pycache__/vo.cpython-314.pyc +0 -0
  137. package/skills/media/kaizen-video/scripts/check.sh +22 -0
  138. package/skills/{story-video → media/kaizen-video}/scripts/intake.py +2 -2
  139. package/skills/media/kaizen-video/scripts/make_film.py +263 -0
  140. package/skills/media/kaizen-video/scripts/make_tiktok.py +213 -0
  141. package/skills/{story-video → media/kaizen-video}/scripts/master.sh +12 -11
  142. package/skills/media/kaizen-video/scripts/render_cut.py +88 -0
  143. package/skills/media/kaizen-video/scripts/setup.sh +14 -0
  144. package/skills/{story-video → media/kaizen-video}/scripts/sfx.py +3 -3
  145. package/skills/media/kaizen-video/scripts/srt.py +9 -0
  146. package/skills/media/kaizen-video/scripts/still.sh +7 -0
  147. package/skills/media/kaizen-video/scripts/transcribe.py +45 -0
  148. package/skills/media/kaizen-video/tools/carve.mjs +560 -0
  149. package/skills/media/kaizen-video/tools/lib/main-module.mjs +13 -0
  150. package/web/board/views.ts +1 -1
  151. package/web/board.html +3 -1
  152. package/web/board.js +2 -2
  153. package/web/notebook.js +1 -1
  154. package/web/notes.html +2 -0
  155. package/web/term.js +38 -36
  156. package/web/term.ts +43 -10
  157. package/web/video.html +298 -0
  158. package/web/video.js +81 -0
  159. package/web/video.ts +610 -0
  160. package/skills/story-video/SKILL.md +0 -108
  161. package/skills/story-video/engine/package.json +0 -12
  162. package/skills/story-video/engine/src/Root.tsx +0 -24
  163. package/skills/story-video/engine/src/engine/Film.tsx +0 -405
  164. package/skills/story-video/engine/src/engine/presets.json +0 -58
  165. package/skills/story-video/engine/src/index.ts +0 -3
  166. package/skills/story-video/engine/tsconfig.json +0 -1
  167. package/skills/story-video/examples/sample-film/README.md +0 -12
  168. package/skills/story-video/examples/sample-film/film.json +0 -16
  169. package/skills/story-video/references/presets.md +0 -21
  170. package/skills/story-video/scripts/check.sh +0 -19
  171. package/skills/story-video/scripts/setup.sh +0 -25
  172. package/skills/story-video/scripts/srt.py +0 -30
  173. package/skills/story-video/scripts/still.sh +0 -10
  174. /package/skills/{story-deck → media/kaizen-deck}/examples/build-example.js +0 -0
  175. /package/skills/{story-deck → media/kaizen-deck}/references/rules.md +0 -0
  176. /package/skills/{story-deck → media/kaizen-deck}/references/story-arc.md +0 -0
  177. /package/skills/{story-deck → media/kaizen-deck}/scripts/kit.js +0 -0
  178. /package/skills/{story-deck → media/kaizen-deck}/scripts/prep_images.py +0 -0
  179. /package/skills/{story-deck → media/kaizen-deck}/scripts/qa.sh +0 -0
  180. /package/skills/{story-video → media/kaizen-video}/examples/sample-film/lines.json +0 -0
  181. /package/skills/{story-video → media/kaizen-video}/references/licensing.md +0 -0
  182. /package/skills/{story-video → media/kaizen-video}/references/script.md +0 -0
  183. /package/skills/{story-video → media/kaizen-video}/scripts/music.sh +0 -0
  184. /package/skills/{story-video → media/kaizen-video}/scripts/vo.py +0 -0
@@ -1,16 +0,0 @@
1
- {
2
- "preset": "cinematic-drama",
3
- "language": "en",
4
- "voiceProvider": "edge",
5
- "edgeVoice": "en-US-AriaNeural",
6
- "brand": { "palette": { "accent": "#D9A441", "accentBg": "#D9A441" } },
7
- "labels": { "source": "Source", "next": "Next step" },
8
- "cta": { "title": "See your own numbers in 20 minutes.", "sub": "Book a demo", "url": "[website]" },
9
- "beats": [
10
- { "vo": "v01", "kind": "black", "title": "Every café closes at ten.", "sub": "The real work starts after.", "ambience": "amb-night" },
11
- { "vo": "v02", "kind": "stat", "kick": "The hidden shift", "stat": [{ "value": 4, "suffix": "+ hours", "label": "a week reconciling receipts (example figure — replace with a sourced one)", "source": "[source]" }] },
12
- { "vo": "v03", "kind": "question", "title": "What if the books closed themselves?" },
13
- { "vo": "v04", "kind": "reveal", "title": "Ledgerly", "sub": "Bookkeeping that closes with the café.", "line": "Invoices · Cash · Reports" },
14
- { "vo": "v05", "kind": "cta", "hold": 2.5 }
15
- ]
16
- }
@@ -1,21 +0,0 @@
1
- # Presets (src/engine/presets.json)
2
-
3
- | preset | use for | look & motion | audio | captions | loudness |
4
- |---|---|---|---|---|---|
5
- | cinematic-drama | pitch opener, brand film | dark, full-bleed photos, slow push-in, rise text, grain + vignette, fades | quiet music, hit on reveal, riser into the question, room tone | subtitle bar | −16 |
6
- | promo-booth | exhibition loop, deck-faithful promo (the friend's style) | photo in a framed window beside the text, wipes, slide-in text, staged builds | whoosh on cuts, tick on titles, slightly louder music | subtitle bar | −16 |
7
- | fun-energetic | social posts, parents, events | cream background, rounded photo cards that bounce in, pop text, light leaks | bright track (Carefree), pops and a chime | subtitle bar | −14 |
8
- | viral-social | TikTok / Reels / Shorts (9:16) | full-bleed, fast punch-in cuts, bold Inter, strong Ken Burns | Easy Lemon-type track, whooshes | kinetic 2–3 words, accent on the spoken word | −14 |
9
-
10
- Pace: `lead` / `tail` = silence before and after each line. Drama 0.8/1.1, booth 0.45/0.7, fun 0.2/0.35, viral 0.05/0.2.
11
-
12
- ## Writing for each preset
13
- - **drama**: full story arc, 70–110 s, long pauses allowed.
14
- - **booth**: the deck's beats in order, 80–100 s, must make sense when joined mid-loop; real contacts on the CTA.
15
- - **fun**: 35–50 s, playful lines ("Kenal rasanya?"), one problem montage, three quick benefits.
16
- - **viral**: ≤ 30 s, line 1 is the hook (a sharp, relatable pain), product by second ~12, one CTA.
17
-
18
- ## Adding a preset
19
- Copy an entry in presets.json; fields: palette, fonts (Playfair Display / Inter / Fraunces are loaded —
20
- add others in Film.tsx FONTS), pace, text (rise|slide|pop), transition (fade|wipe|punch),
21
- layout (fullbleed|window|card), grade, captions (subtitle|kinetic|none), music levels, sfx names, kenburns, loudness.
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Requirements for story-video. Prints what is missing and how to install it; exit 1 if anything required is missing.
3
- miss=0
4
- need(){ command -v "$1" >/dev/null 2>&1 && echo "ok $1" || { echo "MISSING $1 — $2"; miss=1; }; }
5
- opt(){ command -v "$1" >/dev/null 2>&1 && echo "ok $1" || echo "opt $1 — $2"; }
6
- need node "Node.js 18+ (https://nodejs.org or your package manager)"
7
- need npm "comes with Node.js"
8
- need python3 "Python 3.9+"
9
- need ffmpeg "ffmpeg (brew install ffmpeg / apt install ffmpeg / pacman -S ffmpeg / winget install ffmpeg)"
10
- need ffprobe "comes with ffmpeg"
11
- opt soffice "LibreOffice — only for importing .pptx decks"
12
- opt pdftoppm "poppler-utils — only for importing decks"
13
- opt markitdown "pip install 'markitdown[pptx]' — only for reading .pptx text"
14
- python3 -c "import PIL" 2>/dev/null && echo "ok Pillow" || { echo "MISSING Pillow — pip install pillow"; miss=1; }
15
- python3 -c "import edge_tts" 2>/dev/null && echo "ok edge-tts (free voices)" || echo "opt edge-tts — pip install edge-tts (free voice when there is no ElevenLabs key)"
16
- python3 -c "import qrcode" 2>/dev/null && echo "ok qrcode" || echo "opt qrcode — pip install 'qrcode[pil]' (QR on the CTA)"
17
- [ -n "${ELEVENLABS_API_KEY:-}" ] && echo "ok ELEVENLABS_API_KEY set" || echo "info no ELEVENLABS_API_KEY — free voice (edge-tts) and synthesized sound effects will be used"
18
- echo "note first setup downloads the Remotion engine (~750 MB) into ~/.kaizen/story-video/engine"
19
- exit $miss
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Prepare a video workspace inside the project's .kaizen and the shared engine (installed once).
3
- # Usage: scripts/setup.sh <slug>
4
- # -> ~/.kaizen/videos/<slug>/{inputs,out,intake} (all film data and deliverables; override STORY_VIDEO_HOME)
5
- # -> ~/.kaizen/story-video/engine (Remotion engine + node_modules, shared by all projects)
6
- set -euo pipefail
7
- "$(dirname "$0")/check.sh" >/dev/null || { "$(dirname "$0")/check.sh"; exit 1; }
8
- SLUG=${1:?usage: setup.sh <slug>}
9
- SKILL=$(cd "$(dirname "$0")/.." && pwd)
10
- ENGINE=${STORY_VIDEO_ENGINE:-$HOME/.kaizen/story-video/engine}
11
- if [ ! -d "$ENGINE/node_modules/remotion" ]; then
12
- mkdir -p "$ENGINE"
13
- cp -r "$SKILL/engine/." "$ENGINE/"
14
- (cd "$ENGINE" && npm install --silent --no-audit --no-fund)
15
- fi
16
- # keep engine code current with the skill (node_modules untouched)
17
- cp -r "$SKILL/engine/src" "$SKILL/engine/package.json" "$SKILL/engine/tsconfig.json" "$ENGINE/"
18
- # sound library: made on this machine (never shipped) — ElevenLabs with a key, otherwise synthesized
19
- [ "$(ls "$ENGINE/sfx" 2>/dev/null | wc -l)" -ge 14 ] || STORY_VIDEO_ENGINE="$ENGINE" python3 "$SKILL/scripts/sfx.py" ${SFX_PROVIDER:+--provider "$SFX_PROVIDER"}
20
- DIR="${STORY_VIDEO_HOME:-$HOME/.kaizen/videos}/$SLUG"
21
- mkdir -p "$DIR/inputs" "$DIR/out/previous" "$DIR/intake"
22
- [ -e "$DIR/sfx" ] || ln -s "$ENGINE/sfx" "$DIR/sfx"
23
- [ -f "$DIR/REVISIONS.md" ] || printf '# Revisions — %s\n\n' "$SLUG" > "$DIR/REVISIONS.md"
24
- echo "engine: $ENGINE"
25
- echo "film: $DIR (put the user's material in $DIR/inputs)"
@@ -1,30 +0,0 @@
1
- """Write an .srt from film.json + words.json using the same timeline as the engine.
2
- Usage: python3 scripts/srt.py <film-dir> <out.srt>"""
3
- import json, sys
4
- folder, out = sys.argv[1], sys.argv[2]
5
- film = json.load(open(f"{folder}/film.json")); words = json.load(open(f"{folder}/words.json"))
6
- import os
7
- ENGINE = os.path.expanduser(os.environ.get("STORY_VIDEO_ENGINE", "~/.kaizen/story-video/engine"))
8
- p = json.load(open(f"{ENGINE}/src/engine/presets.json"))[film["preset"]]
9
- FPS = 30
10
- def blen(b):
11
- v = (p["pace"]["lead"] + words[b["vo"]]["dur"] + p["pace"]["tail"]) if b.get("vo") else 0
12
- return round((v + b.get("hold", 0)) * FPS)
13
- def ts(sec):
14
- ms = int(round(sec * 1000)); h, ms = divmod(ms, 3600000); m, ms = divmod(ms, 60000); s, ms = divmod(ms, 1000)
15
- return f"{h:02}:{m:02}:{s:02},{ms:03}"
16
- start, cues = 0, []
17
- for b in film["beats"]:
18
- if b.get("vo"):
19
- ws = words[b["vo"]]["words"]; t0 = start / FPS + p["pace"]["lead"]
20
- chunk = []
21
- for w in ws:
22
- chunk.append(w)
23
- if len(chunk) >= 7 or w["w"][-1] in ".,?!" or w is ws[-1]:
24
- cues.append([t0 + chunk[0]['s'], t0 + chunk[-1]['e'] + 0.2, ' '.join(x['w'] for x in chunk)])
25
- chunk = []
26
- start += blen(b)
27
- for a_, b_ in zip(cues, cues[1:]):
28
- a_[1] = min(a_[1], b_[0] - 0.02) # no overlapping cues
29
- lines = [f"{i}\n{ts(s)} --> {ts(e)}\n{t}\n" for i, (s, e, t) in enumerate(cues, 1)]
30
- open(out, "w").write("\n".join(lines)); print("srt", len(cues), "cues")
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Quick check frames: scripts/still.sh <film-dir> <16x9|9x16> <frame> [<frame>...] -> <film-dir>/out/check-<frame>.jpg
3
- set -euo pipefail
4
- DIR=$(cd "$1" && pwd); FMT=$2; shift 2
5
- ENGINE=${STORY_VIDEO_ENGINE:-$HOME/.kaizen/story-video/engine}
6
- python3 -c "import json; json.dump({'film': json.load(open('$DIR/film.json')), 'words': json.load(open('$DIR/words.json'))}, open('$DIR/.props.json','w'))"
7
- for fr in "$@"; do
8
- (cd "$ENGINE" && npx remotion still src/index.ts "Film-$FMT" "$DIR/out/check-$fr.jpg" --frame="$fr" --props="$DIR/.props.json" --public-dir="$DIR" --image-format=jpeg --scale=0.33 --log=error 2>&1 | grep -iv network | tail -1 || true)
9
- done
10
- rm "$DIR/.props.json"; ls "$DIR"/out/check-*.jpg