frameyard 0.5.0 → 0.6.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 (96) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/GLOSSARY.md +152 -24
  3. package/README.md +94 -29
  4. package/dist/cli.js +111 -14
  5. package/dist/cli.js.map +1 -1
  6. package/dist/contracts.d.ts +12 -0
  7. package/dist/contracts.d.ts.map +1 -1
  8. package/dist/contracts.js.map +1 -1
  9. package/dist/errors.d.ts +1 -1
  10. package/dist/errors.d.ts.map +1 -1
  11. package/dist/errors.js.map +1 -1
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/preview/main.js +89 -11
  17. package/dist/preview/main.js.map +1 -1
  18. package/dist/preview/timeline-data.d.ts +85 -0
  19. package/dist/preview/timeline-data.d.ts.map +1 -0
  20. package/dist/preview/timeline-data.js +2 -0
  21. package/dist/preview/timeline-data.js.map +1 -0
  22. package/dist/preview/timeline-host.d.ts +19 -0
  23. package/dist/preview/timeline-host.d.ts.map +1 -0
  24. package/dist/preview/timeline-host.js +297 -0
  25. package/dist/preview/timeline-host.js.map +1 -0
  26. package/dist/preview/timeline-main.d.ts +17 -0
  27. package/dist/preview/timeline-main.d.ts.map +1 -0
  28. package/dist/preview/timeline-main.js +364 -0
  29. package/dist/preview/timeline-main.js.map +1 -0
  30. package/dist/project.d.ts +16 -1
  31. package/dist/project.d.ts.map +1 -1
  32. package/dist/project.js +81 -26
  33. package/dist/project.js.map +1 -1
  34. package/dist/renderer/browser.d.ts +2 -0
  35. package/dist/renderer/browser.d.ts.map +1 -1
  36. package/dist/renderer/browser.js +6 -1
  37. package/dist/renderer/browser.js.map +1 -1
  38. package/dist/renderer/ffmpeg.d.ts +61 -0
  39. package/dist/renderer/ffmpeg.d.ts.map +1 -1
  40. package/dist/renderer/ffmpeg.js +198 -0
  41. package/dist/renderer/ffmpeg.js.map +1 -1
  42. package/dist/renderer/timeline.d.ts +109 -0
  43. package/dist/renderer/timeline.d.ts.map +1 -0
  44. package/dist/renderer/timeline.js +984 -0
  45. package/dist/renderer/timeline.js.map +1 -0
  46. package/dist/scaffold.d.ts.map +1 -1
  47. package/dist/scaffold.js +89 -24
  48. package/dist/scaffold.js.map +1 -1
  49. package/dist/server/preview-html.d.ts.map +1 -1
  50. package/dist/server/preview-html.js +15 -1
  51. package/dist/server/preview-html.js.map +1 -1
  52. package/dist/server/server.d.ts.map +1 -1
  53. package/dist/server/server.js +39 -1
  54. package/dist/server/server.js.map +1 -1
  55. package/dist/server/timeline-preview-data.d.ts +4 -0
  56. package/dist/server/timeline-preview-data.d.ts.map +1 -0
  57. package/dist/server/timeline-preview-data.js +97 -0
  58. package/dist/server/timeline-preview-data.js.map +1 -0
  59. package/dist/server/timeline-preview-html.d.ts +4 -0
  60. package/dist/server/timeline-preview-html.d.ts.map +1 -0
  61. package/dist/server/timeline-preview-html.js +227 -0
  62. package/dist/server/timeline-preview-html.js.map +1 -0
  63. package/dist/timeline/plan.d.ts +32 -0
  64. package/dist/timeline/plan.d.ts.map +1 -0
  65. package/dist/timeline/plan.js +68 -0
  66. package/dist/timeline/plan.js.map +1 -0
  67. package/dist/timeline/resolve.d.ts +60 -0
  68. package/dist/timeline/resolve.d.ts.map +1 -0
  69. package/dist/timeline/resolve.js +523 -0
  70. package/dist/timeline/resolve.js.map +1 -0
  71. package/dist/timeline/schema.d.ts +71 -0
  72. package/dist/timeline/schema.d.ts.map +1 -0
  73. package/dist/timeline/schema.js +425 -0
  74. package/dist/timeline/schema.js.map +1 -0
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/docs/adr/0002-make-frame-and-props-the-only-animation-state.md +2 -0
  78. package/docs/adr/0005-keep-parallel-rendering-opt-in-and-frame-ordered.md +2 -0
  79. package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
  80. package/docs/adr/0009-composite-production-frames-in-software.md +1 -1
  81. package/docs/adr/0010-make-timelines-the-render-unit.md +24 -0
  82. package/docs/adr/0011-compose-timeline-frames-in-a-live-browser-host.md +22 -0
  83. package/docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md +31 -0
  84. package/docs/v0.1-design.md +135 -86
  85. package/examples/demo/README.md +10 -3
  86. package/examples/demo/timelines/demo.timeline.json +12 -0
  87. package/examples/demo/video.config.js +4 -0
  88. package/examples/video/README.md +50 -6
  89. package/examples/video/compositions/video-overlay.html +350 -0
  90. package/examples/video/props/video-timeline.json +10 -0
  91. package/examples/video/timelines/video-timeline-mp4.timeline.json +44 -0
  92. package/examples/video/timelines/video-timeline.timeline.json +44 -0
  93. package/examples/video/video.config.js +6 -0
  94. package/package.json +1 -1
  95. package/skills/frameyard/SKILL.md +17 -13
  96. package/skills/frameyard/references/timelines.md +141 -0
@@ -2,155 +2,196 @@
2
2
 
3
3
  **Status:** Accepted
4
4
  **Initial acceptance:** 2026-10-27
5
- **Last design revision:** 2026-10-30
5
+ **Last design revision:** 2026-10-31
6
6
 
7
- This document records the decisions confirmed during design sessions. It is the living product and architecture baseline; later changes revise this document explicitly rather than silently broaden the scope. The original v0.1 baseline has been revised through 0.4. Architecture decisions that changed the baseline are recorded in `docs/adr/`.
7
+ This document records the decisions confirmed during design sessions. It is the living product and architecture baseline; later changes revise this document explicitly rather than silently broaden the scope. The original v0.1 baseline has been revised through 0.6. Architecture decisions that changed the baseline are recorded in `docs/adr/`.
8
8
 
9
9
  ## 1. Product contract
10
10
 
11
- Frameyard is a local-first, open-source framework for frontend developers and creative coders who build short, parameterized videos with HTML, CSS, and JavaScript. AI agents can perform the same workflows on a user's behalf through an official skill. Its differentiator is web-native authoring combined with deterministic, frame-accurate output—not a React-centric composition model or a feature-for-feature clone of an existing tool.
11
+ Frameyard is a local-first, open-source framework for frontend developers and creative coders who build parameterized videos with HTML, CSS, and JavaScript. It separates reusable, prop-parameterized compositions from the timelines that assemble compositions and media into one video. AI agents can perform the same workflows on a user's behalf through an official skill.
12
12
 
13
- The initial use cases are product demos, social clips, animated diagrams, data visualizations, karaoke-style subtitles, and personalized videos. Optional local speech synthesis and transcription produce assets for these workflows. Professional long-form editing is outside the target audience.
13
+ Its differentiator is web-native authoring combined with deterministic, frame-accurate output and an explicit timeline model—not a React-centric composition model or a feature-for-feature clone of an existing NLE.
14
+
15
+ The target use cases are product demos, social clips, animated diagrams, data visualizations, karaoke-style subtitles, personalized videos, and long-form edits up to roughly 60 minutes. Professional collaborative editing, cloud production, and broadcast workflows remain outside the target audience.
14
16
 
15
17
  The core success criterion is an end-to-end example in which a developer can:
16
18
 
17
- 1. Create a reusable 30-second, 1920×1080 HTML composition.
18
- 2. Animate it with HTML, CSS, SVG, and, where needed, a seek-safe controller for Canvas 2D and WebGL.
19
+ 1. Create reusable, 1920×1080 HTML compositions with fixed metadata.
20
+ 2. Animate them with HTML, CSS, SVG, and, where needed, a seek-safe controller for Canvas 2D and WebGL.
19
21
  3. Supply JSON props and synchronized audio.
20
- 4. Preview and scrub it interactively.
21
- 5. Render it reproducibly to MP4 without dropped frames or timing drift.
22
+ 4. Assemble compositions and local media into a timeline with tracks, clips, trims, layers, and nested timelines.
23
+ 5. Preview and scrub the timeline interactively.
24
+ 6. Render it reproducibly to MP4 without dropped frames or timing drift.
25
+ 7. Render a 60-minute timeline with up to three active layers within the long-form performance target.
22
26
 
23
- The agent-enabled success criterion additionally requires an agent using the official skill to create and preserve a valid source project, optionally produce local audio and transcript assets, validate and inspect the composition, render it, and report all resulting artifact paths without concealing validation failures or skipped visual review.
27
+ The agent-enabled success criterion additionally requires an agent using the official skill to create and preserve a valid source project, optionally produce local audio and transcript assets, validate and inspect the timeline and its compositions, render it, and report all resulting artifact paths without concealing validation failures or skipped visual review.
24
28
 
25
29
  ## 2. Project and authoring model
26
30
 
31
+ ### Project
32
+
27
33
  - Projects use ordinary HTML, CSS, static assets, and native JavaScript controllers, either inline in a composition document or in external modules.
28
- - `video.config.js` explicitly lists `.html` composition entry points. There is no directory-scanning discovery convention.
29
- - A project may contain multiple compositions, each with a unique ID.
34
+ - `video.config.js` explicitly maps project IDs to source files. There is no directory scanning. It has three optional maps:
35
+ - `format`: the project's fixed `width`, `height`, and `fps`.
36
+ - `compositions`: IDs mapped to `.html` composition documents.
37
+ - `timelines`: IDs mapped to JSON timeline documents.
38
+ - `format` is required when a project has timelines. Every timeline uses it. A composition used in a timeline must share the project frame rate exactly; a different size is fitted and transformed by the clip. A standalone composition render keeps using the composition's own metadata.
39
+ - Composition and timeline IDs share one namespace so `render <id>`, `check <id>`, and `still <id>` are unambiguous. The config rejects duplicates.
40
+ - A project may contain any number of compositions and timelines.
41
+
42
+ ### Composition
43
+
30
44
  - A composition is a full HTML document with one `<fy-composition>` root. The root declares fixed `width`, `height`, `fps`, and `duration-in-frames` metadata. Props cannot change this metadata.
31
- - Default props are a JSON block, `<script type="application/json" data-fy="props">`. A render's JSON props merge shallowly over the defaults, are validated as JSON, deep-frozen, and fixed for the render.
45
+ - Default props are a JSON block, `<script type="application/json" data-fy="props">`. A load's JSON props merge shallowly over the defaults, are validated as JSON, deep-frozen, and fixed for that load.
32
46
  - Props bind into the document through explicit `data-fy-*` attributes: `data-fy-text`, `data-fy-attr-*`, `data-fy-class-*`, `data-fy-if`, and `data-fy-repeat`. Primitive top-level props are also exposed as `--fy-prop-<name>` CSS custom properties. Bindings apply once per load; props are immutable.
33
47
  - CSS and the Web Animations API are the animation language. `data-fy-anim-start`, `data-fy-anim-duration`, and `data-fy-anim-easing` schedule one animation per element in composition frames.
34
- - An optional composition controller is declared with `<script type="text/fy-controller">`. It is either inline source or an external module referenced by `src`; a composition has exactly one controller. It may export `mount({ root, props })`, `update({ frame, props, root })`, `dispose()`, and `validateProps(props)`; at least one is required, and `mount` and `update` are optional for validation-only controllers. It has no metadata, default props, audio, or transcripts. Inline keeps small compositions in one file; external is for reuse, tests, and complex logic.
35
- - Inline controllers are the default for small, single-use controllers. Extract to an external module when the controller grows, is reused, needs separate imports or tests, or drives Canvas 2D, WebGL, or karaoke.
36
- - The controller is the only executable code in a composition document. Other executable `<script>` elements and inline `on*` handlers are rejected. Libraries are imported as ES modules from the controller.
48
+ - An optional composition controller is declared with `<script type="text/fy-controller">`. It is either inline source or an external module referenced by `src`; a composition has exactly one controller. It may export `mount`, `update`, `dispose`, and `validateProps`; at least one is required. The controller is the only executable code in the document.
37
49
  - `fy` is the authoring namespace: `fy-composition`, `fy-transcript`, `data-fy-*`, `--fy-*`, and `text/fy-controller`. `frameyard` remains the product, package, CLI, config, manifest, server-route, import-specifier, and error-code namespace.
38
- - User controllers are native JavaScript. The framework itself is authored in TypeScript and ships declarations, but 0.4 does not transpile user TypeScript.
50
+ - User controllers are native JavaScript. The framework itself is authored in TypeScript and ships declarations, but 0.6 does not transpile user TypeScript.
51
+
52
+ ### Timeline
53
+
54
+ - A timeline is a versioned JSON document. It references compositions and nested timelines by project ID and media clips by project-relative path.
55
+ - A timeline has a project-fixed format, an ordered list of tracks, and a list of clips. It may declare a `background` color and an optional `durationInFrames`.
56
+ - Tracks are `video` or `audio`. Video tracks composite from bottom to top; audio tracks mix. Each clip belongs to exactly one track. Clips on the same track cannot overlap; clips on different tracks can. Touching endpoints are allowed. Transitions are deferred, so overlap within a track would have ambiguous precedence.
57
+ - A clip has an ID, a track, a source, a timeline start, a source in-point, a duration, and clip-specific presentation settings. Source in-point, duration, and timeline start are integer project frames.
58
+ - Clip sources are:
59
+ - a composition, identified by its project ID;
60
+ - a nested timeline, identified by its project ID;
61
+ - a local video, image, or audio asset.
62
+ - A composition clip fixes props for that instance and may trim the composition's source range. The same composition may appear multiple times with different props, source ranges, transforms, and audio settings.
63
+ - A nested timeline clip is a visual and audio source. It uses the project format, trims with the same source in-point and duration, contributes its audio, and is rendered as a group so parent opacity and transform apply to the whole nested result. Cycles are rejected statically. Timeline clips do not override props of compositions inside the nested timeline in 0.6.
64
+ - Media clips use local project files only. Video and audio durations, dimensions, and audio presence are probed before frame production. Images are static and require an explicit duration. A video or audio clip that exceeds its source range is an error; an omitted duration uses the remaining source.
65
+ - Visual clips support a static transform: fit policy (`contain`, `cover`, `stretch`), an optional explicit `width`/`height` box (both fields together, mutually exclusive with `scale`) or a `scale` multiplier, pixel offset, rotation, and opacity. `fit` applies inside the box; without one, the project frame is the box. No keyframes, blend modes, masks, filters, or other effects in 0.6.
66
+ - Visual clips contribute their audio to the timeline mix unless muted: composition audio, embedded video audio, and nested timeline audio. Audio-only clips live on audio tracks and may source audio or video files. Per-clip and per-audio-track gain and mute are supported. There are no linked A/V pairs; a J/L cut is expressed by muting a video clip and placing a separate audio clip with a different source in-point.
67
+ - A timeline's duration is derived from the latest clip end. An explicit `durationInFrames` may extend it but not cut clips. A timeline with no clips is invalid; an audio-only timeline is valid and renders black video with audio.
68
+ - A timeline background is transparent by default. The final video composites it over black; a nested timeline remains transparent so lower layers can show through. A composition that paints no background is transparent and may be used as an overlay.
69
+ - The preview provides a read-only timeline view: tracks, clips, playhead, program monitor, and diagnostics. It is not a visual editor.
39
70
 
40
71
  ## 3. Deterministic execution
41
72
 
42
- The only sources of animation state are the integer frame number and immutable props. Composition frame rate establishes the mapping between frames and time.
73
+ The timeline frame is the master clock. A composition's frame is derived from the clip's timeline start, source in-point, and duration. The only sources of a composition's animation state remain the integer composition frame and its immutable props.
43
74
 
44
- - The runtime owns the frame clock and deterministic randomness. The controller imports `random("stable:key")` from `frameyard/runtime`.
45
- - CSS `@keyframes` and Web Animations API animations are paused and positioned from the shared frame clock. `data-fy-anim-*` attributes schedule one animation per element in composition frames; the runtime maps frames to milliseconds and sets the corresponding animation delay and duration.
46
- - The runtime sets `--fy-frame`, `--fy-time`, `--fy-progress`, `--fy-fps`, `--fy-duration`, and `--fy-duration-frames` on the composition root every seek. Authors use them for simple computed CSS values.
75
+ - The runtime owns the frame clock and deterministic randomness. A composition controller imports `random("stable:key")` from `frameyard/runtime`.
76
+ - CSS `@keyframes` and Web Animations API animations are paused and positioned from the shared composition frame clock. `data-fy-anim-*` schedules one animation per element in composition frames; the runtime maps frames to milliseconds.
77
+ - The runtime sets `--fy-frame`, `--fy-time`, `--fy-progress`, `--fy-fps`, `--fy-duration`, and `--fy-duration-frames` on the composition root every seek.
47
78
  - JavaScript animation runs in the controller's `update()`, which must be synchronous and seek-safe. It cannot depend on previously visited frames.
48
79
  - Declarative bindings apply once per load, before the controller mounts. Controller-created DOM is the controller's responsibility.
49
80
  - Independent `requestAnimationFrame` loops, timers, CSS transitions, wall-clock reads, and unseeded randomness are not supported animation drivers.
50
- - Development mode provides best-effort diagnostics for forbidden clocks and randomness in the controller; it does not claim to police every third-party library perfectly.
51
- - Assets, remote data, images, fonts, generated audio, and transcripts are resolved during an explicit loading phase before frame production. Network requests are blocked during frame capture.
81
+ - Timeline clips use static transforms. Timeline-level animation, transitions, effects, and keyframes are not part of 0.6.
82
+ - Preview and production seek composition clips explicitly. The timeline compositor is deterministic given the captured clip frames, media frames, clip settings, and segment boundaries.
83
+ - Assets, remote data, images, fonts, generated audio, transcripts, and media are resolved before frame production. For a segmented timeline render, each segment's composition and nested-timeline clips are loaded and settled before that segment's frames are captured; no frame production depends on a new network request. Network is blocked during capture.
52
84
  - AI model inference is never part of the loading phase, controller lifecycle, or frame production.
53
85
  - The baseline supports DOM, CSS, SVG, Canvas 2D, WebGL, and frame-seeked embedded video. Canvas 2D and WebGL are drawn from the current frame by the controller.
54
- - Embedded video and audio are declared in the composition HTML with `data-fy-*` attributes. The runtime loads local files during the loading phase, pauses them, and seeks video from the frame-derived source time before capture. An unmuted video contributes its audio track to the offline mix unless the composition opts out.
55
- - Full-scene opacity animations above an embedded video can make interactive preview reuse the load frame after a large seek; fade overlay layers instead. Capture sessions keep the composition hidden until the first seek, so production stills resolve to the requested frame.
86
+ - Embedded video and audio inside compositions are declared with `data-fy-*` attributes. The runtime loads local files, pauses them, and seeks video from the frame-derived source time before capture. An unmuted video contributes its audio track to the timeline mix unless the composition opts out or the clip mutes it.
87
+ - Transparent compositions are captured with an alpha-preserving browser background. Without that step, a top-level Chromium capture paints a white canvas and overlays become white rectangles.
56
88
  - WebGL 1 and WebGL 2 canvases are captured through the normal screenshot path. Production sessions pin software WebGL so pixel output does not depend on the host GPU.
57
89
  - Compositions are trusted local developer code. Frameyard does not claim to render untrusted compositions safely.
58
90
 
59
91
  ### Reproducibility guarantee
60
92
 
61
- For the same composition revision, props, frame, assets, and pinned runtime/browser environment, Frameyard guarantees identical visual state. It does not promise bit-identical MP4 bytes, even across runs on the same machine; encoded output depends on the FFmpeg build, encoder threading, and runtime environment.
93
+ For the same timeline or composition revision, props, assets, segment plan, and frame under a pinned runtime/browser/FFmpeg environment, the captured composition frames and the deterministic timeline composite are identical. The final MP4 is not promised to be bit-identical: encoded bytes depend on the encoder and its runtime.
62
94
 
63
- Generated assets are covered once frozen. Frameyard does not promise that repeating speech synthesis or transcription produces identical artifacts across different binaries, models, parameters, or hardware.
95
+ Preview and production share composition behavior and capture composition frames the same way, but the timeline preview composites layers in Chromium while production composites them with FFmpeg. Small differences in scaling, alpha, and video color conversion are expected and do not violate clip-capture parity.
64
96
 
65
97
  ## 4. Preview and production rendering
66
98
 
67
- Preview and production execute the same composition document and browser host runtime. They differ only in which component drives the frame clock and whether frames are captured.
99
+ Preview and production execute the same composition documents and host runtime. They differ in which component drives the frame clock, which compositor combines timeline layers, and whether frames are captured.
68
100
 
69
101
  The preview provides:
70
102
 
71
- - Composition selection
72
- - JSON props editing
73
- - Play/pause and frame-accurate scrubbing
74
- - Current frame and time display
75
- - Audio controls
103
+ - Composition preview: composition selection, JSON props editing, play/pause, frame-accurate scrubbing, frame-by-frame stepping with buttons or arrow keys, one-second jumps with buttons or Shift+arrow keys, current frame and time, audio controls, and diagnostics.
104
+ - Timeline preview: timeline selection, a read-only track/clip view, playhead, program monitor, frame-by-frame stepping with buttons or arrow keys, one-second jumps with buttons or Shift+arrow keys, audio controls, and diagnostics.
105
+ - A bounded pool of active composition and nested-timeline clips. It loads clips around the playhead instead of preloading a whole long timeline.
76
106
 
77
- It is a developer inspection tool, not a visual composition editor.
107
+ The preview server serves each composition HTML document at its project path and injects the framework import map and host runtime. It serves timeline documents and a timeline preview host. The timeline preview host drives active composition/nested-timeline clips, seeks them, and exposes a timeline API to the preview. Preview audio is mixed by the preview page from the resolved timeline audio clips.
78
108
 
79
- The preview server serves each composition HTML document at its project path and injects the framework import map and a host module into composition entries. The host reads the composition descriptor—metadata, default props, and the controller declaration—from the same browser-safe composition document reader used by static validation, applies bindings, imports the controller from its authoring `src` or from the inline block's virtual module URL, mounts it, and exposes a small `window.__fy` API. Preview loads the document in a same-origin iframe and drives that API. The iframe is not a security sandbox; compositions are trusted local code. The server runs the static composition validation described in §6 before serving a composition to the preview.
109
+ Production composition rendering is unchanged: one Chromium session per composition, explicit frame seeks, PNG capture, and FFmpeg encoding.
80
110
 
81
- Production rendering:
111
+ Production timeline rendering is segmented and parallel:
82
112
 
83
- 1. Uses a pinned, Playwright-managed Chromium through the Chrome DevTools Protocol.
84
- 2. Navigates directly to the composition document, waits for the host, and loads the render's props.
85
- 3. Seeks explicitly to each requested frame.
86
- 4. Waits for composition readiness, embedded media decode, and browser paint.
87
- 5. Captures the frame.
88
- 6. Pipes frames in timeline order to FFmpeg for encoding and audio muxing.
113
+ 1. Run static timeline validation and resolve the render plan.
114
+ 2. Split the timeline into segments at active-layer changes or a maximum segment duration. Each segment has a fixed set of visual layers and a fixed filter graph.
115
+ 3. In parallel workers, capture the active composition and nested-timeline clip frames for each segment with Chromium and encode them to lossless FFV1 intermediates. Transparent clips are captured with an alpha-preserving background.
116
+ 4. Decode media clips, apply trims, fit, static transforms, and opacity, composite the segment with FFmpeg, and encode H.264.
117
+ 5. Join the ordered segments with a stream copy. Segment boundaries never change frame order or timing.
118
+ 6. Mix the timeline audio once with FFmpeg and mux it into the final output.
119
+ 7. Publish the output atomically; delete scratch intermediates on success and failure.
89
120
 
90
- `check` and `still` use the same host and capture path. `check` evaluates every frame without capturing or encoding. `still` captures one frame through the production path.
121
+ The default timeline worker count is 8, configurable up to the machine's capacity. Scratch is a configurable directory with a bounded budget; it must not depend on `/tmp` alone. The reference long-form target is a representative 60-minute 1920×1080 30 fps timeline with a 50/50 composition/media split by layer-seconds, 60% one active layer, 30% two, and 10% three, rendered in 30 minutes or less on the reference machine. The 10-second benchmark measured 10.7 s for two composition captures, 35.2 MB of FFV1, and 6.1 s to composite and encode. Continuous three-layer stress runs measured 52.4 s and 58.5 s for 60 s of timeline, about 1× real time, and are documented as worst-case rather than the target workload. The representative gate measured 29.39 s for 60 s with four workers, exact 1800-frame output, and a 1080p media fast path, extrapolating to about 29.4 minutes for 60 minutes. The full 60-minute composition-only gate rendered 108,000 frames in 35.35 minutes with exact 108,000-frame / 3,600 s output; it is stricter than the 50/50 target mix because every frame is an HTML composition capture. The fast path copies full-frame, untransformed video whose source matches the project format and has keyframes at segment boundaries; media that needs scaling or transforms is re-encoded and adds cost not included in that projection.
91
122
 
92
- The renderer is sequential by default and has no frame cache. Optional `--concurrency <n>` rendering, with `n` from 1 to 16, opens up to `n` independent browser sessions, each loading the same composition document and props from the same preview server. Workers seek and capture assigned frames, while a single ordered writer pipes them to FFmpeg with bounded lookahead. Parallelism therefore changes scheduling only: every frame remains derivable from its integer frame number and immutable props, and output order is unchanged. The default stays at one session for predictable resource use, and the upper bound limits accidental browser-process and memory growth. Simple scenes target real-time preview, but there is no production rendering-speed guarantee; the CLI reports progress, current frame, and elapsed time.
123
+ The renderer uses a bounded segment plan, a worker pool, and a scratch budget. It never publishes a partial MP4, and it cleans scratch on success and failure. Segment boundaries preserve timeline frame order and timing; the final audio mix is muxed once.
124
+
125
+ `check` and `still` use the same clip capture and timeline composite path for a requested frame. `check` evaluates every timeline frame; on long timelines this is a validation cost, not a render. `still` captures one frame as PNG without encoding a video.
93
126
 
94
127
  ## 5. Audio and output
95
128
 
96
- Audio is a declarative timeline of `<audio>` elements. Each element uses `data-fy-start` (composition frame), `data-fy-trim` (seconds from the source start), optional `data-fy-duration` (seconds to use), and `data-fy-volume` (0-1). Preview synchronizes this timeline in the browser; production mixes it offline with FFmpeg rather than treating live `<audio>` or Web Audio playback as the production source of truth. Unmuted embedded videos contribute their own audio tracks to the same mix, placed by the video's frame and trim attributes. Muting a video or setting `data-fy-audio="off"` keeps it visual-only.
129
+ A timeline has one audio mix. It combines:
130
+
131
+ - composition audio clips declared inside composition clips, shifted and trimmed by the clip's source range;
132
+ - embedded video audio from composition clips and media video clips, unless muted;
133
+ - timeline audio clips on audio tracks;
134
+ - audio from nested timeline clips, recursively.
135
+
136
+ Per-clip gain and mute, per-audio-track gain and mute, and composition-level volume apply. Audio fades are deferred. The mix is produced once with FFmpeg and muxed into the final MP4. Preview mixes the same resolved clips in the browser for monitoring; it is not the production source of truth.
97
137
 
98
- Audio, video, and transcript `src` values resolve from the project root. The controller `src` and ordinary HTML asset URLs (`img`, stylesheets) resolve relative to the composition document.
138
+ Audio, video, and transcript `src` values resolve from the project root. The controller `src` and ordinary HTML asset URLs resolve relative to the composition document.
99
139
 
100
- Generated speech behaves like any other audio clip. Frameyard does not automatically time-stretch it, change composition duration, or regenerate it to fit. `check` reports clip durations and overrun warnings so users and agents can revise text, timing, or composition deliberately.
140
+ Generated speech behaves like any other audio clip. Frameyard does not automatically time-stretch it, change timeline duration, or regenerate it to fit. `check` reports clip durations and overrun warnings so users and agents can revise text, timing, or the timeline deliberately.
101
141
 
102
- 0.4 produces portable MP4 files with H.264 video and AAC audio. It exposes only a small set of validated encoding options, not arbitrary FFmpeg arguments. Single-frame PNG output through `still` is a debugging artifact, not general image-sequence support.
142
+ 0.6 produces portable MP4 files with H.264 video and AAC audio. It exposes only a small set of validated encoding options, not arbitrary FFmpeg arguments. Single-frame PNG output through `still` is a debugging artifact, not general image-sequence support.
103
143
 
104
- A render fails immediately on an uncaught exception, unhandled rejection, required-asset failure, or invalid composition output. Diagnostics identify the composition and, where applicable, the frame. The CLI exits nonzero, cleans temporary files, and never reports a partial video as successful. Existing output files are not overwritten unless explicitly requested.
144
+ A render fails immediately on an uncaught exception, unhandled rejection, required-asset failure, invalid composition output, segment encoding failure, or scratch failure. Diagnostics identify the timeline, clip, segment, and, where applicable, the frame. The CLI exits nonzero, cleans temporary files, and never reports a partial video as successful. Existing output files are not overwritten unless explicitly requested.
105
145
 
106
146
  ## 6. CLI, tooling, and package boundaries
107
147
 
108
148
  Project and composition commands are:
109
149
 
110
- - `init`: scaffold a minimal HTML composition project, including an agent guide (`AGENTS.md`), a `.gitignore` for `out/`, and a private `package.json` with pinned `dev`, `check`, `render`, and `still` scripts
111
- - `dev`: start the preview
112
- - `render <composition-id> [--out video.mp4]`: render a composition, optionally with `--concurrency <n>` from 1 to 16; the default output is `out/<composition-id>.mp4` in the project root
113
- - `check <composition-id>`: run static composition validation, then validate configuration, props, assets, audio, and transcript requirements, load the composition, and evaluate every frame without capturing or encoding
114
- - `still <composition-id> --frame <n>`: capture one requested frame as PNG through the production rendering path
115
- - `doctor`: inspect core requirements and optional integrations without repairing or downloading anything
150
+ - `init`: scaffold a timeline-first project with a composition, a one-clip timeline, a project format, an agent guide, a `.gitignore` for `out/`, and a private `package.json` with pinned `dev`, `check`, `render`, and `still` scripts.
151
+ - `dev`: start the preview with composition and timeline modes.
152
+ - `render <id> [--out video.mp4]`: render a timeline or a composition. Timeline renders accept `--workers <n>` and `--scratch <dir>`; composition renders accept `--concurrency <n>` from 1 to 16. The default output is `out/<id>.mp4`.
153
+ - `check <id>`: run static validation, then validate configuration, props, assets, media, audio, and transcript requirements, load the target, and evaluate every frame without capturing or encoding.
154
+ - `still <id> --frame <n>`: capture one requested frame as PNG through the clip capture and timeline composite path.
155
+ - `doctor`: inspect core requirements and optional integrations without repairing or downloading anything.
116
156
 
117
- `check`, `still`, and `render` run a Node-side static composition validation before launching Chromium. It validates metadata, the composition root, the controller declaration, default props, binding attributes and paths, animation attributes, scripts and event handlers, unsupported visual elements, and audio/transcript references. Static validation and the composition host read the composition grammar through one browser-safe composition document reader with parse5 and DOM adapters; the reader returns fixed facts and per-kind declarations, while the validator adds source locations, filesystem checks, and transcript parsing. Controller `src` is project-relative in composition source info and results; the authoring value is retained as `rawSrc` for the host import. Diagnostics carry stable codes and optional source locations; `check` exits nonzero on static errors without starting a browser. `dev` runs the same validation on load and surfaces its diagnostics in the preview.
157
+ `check`, `still`, and `render` run a Node-side static validation before launching Chromium. For a timeline it validates the JSON document, tracks, clips, references, nested timelines, cycles, frame-rate compatibility, overlaps, source bounds, media, transforms, audio settings, props, and every referenced composition. Static validation and the composition host read the composition grammar through one browser-safe document reader. Timeline diagnostics carry stable codes and optional source locations or JSON paths, and composition diagnostics from inside a timeline carry the clip and track context.
118
158
 
119
159
  Local asset-production commands are `tts` and `transcribe`. Every non-interactive command supports `--json` with stable result and error schemas. Structured results go to stdout; human diagnostics and inference progress go to stderr.
120
160
 
121
- The built-in server serves native ES modules and static assets, injects an import map and composition host into composition entries, and serves an inline controller through a virtual module URL under the composition's directory. It performs no dependency pre-bundling. Third-party libraries must initially be browser-ready ES modules referenced explicitly. Running through the CLI server is required; direct `file://` execution is unsupported for deterministic preview or rendering. A composition document can still be opened directly as static HTML/CSS.
161
+ The built-in server serves native ES modules, static assets, composition entries, timeline documents, and the timeline preview host. It injects an import map and composition host into composition entries and an inline controller through a virtual module URL. It performs no dependency pre-bundling. Third-party libraries must initially be browser-ready ES modules referenced explicitly. Running through the CLI server is required; direct `file://` execution is unsupported for deterministic preview or rendering.
122
162
 
123
- Frameyard uses one repository and one publishable npm package with three internal layers:
163
+ Frameyard uses one repository and one publishable npm package with four internal layers:
124
164
 
125
- 1. Shared composition contracts and HTML binding/metadata parsing
126
- 2. Browser host runtime
127
- 3. Node-based CLI and renderer
165
+ 1. Shared composition and timeline contracts and HTML/JSON parsing
166
+ 2. Browser composition host and timeline preview host
167
+ 3. Node-based static validation and segmented timeline renderer
168
+ 4. Node-based CLI, asset production, and doctor
128
169
 
129
- These layers have clean internal boundaries but no public plugin API. FFmpeg is discovered on the user's PATH and checked for required capabilities, with actionable installation and version diagnostics. The project supports the current active Node.js LTS; Linux is the reference and CI platform, while macOS and Windows remain best-effort until covered by real rendering tests.
170
+ These layers have clean internal boundaries but no public plugin API. FFmpeg is required for encoding, probing, media decoding, audio mixing, and timeline compositing. Skia is not required in 0.6. The project supports the current active Node.js LTS; Linux is the reference and CI platform, while macOS and Windows remain best-effort until covered by real rendering tests.
130
171
 
131
172
  ## 7. Official agent skill
132
173
 
133
- Frameyard ships an optional, host-neutral agent skill with a `SKILL.md`, supporting references, and thin scripts. The npm package includes skill files matching its API version, and documentation explains host-specific installation or referencing. 0.4 does not add a skill-installer command.
174
+ Frameyard ships an optional, host-neutral agent skill with a `SKILL.md`, supporting references, and thin scripts. The npm package includes skill files matching its API version, and documentation explains host-specific installation or referencing. 0.6 does not add a skill-installer command.
134
175
 
135
176
  The skill:
136
177
 
137
- - Uses the normal project format, HTML composition contract, optional controller, and CLI available to humans.
178
+ - Uses the normal project format, HTML composition contract, JSON timeline contract, optional controller, and CLI available to humans.
138
179
  - Does not introduce an agent-only runtime, MCP server, hosted control plane, or separate rendering API.
139
180
  - Triggers for Frameyard authoring and operation rather than claiming to be a general-purpose media-generation skill.
140
181
  - Uses Frameyard's audio wrappers instead of invoking `qwen-tts` or `whisper-cli` directly.
141
- - Includes references for deterministic HTML authoring, bindings, animation scheduling, controller rules, static validation, structured diagnostics, common authoring mistakes, audio assets, subtitle and karaoke recipes, JSON command results, and failure recovery.
182
+ - Includes references for deterministic HTML authoring, timeline JSON authoring, tracks, clips, source ranges, props, media, nested timelines, static transforms, audio, validation, diagnostics, common mistakes, subtitle and karaoke recipes, JSON command results, long-form worker/scratch settings, and failure recovery.
142
183
  - Invokes speech synthesis or transcription only when requested or explicitly approved as part of the brief.
143
184
  - Does not overwrite or regenerate existing generated assets without permission.
144
185
  - Runs `check`, inspects representative `still` images when the host supports image viewing, and discloses when visual inspection was impossible.
145
186
  - Does not claim success when checks fail or rendering is partial.
146
187
 
147
- A successful agent workflow preserves and reports the source project, props, generated assets, provenance manifest, validation results, and final video path. The user must be able to inspect, modify, and reproduce the result rather than receiving only an opaque MP4.
188
+ A successful agent workflow preserves and reports the source project, timeline document, props, generated assets, provenance manifest, validation results, and final video path. The user must be able to inspect, modify, and reproduce the result rather than receiving only an opaque MP4.
148
189
 
149
190
  ## 8. Local speech synthesis
150
191
 
151
192
  The `tts` command integrates [`qwentts.cpp`](https://github.com/ServeurpersoCom/qwentts.cpp) through its external `qwen-tts` executable. It does not link the native library or require the upstream server.
152
193
 
153
- 0.4 supports CustomVoice mode only:
194
+ 0.6 supports CustomVoice mode only:
154
195
 
155
196
  - A named speaker is required.
156
197
  - An optional style instruction and language may be supplied.
@@ -176,7 +217,7 @@ The canonical artifact is a versioned Frameyard JSON document containing:
176
217
  - Timed segments
177
218
  - Optional word timings
178
219
 
179
- All timestamps are integer milliseconds relative to the source audio, not composition frame numbers. The controller converts them using the audio clip's start frame, source trim, and composition frame rate.
220
+ All timestamps are integer milliseconds relative to the source audio, not timeline or composition frame numbers. A controller converts them using the audio clip's start frame, source trim, and the composition frame rate.
180
221
 
181
222
  Compositions declare required transcript assets with `<fy-transcript>` elements:
182
223
 
@@ -188,11 +229,11 @@ Compositions declare required transcript assets with `<fy-transcript>` elements:
188
229
 
189
230
  SRT and VTT are derived exports, not the canonical contract. Word-level karaoke requires actual word timings and fails validation when they are unavailable. Frameyard never fabricates word timings by interpolating segment timestamps and never executes Whisper's generated bash/FFmpeg karaoke script.
190
231
 
191
- The official skill documents seek-safe subtitle and karaoke recipes. Compositions retain responsibility for visual presentation; 0.4 has no built-in subtitle renderer and does not automatically burn captions into videos. Karaoke presentation uses the optional controller.
232
+ The official skill documents seek-safe subtitle and karaoke recipes. Compositions retain responsibility for visual presentation; 0.6 has no built-in subtitle renderer and does not automatically burn captions into videos. Karaoke presentation uses the optional controller.
192
233
 
193
234
  ## 10. Generated assets and inference operation
194
235
 
195
- Speech synthesis and transcription are separate asset-production operations that complete before composition loading and rendering. Their outputs are ordinary local project assets. Once those assets are frozen, ordinary authoring, preview, checking, and rendering require neither AI executable nor model.
236
+ Speech synthesis and transcription are separate asset-production operations that complete before a timeline or composition is loaded or rendered. Their outputs are ordinary local project assets. Once those assets are frozen, ordinary authoring, preview, checking, and rendering require neither AI executable nor model.
196
237
 
197
238
  Both integrations are optional and local-only, with no cloud fallback. Network activity needed to acquire tools or models is a separate explicit setup operation, never a hidden side effect of generation or rendering.
198
239
 
@@ -215,19 +256,21 @@ Tests prioritize public behavior and end-to-end evidence over implementation-onl
215
256
 
216
257
  - HTML compositions validate metadata, default props, bindings, conditionals, repeats, and controller declarations, including inline/external parity and the exactly-one-controller rule.
217
258
  - Static composition validation catches metadata, root/controller count, binding, animation, script, element, and asset-reference errors before Chromium.
218
- - Diagnostics carry stable codes and source locations; JSON results expose the composition entry, controller declaration, and top-level diagnostics.
219
- - Sequential, individual, random-order, and parallel frame renders produce equivalent images.
220
- - Determinism checks compare captured pixels or stills; encoded MP4 bytes are not a reproducibility oracle.
221
- - Preview and renderer use the same composition document and host runtime.
222
- - CSS, controller JavaScript, SVG, and Canvas animations seek correctly.
259
+ - Timeline JSON validation catches schema, track, clip, reference, cycle, frame-rate, overlap, bounds, media, transform, audio, and props errors before Chromium.
260
+ - Diagnostics carry stable codes and source locations or JSON paths; JSON results expose the composition or timeline entry, clips, tracks, and top-level diagnostics.
261
+ - Sequential, individual, random-order, and parallel composition renders produce equivalent images; timeline segment workers produce ordered output and identical captured composition frames.
262
+ - Determinism checks compare captured composition pixels or stills. The final H.264 bytes and the FFmpeg composite versus Chromium preview are not reproducibility oracles.
263
+ - Preview and renderer use the same composition document and host behavior; timeline preview uses the same active clip hosts.
264
+ - CSS, controller JavaScript, SVG, Canvas, WebGL, embedded video, and audio frames seek correctly.
223
265
  - Frame-scheduled `data-fy-anim-*` animations and frame-state CSS variables produce the expected frames.
224
- - Embedded video and audio frames seek deterministically, including under parallel capture, and their audio appears in the offline mix.
225
- - WebGL canvases produce deterministic stills and rendered frames under the pinned software renderer.
226
- - Executable scripts other than the inline or external controller, inline event handlers, `javascript:` URLs, and unsupported visual elements are rejected.
227
- - Asset and runtime failures produce nonzero CLI exits.
228
- - Rendered MP4 files have the expected dimensions, frame count, duration, and audio stream.
229
- - Golden-frame tests cover representative visual behavior.
230
- - `check` exercises every frame, and `still` follows the production capture path.
266
+ - Timeline capture preserves alpha for transparent compositions; FFV1 intermediates decode pixel-identically to the captured frames.
267
+ - Timeline segment encoding, ordered concatenation, global audio mix, and scratch cleanup produce the expected MP4 dimensions, frame count, duration, and audio stream.
268
+ - Nested timelines preserve group opacity and transform semantics; cycles fail static validation.
269
+ - Media clips trim and fit deterministically; images require durations; source overruns fail.
270
+ - Props overrides for timeline composition clips merge over clip props and are reflected in the render.
271
+ - `check` exercises every frame; `still` follows the clip capture and timeline composite path.
272
+ - The 10-second and 60-second long-form benchmarks record capture, FFV1, composite, encode, disk, worker, and audio numbers. Continuous three-layer runs measured 52.4 s and 58.5 s for 60 s of timeline and are documented as worst-case (~1× real time). The representative 50/50, 60/30/10 occupancy gate measured 29.39 s for 60 s with four workers and a 1080p media fast path, extrapolating to about 29.4 minutes for 60 minutes with exact 1800-frame output. The full 60-minute composition-only gate rendered 108,000 frames in 35.35 minutes with exact output and clean scratch, documenting composition-heavy performance above 30 minutes.
273
+ - Golden-frame tests cover representative composition and timeline visual behavior.
231
274
  - Normal CI uses fake `qwen-tts` and `whisper-cli` executables and small fixtures to verify arguments, artifacts, manifests, cancellation, and errors without model downloads or GPU hardware.
232
275
  - Real-model integration tests are explicitly opt-in and use documented upstream revisions.
233
276
  - Agent-workflow evaluations verify source preservation, provenance, validation, still inspection behavior, failure reporting, and final renders.
@@ -236,7 +279,14 @@ Tests prioritize public behavior and end-to-end evidence over implementation-onl
236
279
 
237
280
  These are scope boundaries, not permanent rejections:
238
281
 
239
- - Visual editing, hosted rendering, collaboration, and asset marketplaces
282
+ - Transitions, effects, keyframes, blend modes, masks, and audio fades
283
+ - Full visual timeline editing, drag-and-drop, clip handles, and undo/redo
284
+ - Timeline-level variables and prop overrides for compositions inside nested timelines
285
+ - Track solo and video-track visibility
286
+ - Per-timeline formats and frame-rate conversion/retiming
287
+ - Persistent clip caches; the segmented renderer cleans its intermediates
288
+ - Hardware encoders, GPU compositing, and non-H.264 output
289
+ - Hosted rendering, collaboration, and asset marketplaces
240
290
  - Cloud generative-AI services, text-to-video generation, and image generation
241
291
  - `qwentts.cpp` reference-audio voice cloning and VoiceDesign
242
292
  - Automatic long-text chunking, streaming speech synthesis, and alternative generated-audio formats
@@ -248,17 +298,16 @@ These are scope boundaries, not permanent rejections:
248
298
  - Agent-only runtimes, MCP servers, hosted agent control planes, and host-specific skill installers
249
299
  - React or other UI-framework adapters in the core
250
300
  - Public plugin APIs and a broad integration ecosystem
251
- - Dynamic composition metadata derived from props
301
+ - Dynamic composition or timeline metadata derived from props
252
302
  - Live streams, remote media, and other visual sources that cannot be deterministically seeked
253
303
  - Dynamic per-frame asset loading or AI inference
254
- - Frame caches
255
304
  - Batch still capture; agents can run `still` once per representative frame
256
305
  - Additional final-video formats, general image-sequence output, and arbitrary FFmpeg argument passthrough
257
306
  - Built-in TypeScript transpilation and npm dependency optimization
258
307
  - Rendering untrusted compositions
259
308
  - Bit-identical cross-platform encoded output or AI regeneration
260
- - A minimum production rendering-speed guarantee
309
+ - A minimum production rendering-speed guarantee for compositions or timelines
261
310
 
262
311
  ## 13. Release posture
263
312
 
264
- Frameyard is MIT-licensed. Initial releases use `0.x` versioning, and composition, configuration, CLI, JSON-result, transcript, and skill-contract changes are documented explicitly until those contracts stabilize. 0.4.0 is a breaking authoring-model release: HTML documents replace JavaScript composition modules, and the `fy` namespace replaces `data-frameyard-*` authoring attributes. See [ADR 0007](./adr/0007-make-html-documents-the-composition-unit.md) and the [0.4 migration guide](./migration-0.4.md).
313
+ Frameyard is MIT-licensed. Initial releases use `0.x` versioning, and composition, timeline, configuration, CLI, JSON-result, transcript, and skill-contract changes are documented explicitly until those contracts stabilize. 0.6.0 adds timelines, project formats, segmented timeline rendering, and a timeline-first scaffold without breaking the existing HTML composition authoring contract. See [ADR 0010](./adr/0010-make-timelines-the-render-unit.md), [ADR 0011](./adr/0011-compose-timeline-frames-in-a-live-browser-host.md), and [ADR 0012](./adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md).
@@ -10,14 +10,21 @@ A 30-second, 1920×1080 HTML composition that exercises the current core:
10
10
  - frame-state CSS variables for the progress bar
11
11
 
12
12
  The composition lives in `compositions/demo.html`; the optional controller is
13
- `compositions/demo.controller.js`.
13
+ `compositions/demo.controller.js`. `timelines/demo.timeline.json` wraps the
14
+ composition as a clip in a 1920×1080, 30 fps timeline.
14
15
 
15
16
  From the repository root:
16
17
 
17
18
  ```sh
18
19
  pnpm build
19
- node dist/cli.js check demo --project examples/demo
20
- node dist/cli.js still demo --frame 240 --project examples/demo --out demo-still.png
20
+ node dist/cli.js check demo-timeline --project examples/demo
21
+ node dist/cli.js still demo-timeline --frame 240 --project examples/demo --out demo-still.png
22
+ node dist/cli.js render demo-timeline --project examples/demo --props examples/demo/props/demo.json
23
+ ```
24
+
25
+ The composition remains renderable on its own:
26
+
27
+ ```sh
21
28
  node dist/cli.js render demo --project examples/demo --props examples/demo/props/demo.json
22
29
  ```
23
30
 
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 1,
3
+ "tracks": [{ "id": "v1", "kind": "video" }],
4
+ "clips": [
5
+ {
6
+ "id": "demo",
7
+ "track": "v1",
8
+ "source": { "kind": "composition", "id": "demo" },
9
+ "start": 0
10
+ }
11
+ ]
12
+ }
@@ -1,5 +1,9 @@
1
1
  export default {
2
+ format: { width: 1920, height: 1080, fps: 30 },
2
3
  compositions: {
3
4
  demo: "./compositions/demo.html",
4
5
  },
6
+ timelines: {
7
+ "demo-timeline": "./timelines/demo.timeline.json",
8
+ },
5
9
  };
@@ -1,7 +1,7 @@
1
1
  # Frameyard video example
2
2
 
3
- A 12-second, 1920×1080 composition that treats a local clip as source footage
4
- and seeks it twice. The project includes the same layout for two source codecs:
3
+ A 12-second, 1920×1080 project that treats a local clip as source footage. The
4
+ project includes the same layout for two source codecs:
5
5
 
6
6
  - `video` reads `assets/clip.webm` (VP9 + Opus)
7
7
  - `video-mp4` reads `assets/clip.mp4` (H.264 + AAC)
@@ -25,11 +25,49 @@ controller is needed. The header, copy, and footer fade individually rather
25
25
  than the whole scene; a full-scene opacity animation above a video can leave
26
26
  the load frame on screen in interactive preview after a large seek.
27
27
 
28
+ ## Timeline with the video on a track
29
+
30
+ `video-timeline` and `video-timeline-mp4` move the footage out of the
31
+ composition and onto timeline tracks. The HTML is now a transparent overlay
32
+ above it:
33
+
34
+ - `v1` holds the hero clip: the whole 12-second source, audio at `0.85`
35
+ - `v2` holds the detail pass from source frame 174 (5.8 s) for 150 frames,
36
+ muted, placed in a 440×248 transform box in the bottom right
37
+ - `v3` holds `video-overlay`, an HTML-only composition with no `<video>`
38
+ elements and a transparent document background
39
+
40
+ `video-timeline` reads `assets/clip.webm` (VP9 + Opus) and
41
+ `video-timeline-mp4` reads `assets/clip.mp4` (H.264 + AAC). Both share the same
42
+ overlay composition and props file; the overlay clip sets its own `format` prop
43
+ so the header reports the codec of each timeline.
44
+
45
+ The detail clip uses `transform.width` and `transform.height` instead of
46
+ `scale`, with `fit: "cover"` filling that box. The box matches the overlay's
47
+ detail window exactly, so the video and its chrome stay aligned in production
48
+ and preview.
49
+
50
+ The overlay draws the scrim, typography, frame border, detail-window chrome,
51
+ progress bar, and outro fade. `video-overlay` declares its own frame animations,
52
+ so the title and footer still animate on the timeline clock. Production captures
53
+ the overlay with alpha and composites it over the video layers with FFmpeg; the
54
+ interactive timeline preview composites the same layers in Chromium.
55
+
56
+ Both timelines accept `props/video-timeline.json`, which overrides the overlay
57
+ composition's props. Timeline `--props` is keyed by composition clip id, so the
58
+ file targets the `overlay` clip.
59
+
60
+ Open the preview with `node dist/cli.js dev --project examples/video`; the
61
+ compositions and both timelines are listed.
62
+
28
63
  The compositions live in `compositions/video.html` and
29
- `compositions/video-mp4.html`. Both clips are 12-second 1280×720 files generated
30
- procedurally for this example; the MP4 is transcoded from the WebM source.
31
- Replace either asset with a local, seekable video file that is at least
32
- 12 seconds long; remote URLs and live streams are not supported.
64
+ `compositions/video-mp4.html`; the overlay lives in
65
+ `compositions/video-overlay.html`, and the timelines in
66
+ `timelines/video-timeline.timeline.json` and
67
+ `timelines/video-timeline-mp4.timeline.json`. Both clips are 12-second 1280×720
68
+ files generated procedurally for this example; the MP4 is transcoded from the
69
+ WebM source. Replace either asset with a local, seekable video file that is at
70
+ least 12 seconds long; remote URLs and live streams are not supported.
33
71
 
34
72
  Regenerate both clips from scratch with the bundled FFmpeg script:
35
73
 
@@ -48,10 +86,16 @@ From the repository root:
48
86
  pnpm build
49
87
  node dist/cli.js check video --project examples/video
50
88
  node dist/cli.js check video-mp4 --project examples/video
89
+ node dist/cli.js check video-timeline --project examples/video
90
+ node dist/cli.js check video-timeline-mp4 --project examples/video
51
91
  node dist/cli.js still video --frame 210 --project examples/video --out video-still.png
52
92
  node dist/cli.js still video-mp4 --frame 210 --project examples/video --out video-mp4-still.png
93
+ node dist/cli.js still video-timeline --frame 210 --project examples/video --out video-timeline-still.png
94
+ node dist/cli.js still video-timeline-mp4 --frame 210 --project examples/video --out video-timeline-mp4-still.png
53
95
  node dist/cli.js render video --project examples/video --props examples/video/props/video.json
54
96
  node dist/cli.js render video-mp4 --project examples/video --props examples/video/props/video.json
97
+ node dist/cli.js render video-timeline --project examples/video --props examples/video/props/video-timeline.json
98
+ node dist/cli.js render video-timeline-mp4 --project examples/video --props examples/video/props/video-timeline.json
55
99
  ```
56
100
 
57
101
  Start the interactive preview with: