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.
- package/CHANGELOG.md +55 -0
- package/GLOSSARY.md +152 -24
- package/README.md +94 -29
- package/dist/cli.js +111 -14
- package/dist/cli.js.map +1 -1
- package/dist/contracts.d.ts +12 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/preview/main.js +89 -11
- package/dist/preview/main.js.map +1 -1
- package/dist/preview/timeline-data.d.ts +85 -0
- package/dist/preview/timeline-data.d.ts.map +1 -0
- package/dist/preview/timeline-data.js +2 -0
- package/dist/preview/timeline-data.js.map +1 -0
- package/dist/preview/timeline-host.d.ts +19 -0
- package/dist/preview/timeline-host.d.ts.map +1 -0
- package/dist/preview/timeline-host.js +297 -0
- package/dist/preview/timeline-host.js.map +1 -0
- package/dist/preview/timeline-main.d.ts +17 -0
- package/dist/preview/timeline-main.d.ts.map +1 -0
- package/dist/preview/timeline-main.js +364 -0
- package/dist/preview/timeline-main.js.map +1 -0
- package/dist/project.d.ts +16 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +81 -26
- package/dist/project.js.map +1 -1
- package/dist/renderer/browser.d.ts +2 -0
- package/dist/renderer/browser.d.ts.map +1 -1
- package/dist/renderer/browser.js +6 -1
- package/dist/renderer/browser.js.map +1 -1
- package/dist/renderer/ffmpeg.d.ts +61 -0
- package/dist/renderer/ffmpeg.d.ts.map +1 -1
- package/dist/renderer/ffmpeg.js +198 -0
- package/dist/renderer/ffmpeg.js.map +1 -1
- package/dist/renderer/timeline.d.ts +109 -0
- package/dist/renderer/timeline.d.ts.map +1 -0
- package/dist/renderer/timeline.js +984 -0
- package/dist/renderer/timeline.js.map +1 -0
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +89 -24
- package/dist/scaffold.js.map +1 -1
- package/dist/server/preview-html.d.ts.map +1 -1
- package/dist/server/preview-html.js +15 -1
- package/dist/server/preview-html.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +39 -1
- package/dist/server/server.js.map +1 -1
- package/dist/server/timeline-preview-data.d.ts +4 -0
- package/dist/server/timeline-preview-data.d.ts.map +1 -0
- package/dist/server/timeline-preview-data.js +97 -0
- package/dist/server/timeline-preview-data.js.map +1 -0
- package/dist/server/timeline-preview-html.d.ts +4 -0
- package/dist/server/timeline-preview-html.d.ts.map +1 -0
- package/dist/server/timeline-preview-html.js +227 -0
- package/dist/server/timeline-preview-html.js.map +1 -0
- package/dist/timeline/plan.d.ts +32 -0
- package/dist/timeline/plan.d.ts.map +1 -0
- package/dist/timeline/plan.js +68 -0
- package/dist/timeline/plan.js.map +1 -0
- package/dist/timeline/resolve.d.ts +60 -0
- package/dist/timeline/resolve.d.ts.map +1 -0
- package/dist/timeline/resolve.js +523 -0
- package/dist/timeline/resolve.js.map +1 -0
- package/dist/timeline/schema.d.ts +71 -0
- package/dist/timeline/schema.d.ts.map +1 -0
- package/dist/timeline/schema.js +425 -0
- package/dist/timeline/schema.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/adr/0002-make-frame-and-props-the-only-animation-state.md +2 -0
- package/docs/adr/0005-keep-parallel-rendering-opt-in-and-frame-ordered.md +2 -0
- package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
- package/docs/adr/0009-composite-production-frames-in-software.md +1 -1
- package/docs/adr/0010-make-timelines-the-render-unit.md +24 -0
- package/docs/adr/0011-compose-timeline-frames-in-a-live-browser-host.md +22 -0
- package/docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md +31 -0
- package/docs/v0.1-design.md +135 -86
- package/examples/demo/README.md +10 -3
- package/examples/demo/timelines/demo.timeline.json +12 -0
- package/examples/demo/video.config.js +4 -0
- package/examples/video/README.md +50 -6
- package/examples/video/compositions/video-overlay.html +350 -0
- package/examples/video/props/video-timeline.json +10 -0
- package/examples/video/timelines/video-timeline-mp4.timeline.json +44 -0
- package/examples/video/timelines/video-timeline.timeline.json +44 -0
- package/examples/video/video.config.js +6 -0
- package/package.json +1 -1
- package/skills/frameyard/SKILL.md +17 -13
- package/skills/frameyard/references/timelines.md +141 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Timelines
|
|
2
|
+
|
|
3
|
+
A timeline is a project-local JSON document that assembles composition and media clips on tracks and renders as one video. Compositions remain reusable HTML sources; a composition clip is one placement of a composition with its own source range and props.
|
|
4
|
+
|
|
5
|
+
## Project configuration
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
export default {
|
|
9
|
+
format: { width: 1920, height: 1080, fps: 30 },
|
|
10
|
+
compositions: {
|
|
11
|
+
intro: "./compositions/intro.html",
|
|
12
|
+
},
|
|
13
|
+
timelines: {
|
|
14
|
+
main: "./timelines/main.timeline.json",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- `format` fixes width, height, and fps for every timeline. It is required when the project lists timelines.
|
|
20
|
+
- Composition and timeline IDs share one namespace and must be unique.
|
|
21
|
+
- A composition used in a timeline must match the project fps exactly. A different size is fitted by the clip.
|
|
22
|
+
- Composition-only projects remain valid without `format` or `timelines`.
|
|
23
|
+
|
|
24
|
+
## Timeline document
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"version": 1,
|
|
29
|
+
"name": "Main edit",
|
|
30
|
+
"tracks": [
|
|
31
|
+
{ "id": "v1", "kind": "video" },
|
|
32
|
+
{ "id": "v2", "kind": "video" },
|
|
33
|
+
{ "id": "a1", "kind": "audio", "gain": 1, "muted": false }
|
|
34
|
+
],
|
|
35
|
+
"clips": [
|
|
36
|
+
{
|
|
37
|
+
"id": "intro",
|
|
38
|
+
"track": "v1",
|
|
39
|
+
"source": { "kind": "composition", "id": "intro" },
|
|
40
|
+
"start": 0,
|
|
41
|
+
"duration": 150,
|
|
42
|
+
"sourceIn": 0,
|
|
43
|
+
"props": { "title": "Hello" },
|
|
44
|
+
"transform": { "fit": "contain", "x": 0, "y": 0, "scale": 1, "rotation": 0, "opacity": 1 },
|
|
45
|
+
"audio": { "muted": false, "gain": 1 }
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "logo",
|
|
49
|
+
"track": "v2",
|
|
50
|
+
"source": { "kind": "image", "src": "assets/logo.png" },
|
|
51
|
+
"start": 30,
|
|
52
|
+
"duration": 60,
|
|
53
|
+
"transform": { "fit": "contain", "width": 480, "height": 270, "x": 640, "y": -320, "rotation": 0, "opacity": 0.9 }
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "music",
|
|
57
|
+
"track": "a1",
|
|
58
|
+
"source": { "kind": "audio", "src": "assets/music.wav" },
|
|
59
|
+
"start": 0,
|
|
60
|
+
"duration": 210,
|
|
61
|
+
"audio": { "gain": 0.5 }
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- `version` is `1`.
|
|
68
|
+
- `tracks` and `clips` are required. Track order is bottom-to-top for video and irrelevant for audio.
|
|
69
|
+
- `background` is an optional color; the final video composites over black.
|
|
70
|
+
- `durationInFrames` is optional. The duration is derived from the latest clip end unless declared; a declared duration may extend but not cut clips.
|
|
71
|
+
- Unknown fields are errors. No transitions, effects, keyframes, or track solo/visibility in 0.6.
|
|
72
|
+
|
|
73
|
+
## Sources
|
|
74
|
+
|
|
75
|
+
| `source.kind` | Fields | Notes |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `composition` | `id` | Project composition ID. The clip may set `props`. |
|
|
78
|
+
| `timeline` | `id` | Nested timeline ID. Rendered as a group. |
|
|
79
|
+
| `video` | `src` | Local MP4/WebM, project-relative. |
|
|
80
|
+
| `image` | `src` | Local PNG/JPEG/WebP. `duration` is required. |
|
|
81
|
+
| `audio` | `src` | Local WAV/MP3/M4A/AAC or a video file used only for audio. |
|
|
82
|
+
|
|
83
|
+
Media paths resolve from the project root. No remote URLs.
|
|
84
|
+
|
|
85
|
+
## Time and trims
|
|
86
|
+
|
|
87
|
+
- `start` is the timeline frame where the clip begins.
|
|
88
|
+
- `sourceIn` is the first source frame. It defaults to `0` and must be `0` for images.
|
|
89
|
+
- `duration` is the number of timeline frames. It is optional for compositions, nested timelines, video, and audio; it defaults to the rest of the source. Images require it.
|
|
90
|
+
- A clip that exceeds its source is an error.
|
|
91
|
+
- Clips on one track cannot overlap. Touching endpoints are allowed. Use separate tracks for overlays.
|
|
92
|
+
|
|
93
|
+
## Presentation
|
|
94
|
+
|
|
95
|
+
Visual clips accept a static transform:
|
|
96
|
+
|
|
97
|
+
- `fit`: `contain`, `cover`, or `stretch`.
|
|
98
|
+
- `width`, `height`: optional clip box in output pixels. Both are required together and cannot be combined with `scale`. `fit` applies inside the box, and `x`/`y` offset the box center. Without them, the project frame is the box.
|
|
99
|
+
- `x`, `y`: pixel offsets from the centered fitted result.
|
|
100
|
+
- `scale`: multiplier after fitting to the project frame; an alternative to `width`/`height`.
|
|
101
|
+
- `rotation`: degrees around the center.
|
|
102
|
+
- `opacity`: 0–1.
|
|
103
|
+
|
|
104
|
+
No keyframes or animated transforms in 0.6.
|
|
105
|
+
|
|
106
|
+
## Audio
|
|
107
|
+
|
|
108
|
+
- Composition, video, and nested-timeline clips contribute audio automatically unless `audio.muted` is true.
|
|
109
|
+
- Timeline audio clips live on audio tracks. Audio tracks support `gain` and `muted`.
|
|
110
|
+
- `audio.gain` on a clip is 0–1 and multiplies the source audio.
|
|
111
|
+
- There are no linked A/V pairs. For a J/L cut, mute the visual clip and add an audio clip with a different `sourceIn`.
|
|
112
|
+
- Audio is mixed once for the whole timeline and muxed into the final MP4.
|
|
113
|
+
|
|
114
|
+
## Nested timelines
|
|
115
|
+
|
|
116
|
+
A nested timeline clip behaves as one layer: its internal tracks are composited first, then the parent clip's opacity and transform apply to the whole group. Nested audio is included. Cycles are rejected statically. Timeline clips do not override props of compositions inside a nested timeline in 0.6.
|
|
117
|
+
|
|
118
|
+
## Commands
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
npx frameyard check main --json
|
|
122
|
+
npx frameyard still main --frame 42 --out main-42.png --json
|
|
123
|
+
npx frameyard render main --props props/main.json --workers 8 --scratch /path/to/scratch --json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- `--props` on a timeline is a JSON object keyed by top-level composition clip ID; values merge over the clip's `props`.
|
|
127
|
+
- `--workers` is 1–16. The default is 8.
|
|
128
|
+
- `--scratch` selects the FFV1 intermediate directory. Use a disk with enough space; intermediates are cleaned after the render.
|
|
129
|
+
- `--concurrency` is composition-only.
|
|
130
|
+
- `render` defaults to `out/<timeline-id>.mp4`.
|
|
131
|
+
- `check` evaluates every timeline frame and composition frame. `still` captures one frame through the same clip capture and composite path.
|
|
132
|
+
- `npx frameyard dev` lists timelines in the preview; the timeline view has a program monitor, read-only tracks and clips, playhead, playback, audio controls, and diagnostics.
|
|
133
|
+
|
|
134
|
+
## Determinism and performance
|
|
135
|
+
|
|
136
|
+
- A timeline frame derives only from its active clips, their composition frames, props, assets, and the render plan.
|
|
137
|
+
- Composition frames are captured with Chromium; transparent compositions preserve alpha.
|
|
138
|
+
- Timeline production captures active composition and nested-timeline clips to lossless FFV1, composites segments with FFmpeg, concatenates the ordered segments, and mixes audio once.
|
|
139
|
+
- Preview composites in Chromium; production composites with FFmpeg. Small scaling, alpha, and video color differences are expected. Parity is guaranteed at clip capture, not at final encoded pixels.
|
|
140
|
+
- Final MP4 bytes are not a reproducibility guarantee.
|
|
141
|
+
- Long timelines are segmented and bounded. The reference target and measured worst cases are documented in `docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md`.
|