@editframe/create 0.43.0 → 0.45.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 (99) hide show
  1. package/README.md +11 -0
  2. package/dist/index.js +16 -28
  3. package/dist/index.js.map +1 -1
  4. package/dist/skills/editframe-brand-video-generator/README.md +155 -0
  5. package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
  6. package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
  7. package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
  8. package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
  9. package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
  10. package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
  11. package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
  12. package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
  13. package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
  14. package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
  15. package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
  16. package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
  17. package/dist/skills/editframe-composition/SKILL.md +169 -0
  18. package/dist/skills/editframe-composition/references/audio.md +483 -0
  19. package/dist/skills/editframe-composition/references/captions.md +844 -0
  20. package/dist/skills/editframe-composition/references/composition-model.md +73 -0
  21. package/dist/skills/editframe-composition/references/configuration.md +403 -0
  22. package/dist/skills/editframe-composition/references/css-parts.md +105 -0
  23. package/dist/skills/editframe-composition/references/css-variables.md +640 -0
  24. package/dist/skills/editframe-composition/references/entry-points.md +810 -0
  25. package/dist/skills/editframe-composition/references/events.md +499 -0
  26. package/dist/skills/editframe-composition/references/getting-started.md +259 -0
  27. package/dist/skills/editframe-composition/references/hooks.md +234 -0
  28. package/dist/skills/editframe-composition/references/image.md +241 -0
  29. package/dist/skills/editframe-composition/references/r3f.md +580 -0
  30. package/dist/skills/editframe-composition/references/render-api.md +484 -0
  31. package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
  32. package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
  33. package/dist/skills/editframe-composition/references/scripting.md +606 -0
  34. package/dist/skills/editframe-composition/references/sequencing.md +116 -0
  35. package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
  36. package/dist/skills/editframe-composition/references/surface.md +329 -0
  37. package/dist/skills/editframe-composition/references/text.md +627 -0
  38. package/dist/skills/editframe-composition/references/time-model.md +99 -0
  39. package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
  40. package/dist/skills/editframe-composition/references/timegroup.md +457 -0
  41. package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
  42. package/dist/skills/editframe-composition/references/transcription.md +47 -0
  43. package/dist/skills/editframe-composition/references/transitions.md +608 -0
  44. package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
  45. package/dist/skills/editframe-composition/references/video.md +506 -0
  46. package/dist/skills/editframe-composition/references/waveform.md +327 -0
  47. package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
  48. package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
  49. package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
  50. package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
  51. package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
  52. package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
  53. package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
  54. package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
  55. package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
  56. package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
  57. package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
  58. package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
  59. package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
  60. package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
  61. package/dist/skills/editframe-editor-gui/references/play.md +370 -0
  62. package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
  63. package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
  64. package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
  65. package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
  66. package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
  67. package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
  68. package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
  69. package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
  70. package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
  71. package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
  72. package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
  73. package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
  74. package/dist/skills/editframe-motion-design/SKILL.md +101 -0
  75. package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
  76. package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
  77. package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
  78. package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
  79. package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
  80. package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
  81. package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
  82. package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
  83. package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
  84. package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
  85. package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
  86. package/dist/skills/editframe-webhooks/SKILL.md +126 -0
  87. package/dist/skills/editframe-webhooks/references/events.md +382 -0
  88. package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
  89. package/dist/skills/editframe-webhooks/references/security.md +418 -0
  90. package/dist/skills/editframe-webhooks/references/testing.md +409 -0
  91. package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
  92. package/dist/templates/html/AGENTS.md +13 -0
  93. package/dist/templates/react/AGENTS.md +13 -0
  94. package/dist/utils.js +15 -16
  95. package/dist/utils.js.map +1 -1
  96. package/package.json +2 -2
  97. package/tsdown.config.ts +4 -0
  98. package/dist/detectAgent.js +0 -89
  99. package/dist/detectAgent.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ ---
2
+ title: Time Model
3
+ description: "How time propagation works in composition trees: duration inheritance, offset calculation, and element scheduling rules."
4
+ type: explanation
5
+ nav:
6
+ parent: "Concepts"
7
+ priority: 11
8
+ related: ["timegroup-modes"]
9
+ ---
10
+
11
+ # Time Model
12
+
13
+ Editframe uses a declarative time model. You describe structure — the system computes all timing.
14
+
15
+ ## Single Source of Truth
16
+
17
+ Only the root timegroup's `currentTime` is writable. All child times are computed from parent state. This guarantees synchronization — it's impossible for timelines to drift.
18
+
19
+ ```javascript
20
+ const root = document.querySelector('ef-timegroup');
21
+ root.currentTime = 5.5; // All children update atomically
22
+ ```
23
+
24
+ ## Time Flows Down the Tree
25
+
26
+ Each timegroup computes its `ownCurrentTimeMs` (local time) from the parent's time based on its mode and position in the tree.
27
+
28
+ **Root writes `currentTime`** → parent computes child offsets → each child derives its local time → media elements map to source time.
29
+
30
+ In a sequence, a child at position 5s–8s receives `ownCurrentTimeMs = 0` when the root is at 5s, and `ownCurrentTimeMs = 3000` when the root is at 8s.
31
+
32
+ ## Duration Calculation by Mode
33
+
34
+ Each mode computes duration differently:
35
+
36
+ | Mode | Duration rule |
37
+ |------|--------------|
38
+ | `fixed` | Explicit `duration` attribute |
39
+ | `sequence` | Sum of children minus overlaps |
40
+ | `contain` | Maximum child duration |
41
+ | `fit` | Inherited from parent |
42
+
43
+ Duration bubbles up — a `sequence` inside a `contain` resolves its sum, and the `contain` parent takes the max of that and its other children.
44
+
45
+ ```html
46
+ <ef-timegroup mode="contain">
47
+ <!-- sequence resolves to 8s (3+5) -->
48
+ <ef-timegroup mode="sequence">
49
+ <ef-timegroup mode="fixed" duration="3s">A</ef-timegroup>
50
+ <ef-timegroup mode="fixed" duration="5s">B</ef-timegroup>
51
+ </ef-timegroup>
52
+ <!-- contain takes max(8s, 6s) = 8s -->
53
+ <ef-timegroup mode="fixed" duration="6s">C</ef-timegroup>
54
+ </ef-timegroup>
55
+ ```
56
+
57
+ ## Trimming and the Timeline
58
+
59
+ When a video is trimmed, its effective duration changes, which propagates up through the tree:
60
+
61
+ - `sourcein="2s" sourceout="6s"` → effective duration is 4s
62
+ - `trimstart="1s" trimend="2s"` on a 10s source → effective duration is 7s
63
+
64
+ In a `sequence`, changing a trim value shifts all subsequent items automatically. In `contain`, it may change the overall duration if it was the longest child.
65
+
66
+ ## Overlap Creates Shared Time
67
+
68
+ In `sequence` mode, `overlap` subtracts time between adjacent items, creating a region where both are active:
69
+
70
+ ```
71
+ Scene A: |---------|
72
+ Scene B: |---------|
73
+ overlap: |---|
74
+ ```
75
+
76
+ Total duration: `durationA + durationB - overlap`
77
+
78
+ During the overlap region, both scenes receive valid `ownCurrentTimeMs` values. Scene A is near its end, Scene B is near its start. This shared time is where transitions happen.
79
+
80
+ See [transitions.md](references/transitions.md) for using overlap with CSS animations.
81
+
82
+ ## Two Coordinate Systems
83
+
84
+ Every element has two time perspectives:
85
+
86
+ - **`currentTimeMs`** — position in the root timeline (global). Same value for all elements at any given moment.
87
+ - **`ownCurrentTimeMs`** — position in the element's local timeline (local). Resets to 0 at the element's start.
88
+
89
+ Media elements add a third:
90
+
91
+ - **`currentSourceTimeMs`** — position in the source file, accounting for trims. Survives trim changes.
92
+
93
+ > **Note:** `ownCurrentTimeMs` is what you use in `addFrameTask` callbacks and CSS animations. It provides element-relative timing that works regardless of where the element sits in the composition.
94
+
95
+ ## See Also
96
+
97
+ - [timegroup-modes.md](references/timegroup-modes.md) — mode examples
98
+ - [timegroup.md](references/timegroup.md) — attribute reference
99
+ - [sequencing.md](references/sequencing.md) — sequence patterns
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: Timegroup Modes
3
+ description: How the four timegroup layout modes — par, seq, excl, and media — control duration, ordering, and child element scheduling.
4
+ type: explanation
5
+ nav:
6
+ parent: "Concepts"
7
+ priority: 12
8
+ related: ["timegroup", "sequencing"]
9
+ track: "layout-mastery"
10
+ track_step: 2
11
+ track_title: "Understanding Timeline Modes"
12
+ prerequisites: ["timegroup"]
13
+ next_steps: ["sequencing"]
14
+ ---
15
+
16
+ # Timegroup Modes
17
+
18
+ Every `ef-timegroup` has a `mode` that determines how its duration is calculated and how children are arranged in time.
19
+
20
+ ## Fixed
21
+
22
+ Explicit duration. The base case — you set the length directly.
23
+
24
+ ```html live
25
+ <ef-timegroup mode="fixed" duration="3s" class="w-[720px] h-[300px] bg-slate-600 flex items-center justify-center">
26
+ <p class="text-white text-4xl">3 Second Scene</p>
27
+ </ef-timegroup>
28
+ ```
29
+
30
+ Use `fixed` when you know the exact duration: title cards, countdowns, static scenes.
31
+
32
+ ## Sequence
33
+
34
+ Children play one after another. Duration is the sum of all children minus any overlap.
35
+
36
+ ```html live
37
+ <ef-timegroup mode="sequence" class="w-[720px] h-[300px] bg-black">
38
+ <ef-timegroup mode="fixed" duration="2s" class="bg-red-400 text-red-900 text-3xl flex items-center justify-center">
39
+ <p>Scene 1 (2s)</p>
40
+ </ef-timegroup>
41
+ <ef-timegroup mode="fixed" duration="3s" class="bg-green-400 text-green-900 text-3xl flex items-center justify-center">
42
+ <p>Scene 2 (3s)</p>
43
+ </ef-timegroup>
44
+ <ef-timegroup mode="fixed" duration="1s" class="bg-blue-400 text-blue-900 text-3xl flex items-center justify-center">
45
+ <p>Scene 3 (1s)</p>
46
+ </ef-timegroup>
47
+ </ef-timegroup>
48
+ ```
49
+
50
+ Use `sequence` for cut-based editing, multi-scene videos, anything where children play in order. See [sequencing.md](references/sequencing.md).
51
+
52
+ ## Contain
53
+
54
+ Children play simultaneously. Duration is the longest child.
55
+
56
+ ```html live
57
+ <ef-timegroup mode="contain" class="w-[720px] h-[300px] bg-black">
58
+ <ef-timegroup mode="fixed" duration="5s" class="absolute top-0 left-0 w-full h-1/2 bg-red-400 text-red-900 text-2xl flex items-center justify-center">
59
+ <p>Layer A (5s)</p>
60
+ </ef-timegroup>
61
+ <ef-timegroup mode="fixed" duration="8s" class="absolute top-1/2 left-0 w-full h-1/2 bg-green-400 text-green-900 text-2xl flex items-center justify-center">
62
+ <p>Layer B (8s) — sets total to 8s</p>
63
+ </ef-timegroup>
64
+ </ef-timegroup>
65
+ ```
66
+
67
+ Use `contain` for layered compositions: video with overlays, picture-in-picture, parallel tracks.
68
+
69
+ ## Fit
70
+
71
+ Inherits duration from parent. No duration of its own.
72
+
73
+ ```html live
74
+ <ef-timegroup mode="contain" class="w-[720px] h-[300px] bg-black">
75
+ <ef-timegroup mode="fixed" duration="4s" class="absolute top-0 left-0 w-full h-1/2 bg-amber-400 text-amber-900 text-2xl flex items-center justify-center">
76
+ <p>Content (4s)</p>
77
+ </ef-timegroup>
78
+ <ef-timegroup mode="fit" class="absolute top-1/2 left-0 w-full h-1/2 bg-blue-900 text-blue-200 text-2xl flex items-center justify-center">
79
+ <p>Fit background — spans full 4s</p>
80
+ </ef-timegroup>
81
+ </ef-timegroup>
82
+ ```
83
+
84
+ Use `fit` for backgrounds, watermarks, or any element that should span its parent's full duration.
85
+
86
+ ## Decision Guide
87
+
88
+ | Scenario | Mode | Why |
89
+ |----------|------|-----|
90
+ | Title card with known length | `fixed` | Explicit control |
91
+ | Multi-scene video | `sequence` | Sequential playback |
92
+ | Video with text overlay | `contain` | Parallel layers |
93
+ | Background music/watermark | `fit` | Span parent duration |
94
+ | Scenes with transitions | `sequence` + `overlap` | Shared time for crossfades |
95
+
96
+ > **Note:** Modes compose — a `contain` parent with a `sequence` child and a `fit` background is a common pattern for videos with a background track spanning the full timeline.
97
+
98
+ ## See Also
99
+
100
+ - [timegroup.md](references/timegroup.md) — attribute reference
101
+ - [time-model.md](references/time-model.md) — how time propagates through modes
102
+ - [sequencing.md](references/sequencing.md) — sequence patterns
@@ -0,0 +1,457 @@
1
+ ---
2
+ title: Timegroup Element
3
+ description: Container element for grouping and sequencing composition elements, controlling layout mode, duration, and playback behavior.
4
+ type: reference
5
+ nav:
6
+ parent: "Layout & Timing"
7
+ priority: 10
8
+ related: ["timegroup-modes", "sequencing"]
9
+ track: "layout-mastery"
10
+ track_step: 1
11
+ track_title: "Understanding Timegroups"
12
+ next_steps: ["timegroup-modes"]
13
+ api:
14
+ attributes:
15
+ - name: mode
16
+ type: string
17
+ required: true
18
+ description: Duration calculation mode
19
+ values: ["fixed", "sequence", "contain", "fit"]
20
+ - name: duration
21
+ type: timestring
22
+ description: Explicit duration (for fixed mode)
23
+ - name: overlap
24
+ type: timestring
25
+ description: Overlap time between sequence items (e.g., "1s")
26
+ - name: fps
27
+ type: number
28
+ default: 30
29
+ description: Frame rate for rendering
30
+ - name: auto-init
31
+ type: boolean
32
+ default: false
33
+ description: Auto-seek to frame 0 on load (root only)
34
+ - name: workbench
35
+ type: boolean
36
+ default: false
37
+ description: Enable timeline/hierarchy UI (root only)
38
+ methods:
39
+ - name: renderToVideo()
40
+ signature: "async renderToVideo(options?: RenderToVideoOptions): Promise<Uint8Array | undefined>"
41
+ description: Export timegroup to MP4 video using WebCodecs API
42
+ returns: Promise<Uint8Array | undefined>
43
+ - name: createRenderClone()
44
+ signature: "async createRenderClone(): Promise<RenderCloneResult>"
45
+ description: Create independent off-DOM clone for background rendering without affecting preview
46
+ returns: Promise<RenderCloneResult>
47
+ - name: addFrameTask()
48
+ signature: "addFrameTask(callback: FrameTaskCallback): () => void"
49
+ description: Register callback executed on each frame during rendering or playback
50
+ returns: Cleanup function that removes the callback
51
+ - name: seek()
52
+ signature: "async seek(timeMs: number): Promise<void>"
53
+ description: Seek to specific time position and wait for content to be ready
54
+ returns: Promise<void>
55
+ react:
56
+ generate: true
57
+ componentName: Timegroup
58
+ importPath: "@editframe/react"
59
+ propMapping:
60
+ auto-init: autoInit
61
+ additionalProps:
62
+ - name: className
63
+ type: string
64
+ description: CSS classes for styling
65
+ - name: ref
66
+ type: React.Ref
67
+ description: React ref (useful with hooks)
68
+ nav:
69
+ parent: "Core Concepts"
70
+ priority: 2
71
+ related: ["timeline-root", "hooks"]
72
+ ---
73
+
74
+ <!-- html-only -->
75
+ # ef-timegroup
76
+ <!-- /html-only -->
77
+ <!-- react-only -->
78
+ # Timegroup
79
+ <!-- /react-only -->
80
+
81
+ Container for sequencing and grouping elements.
82
+
83
+ <!-- react-only -->
84
+ ## Import
85
+
86
+ ```tsx
87
+ import { Timegroup } from "@editframe/react";
88
+ ```
89
+ <!-- /react-only -->
90
+
91
+ ## Modes
92
+
93
+ <!-- html-only -->
94
+ - `fixed` - Uses `duration` attribute
95
+ <!-- /html-only -->
96
+ <!-- react-only -->
97
+ - `fixed` - Uses `duration` prop
98
+ <!-- /react-only -->
99
+ - `sequence` - Sum of children (sequential playback)
100
+ - `contain` - Longest child duration
101
+ - `fit` - Inherit from parent
102
+
103
+ ## Root Timegroup
104
+
105
+ <!-- html-only -->
106
+ ```html live
107
+ <ef-timegroup mode="sequence" workbench class="w-[720px] h-[480px] bg-black">
108
+ <ef-timegroup mode="fixed" duration="3s" class="absolute w-full h-full flex items-center justify-center">
109
+ <ef-text duration="3s" class="text-white text-3xl">Scene 1</ef-text>
110
+ </ef-timegroup>
111
+ <ef-timegroup mode="fixed" duration="3s" class="absolute w-full h-full flex items-center justify-center">
112
+ <ef-text duration="3s" class="text-white text-3xl">Scene 2</ef-text>
113
+ </ef-timegroup>
114
+ </ef-timegroup>
115
+ ```
116
+ <!-- /html-only -->
117
+ <!-- react-only -->
118
+ ```tsx
119
+ import { Timegroup } from "@editframe/react";
120
+
121
+ export const Video = () => {
122
+ return (
123
+ <Timegroup workbench mode="sequence" className="w-[800px] h-[500px] bg-black">
124
+ {/* scenes here */}
125
+ </Timegroup>
126
+ );
127
+ };
128
+ ```
129
+ <!-- /react-only -->
130
+
131
+ ## Scene (Fixed Duration)
132
+
133
+ <!-- html-only -->
134
+ ```html
135
+ <ef-timegroup mode="fixed" duration="5s" class="absolute w-full h-full">
136
+ <ef-video src="clip.mp4" class="size-full object-cover"></ef-video>
137
+ <ef-text class="absolute top-4 left-4 text-white">Overlay</ef-text>
138
+ </ef-timegroup>
139
+ ```
140
+ <!-- /html-only -->
141
+ <!-- react-only -->
142
+ ```tsx
143
+ <Timegroup mode="fixed" duration="5s" className="absolute w-full h-full">
144
+ <Video src="/assets/clip.mp4" className="size-full object-cover" />
145
+ <Text className="absolute top-4 left-4 text-white">Overlay</Text>
146
+ </Timegroup>
147
+ ```
148
+ <!-- /react-only -->
149
+
150
+ ## Nested Sequence
151
+
152
+ <!-- html-only -->
153
+ ```html
154
+ <ef-timegroup mode="sequence">
155
+ <ef-timegroup mode="fixed" duration="3s"><!-- Scene 1 --></ef-timegroup>
156
+ <ef-timegroup mode="fixed" duration="5s"><!-- Scene 2 --></ef-timegroup>
157
+ <ef-timegroup mode="fixed" duration="4s"><!-- Scene 3 --></ef-timegroup>
158
+ </ef-timegroup>
159
+ ```
160
+ <!-- /html-only -->
161
+ <!-- react-only -->
162
+ ```tsx
163
+ <Timegroup mode="sequence">
164
+ <Timegroup mode="fixed" duration="3s">
165
+ {/* Scene 1 */}
166
+ </Timegroup>
167
+ <Timegroup mode="fixed" duration="5s">
168
+ {/* Scene 2 */}
169
+ </Timegroup>
170
+ <Timegroup mode="fixed" duration="4s">
171
+ {/* Scene 3 */}
172
+ </Timegroup>
173
+ </Timegroup>
174
+ ```
175
+ <!-- /react-only -->
176
+
177
+ <!-- react-only -->
178
+ ## Dynamic Content
179
+
180
+ Map over data to create scenes:
181
+
182
+ ```tsx
183
+ const scenes = [
184
+ { id: 1, text: "Scene 1", duration: "3s" },
185
+ { id: 2, text: "Scene 2", duration: "5s" },
186
+ { id: 3, text: "Scene 3", duration: "4s" },
187
+ ];
188
+
189
+ <Timegroup workbench mode="sequence" className="w-[800px] h-[500px]">
190
+ {scenes.map((scene) => (
191
+ <Timegroup
192
+ key={scene.id}
193
+ mode="fixed"
194
+ duration={scene.duration}
195
+ className="absolute w-full h-full"
196
+ >
197
+ <Text className="text-white text-4xl">{scene.text}</Text>
198
+ </Timegroup>
199
+ ))}
200
+ </Timegroup>
201
+ ```
202
+ <!-- /react-only -->
203
+
204
+ ## Sequence with Overlap
205
+
206
+ Use `overlap` to create transitions between items:
207
+
208
+ <!-- html-only -->
209
+ ```html
210
+ <ef-timegroup mode="sequence" overlap="1s">
211
+ <ef-timegroup mode="contain"><!-- Scene 1 --></ef-timegroup>
212
+ <ef-timegroup mode="contain"><!-- Scene 2 --></ef-timegroup>
213
+ </ef-timegroup>
214
+ ```
215
+ <!-- /html-only -->
216
+ <!-- react-only -->
217
+ ```tsx
218
+ <Timegroup mode="sequence" overlap="1s">
219
+ <Timegroup mode="contain">{/* Scene 1 */}</Timegroup>
220
+ <Timegroup mode="contain">{/* Scene 2 */}</Timegroup>
221
+ </Timegroup>
222
+ ```
223
+ <!-- /react-only -->
224
+
225
+ See [transitions.md](references/transitions.md) for crossfade examples.
226
+
227
+ <!-- react-only -->
228
+ ## With useTimingInfo Hook
229
+
230
+ ```tsx
231
+ import { Timegroup } from "@editframe/react";
232
+ import { useTimingInfo } from "@editframe/react";
233
+
234
+ const AnimatedScene = () => {
235
+ const { ref, percentComplete, ownCurrentTimeMs } = useTimingInfo();
236
+
237
+ return (
238
+ <Timegroup ref={ref} mode="contain" className="absolute w-full h-full">
239
+ <div style={{ opacity: percentComplete }}>
240
+ Fading in... {(ownCurrentTimeMs / 1000).toFixed(2)}s
241
+ </div>
242
+ </Timegroup>
243
+ );
244
+ };
245
+ ```
246
+ <!-- /react-only -->
247
+
248
+ ## Methods
249
+
250
+ ### renderToVideo()
251
+
252
+ Export the timegroup composition to MP4 video using the WebCodecs API. See [render-api.md](references/render-api.md) for complete documentation.
253
+
254
+ ```typescript
255
+ async renderToVideo(options?: RenderToVideoOptions): Promise<Uint8Array | undefined>
256
+ ```
257
+
258
+ **Basic Example:**
259
+
260
+ ```typescript
261
+ const tg = document.querySelector('ef-timegroup');
262
+
263
+ await tg.renderToVideo({
264
+ fps: 30,
265
+ codec: 'avc',
266
+ filename: 'output.mp4',
267
+ onProgress: (progress) => {
268
+ console.log(`${Math.round(progress.progress * 100)}% complete`);
269
+ }
270
+ });
271
+ ```
272
+
273
+ **RenderToVideoOptions:**
274
+ - `fps` - Frame rate (default: 30)
275
+ - `codec` - Video codec: "avc", "hevc", "vp9", "av1", "vp8" (default: "avc")
276
+ - `bitrate` - Video bitrate in bits/second (default: 5000000)
277
+ - `filename` - Download filename (default: "video.mp4")
278
+ - `scale` - Resolution multiplier (default: 1)
279
+ - `fromMs`, `toMs` - Time range to export
280
+ - `onProgress` - Progress callback receiving `RenderProgress` object
281
+ - `includeAudio` - Include audio tracks (default: true)
282
+ - `signal` - AbortSignal for cancellation
283
+ - `returnBuffer` - Return Uint8Array instead of downloading
284
+ - And more - see [render-api.md](references/render-api.md)
285
+
286
+ ### createRenderClone()
287
+
288
+ Create an independent off-DOM clone for background rendering without affecting the preview timeline.
289
+
290
+ ```typescript
291
+ async createRenderClone(): Promise<RenderCloneResult>
292
+ ```
293
+
294
+ **Example:**
295
+
296
+ ```typescript
297
+ const tg = document.querySelector('ef-timegroup');
298
+
299
+ // Create isolated render clone
300
+ const { clone, container, cleanup } = await tg.createRenderClone();
301
+
302
+ try {
303
+ // Clone has independent time state
304
+ await clone.seek(5000); // Seek clone to 5 seconds
305
+
306
+ // Original timeline unaffected
307
+ console.log('Clone time:', clone.currentTimeMs);
308
+ console.log('Original time:', tg.currentTimeMs);
309
+ } finally {
310
+ // Always clean up
311
+ cleanup();
312
+ }
313
+ ```
314
+
315
+ **RenderCloneResult:**
316
+ ```typescript
317
+ interface RenderCloneResult {
318
+ clone: EFTimegroup; // Cloned timegroup with independent state
319
+ container: HTMLElement; // Off-screen container holding the clone
320
+ cleanup: () => void; // Remove clone from DOM and clean up
321
+ }
322
+ ```
323
+
324
+ Clones automatically re-run the `initializer` function if set, enabling JavaScript-driven animations in renders.
325
+
326
+ ### addFrameTask()
327
+
328
+ Register a callback that executes on each frame during playback or rendering. Returns cleanup function.
329
+
330
+ ```typescript
331
+ addFrameTask(callback: FrameTaskCallback): () => void
332
+ ```
333
+
334
+ **Example:**
335
+
336
+ ```typescript
337
+ const tg = document.querySelector('ef-timegroup');
338
+
339
+ const cleanup = tg.addFrameTask((info) => {
340
+ // Update DOM based on current time
341
+ const progress = info.percentComplete;
342
+ console.log(`Frame at ${info.ownCurrentTimeMs}ms (${Math.round(progress * 100)}%)`);
343
+
344
+ // Modify child elements
345
+ const textEl = info.element.querySelector('.dynamic-text');
346
+ if (textEl) {
347
+ textEl.textContent = `Time: ${(info.ownCurrentTimeMs / 1000).toFixed(2)}s`;
348
+ }
349
+ });
350
+
351
+ // Remove callback when done
352
+ cleanup();
353
+ ```
354
+
355
+ **FrameTaskCallback:**
356
+ ```typescript
357
+ type FrameTaskCallback = (info: {
358
+ ownCurrentTimeMs: number; // This element's local time
359
+ currentTimeMs: number; // Root timeline's global time
360
+ durationMs: number; // This element's duration
361
+ percentComplete: number; // Completion percentage (0.0 to 1.0)
362
+ element: EFTimegroup; // The timegroup instance
363
+ }) => void | Promise<void>;
364
+ ```
365
+
366
+ The callback can be sync or async. Multiple callbacks can be registered and execute in parallel.
367
+
368
+ ### seek()
369
+
370
+ Seek to a specific time position and wait for all visible content to be ready.
371
+
372
+ ```typescript
373
+ async seek(timeMs: number): Promise<void>
374
+ ```
375
+
376
+ **Example:**
377
+
378
+ ```typescript
379
+ const tg = document.querySelector('ef-timegroup');
380
+
381
+ // Seek to 3 seconds
382
+ await tg.seek(3000);
383
+
384
+ // Timeline is now at 3s, all visible media loaded
385
+ console.log('Current time:', tg.currentTimeMs);
386
+ ```
387
+
388
+ Time is automatically quantized to frame boundaries based on the `fps` attribute.
389
+
390
+ ## Scripting
391
+
392
+ <!-- html-only -->
393
+ Add dynamic behavior with JavaScript using the `initializer` property. The initializer function runs on both the original timeline and all render clones.
394
+
395
+ ```html
396
+ <ef-timegroup id="dynamic-scene" mode="fixed" duration="5s">
397
+ <div class="dynamic-text"></div>
398
+ </ef-timegroup>
399
+
400
+ <script>
401
+ const tg = document.querySelector('#dynamic-scene');
402
+
403
+ // Initializer runs once per instance (original + clones)
404
+ tg.initializer = (instance) => {
405
+ instance.addFrameTask((info) => {
406
+ const text = instance.querySelector('.dynamic-text');
407
+ text.textContent = `Time: ${(info.ownCurrentTimeMs / 1000).toFixed(2)}s`;
408
+ });
409
+ };
410
+ </script>
411
+ ```
412
+ <!-- /html-only -->
413
+ <!-- react-only -->
414
+ Add dynamic behavior with JavaScript. See [scripting.md](references/scripting.md) for details.
415
+
416
+ ```tsx
417
+ import { useRef, useEffect } from "react";
418
+ import { Timegroup } from "@editframe/react";
419
+
420
+ const DynamicScene = () => {
421
+ const timegroupRef = useRef<HTMLElement>(null);
422
+
423
+ useEffect(() => {
424
+ const tg = timegroupRef.current;
425
+ if (!tg) return;
426
+
427
+ tg.initializer = (instance) => {
428
+ const cleanup = instance.addFrameTask((info) => {
429
+ // Update content based on time
430
+ console.log(`Time: ${info.ownCurrentTimeMs}ms`);
431
+ });
432
+
433
+ return cleanup;
434
+ };
435
+ }, []);
436
+
437
+ return (
438
+ <Timegroup ref={timegroupRef} mode="fixed" duration="5s">
439
+ {/* Content */}
440
+ </Timegroup>
441
+ );
442
+ };
443
+ ```
444
+ <!-- /react-only -->
445
+
446
+ <!-- html-only -->
447
+ **TimegroupInitializer:**
448
+ ```typescript
449
+ type TimegroupInitializer = (timegroup: EFTimegroup) => void;
450
+ ```
451
+
452
+ **Constraints:**
453
+ - Must be synchronous (no async/await, no Promise return)
454
+ - Must complete quickly (&lt;10ms warning, &lt;100ms error)
455
+ - Should only register callbacks and set up behavior
456
+ - Runs once per instance (prime timeline + each render clone)
457
+ <!-- /html-only -->