videowright 0.1.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.
- package/README.md +91 -0
- package/dist/cli/argv.d.ts +28 -0
- package/dist/cli/argv.d.ts.map +1 -0
- package/dist/cli/argv.js +115 -0
- package/dist/cli/argv.js.map +1 -0
- package/dist/cli/bin.d.ts +7 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +10 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/dev.d.ts +19 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dev.js +104 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/discover.d.ts +29 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +104 -0
- package/dist/cli/discover.js.map +1 -0
- package/dist/cli/discover_project.d.ts +29 -0
- package/dist/cli/discover_project.d.ts.map +1 -0
- package/dist/cli/discover_project.js +108 -0
- package/dist/cli/discover_project.js.map +1 -0
- package/dist/cli/errors.d.ts +10 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +13 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/ffmpeg.d.ts +57 -0
- package/dist/cli/ffmpeg.d.ts.map +1 -0
- package/dist/cli/ffmpeg.js +122 -0
- package/dist/cli/ffmpeg.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +152 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/playwright_check.d.ts +44 -0
- package/dist/cli/playwright_check.d.ts.map +1 -0
- package/dist/cli/playwright_check.js +20 -0
- package/dist/cli/playwright_check.js.map +1 -0
- package/dist/cli/prompt.d.ts +13 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +47 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/render.d.ts +60 -0
- package/dist/cli/render.d.ts.map +1 -0
- package/dist/cli/render.js +471 -0
- package/dist/cli/render.js.map +1 -0
- package/dist/cli/script_cmd.d.ts +26 -0
- package/dist/cli/script_cmd.d.ts.map +1 -0
- package/dist/cli/script_cmd.js +88 -0
- package/dist/cli/script_cmd.js.map +1 -0
- package/dist/cli/time_shim.d.ts +44 -0
- package/dist/cli/time_shim.d.ts.map +1 -0
- package/dist/cli/time_shim.js +390 -0
- package/dist/cli/time_shim.js.map +1 -0
- package/dist/cli/ts_loader.d.ts +28 -0
- package/dist/cli/ts_loader.d.ts.map +1 -0
- package/dist/cli/ts_loader.js +95 -0
- package/dist/cli/ts_loader.js.map +1 -0
- package/dist/cli/vite_helpers.d.ts +62 -0
- package/dist/cli/vite_helpers.d.ts.map +1 -0
- package/dist/cli/vite_helpers.js +273 -0
- package/dist/cli/vite_helpers.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/player/hash_router.d.ts +23 -0
- package/dist/player/hash_router.d.ts.map +1 -0
- package/dist/player/hash_router.js +49 -0
- package/dist/player/hash_router.js.map +1 -0
- package/dist/player/hud.d.ts +33 -0
- package/dist/player/hud.d.ts.map +1 -0
- package/dist/player/hud.js +357 -0
- package/dist/player/hud.js.map +1 -0
- package/dist/player/index.d.ts +123 -0
- package/dist/player/index.d.ts.map +1 -0
- package/dist/player/index.js +848 -0
- package/dist/player/index.js.map +1 -0
- package/dist/player/input.d.ts +14 -0
- package/dist/player/input.d.ts.map +1 -0
- package/dist/player/input.js +90 -0
- package/dist/player/input.js.map +1 -0
- package/dist/player/slot.d.ts +22 -0
- package/dist/player/slot.d.ts.map +1 -0
- package/dist/player/slot.js +43 -0
- package/dist/player/slot.js.map +1 -0
- package/dist/player/transitions/cut.d.ts +7 -0
- package/dist/player/transitions/cut.d.ts.map +1 -0
- package/dist/player/transitions/cut.js +9 -0
- package/dist/player/transitions/cut.js.map +1 -0
- package/dist/player/transitions/fade.d.ts +7 -0
- package/dist/player/transitions/fade.d.ts.map +1 -0
- package/dist/player/transitions/fade.js +18 -0
- package/dist/player/transitions/fade.js.map +1 -0
- package/dist/player/transitions/index.d.ts +4 -0
- package/dist/player/transitions/index.d.ts.map +1 -0
- package/dist/player/transitions/index.js +4 -0
- package/dist/player/transitions/index.js.map +1 -0
- package/dist/player/transitions/slide.d.ts +6 -0
- package/dist/player/transitions/slide.d.ts.map +1 -0
- package/dist/player/transitions/slide.js +35 -0
- package/dist/player/transitions/slide.js.map +1 -0
- package/dist/script/index.d.ts +2 -0
- package/dist/script/index.d.ts.map +1 -0
- package/dist/script/index.js +2 -0
- package/dist/script/index.js.map +1 -0
- package/dist/script/script.d.ts +10 -0
- package/dist/script/script.d.ts.map +1 -0
- package/dist/script/script.js +41 -0
- package/dist/script/script.js.map +1 -0
- package/dist/segment/SegmentRunner.d.ts +52 -0
- package/dist/segment/SegmentRunner.d.ts.map +1 -0
- package/dist/segment/SegmentRunner.js +187 -0
- package/dist/segment/SegmentRunner.js.map +1 -0
- package/dist/segment/defineConfig.d.ts +6 -0
- package/dist/segment/defineConfig.d.ts.map +1 -0
- package/dist/segment/defineConfig.js +7 -0
- package/dist/segment/defineConfig.js.map +1 -0
- package/dist/segment/defineSegment.d.ts +7 -0
- package/dist/segment/defineSegment.d.ts.map +1 -0
- package/dist/segment/defineSegment.js +25 -0
- package/dist/segment/defineSegment.js.map +1 -0
- package/dist/segment/index.d.ts +5 -0
- package/dist/segment/index.d.ts.map +1 -0
- package/dist/segment/index.js +4 -0
- package/dist/segment/index.js.map +1 -0
- package/dist/timeline/index.d.ts +73 -0
- package/dist/timeline/index.d.ts.map +1 -0
- package/dist/timeline/index.js +142 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/loadAudioTrack.d.ts +18 -0
- package/dist/timeline/loadAudioTrack.d.ts.map +1 -0
- package/dist/timeline/loadAudioTrack.js +44 -0
- package/dist/timeline/loadAudioTrack.js.map +1 -0
- package/dist/timeline/loadVoiceover.d.ts +18 -0
- package/dist/timeline/loadVoiceover.d.ts.map +1 -0
- package/dist/timeline/loadVoiceover.js +38 -0
- package/dist/timeline/loadVoiceover.js.map +1 -0
- package/dist/timeline/resolveTiming.d.ts +28 -0
- package/dist/timeline/resolveTiming.d.ts.map +1 -0
- package/dist/timeline/resolveTiming.js +63 -0
- package/dist/timeline/resolveTiming.js.map +1 -0
- package/dist/timeline/validateTiming.d.ts +29 -0
- package/dist/timeline/validateTiming.d.ts.map +1 -0
- package/dist/timeline/validateTiming.js +62 -0
- package/dist/timeline/validateTiming.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
- package/skill/SKILL.md +64 -0
- package/skill/assets/hello_world/PLAN.md +31 -0
- package/skill/assets/hello_world/README.md +27 -0
- package/skill/assets/hello_world/audio/audio_plan.md +14 -0
- package/skill/assets/hello_world/segments/hello_intro.ts +69 -0
- package/skill/assets/hello_world/segments/hello_outro.ts +71 -0
- package/skill/assets/hello_world/timeline.ts +15 -0
- package/skill/assets/hello_world/voiceover_script/script.md +10 -0
- package/skill/assets/install/package.json +10 -0
- package/skill/assets/install/tsconfig.json +23 -0
- package/skill/assets/styles/editorial-mono/STYLE.md +124 -0
- package/skill/assets/styles/editorial-mono/brand.md +85 -0
- package/skill/assets/styles/editorial-mono/reference/animations.jsx +752 -0
- package/skill/assets/styles/editorial-mono/reference/scenes.html +563 -0
- package/skill/assets/styles/editorial-mono/sample/bullet.ts +101 -0
- package/skill/assets/styles/editorial-mono/sample/content.ts +104 -0
- package/skill/assets/styles/editorial-mono/sample/cta.ts +113 -0
- package/skill/assets/styles/editorial-mono/sample/feature.ts +111 -0
- package/skill/assets/styles/editorial-mono/sample/grid.ts +97 -0
- package/skill/assets/styles/editorial-mono/sample/kinetic.ts +96 -0
- package/skill/assets/styles/editorial-mono/sample/section.ts +101 -0
- package/skill/assets/styles/editorial-mono/sample/stat.ts +128 -0
- package/skill/assets/styles/editorial-mono/sample/title.ts +97 -0
- package/skill/assets/styles/editorial-mono/sample/ui-showcase.ts +159 -0
- package/skill/assets/styles/editorial-mono/tokens.css +44 -0
- package/skill/assets/styles/iso-diagram/STYLE.md +109 -0
- package/skill/assets/styles/iso-diagram/brand.md +32 -0
- package/skill/assets/styles/iso-diagram/reference/animations.jsx +673 -0
- package/skill/assets/styles/iso-diagram/reference/scenes.html +427 -0
- package/skill/assets/styles/iso-diagram/sample/bullet.ts +144 -0
- package/skill/assets/styles/iso-diagram/sample/content.ts +192 -0
- package/skill/assets/styles/iso-diagram/sample/cta.ts +162 -0
- package/skill/assets/styles/iso-diagram/sample/feature.ts +205 -0
- package/skill/assets/styles/iso-diagram/sample/grid.ts +181 -0
- package/skill/assets/styles/iso-diagram/sample/kinetic.ts +102 -0
- package/skill/assets/styles/iso-diagram/sample/section.ts +149 -0
- package/skill/assets/styles/iso-diagram/sample/stat.ts +164 -0
- package/skill/assets/styles/iso-diagram/sample/title.ts +173 -0
- package/skill/assets/styles/iso-diagram/sample/ui-showcase.ts +162 -0
- package/skill/assets/styles/iso-diagram/tokens.css +40 -0
- package/skill/assets/styles/motion-engineering/STYLE.md +106 -0
- package/skill/assets/styles/motion-engineering/brand.md +29 -0
- package/skill/assets/styles/motion-engineering/reference/animations.jsx +673 -0
- package/skill/assets/styles/motion-engineering/reference/scenes.html +513 -0
- package/skill/assets/styles/motion-engineering/sample/bullet.ts +176 -0
- package/skill/assets/styles/motion-engineering/sample/content.ts +228 -0
- package/skill/assets/styles/motion-engineering/sample/cta.ts +209 -0
- package/skill/assets/styles/motion-engineering/sample/feature.ts +299 -0
- package/skill/assets/styles/motion-engineering/sample/grid.ts +190 -0
- package/skill/assets/styles/motion-engineering/sample/kinetic.ts +159 -0
- package/skill/assets/styles/motion-engineering/sample/section.ts +196 -0
- package/skill/assets/styles/motion-engineering/sample/stat.ts +230 -0
- package/skill/assets/styles/motion-engineering/sample/title.ts +219 -0
- package/skill/assets/styles/motion-engineering/sample/ui-showcase.ts +267 -0
- package/skill/assets/styles/motion-engineering/tokens.css +40 -0
- package/skill/assets/styles/neon-terminal/STYLE.md +105 -0
- package/skill/assets/styles/neon-terminal/brand.md +27 -0
- package/skill/assets/styles/neon-terminal/reference/animations.jsx +673 -0
- package/skill/assets/styles/neon-terminal/reference/scenes.html +387 -0
- package/skill/assets/styles/neon-terminal/sample/bullet.ts +113 -0
- package/skill/assets/styles/neon-terminal/sample/content.ts +117 -0
- package/skill/assets/styles/neon-terminal/sample/cta.ts +131 -0
- package/skill/assets/styles/neon-terminal/sample/feature.ts +112 -0
- package/skill/assets/styles/neon-terminal/sample/grid.ts +128 -0
- package/skill/assets/styles/neon-terminal/sample/kinetic.ts +105 -0
- package/skill/assets/styles/neon-terminal/sample/section.ts +96 -0
- package/skill/assets/styles/neon-terminal/sample/stat.ts +123 -0
- package/skill/assets/styles/neon-terminal/sample/title.ts +122 -0
- package/skill/assets/styles/neon-terminal/sample/ui-showcase.ts +127 -0
- package/skill/assets/styles/neon-terminal/tokens.css +39 -0
- package/skill/assets/styles/risograph/STYLE.md +110 -0
- package/skill/assets/styles/risograph/brand.md +26 -0
- package/skill/assets/styles/risograph/reference/animations.jsx +673 -0
- package/skill/assets/styles/risograph/reference/scenes.html +403 -0
- package/skill/assets/styles/risograph/sample/bullet.ts +124 -0
- package/skill/assets/styles/risograph/sample/content.ts +135 -0
- package/skill/assets/styles/risograph/sample/cta.ts +149 -0
- package/skill/assets/styles/risograph/sample/feature.ts +152 -0
- package/skill/assets/styles/risograph/sample/grid.ts +123 -0
- package/skill/assets/styles/risograph/sample/kinetic.ts +125 -0
- package/skill/assets/styles/risograph/sample/section.ts +130 -0
- package/skill/assets/styles/risograph/sample/stat.ts +145 -0
- package/skill/assets/styles/risograph/sample/title.ts +132 -0
- package/skill/assets/styles/risograph/sample/ui-showcase.ts +147 -0
- package/skill/assets/styles/risograph/tokens.css +39 -0
- package/skill/assets/styles/swiss-console/STYLE.md +107 -0
- package/skill/assets/styles/swiss-console/brand.md +37 -0
- package/skill/assets/styles/swiss-console/reference/animations.jsx +673 -0
- package/skill/assets/styles/swiss-console/reference/scenes.html +420 -0
- package/skill/assets/styles/swiss-console/sample/bullet.ts +122 -0
- package/skill/assets/styles/swiss-console/sample/content.ts +137 -0
- package/skill/assets/styles/swiss-console/sample/cta.ts +109 -0
- package/skill/assets/styles/swiss-console/sample/feature.ts +163 -0
- package/skill/assets/styles/swiss-console/sample/grid.ts +145 -0
- package/skill/assets/styles/swiss-console/sample/kinetic.ts +117 -0
- package/skill/assets/styles/swiss-console/sample/section.ts +127 -0
- package/skill/assets/styles/swiss-console/sample/stat.ts +148 -0
- package/skill/assets/styles/swiss-console/sample/title.ts +148 -0
- package/skill/assets/styles/swiss-console/sample/ui-showcase.ts +198 -0
- package/skill/assets/styles/swiss-console/tokens.css +39 -0
- package/skill/install/INSTALL.md +400 -0
- package/skill/references/audio/audio_plan.md +199 -0
- package/skill/references/audio/build.md +208 -0
- package/skill/references/audio/cue_template.md +219 -0
- package/skill/references/audio/ffmpeg_cookbook.md +267 -0
- package/skill/references/audio/music/music.md +171 -0
- package/skill/references/audio/music/providers/elevenlabs.md +170 -0
- package/skill/references/audio/music/providers/manual.md +140 -0
- package/skill/references/audio/music/providers/openverse.md +265 -0
- package/skill/references/audio/sfx/providers/elevenlabs.md +152 -0
- package/skill/references/audio/sfx/providers/manual.md +117 -0
- package/skill/references/audio/sfx/providers/openverse.md +243 -0
- package/skill/references/audio/sfx/sfx.md +149 -0
- package/skill/references/audio/styles.md +102 -0
- package/skill/references/audio/sync.md +237 -0
- package/skill/references/audio/voiceover/animation_sync.md +142 -0
- package/skill/references/audio/voiceover/provider_script.md +153 -0
- package/skill/references/audio/voiceover/providers/elevenlabs.md +288 -0
- package/skill/references/audio/voiceover/providers/manual.md +100 -0
- package/skill/references/audio/voiceover/script_writing.md +100 -0
- package/skill/references/audio/voiceover/style_intake.md +56 -0
- package/skill/references/audio/voiceover/sync_algorithm.md +167 -0
- package/skill/references/audio/voiceover.md +296 -0
- package/skill/references/audio.md +135 -0
- package/skill/references/authoring_segment.md +446 -0
- package/skill/references/create_or_edit_video.md +232 -0
- package/skill/references/dev_server.md +157 -0
- package/skill/references/export.md +145 -0
- package/skill/references/new_video.md +117 -0
- package/skill/references/project_structure.md +144 -0
- package/skill/references/setup.md +109 -0
- package/skill/references/setup_new_style.md +158 -0
- package/skill/references/styles.md +154 -0
- package/skill/references/testing.md +115 -0
- package/skill/references/types.md +240 -0
- package/src/cli/entry/components/copy_button.ts +42 -0
- package/src/cli/entry/components/download_modal.ts +204 -0
- package/src/cli/entry/components/empty_state.ts +55 -0
- package/src/cli/entry/components/hide_hud_tab.ts +37 -0
- package/src/cli/entry/components/icons.ts +31 -0
- package/src/cli/entry/components/top_bar.ts +69 -0
- package/src/cli/entry/components/video_card.ts +57 -0
- package/src/cli/entry/dev_frame.ts +189 -0
- package/src/cli/entry/entry_index.ts +16 -0
- package/src/cli/entry/entry_video.ts +24 -0
- package/src/cli/entry/index.html +12 -0
- package/src/cli/entry/parse_slug.ts +14 -0
- package/src/cli/entry/render.html +17 -0
- package/src/cli/entry/render_entry.ts +121 -0
- package/src/cli/entry/styles/base.css +45 -0
- package/src/cli/entry/styles/components.css +605 -0
- package/src/cli/entry/styles/tokens.css +44 -0
- package/src/cli/entry/video.html +22 -0
- package/src/cli/entry/views/homepage.ts +66 -0
- package/src/cli/entry/views/video_view.ts +286 -0
- package/src/cli/entry/virtual.d.ts +8 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Create or Edit Video
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You were dispatched here from one of:
|
|
6
|
+
|
|
7
|
+
- **[new_video.md](new_video.md)** — create mode. The `videos/<name>/` folder is new and PLAN.md was just confirmed. Scaffold segments and timeline from the plan.
|
|
8
|
+
- **SKILL.md intent dispatch** — edit mode. The video already exists. Read PLAN.md, make the requested change, and append to the log.
|
|
9
|
+
|
|
10
|
+
This is a single file because the underlying mechanics — segments, timeline composition, styles, voiceover — are the same whether scaffolding fresh or modifying.
|
|
11
|
+
|
|
12
|
+
## What you need to know
|
|
13
|
+
|
|
14
|
+
These reference files cover the building blocks. Load them as needed — do not re-read this section's summaries when the full reference is available.
|
|
15
|
+
|
|
16
|
+
- **[authoring_segment.md](authoring_segment.md)** — segment lifecycle (`mount`/`play`/`unmount`), `defineSegment`, timing with `ctx.waitForNext()` and `ctx.hold(ms)`, render-safe animation patterns (WAAPI, `ctx.clock()`, patterns and recommendations), idempotency, any-web-tech guidance.
|
|
17
|
+
- **[audio.md](audio.md)** — audio workflow (voiceover, SFX, music), the `voiceover` field on segments, VO-first authoring pattern, `videowright script` CLI, file conventions, CLI usage (`--audio-track`).
|
|
18
|
+
- **[styles.md](styles.md)** — style folder structure, how segments consume tokens via CSS variables, switching styles, the timeline.ts import convention.
|
|
19
|
+
- **[project_structure.md](project_structure.md)** — consumer repo layout, file-ownership rules (top-level dirs are shared, per-video files live in `videos/<name>/`).
|
|
20
|
+
- **[types.md](types.md)** — quick reference for `Segment`, `PlayerContext`, `Timeline`, `TimelineMeta`, `Config`.
|
|
21
|
+
|
|
22
|
+
## Create mode
|
|
23
|
+
|
|
24
|
+
Entry condition: `videos/<name>/` was just created by new_video.md, and PLAN.md is confirmed.
|
|
25
|
+
|
|
26
|
+
### Step 1 — Read the plan
|
|
27
|
+
|
|
28
|
+
Read `videos/<name>/PLAN.md`. Extract:
|
|
29
|
+
|
|
30
|
+
- The segment outline (segment ids and their purposes).
|
|
31
|
+
- The style slug (from the Style section).
|
|
32
|
+
- The audio intent.
|
|
33
|
+
- The script (if present).
|
|
34
|
+
|
|
35
|
+
### Step 2 — Author segments
|
|
36
|
+
|
|
37
|
+
For each segment in the outline:
|
|
38
|
+
|
|
39
|
+
1. **Check if a segment with that id already exists** in `segments/<id>/index.ts`. If it does and is reusable for this video, use it. Do not duplicate.
|
|
40
|
+
2. **Create `segments/<id>/index.ts`** using `defineSegment`. Follow the rules in [authoring_segment.md](authoring_segment.md):
|
|
41
|
+
- **Fill the frame.** Size text and visuals for a video canvas, not a web page. Body text 36px+ at 1080p, headings 64px+. Content containers should span 80-90%+ of the video width. See the "Visual sizing" section in [authoring_segment.md](authoring_segment.md).
|
|
42
|
+
- **`waitForNext()` for VO-aligned beats.** Place a `waitForNext()` at every content reveal that a voiceover should cue. Use `ctx.hold(ms)` only for animation lead-in or fixed internal pauses. This keeps segments decoupled from any single voiceover — swapping narration only requires new timing data, not segment rewrites.
|
|
43
|
+
- Prefer WAAPI (`.animate()` with `delay`) or CSS animations for smooth visual motion (smoother easing, less code). Timer-based patterns (`setTimeout`, `setInterval`, hold loops) also work deterministically under the render shim. See the render-safe animation patterns in [authoring_segment.md](authoring_segment.md).
|
|
44
|
+
- Set the `advances` array to match the timing — one entry per beat, including the final advance that transitions to the next segment (see [authoring_segment.md](authoring_segment.md) for details on how `advances` maps to `waitForNext` and `hold` calls).
|
|
45
|
+
- If audio intent is voiceover, set the `voiceover` field to the segment's VO text (from the script or drafted to match the segment's purpose). For music or silent videos, leave `voiceover` empty — use code comments to document what the segment shows.
|
|
46
|
+
- Use CSS variables from the active style: `var(--color-accent)`, `var(--font-display)`, etc. Do not import tokens.css in segments — the timeline-level import provides them.
|
|
47
|
+
3. **Use any web tech.** Three.js, GSAP, Lottie, animated SVG, shadcn, echarts — all welcome inside segments. Pick the right tool for the visual.
|
|
48
|
+
|
|
49
|
+
### Step 2b — Review each segment (render-safety and design CR)
|
|
50
|
+
|
|
51
|
+
After writing each segment, perform a focused code review before moving on. This catches style issues, visual sizing problems, timing anti-patterns, and ensures idiomatic use of render-safe patterns.
|
|
52
|
+
|
|
53
|
+
**Checklist -- review the segment code for:**
|
|
54
|
+
|
|
55
|
+
1. **Visual sizing — content fills the frame.** Text, cards, stats, and key visuals should be large and legible. Body text should be at least 36px at 1080p; headings 64px+. No `max-width: 800px` web-page centering. Primary containers should span 80-90%+ of the video width. If the segment would look like a small island surrounded by empty space, increase sizes. See the "Visual sizing" section in [authoring_segment.md](authoring_segment.md).
|
|
56
|
+
2. **`waitForNext()` used for VO-aligned beats.** Every content reveal that a voiceover might want to cue differently should be gated by `waitForNext()`, not `hold()`. `hold()` is for animation lead-in or fixed internal pauses. If a different voiceover would want to trigger a reveal at a different time, it must be `waitForNext()`. See the timing guidance in [authoring_segment.md](authoring_segment.md).
|
|
57
|
+
3. **Prefer WAAPI for DOM animation** (smoother easing, less code). Timer-based patterns (`setTimeout`, `setInterval`, rAF loops, `performance.now`) all work deterministically under the render shim but WAAPI provides smoother sub-frame interpolation.
|
|
58
|
+
4. **`ctx.hold` loops are fine for stepped/discrete changes** (e.g., typing out characters). For eased motion, prefer WAAPI with per-element `delay`.
|
|
59
|
+
5. **`ctx.clock()` used** for any code that needs the current render time (Three.js rotation, Lottie frame drive, shader uniforms, etc.).
|
|
60
|
+
6. **WAAPI / CSS animations used** for DOM animations. Staggered entrances prefer WAAPI `delay` parameter over `ctx.hold()` between `.animate()` calls (less code, smoother easing).
|
|
61
|
+
7. **Lottie uses manual frame drive** -- `autoplay: false` with `anim.goToAndStop(ctx.clock(), false)` per tick.
|
|
62
|
+
8. **Three.js reads `ctx.clock()`** for time-derived values (preferred for clarity; `performance.now()` also works under the shim).
|
|
63
|
+
9. **Imports, types, and segment shape** match project conventions (see [authoring_segment.md](authoring_segment.md)).
|
|
64
|
+
|
|
65
|
+
**If any issue is found:** fix the segment code, then re-check the full checklist before continuing. A segment is ready only after a clean pass.
|
|
66
|
+
|
|
67
|
+
See the "Render-safe animation patterns" section in [authoring_segment.md](authoring_segment.md) for the full list of patterns and recommendations with examples.
|
|
68
|
+
|
|
69
|
+
### Step 3 — Write timeline.ts
|
|
70
|
+
|
|
71
|
+
Create `videos/<name>/timeline.ts`:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import '../../styles/<slug>/tokens.css';
|
|
75
|
+
import type { Timeline } from 'videowright';
|
|
76
|
+
|
|
77
|
+
const timeline: Timeline = {
|
|
78
|
+
meta: {
|
|
79
|
+
title: '<video title from PLAN.md>',
|
|
80
|
+
// style: '<slug>', // include only if overriding defaultStyle
|
|
81
|
+
},
|
|
82
|
+
segments: [
|
|
83
|
+
{ id: '<segment-1>' },
|
|
84
|
+
{ id: '<segment-2>', transition: 'fade' },
|
|
85
|
+
// ...
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
export default timeline;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Key rules:
|
|
92
|
+
|
|
93
|
+
- **Top-of-file CSS import.** Always import the active style's `tokens.css` as the first line. The agent writes this import to match the chosen style — it is not copied from a template. The import path is relative to `timeline.ts`. Adjust `../../` depth to match directory structure.
|
|
94
|
+
- **Keep the import in sync.** The CSS import must match `meta.style ?? config.defaultStyle`. See [styles.md](styles.md) for details.
|
|
95
|
+
- **Set `meta.style`** only when overriding the project `defaultStyle`. If using the default, omit the field.
|
|
96
|
+
- **Transitions** are optional on each segment entry. Use built-in transitions (`fade`, `slideLeft`, `slideRight`) or custom ones from `transitions/`.
|
|
97
|
+
|
|
98
|
+
### Step 4 — Write voiceover script file
|
|
99
|
+
|
|
100
|
+
This step applies only when the video has a voiceover. For videos without voiceover, skip it entirely.
|
|
101
|
+
|
|
102
|
+
The voiceover system has two parts that stay in sync:
|
|
103
|
+
- **`voiceover` field** on each segment (in `segments/<id>/index.ts`) — the VO text for that segment. Set this in step 2 above.
|
|
104
|
+
- **`voiceover_script/script.md` file** (in `videos/<name>/voiceover_script/script.md`) — the full script for the video, organized by segment id. Written here.
|
|
105
|
+
|
|
106
|
+
Steps:
|
|
107
|
+
|
|
108
|
+
1. Create `videos/<name>/voiceover_script/script.md` with the full script, organized by segment id (one `## segment-id` heading per segment).
|
|
109
|
+
2. Verify each segment's `voiceover` field matches its section in the script. These must stay in sync — `videowright script` can regenerate one from the other.
|
|
110
|
+
3. See [audio.md](audio.md) for the audio workflow and [audio/voiceover.md](audio/voiceover.md) for the VO-first authoring pattern and `videowright script` usage.
|
|
111
|
+
|
|
112
|
+
### Step 5 — Shared resources
|
|
113
|
+
|
|
114
|
+
When writing segments, decide what belongs in shared directories:
|
|
115
|
+
|
|
116
|
+
- **`components/`** — reusable web components used across multiple segments (e.g., `<animated-title>`, `<feature-card>`). If a visual element appears in more than one segment, extract it.
|
|
117
|
+
- **`transitions/`** — custom transition functions. Only create if a built-in transition does not fit.
|
|
118
|
+
- **`segments/`** — all segments live here, shared across all videos. Any video can reference any segment. Name them descriptively.
|
|
119
|
+
|
|
120
|
+
The reuse rule: do not copy a segment to modify it for a different video. If two videos need the same visual with slight differences, parameterize the segment or extract the shared parts into a component.
|
|
121
|
+
|
|
122
|
+
### Step 6 — Update PLAN.md log
|
|
123
|
+
|
|
124
|
+
Append a dated entry to the Log section of `videos/<name>/PLAN.md`:
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
### YYYY-MM-DD — Initial scaffold
|
|
128
|
+
- Created segments: <list of segment ids>
|
|
129
|
+
- Timeline: <number> segments, style: <slug>
|
|
130
|
+
- Voiceover: <drafted / user-provided / none>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Step 7 — Verify
|
|
134
|
+
|
|
135
|
+
Run `npx videowright dev` (or ask the user to run it) and confirm:
|
|
136
|
+
|
|
137
|
+
- The video loads without errors.
|
|
138
|
+
- All segments play in order.
|
|
139
|
+
- Transitions work.
|
|
140
|
+
- The style's CSS variables are applied (colors, fonts look correct).
|
|
141
|
+
|
|
142
|
+
If something is broken, fix it before declaring done.
|
|
143
|
+
|
|
144
|
+
### Step 8 — Post-build handoff
|
|
145
|
+
|
|
146
|
+
After the video is verified, present the user with an explicit choice. Show this message verbatim:
|
|
147
|
+
|
|
148
|
+
> Two options:
|
|
149
|
+
> 1. **Edit the video content** — tell me what to change (segments, copy, animations, style).
|
|
150
|
+
> 2. **Set up audio** — I'll walk you through voiceover, SFX, and music.
|
|
151
|
+
|
|
152
|
+
If the user picks option 1, stay in this file and follow edit-mode instructions below for whatever they want to change.
|
|
153
|
+
|
|
154
|
+
If the user picks option 2, immediately load [audio.md](audio.md) and follow its flow entry point. Do not add any intermediate questions — audio.md handles intake.
|
|
155
|
+
|
|
156
|
+
If audio intent is **silent**, omit option 2 and instead just ask: "The video is ready. Want to make any changes?"
|
|
157
|
+
|
|
158
|
+
## Edit mode
|
|
159
|
+
|
|
160
|
+
Entry condition: `videos/<name>/` already exists with a PLAN.md and timeline.ts.
|
|
161
|
+
|
|
162
|
+
### Step 1 — Read PLAN.md
|
|
163
|
+
|
|
164
|
+
Always read `videos/<name>/PLAN.md` before making any changes. Understand the current state of the video — its segments, style, audio intent, and history.
|
|
165
|
+
|
|
166
|
+
### Step 2 — Make the requested change
|
|
167
|
+
|
|
168
|
+
Common edit operations:
|
|
169
|
+
|
|
170
|
+
**Add a segment:**
|
|
171
|
+
1. Create `segments/<id>/index.ts` following the rules above.
|
|
172
|
+
2. Add the segment entry to `timeline.ts` in the correct position.
|
|
173
|
+
3. Update the segment outline in PLAN.md.
|
|
174
|
+
|
|
175
|
+
**Remove a segment:**
|
|
176
|
+
1. Remove the segment entry from `timeline.ts`.
|
|
177
|
+
2. Do **not** delete the segment file from `segments/` — other videos may use it. Only delete if you confirm no other timeline references it.
|
|
178
|
+
3. Update the segment outline in PLAN.md.
|
|
179
|
+
|
|
180
|
+
**Reorder segments:**
|
|
181
|
+
1. Reorder the entries in `timeline.ts`.
|
|
182
|
+
2. Update the segment outline in PLAN.md.
|
|
183
|
+
|
|
184
|
+
**Restyle the video:**
|
|
185
|
+
1. Update the top-of-file CSS import in `timeline.ts` to point to the new style.
|
|
186
|
+
2. Update `meta.style` (if present) to match.
|
|
187
|
+
3. Segments do not need to change — CSS variables resolve at runtime from the timeline's import. If the new style defines different tokens than what segments reference, verify the segments still look correct.
|
|
188
|
+
4. See [styles.md](styles.md) for the full swap workflow.
|
|
189
|
+
|
|
190
|
+
**Rewrite voiceover:**
|
|
191
|
+
1. Edit the `voiceover` field on affected segments.
|
|
192
|
+
2. Run `npx videowright script` to regenerate `voiceover_script/script.md` from the updated segment fields. See [audio/voiceover.md](audio/voiceover.md).
|
|
193
|
+
|
|
194
|
+
**Edit a segment's content:**
|
|
195
|
+
1. Modify `segments/<id>/index.ts` directly.
|
|
196
|
+
2. If timing changes, update the `advances` array to match.
|
|
197
|
+
3. If voiceover changes, update the `voiceover` field.
|
|
198
|
+
|
|
199
|
+
**After any segment is created or modified**, run the render-safety CR checklist from Step 2b (create mode) against the changed segment. Fix any issues before continuing.
|
|
200
|
+
|
|
201
|
+
### Step 3 — Respect existing segment ids
|
|
202
|
+
|
|
203
|
+
Segment ids are the primary key. Renaming a segment id cascades through:
|
|
204
|
+
- Every `timeline.ts` that references it.
|
|
205
|
+
- The `voiceover_script/script.md` heading.
|
|
206
|
+
- The PLAN.md segment outline.
|
|
207
|
+
|
|
208
|
+
If you must rename, update all references. Prefer keeping existing ids unless the user explicitly asks for a rename.
|
|
209
|
+
|
|
210
|
+
### Step 4 — Append to PLAN.md log
|
|
211
|
+
|
|
212
|
+
After any meaningful change, append a dated entry:
|
|
213
|
+
|
|
214
|
+
```markdown
|
|
215
|
+
### YYYY-MM-DD — <what changed>
|
|
216
|
+
- <description of the change and why>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Step 5 — Verify
|
|
220
|
+
|
|
221
|
+
Run `npx videowright dev` and confirm the video still plays end-to-end. Check that the edit did not break existing segments or transitions.
|
|
222
|
+
|
|
223
|
+
## Edge cases
|
|
224
|
+
|
|
225
|
+
| Situation | Behavior |
|
|
226
|
+
|---|---|
|
|
227
|
+
| Segment id in PLAN.md conflicts with an existing segment | Surface the collision. Ask the user to rename or merge. |
|
|
228
|
+
| Video references a segment that does not exist | Create it. Follow the create-mode segment authoring rules. |
|
|
229
|
+
| Style slug in PLAN.md does not exist in `styles/` | Offer to create it via [setup_new_style.md](setup_new_style.md) or pick an existing style. |
|
|
230
|
+
| User asks to edit a video that has no PLAN.md | Create a PLAN.md by reading the existing `timeline.ts` and segments. Back-fill the plan from what exists, then proceed with the edit. |
|
|
231
|
+
| User asks to "add a segment" without specifying which video | Check how many videos exist. If one, use it. If multiple, ask which video. |
|
|
232
|
+
| `npx videowright dev` fails | Read the error output. Common issues: missing segment file, TypeScript error in a segment, broken import path. Fix and re-run. |
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Dev Server
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You were routed here from the intent dispatch table because the user wants to run, preview, or interact with the dev server.
|
|
6
|
+
|
|
7
|
+
## Starting the dev server
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx videowright dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This boots a Vite dev server with the player pointed at the consumer's timeline. Open the printed URL in a browser to step through segments, review voiceover text, and iterate on content with hot reload.
|
|
14
|
+
|
|
15
|
+
### Options
|
|
16
|
+
|
|
17
|
+
| Flag | Default | Purpose |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `--port <n>` | `5173` | Dev server port. If the port is taken, Vite picks the next available. |
|
|
20
|
+
| `--verbose` | off | Show extra detail (config path, timeline path). |
|
|
21
|
+
|
|
22
|
+
### Positional argument
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx videowright dev videos/my_video/timeline.ts
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Pass a specific timeline path to preview that video. Without it, the dev server uses default discovery.
|
|
29
|
+
|
|
30
|
+
## Default discovery
|
|
31
|
+
|
|
32
|
+
When no timeline path is given, `videowright dev` finds the most recently modified `timeline.ts` under `videos/`. It scans `videos/*/timeline.ts`, sorts by file modification time (newest first), and picks the top result.
|
|
33
|
+
|
|
34
|
+
This means after editing a video, `npx videowright dev` automatically picks it up without needing to specify the path.
|
|
35
|
+
|
|
36
|
+
If no videos exist, the command errors with a hint to create one.
|
|
37
|
+
|
|
38
|
+
## URL hash navigation
|
|
39
|
+
|
|
40
|
+
The player URL supports hash-based positioning:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
http://localhost:5173/#/<segmentId>/<beat>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
For example, `#/feature-cards/2` jumps to the `feature-cards` segment at beat 2. This is useful for:
|
|
47
|
+
|
|
48
|
+
- Sharing a specific position with someone reviewing the video.
|
|
49
|
+
- Bookmarking a position during development.
|
|
50
|
+
- Jumping directly to a segment you are iterating on.
|
|
51
|
+
|
|
52
|
+
The player updates the hash as you navigate, so the URL always reflects the current position.
|
|
53
|
+
|
|
54
|
+
### `?to=<id>` query fallback
|
|
55
|
+
|
|
56
|
+
The URL also supports a `?to=<id>` query parameter to jump to a specific segment:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
http://localhost:5173/?to=feature-cards
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If present, the player jumps to that segment, removes the query parameter from the URL, and replaces the history entry. This is a one-shot jump — the query is consumed on use.
|
|
63
|
+
|
|
64
|
+
## Hot reload
|
|
65
|
+
|
|
66
|
+
The dev server uses Vite's file-watching with full page reloads. When you save changes to:
|
|
67
|
+
|
|
68
|
+
- **Segment files** (`segments/<id>/index.ts`) — the page reloads and replays from the current segment.
|
|
69
|
+
- **Timeline files** (`videos/<name>/timeline.ts`) — the page reloads with the updated segment order.
|
|
70
|
+
- **Style tokens** (`styles/<slug>/tokens.css`) — the page reloads with the updated CSS variables.
|
|
71
|
+
- **Components** (`components/*/index.ts`) — the page reloads.
|
|
72
|
+
|
|
73
|
+
Edits appear almost instantly. You do not need to restart the dev server when editing content.
|
|
74
|
+
|
|
75
|
+
## Audio playback
|
|
76
|
+
|
|
77
|
+
When the video has a `default_audio_track` set in `timeline.ts`, the dev server loads the audio and enables synced playback:
|
|
78
|
+
|
|
79
|
+
- The play button in the HUD starts auto-advance with audio playing through an HTML `<audio>` element.
|
|
80
|
+
- Audio is synced to the player's logical timeline position.
|
|
81
|
+
- Manual navigation (arrow keys, clicking, number keys) pauses audio and stops auto-advance.
|
|
82
|
+
- Pressing play again resumes from the current position.
|
|
83
|
+
|
|
84
|
+
If no `default_audio_track` is set, the play button still works — it auto-advances silently using `default_timing` or segment `advances`.
|
|
85
|
+
|
|
86
|
+
`dev` does not accept an `--audio-track` flag. It always uses `default_audio_track` from `timeline.ts`. To test a specific audio track, set it as the default.
|
|
87
|
+
|
|
88
|
+
## HUD (Heads-Up Display)
|
|
89
|
+
|
|
90
|
+
The HUD is a semi-transparent overlay at the bottom of the player that shows:
|
|
91
|
+
|
|
92
|
+
| Field | Description |
|
|
93
|
+
|---|---|
|
|
94
|
+
| **play/pause button** | Toggle auto-advance with synced audio. Shows triangle (play) in idle, pause icon when playing. |
|
|
95
|
+
| **segment** | Current segment id. |
|
|
96
|
+
| **beat** | Current beat number within the segment. |
|
|
97
|
+
| **seg time** | Elapsed time since this segment mounted. |
|
|
98
|
+
| **total** | Total elapsed time since the video started. |
|
|
99
|
+
| **mode** | `interactive` (always, in dev). |
|
|
100
|
+
| **voiceover** | The current segment's `voiceover` text (if set). Shown in italics. |
|
|
101
|
+
| **keyboard shortcuts** | Reminder line at the bottom of the HUD. |
|
|
102
|
+
|
|
103
|
+
### Toggle
|
|
104
|
+
|
|
105
|
+
Press **H** to toggle the HUD on and off. The HUD is visible by default.
|
|
106
|
+
|
|
107
|
+
The `?hideHud=1` query parameter starts with the HUD hidden. This is used internally by `videowright render` so the HUD does not appear in exported frames.
|
|
108
|
+
|
|
109
|
+
A small hide-HUD tab is anchored to the top edge of the HUD strip. Clicking it (or pressing H) toggles the HUD on and off. This is useful for users who want to screen-record the browser window without HUD clutter.
|
|
110
|
+
|
|
111
|
+
### Error display
|
|
112
|
+
|
|
113
|
+
If a segment throws during `mount()` or `play()`, the HUD displays a full-screen error overlay with:
|
|
114
|
+
|
|
115
|
+
- The segment id that errored.
|
|
116
|
+
- The error message.
|
|
117
|
+
- A "Show stack trace" button.
|
|
118
|
+
- A "Reload" button.
|
|
119
|
+
|
|
120
|
+
This overlay is always visible regardless of HUD toggle state.
|
|
121
|
+
|
|
122
|
+
## Keyboard shortcuts
|
|
123
|
+
|
|
124
|
+
| Key | Action |
|
|
125
|
+
|---|---|
|
|
126
|
+
| **Right Arrow** or **Space** | Advance to next beat / next segment. |
|
|
127
|
+
| **Left Arrow** | Go to previous segment. |
|
|
128
|
+
| **R** | Restart the video from the beginning. |
|
|
129
|
+
| **H** | Toggle HUD visibility. |
|
|
130
|
+
| **1-9** | Jump to segment by index (1 = first segment). |
|
|
131
|
+
|
|
132
|
+
### Mouse and touch
|
|
133
|
+
|
|
134
|
+
- **Click** anywhere on the player (outside the HUD) advances to the next beat.
|
|
135
|
+
- **Swipe left** advances to the next beat.
|
|
136
|
+
- **Swipe right** goes to the previous segment.
|
|
137
|
+
|
|
138
|
+
## Common workflows
|
|
139
|
+
|
|
140
|
+
### Iterating on a segment
|
|
141
|
+
|
|
142
|
+
1. Run `npx videowright dev`.
|
|
143
|
+
2. Navigate to the segment (use number keys or arrow keys).
|
|
144
|
+
3. The user describes what to change; the agent edits the segment file and saves. The page hot-reloads.
|
|
145
|
+
4. Review the change in the browser. Repeat.
|
|
146
|
+
|
|
147
|
+
### Reviewing voiceover
|
|
148
|
+
|
|
149
|
+
1. Run `npx videowright dev` with the HUD visible (default).
|
|
150
|
+
2. Step through segments. The HUD shows each segment's `voiceover` text.
|
|
151
|
+
3. Compare the VO text with the visual content to verify they match.
|
|
152
|
+
|
|
153
|
+
### Previewing a specific video
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npx videowright dev videos/launch_2026/timeline.ts
|
|
157
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Export
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You were routed here from the intent dispatch table because the user wants to export a video to MP4.
|
|
6
|
+
|
|
7
|
+
Videowright has one command for producing video output:
|
|
8
|
+
|
|
9
|
+
- **`render`** -- deterministic frame-by-frame MP4 export via Playwright + ffmpeg. This is the only command that produces an MP4 file.
|
|
10
|
+
|
|
11
|
+
For screen recording, use the dev server and your own screen-capture software (see below).
|
|
12
|
+
|
|
13
|
+
## `videowright render`
|
|
14
|
+
|
|
15
|
+
Deterministic frame-by-frame export. The player runs in render mode with no wall-clock dependence.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx videowright render
|
|
19
|
+
npx videowright render videos/my_video/timeline.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### How it works
|
|
23
|
+
|
|
24
|
+
1. Boots a Vite server with the render entry point.
|
|
25
|
+
2. Launches headless Chromium via Playwright.
|
|
26
|
+
3. Navigates to the render page and waits for render mode to initialize.
|
|
27
|
+
4. Validates all segments' `advances` arrays.
|
|
28
|
+
5. Builds a frame schedule from advances (converts seconds to frame indices at the target fps).
|
|
29
|
+
6. Captures each frame via CDP screenshot and fires `renderAdvance()` at scheduled frame boundaries.
|
|
30
|
+
7. Pipes frames to ffmpeg for MP4 encoding.
|
|
31
|
+
|
|
32
|
+
### Characteristics
|
|
33
|
+
|
|
34
|
+
- **Mode**: render (`ctx.mode === 'render'`). All timer primitives are virtualized; `clock()` returns deterministic time based on frame count.
|
|
35
|
+
- **Default fps**: 60.
|
|
36
|
+
- **Determinism**: Fully deterministic -- frames are byte-identical across runs.
|
|
37
|
+
- **Best for**: Final exports, CI pipelines, videos where reproducibility matters.
|
|
38
|
+
|
|
39
|
+
## Screen Recording
|
|
40
|
+
|
|
41
|
+
For screen recording, use `videowright dev` and open the video view in a browser. The download modal (accessible via the download icon in the top bar or on homepage cards) provides instructions for screen recording:
|
|
42
|
+
|
|
43
|
+
1. Open the video in the dev server.
|
|
44
|
+
2. Press **H** or click the hide-HUD tab to hide the HUD.
|
|
45
|
+
3. Use **← →** keys to advance manually and **Space** to play/pause.
|
|
46
|
+
4. Run your screen-capture software over the browser window.
|
|
47
|
+
|
|
48
|
+
## Render options
|
|
49
|
+
|
|
50
|
+
| Flag | Default | Purpose |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `--width <n>` | `1920` | Video width in pixels. |
|
|
53
|
+
| `--height <n>` | `1080` | Video height in pixels. |
|
|
54
|
+
| `--fps <n>` | `60` | Frames per second. |
|
|
55
|
+
| `--output <path>` | `output.mp4` | Output file path (relative to cwd). |
|
|
56
|
+
| `--audio-track <id>` | | Use audio track from `audio/tracks/<id>/`. |
|
|
57
|
+
| `--audio-track none` | | Disable audio (ignore `default_audio_track`). |
|
|
58
|
+
| `--verbose` | off | Show progress, frame counts, timing, ffmpeg output on error. |
|
|
59
|
+
|
|
60
|
+
### Positional argument
|
|
61
|
+
|
|
62
|
+
`render` accepts an optional positional argument -- either a slug (directory name under `videos/`) or a path to a `timeline.ts`. When no argument is given:
|
|
63
|
+
- **Single video**: renders it automatically.
|
|
64
|
+
- **Multiple videos**: prompts for selection (interactive TTY) or lists slug commands (non-interactive/CI).
|
|
65
|
+
- **No videos**: errors with guidance.
|
|
66
|
+
|
|
67
|
+
## Dependencies
|
|
68
|
+
|
|
69
|
+
### ffmpeg
|
|
70
|
+
|
|
71
|
+
`render` requires `ffmpeg` installed and available on `PATH`. The CLI auto-detects it. If ffmpeg is not found, the command errors with a clear message.
|
|
72
|
+
|
|
73
|
+
Install ffmpeg:
|
|
74
|
+
- **macOS**: `brew install ffmpeg`
|
|
75
|
+
- **Ubuntu/Debian**: `sudo apt install ffmpeg`
|
|
76
|
+
- **Windows**: Download from https://ffmpeg.org/download.html
|
|
77
|
+
|
|
78
|
+
### Playwright / Chromium
|
|
79
|
+
|
|
80
|
+
`render` uses Playwright to launch headless Chromium. Playwright is a dev dependency of Videowright. If Chromium is not installed, Playwright will prompt to install it:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx playwright install chromium
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Audio
|
|
87
|
+
|
|
88
|
+
When an audio track is active, `render` muxes the audio file into the output MP4 via ffmpeg:
|
|
89
|
+
|
|
90
|
+
- The audio file is added as a second input to ffmpeg alongside the frame pipe.
|
|
91
|
+
- Audio is encoded as AAC at 192kbps.
|
|
92
|
+
- The `-shortest` flag bounds output to the shorter of video and audio.
|
|
93
|
+
- The audio track's `Timing` object drives segment advances, so video and audio durations should match.
|
|
94
|
+
|
|
95
|
+
### Audio track selection
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Use a specific audio track
|
|
99
|
+
npx videowright render --audio-track v1
|
|
100
|
+
|
|
101
|
+
# Suppress audio (ignore default_audio_track)
|
|
102
|
+
npx videowright render --audio-track none
|
|
103
|
+
|
|
104
|
+
# No flag: use default_audio_track from timeline.ts if set, otherwise silent
|
|
105
|
+
npx videowright render
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If no audio track is active (no `--audio-track` flag and no `default_audio_track`), the output is silent.
|
|
109
|
+
|
|
110
|
+
## Output
|
|
111
|
+
|
|
112
|
+
The default output path is `output.mp4` in the current working directory. A suggested convention is to place exports inside the video's folder at `videos/<name>/exports/`:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx videowright render --output videos/demo/exports/final.mp4
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The output is an H.264-encoded MP4 with `yuv420p` pixel format (widely compatible).
|
|
119
|
+
|
|
120
|
+
## Advances validation
|
|
121
|
+
|
|
122
|
+
`render` validates every segment's `advances` array before starting capture:
|
|
123
|
+
|
|
124
|
+
- Every segment referenced in the timeline must have a non-empty `advances` array.
|
|
125
|
+
- Values must be positive and monotonically increasing.
|
|
126
|
+
|
|
127
|
+
If validation fails, the command errors with a message identifying which segment has the problem.
|
|
128
|
+
|
|
129
|
+
### Coherence checks during capture
|
|
130
|
+
|
|
131
|
+
During rendering, the driver checks for coherence issues:
|
|
132
|
+
|
|
133
|
+
- **Segment transitioned too early**: A segment moved to the next segment before all its advances were fired. Fix: remove unused entries from the `advances` array.
|
|
134
|
+
- **Segment parked after all advances**: All advances fired but the segment is still waiting (stuck on `waitForNext`). Fix: add more entries to the `advances` array.
|
|
135
|
+
|
|
136
|
+
## Common gotchas
|
|
137
|
+
|
|
138
|
+
| Issue | Explanation |
|
|
139
|
+
|---|---|
|
|
140
|
+
| Video looks different from dev mode | `render` uses render mode where all timing is driven by the deterministic virtual clock. If a segment branches on `ctx.mode`, its behavior may differ. Test in both modes. |
|
|
141
|
+
| ffmpeg not found | Install ffmpeg and ensure it is on your PATH. |
|
|
142
|
+
| Chromium not installed | Run `npx playwright install chromium`. |
|
|
143
|
+
| Export takes a long time | `render` at 60fps captures every frame individually. A 30-second video = 1800 frames. Use `--verbose` to see progress. |
|
|
144
|
+
| `advances` validation error | Check that every segment has a valid `advances` array. See [authoring_segment.md](authoring_segment.md) for how advances maps to `waitForNext`/`hold` calls. |
|
|
145
|
+
| Output file already exists | `render` overwrites the output file (`-y` flag to ffmpeg). |
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# New Video
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You were routed here from the intent dispatch table because the user wants to create a new video. This file covers the **design phase** — capturing intent and building a confirmed PLAN.md. Once the plan is confirmed, you hand off to [create_or_edit_video.md](create_or_edit_video.md) for the **build phase**.
|
|
6
|
+
|
|
7
|
+
## Inputs to capture
|
|
8
|
+
|
|
9
|
+
Before handing off to the build phase, you need all of the following. Ask only for what is missing from the user's input — never re-ask something already answered.
|
|
10
|
+
|
|
11
|
+
| Input | Required | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **Video name** | Yes | Folder name under `videos/`. Suggest a date prefix (e.g., `2026_05_launch`). Default: `demo_video` for the first video; derive from topic for subsequent ones. The first video is usually created during setup — if `videos/demo_video/` already exists, derive from the topic instead to avoid a collision. |
|
|
14
|
+
| **Purpose** | Yes | What the video is for, who the audience is, what they should take away. |
|
|
15
|
+
| **Style** | Yes | Confirm the current `defaultStyle` is right. If not, dispatch to [setup_new_style.md](setup_new_style.md) with `setAsDefault: false`, `copySample: false`. Use the resulting slug for this video's `meta.style`. |
|
|
16
|
+
| **Audio intent** | Yes | Ask about each audio type: **voiceover** (yes/no), **sound effects** (yes/no), **background music** (yes/no), or **silent** (none of the above). Always ask — even when the input is rich. Silent is a real choice that changes pacing (longer beat holds, more visual motion). |
|
|
17
|
+
| **Hard guidelines** | If any | Must-haves: specific charts, logos, screenshots, length cap, things to avoid. |
|
|
18
|
+
| **Script** | If voiceover | Full VO copy if the user has it. If not, you will draft one during the build phase based on the other inputs. |
|
|
19
|
+
| **Segment outline** | Optional | If the user has a structure in mind, capture it. Otherwise, the build phase generates one from the script + purpose. |
|
|
20
|
+
|
|
21
|
+
### Audio intent notes
|
|
22
|
+
|
|
23
|
+
When the user picks **voiceover** (or any audio), note that Videowright supports integrated audio tracks:
|
|
24
|
+
|
|
25
|
+
- Audio plays in the dev server via an HTML `<audio>` element synced to the player.
|
|
26
|
+
- `render` muxes audio into the output MP4 via ffmpeg.
|
|
27
|
+
- The audio flow (voiceover, SFX, music) is handled after the video is scaffolded. See [audio.md](audio.md).
|
|
28
|
+
|
|
29
|
+
## One-shot vs. iterate
|
|
30
|
+
|
|
31
|
+
Read the user's invocation carefully before asking anything.
|
|
32
|
+
|
|
33
|
+
**One-shot** — the user's input already contains:
|
|
34
|
+
- A multi-paragraph script or detailed description, AND
|
|
35
|
+
- Enough style/purpose signals to fill in the plan
|
|
36
|
+
|
|
37
|
+
Even when one-shotting, **always confirm audio intent explicitly** before drafting. Audio intent is never inferred — silent is a real choice that changes pacing. If the user's input includes a clear audio statement (e.g., "this has a voiceover" or "silent video"), that counts as confirmation. Otherwise, ask: "One quick question before I draft the plan — will this video have a voiceover, sound effects, or background music?"
|
|
38
|
+
|
|
39
|
+
Once audio is confirmed, draft the full PLAN.md in one pass and present it: "Here's the plan I built from your input — anything to change?" Do not ask other intermediate questions.
|
|
40
|
+
|
|
41
|
+
**Iterate** — the input is sparse or missing key details.
|
|
42
|
+
|
|
43
|
+
In this case, ask **only the missing questions**, grouped into a single round. Do not ask one question at a time. Example:
|
|
44
|
+
|
|
45
|
+
> Before I build the plan, a few things I need:
|
|
46
|
+
> 1. What's this video for and who's the audience?
|
|
47
|
+
> 2. Should we use the current default style, or do you want something different?
|
|
48
|
+
> 3. Audio: voiceover? sound effects? background music? (or silent)
|
|
49
|
+
|
|
50
|
+
### Propose, don't interrogate
|
|
51
|
+
|
|
52
|
+
The default posture is **propose**. When uncertain about a detail, put a reasonable answer in the proposed PLAN.md and flag it for review — do not ask another question. Let the user correct the proposal rather than drilling them with questions.
|
|
53
|
+
|
|
54
|
+
## PLAN.md skeleton
|
|
55
|
+
|
|
56
|
+
Write PLAN.md into `videos/<name>/PLAN.md`. Use this structure:
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
# Plan: <video title>
|
|
60
|
+
|
|
61
|
+
## Purpose
|
|
62
|
+
- Audience: <who>
|
|
63
|
+
- Takeaway: <what they should leave with>
|
|
64
|
+
- Constraints / hard guidelines: <must-haves, must-avoids>
|
|
65
|
+
|
|
66
|
+
## Style
|
|
67
|
+
- Active style: <slug>
|
|
68
|
+
- Notes: <any per-video style deviations or notes>
|
|
69
|
+
|
|
70
|
+
## Audio intent
|
|
71
|
+
- Voiceover: yes | no
|
|
72
|
+
- Sound effects: yes | no
|
|
73
|
+
- Background music: yes | no
|
|
74
|
+
- Notes: <pacing implications, music vibe, VO tone, etc.>
|
|
75
|
+
|
|
76
|
+
## Segment outline
|
|
77
|
+
1. <id> — <one-line purpose>
|
|
78
|
+
2. <id> — <one-line purpose>
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
## Script (if applicable)
|
|
82
|
+
<full VO script, or "see voiceover_script/script.md">
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Log
|
|
87
|
+
|
|
88
|
+
### YYYY-MM-DD — Initial scaffold
|
|
89
|
+
- <what was built>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### PLAN.md rules
|
|
93
|
+
|
|
94
|
+
- The **Plan block** (Purpose / Style / Audio / Segment outline / Script) is **mutable** — overwritten as the design evolves.
|
|
95
|
+
- The **Log block** is **append-only**. Never delete entries. When meaningful changes happen (script revision, segment add/remove, style swap, design pivot), append a dated log entry.
|
|
96
|
+
- When in doubt, log it.
|
|
97
|
+
|
|
98
|
+
## Flow
|
|
99
|
+
|
|
100
|
+
1. **Evaluate the user's input.** Decide: one-shot or iterate?
|
|
101
|
+
2. **Gather missing inputs** (if iterating). Group questions into a single round.
|
|
102
|
+
3. **Draft PLAN.md.** Fill in all sections from the skeleton above.
|
|
103
|
+
4. **Present the plan for confirmation.** Show a summary — not the raw markdown — and ask: "Here's the plan. Anything to change?"
|
|
104
|
+
5. **Iterate if needed.** The user may want to adjust the script, add segments, change the style, etc. Update the plan each round.
|
|
105
|
+
6. **Write the confirmed PLAN.md** to `videos/<name>/PLAN.md`. Create the `videos/<name>/` directory if it does not exist.
|
|
106
|
+
7. **Hand off to build.** Load [create_or_edit_video.md](create_or_edit_video.md) and follow it with the create-mode entry condition (video folder is new, PLAN.md was just written).
|
|
107
|
+
|
|
108
|
+
## Edge cases
|
|
109
|
+
|
|
110
|
+
| Situation | Behavior |
|
|
111
|
+
|---|---|
|
|
112
|
+
| User already has a `videos/<name>/` folder with a PLAN.md | This is an edit, not a new video. Route to [create_or_edit_video.md](create_or_edit_video.md) in edit mode instead. |
|
|
113
|
+
| User wants a style other than `defaultStyle` | Dispatch to [setup_new_style.md](setup_new_style.md) with `setAsDefault: false`, `copySample: false`. Use the resulting slug for `meta.style` in the plan and timeline. |
|
|
114
|
+
| User provides a complete script but no segment outline | Generate the segment outline from the script during PLAN.md drafting. Each natural section of the script maps to a segment. |
|
|
115
|
+
| User provides a segment outline but no script | Capture the outline. The build phase will draft VO from the outline if audio intent is voiceover. |
|
|
116
|
+
| Video name conflicts with an existing folder | Ask the user to pick a different name, or confirm they want to overwrite. |
|
|
117
|
+
| User skips the audio question | Do not skip it yourself. Audio intent affects pacing. Ask directly: "One more thing — will this video have a voiceover, sound effects, or background music?" |
|