@editframe/create 0.44.0 → 0.45.1
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/dist/index.js +16 -28
- package/dist/index.js.map +1 -1
- package/dist/skills/editframe-brand-video-generator/README.md +155 -0
- package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
- package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
- package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
- package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
- package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
- package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
- package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
- package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
- package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
- package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
- package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
- package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
- package/dist/skills/editframe-composition/SKILL.md +169 -0
- package/dist/skills/editframe-composition/references/audio.md +483 -0
- package/dist/skills/editframe-composition/references/captions.md +844 -0
- package/dist/skills/editframe-composition/references/composition-model.md +73 -0
- package/dist/skills/editframe-composition/references/configuration.md +403 -0
- package/dist/skills/editframe-composition/references/css-parts.md +105 -0
- package/dist/skills/editframe-composition/references/css-variables.md +640 -0
- package/dist/skills/editframe-composition/references/entry-points.md +810 -0
- package/dist/skills/editframe-composition/references/events.md +499 -0
- package/dist/skills/editframe-composition/references/getting-started.md +259 -0
- package/dist/skills/editframe-composition/references/hooks.md +234 -0
- package/dist/skills/editframe-composition/references/image.md +241 -0
- package/dist/skills/editframe-composition/references/r3f.md +580 -0
- package/dist/skills/editframe-composition/references/render-api.md +484 -0
- package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
- package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
- package/dist/skills/editframe-composition/references/scripting.md +606 -0
- package/dist/skills/editframe-composition/references/sequencing.md +116 -0
- package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
- package/dist/skills/editframe-composition/references/surface.md +329 -0
- package/dist/skills/editframe-composition/references/text.md +627 -0
- package/dist/skills/editframe-composition/references/time-model.md +99 -0
- package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
- package/dist/skills/editframe-composition/references/timegroup.md +457 -0
- package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
- package/dist/skills/editframe-composition/references/transcription.md +47 -0
- package/dist/skills/editframe-composition/references/transitions.md +608 -0
- package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
- package/dist/skills/editframe-composition/references/video.md +506 -0
- package/dist/skills/editframe-composition/references/waveform.md +327 -0
- package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
- package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
- package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
- package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
- package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
- package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
- package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
- package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
- package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
- package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
- package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
- package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
- package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
- package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
- package/dist/skills/editframe-editor-gui/references/play.md +370 -0
- package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
- package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
- package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
- package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
- package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
- package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
- package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
- package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
- package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
- package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
- package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
- package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
- package/dist/skills/editframe-motion-design/SKILL.md +101 -0
- package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
- package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
- package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
- package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
- package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
- package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
- package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
- package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
- package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
- package/dist/skills/editframe-webhooks/SKILL.md +126 -0
- package/dist/skills/editframe-webhooks/references/events.md +382 -0
- package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
- package/dist/skills/editframe-webhooks/references/security.md +418 -0
- package/dist/skills/editframe-webhooks/references/testing.md +409 -0
- package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
- package/dist/templates/html/AGENTS.md +13 -0
- package/dist/templates/react/AGENTS.md +13 -0
- package/dist/utils.js +15 -16
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/tsdown.config.ts +4 -0
- package/dist/detectAgent.js +0 -89
- package/dist/detectAgent.js.map +0 -1
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Transitions
|
|
3
|
+
description: Create smooth CSS-animated transitions between sequence items using configurable overlap duration and animation keyframes.
|
|
4
|
+
type: how-to
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Layout & Timing"
|
|
7
|
+
priority: 12
|
|
8
|
+
related: ["sequencing", "video~effects"]
|
|
9
|
+
prerequisites: ["sequencing"]
|
|
10
|
+
react:
|
|
11
|
+
generate: true
|
|
12
|
+
componentName: "Transitions"
|
|
13
|
+
importPath: "@editframe/react"
|
|
14
|
+
nav:
|
|
15
|
+
parent: "Guides"
|
|
16
|
+
priority: 20
|
|
17
|
+
related: ["timegroup", "css-variables"]
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Transitions
|
|
21
|
+
|
|
22
|
+
Create smooth transitions between sequence items using overlap and CSS animations.
|
|
23
|
+
|
|
24
|
+
## Overlap <!-- html-only -->Attribute<!-- /html-only --><!-- react-only -->Prop<!-- /react-only -->
|
|
25
|
+
|
|
26
|
+
Use `overlap` on sequence timegroups to make items overlap in time:
|
|
27
|
+
|
|
28
|
+
<!-- html-only -->
|
|
29
|
+
```html
|
|
30
|
+
<ef-timegroup mode="sequence" overlap="1s">
|
|
31
|
+
<ef-timegroup mode="contain"><!-- Scene 1 --></ef-timegroup>
|
|
32
|
+
<ef-timegroup mode="contain"><!-- Scene 2 --></ef-timegroup>
|
|
33
|
+
</ef-timegroup>
|
|
34
|
+
```
|
|
35
|
+
<!-- /html-only -->
|
|
36
|
+
<!-- react-only -->
|
|
37
|
+
```tsx
|
|
38
|
+
<Timegroup mode="sequence" overlap="1s">
|
|
39
|
+
<Timegroup mode="contain">{/* Scene 1 */}</Timegroup>
|
|
40
|
+
<Timegroup mode="contain">{/* Scene 2 */}</Timegroup>
|
|
41
|
+
</Timegroup>
|
|
42
|
+
```
|
|
43
|
+
<!-- /react-only -->
|
|
44
|
+
|
|
45
|
+
This creates a 1-second overlap where both scenes are visible simultaneously.
|
|
46
|
+
|
|
47
|
+
## CSS Variables for Transitions
|
|
48
|
+
|
|
49
|
+
Use these variables to time animations:
|
|
50
|
+
|
|
51
|
+
- `--ef-duration` - Element's total duration (e.g., `"10s"`)
|
|
52
|
+
- `--ef-transition-duration` - Overlap duration for transitions
|
|
53
|
+
- `--ef-transition-out-start` - When fade-out should start (near end)
|
|
54
|
+
|
|
55
|
+
## Crossfade Transition
|
|
56
|
+
|
|
57
|
+
Fade out first clip while fading in second clip:
|
|
58
|
+
|
|
59
|
+
<!-- html-only -->
|
|
60
|
+
```html
|
|
61
|
+
<style>
|
|
62
|
+
@keyframes fade-in {
|
|
63
|
+
from { opacity: 0; }
|
|
64
|
+
to { opacity: 1; }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes fade-out {
|
|
68
|
+
from { opacity: 1; }
|
|
69
|
+
to { opacity: 0; }
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
72
|
+
|
|
73
|
+
<ef-timegroup mode="sequence" overlap="1s">
|
|
74
|
+
<ef-timegroup mode="contain">
|
|
75
|
+
<ef-video
|
|
76
|
+
src="clip1.mp4"
|
|
77
|
+
class="size-full"
|
|
78
|
+
style="animation: 1s fade-out var(--ef-transition-out-start)"
|
|
79
|
+
></ef-video>
|
|
80
|
+
</ef-timegroup>
|
|
81
|
+
|
|
82
|
+
<ef-timegroup mode="contain">
|
|
83
|
+
<ef-video
|
|
84
|
+
src="clip2.mp4"
|
|
85
|
+
class="size-full"
|
|
86
|
+
style="animation: 1s fade-in 0s"
|
|
87
|
+
></ef-video>
|
|
88
|
+
</ef-timegroup>
|
|
89
|
+
</ef-timegroup>
|
|
90
|
+
```
|
|
91
|
+
<!-- /html-only -->
|
|
92
|
+
<!-- react-only -->
|
|
93
|
+
```tsx
|
|
94
|
+
import { Timegroup, Video } from "@editframe/react";
|
|
95
|
+
|
|
96
|
+
const CrossfadeExample = () => {
|
|
97
|
+
return (
|
|
98
|
+
<>
|
|
99
|
+
<style>{`
|
|
100
|
+
@keyframes fade-in {
|
|
101
|
+
from { opacity: 0; }
|
|
102
|
+
to { opacity: 1; }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes fade-out {
|
|
106
|
+
from { opacity: 1; }
|
|
107
|
+
to { opacity: 0; }
|
|
108
|
+
}
|
|
109
|
+
`}</style>
|
|
110
|
+
|
|
111
|
+
<Timegroup mode="sequence" overlap="1s">
|
|
112
|
+
<Timegroup mode="contain">
|
|
113
|
+
<Video
|
|
114
|
+
src="/assets/clip1.mp4"
|
|
115
|
+
className="size-full"
|
|
116
|
+
style={{ animation: "1s fade-out var(--ef-transition-out-start)" }}
|
|
117
|
+
/>
|
|
118
|
+
</Timegroup>
|
|
119
|
+
|
|
120
|
+
<Timegroup mode="contain">
|
|
121
|
+
<Video
|
|
122
|
+
src="/assets/clip2.mp4"
|
|
123
|
+
className="size-full"
|
|
124
|
+
style={{ animation: "1s fade-in 0s" }}
|
|
125
|
+
/>
|
|
126
|
+
</Timegroup>
|
|
127
|
+
</Timegroup>
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
<!-- /react-only -->
|
|
133
|
+
|
|
134
|
+
**How it works:**
|
|
135
|
+
1. `overlap="1s"` makes clips overlap by 1 second
|
|
136
|
+
2. First clip fades out during last 1 second (`--ef-transition-out-start`)
|
|
137
|
+
3. Second clip fades in during first 1 second (`0s` delay)
|
|
138
|
+
4. Result: Smooth crossfade
|
|
139
|
+
|
|
140
|
+
## Slide Transition
|
|
141
|
+
|
|
142
|
+
Slide second clip in from the right:
|
|
143
|
+
|
|
144
|
+
<!-- html-only -->
|
|
145
|
+
```html
|
|
146
|
+
<style>
|
|
147
|
+
@keyframes slide-in-right {
|
|
148
|
+
from { transform: translateX(100%); }
|
|
149
|
+
to { transform: translateX(0); }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@keyframes slide-out-left {
|
|
153
|
+
from { transform: translateX(0); }
|
|
154
|
+
to { transform: translateX(-100%); }
|
|
155
|
+
}
|
|
156
|
+
</style>
|
|
157
|
+
|
|
158
|
+
<ef-timegroup mode="sequence" overlap="0.5s">
|
|
159
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
160
|
+
<ef-video
|
|
161
|
+
src="clip1.mp4"
|
|
162
|
+
class="size-full"
|
|
163
|
+
style="animation: 0.5s slide-out-left var(--ef-transition-out-start)"
|
|
164
|
+
></ef-video>
|
|
165
|
+
</ef-timegroup>
|
|
166
|
+
|
|
167
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
168
|
+
<ef-video
|
|
169
|
+
src="clip2.mp4"
|
|
170
|
+
class="size-full"
|
|
171
|
+
style="animation: 0.5s slide-in-right 0s"
|
|
172
|
+
></ef-video>
|
|
173
|
+
</ef-timegroup>
|
|
174
|
+
</ef-timegroup>
|
|
175
|
+
```
|
|
176
|
+
<!-- /html-only -->
|
|
177
|
+
<!-- react-only -->
|
|
178
|
+
```tsx
|
|
179
|
+
const SlideTransition = () => {
|
|
180
|
+
return (
|
|
181
|
+
<>
|
|
182
|
+
<style>{`
|
|
183
|
+
@keyframes slide-in-right {
|
|
184
|
+
from { transform: translateX(100%); }
|
|
185
|
+
to { transform: translateX(0); }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@keyframes slide-out-left {
|
|
189
|
+
from { transform: translateX(0); }
|
|
190
|
+
to { transform: translateX(-100%); }
|
|
191
|
+
}
|
|
192
|
+
`}</style>
|
|
193
|
+
|
|
194
|
+
<Timegroup mode="sequence" overlap="0.5s">
|
|
195
|
+
<Timegroup mode="contain" className="absolute w-full h-full">
|
|
196
|
+
<Video
|
|
197
|
+
src="/assets/clip1.mp4"
|
|
198
|
+
className="size-full"
|
|
199
|
+
style={{ animation: "0.5s slide-out-left var(--ef-transition-out-start)" }}
|
|
200
|
+
/>
|
|
201
|
+
</Timegroup>
|
|
202
|
+
|
|
203
|
+
<Timegroup mode="contain" className="absolute w-full h-full">
|
|
204
|
+
<Video
|
|
205
|
+
src="/assets/clip2.mp4"
|
|
206
|
+
className="size-full"
|
|
207
|
+
style={{ animation: "0.5s slide-in-right 0s" }}
|
|
208
|
+
/>
|
|
209
|
+
</Timegroup>
|
|
210
|
+
</Timegroup>
|
|
211
|
+
</>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
<!-- /react-only -->
|
|
216
|
+
|
|
217
|
+
## Zoom Transition
|
|
218
|
+
|
|
219
|
+
Zoom out first clip while zooming in second:
|
|
220
|
+
|
|
221
|
+
<!-- html-only -->
|
|
222
|
+
```html
|
|
223
|
+
<style>
|
|
224
|
+
@keyframes zoom-in {
|
|
225
|
+
from { transform: scale(0.5); opacity: 0; }
|
|
226
|
+
to { transform: scale(1); opacity: 1; }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@keyframes zoom-out {
|
|
230
|
+
from { transform: scale(1); opacity: 1; }
|
|
231
|
+
to { transform: scale(1.5); opacity: 0; }
|
|
232
|
+
}
|
|
233
|
+
</style>
|
|
234
|
+
|
|
235
|
+
<ef-timegroup mode="sequence" overlap="0.8s">
|
|
236
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
237
|
+
<ef-video
|
|
238
|
+
src="clip1.mp4"
|
|
239
|
+
class="size-full object-cover"
|
|
240
|
+
style="animation: 0.8s zoom-out var(--ef-transition-out-start)"
|
|
241
|
+
></ef-video>
|
|
242
|
+
</ef-timegroup>
|
|
243
|
+
|
|
244
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
245
|
+
<ef-video
|
|
246
|
+
src="clip2.mp4"
|
|
247
|
+
class="size-full object-cover"
|
|
248
|
+
style="animation: 0.8s zoom-in 0s"
|
|
249
|
+
></ef-video>
|
|
250
|
+
</ef-timegroup>
|
|
251
|
+
</ef-timegroup>
|
|
252
|
+
```
|
|
253
|
+
<!-- /html-only -->
|
|
254
|
+
<!-- react-only -->
|
|
255
|
+
```tsx
|
|
256
|
+
const ZoomTransition = () => {
|
|
257
|
+
return (
|
|
258
|
+
<>
|
|
259
|
+
<style>{`
|
|
260
|
+
@keyframes zoom-in {
|
|
261
|
+
from { transform: scale(0.5); opacity: 0; }
|
|
262
|
+
to { transform: scale(1); opacity: 1; }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@keyframes zoom-out {
|
|
266
|
+
from { transform: scale(1); opacity: 1; }
|
|
267
|
+
to { transform: scale(1.5); opacity: 0; }
|
|
268
|
+
}
|
|
269
|
+
`}</style>
|
|
270
|
+
|
|
271
|
+
<Timegroup mode="sequence" overlap="0.8s">
|
|
272
|
+
<Timegroup mode="contain" className="absolute w-full h-full">
|
|
273
|
+
<Video
|
|
274
|
+
src="/assets/clip1.mp4"
|
|
275
|
+
className="size-full object-cover"
|
|
276
|
+
style={{ animation: "0.8s zoom-out var(--ef-transition-out-start)" }}
|
|
277
|
+
/>
|
|
278
|
+
</Timegroup>
|
|
279
|
+
|
|
280
|
+
<Timegroup mode="contain" className="absolute w-full h-full">
|
|
281
|
+
<Video
|
|
282
|
+
src="/assets/clip2.mp4"
|
|
283
|
+
className="size-full object-cover"
|
|
284
|
+
style={{ animation: "0.8s zoom-in 0s" }}
|
|
285
|
+
/>
|
|
286
|
+
</Timegroup>
|
|
287
|
+
</Timegroup>
|
|
288
|
+
</>
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
<!-- /react-only -->
|
|
293
|
+
|
|
294
|
+
## Dissolve Transition
|
|
295
|
+
|
|
296
|
+
Gradual opacity transition with blur:
|
|
297
|
+
|
|
298
|
+
<!-- html-only -->
|
|
299
|
+
```html
|
|
300
|
+
<style>
|
|
301
|
+
@keyframes dissolve-in {
|
|
302
|
+
from { opacity: 0; filter: blur(10px); }
|
|
303
|
+
to { opacity: 1; filter: blur(0); }
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@keyframes dissolve-out {
|
|
307
|
+
from { opacity: 1; filter: blur(0); }
|
|
308
|
+
to { opacity: 0; filter: blur(10px); }
|
|
309
|
+
}
|
|
310
|
+
</style>
|
|
311
|
+
|
|
312
|
+
<ef-timegroup mode="sequence" overlap="1.5s">
|
|
313
|
+
<ef-timegroup mode="contain">
|
|
314
|
+
<ef-video
|
|
315
|
+
src="clip1.mp4"
|
|
316
|
+
class="size-full"
|
|
317
|
+
style="animation: 1.5s dissolve-out var(--ef-transition-out-start)"
|
|
318
|
+
></ef-video>
|
|
319
|
+
</ef-timegroup>
|
|
320
|
+
|
|
321
|
+
<ef-timegroup mode="contain">
|
|
322
|
+
<ef-video
|
|
323
|
+
src="clip2.mp4"
|
|
324
|
+
class="size-full"
|
|
325
|
+
style="animation: 1.5s dissolve-in 0s"
|
|
326
|
+
></ef-video>
|
|
327
|
+
</ef-timegroup>
|
|
328
|
+
</ef-timegroup>
|
|
329
|
+
```
|
|
330
|
+
<!-- /html-only -->
|
|
331
|
+
<!-- react-only -->
|
|
332
|
+
```tsx
|
|
333
|
+
const DissolveTransition = () => {
|
|
334
|
+
return (
|
|
335
|
+
<>
|
|
336
|
+
<style>{`
|
|
337
|
+
@keyframes dissolve-in {
|
|
338
|
+
from { opacity: 0; filter: blur(10px); }
|
|
339
|
+
to { opacity: 1; filter: blur(0); }
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@keyframes dissolve-out {
|
|
343
|
+
from { opacity: 1; filter: blur(0); }
|
|
344
|
+
to { opacity: 0; filter: blur(10px); }
|
|
345
|
+
}
|
|
346
|
+
`}</style>
|
|
347
|
+
|
|
348
|
+
<Timegroup mode="sequence" overlap="1.5s">
|
|
349
|
+
<Timegroup mode="contain">
|
|
350
|
+
<Video
|
|
351
|
+
src="/assets/clip1.mp4"
|
|
352
|
+
className="size-full"
|
|
353
|
+
style={{ animation: "1.5s dissolve-out var(--ef-transition-out-start)" }}
|
|
354
|
+
/>
|
|
355
|
+
</Timegroup>
|
|
356
|
+
|
|
357
|
+
<Timegroup mode="contain">
|
|
358
|
+
<Video
|
|
359
|
+
src="/assets/clip2.mp4"
|
|
360
|
+
className="size-full"
|
|
361
|
+
style={{ animation: "1.5s dissolve-in 0s" }}
|
|
362
|
+
/>
|
|
363
|
+
</Timegroup>
|
|
364
|
+
</Timegroup>
|
|
365
|
+
</>
|
|
366
|
+
);
|
|
367
|
+
};
|
|
368
|
+
```
|
|
369
|
+
<!-- /react-only -->
|
|
370
|
+
|
|
371
|
+
## Multiple Clips with Transitions
|
|
372
|
+
|
|
373
|
+
Chain multiple clips with consistent transitions:
|
|
374
|
+
|
|
375
|
+
<!-- html-only -->
|
|
376
|
+
```html
|
|
377
|
+
<ef-timegroup mode="sequence" overlap="1s">
|
|
378
|
+
<ef-timegroup mode="contain">
|
|
379
|
+
<ef-video
|
|
380
|
+
src="clip1.mp4"
|
|
381
|
+
class="size-full"
|
|
382
|
+
style="animation: 1s fade-out var(--ef-transition-out-start)"
|
|
383
|
+
></ef-video>
|
|
384
|
+
</ef-timegroup>
|
|
385
|
+
|
|
386
|
+
<ef-timegroup mode="contain">
|
|
387
|
+
<ef-video
|
|
388
|
+
src="clip2.mp4"
|
|
389
|
+
class="size-full"
|
|
390
|
+
style="animation: 1s fade-in 0s, 1s fade-out var(--ef-transition-out-start)"
|
|
391
|
+
></ef-video>
|
|
392
|
+
</ef-timegroup>
|
|
393
|
+
|
|
394
|
+
<ef-timegroup mode="contain">
|
|
395
|
+
<ef-video
|
|
396
|
+
src="clip3.mp4"
|
|
397
|
+
class="size-full"
|
|
398
|
+
style="animation: 1s fade-in 0s, 1s fade-out var(--ef-transition-out-start)"
|
|
399
|
+
></ef-video>
|
|
400
|
+
</ef-timegroup>
|
|
401
|
+
|
|
402
|
+
<ef-timegroup mode="contain">
|
|
403
|
+
<ef-video
|
|
404
|
+
src="clip4.mp4"
|
|
405
|
+
class="size-full"
|
|
406
|
+
style="animation: 1s fade-in 0s"
|
|
407
|
+
></ef-video>
|
|
408
|
+
</ef-timegroup>
|
|
409
|
+
</ef-timegroup>
|
|
410
|
+
```
|
|
411
|
+
<!-- /html-only -->
|
|
412
|
+
<!-- react-only -->
|
|
413
|
+
```tsx
|
|
414
|
+
const MultiClipTransitions = () => {
|
|
415
|
+
const clips = [
|
|
416
|
+
"/assets/clip1.mp4",
|
|
417
|
+
"/assets/clip2.mp4",
|
|
418
|
+
"/assets/clip3.mp4",
|
|
419
|
+
"/assets/clip4.mp4",
|
|
420
|
+
];
|
|
421
|
+
|
|
422
|
+
return (
|
|
423
|
+
<>
|
|
424
|
+
<style>{`
|
|
425
|
+
@keyframes fade-in {
|
|
426
|
+
from { opacity: 0; }
|
|
427
|
+
to { opacity: 1; }
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
@keyframes fade-out {
|
|
431
|
+
from { opacity: 1; }
|
|
432
|
+
to { opacity: 0; }
|
|
433
|
+
}
|
|
434
|
+
`}</style>
|
|
435
|
+
|
|
436
|
+
<Timegroup mode="sequence" overlap="1s">
|
|
437
|
+
{clips.map((src, index) => {
|
|
438
|
+
const isFirst = index === 0;
|
|
439
|
+
const isLast = index === clips.length - 1;
|
|
440
|
+
|
|
441
|
+
let animation = "";
|
|
442
|
+
if (isFirst) {
|
|
443
|
+
animation = "1s fade-out var(--ef-transition-out-start)";
|
|
444
|
+
} else if (isLast) {
|
|
445
|
+
animation = "1s fade-in 0s";
|
|
446
|
+
} else {
|
|
447
|
+
animation = "1s fade-in 0s, 1s fade-out var(--ef-transition-out-start)";
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return (
|
|
451
|
+
<Timegroup key={src} mode="contain">
|
|
452
|
+
<Video
|
|
453
|
+
src={src}
|
|
454
|
+
className="size-full"
|
|
455
|
+
style={{ animation }}
|
|
456
|
+
/>
|
|
457
|
+
</Timegroup>
|
|
458
|
+
);
|
|
459
|
+
})}
|
|
460
|
+
</Timegroup>
|
|
461
|
+
</>
|
|
462
|
+
);
|
|
463
|
+
};
|
|
464
|
+
```
|
|
465
|
+
<!-- /react-only -->
|
|
466
|
+
|
|
467
|
+
**Pattern:**
|
|
468
|
+
- First clip: fade-out only
|
|
469
|
+
- Middle clips: fade-in and fade-out
|
|
470
|
+
- Last clip: fade-in only
|
|
471
|
+
|
|
472
|
+
## Transition Timing
|
|
473
|
+
|
|
474
|
+
Match overlap duration to animation duration:
|
|
475
|
+
|
|
476
|
+
<!-- html-only -->
|
|
477
|
+
```html
|
|
478
|
+
<!-- overlap="1s" matches animation duration of 1s -->
|
|
479
|
+
<ef-timegroup mode="sequence" overlap="1s">
|
|
480
|
+
<ef-timegroup mode="contain">
|
|
481
|
+
<ef-video style="animation: 1s fade-out var(--ef-transition-out-start)"></ef-video>
|
|
482
|
+
</ef-timegroup>
|
|
483
|
+
<ef-timegroup mode="contain">
|
|
484
|
+
<ef-video style="animation: 1s fade-in 0s"></ef-video>
|
|
485
|
+
</ef-timegroup>
|
|
486
|
+
</ef-timegroup>
|
|
487
|
+
```
|
|
488
|
+
<!-- /html-only -->
|
|
489
|
+
<!-- react-only -->
|
|
490
|
+
```tsx
|
|
491
|
+
{/* overlap="1s" matches animation duration of 1s */}
|
|
492
|
+
<Timegroup mode="sequence" overlap="1s">
|
|
493
|
+
<Timegroup mode="contain">
|
|
494
|
+
<Video style={{ animation: "1s fade-out var(--ef-transition-out-start)" }} />
|
|
495
|
+
</Timegroup>
|
|
496
|
+
<Timegroup mode="contain">
|
|
497
|
+
<Video style={{ animation: "1s fade-in 0s" }} />
|
|
498
|
+
</Timegroup>
|
|
499
|
+
</Timegroup>
|
|
500
|
+
```
|
|
501
|
+
<!-- /react-only -->
|
|
502
|
+
|
|
503
|
+
**Important:** Animation duration should match overlap duration for smooth transitions.
|
|
504
|
+
|
|
505
|
+
## No Overlap (Cut)
|
|
506
|
+
|
|
507
|
+
Omit `overlap` for instant cuts between clips:
|
|
508
|
+
|
|
509
|
+
<!-- html-only -->
|
|
510
|
+
```html
|
|
511
|
+
<ef-timegroup mode="sequence">
|
|
512
|
+
<ef-timegroup mode="contain">
|
|
513
|
+
<ef-video src="clip1.mp4" class="size-full"></ef-video>
|
|
514
|
+
</ef-timegroup>
|
|
515
|
+
<ef-timegroup mode="contain">
|
|
516
|
+
<ef-video src="clip2.mp4" class="size-full"></ef-video>
|
|
517
|
+
</ef-timegroup>
|
|
518
|
+
</ef-timegroup>
|
|
519
|
+
```
|
|
520
|
+
<!-- /html-only -->
|
|
521
|
+
<!-- react-only -->
|
|
522
|
+
```tsx
|
|
523
|
+
<Timegroup mode="sequence">
|
|
524
|
+
<Timegroup mode="contain">
|
|
525
|
+
<Video src="/assets/clip1.mp4" className="size-full" />
|
|
526
|
+
</Timegroup>
|
|
527
|
+
<Timegroup mode="contain">
|
|
528
|
+
<Video src="/assets/clip2.mp4" className="size-full" />
|
|
529
|
+
</Timegroup>
|
|
530
|
+
</Timegroup>
|
|
531
|
+
```
|
|
532
|
+
<!-- /react-only -->
|
|
533
|
+
|
|
534
|
+
<!-- react-only -->
|
|
535
|
+
## Reusable Transition Component
|
|
536
|
+
|
|
537
|
+
Create a reusable component for transitions:
|
|
538
|
+
|
|
539
|
+
```tsx
|
|
540
|
+
interface TransitionProps {
|
|
541
|
+
children: React.ReactNode;
|
|
542
|
+
type?: "fade" | "slide" | "zoom";
|
|
543
|
+
duration?: string;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const TransitionScene = ({
|
|
547
|
+
children,
|
|
548
|
+
type = "fade",
|
|
549
|
+
duration = "1s"
|
|
550
|
+
}: TransitionProps) => {
|
|
551
|
+
const animations = {
|
|
552
|
+
fade: {
|
|
553
|
+
in: `${duration} fade-in 0s`,
|
|
554
|
+
out: `${duration} fade-out var(--ef-transition-out-start)`,
|
|
555
|
+
},
|
|
556
|
+
slide: {
|
|
557
|
+
in: `${duration} slide-in-right 0s`,
|
|
558
|
+
out: `${duration} slide-out-left var(--ef-transition-out-start)`,
|
|
559
|
+
},
|
|
560
|
+
zoom: {
|
|
561
|
+
in: `${duration} zoom-in 0s`,
|
|
562
|
+
out: `${duration} zoom-out var(--ef-transition-out-start)`,
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
return (
|
|
567
|
+
<Timegroup
|
|
568
|
+
mode="contain"
|
|
569
|
+
className="absolute w-full h-full"
|
|
570
|
+
style={{ animation: `${animations[type].in}, ${animations[type].out}` }}
|
|
571
|
+
>
|
|
572
|
+
{children}
|
|
573
|
+
</Timegroup>
|
|
574
|
+
);
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
// Usage
|
|
578
|
+
<Timegroup mode="sequence" overlap="1s">
|
|
579
|
+
<TransitionScene type="fade">
|
|
580
|
+
<Video src="/assets/clip1.mp4" className="size-full" />
|
|
581
|
+
</TransitionScene>
|
|
582
|
+
<TransitionScene type="slide">
|
|
583
|
+
<Video src="/assets/clip2.mp4" className="size-full" />
|
|
584
|
+
</TransitionScene>
|
|
585
|
+
</Timegroup>
|
|
586
|
+
```
|
|
587
|
+
<!-- /react-only -->
|
|
588
|
+
|
|
589
|
+
## Tips
|
|
590
|
+
|
|
591
|
+
1. **Match durations** - Overlap and animation duration should be equal
|
|
592
|
+
2. **Use contain mode** - Wrap clips in `mode="contain"` timegroups
|
|
593
|
+
<!-- html-only -->
|
|
594
|
+
3. **Absolute positioning** - Add `class="absolute w-full h-full"` for overlays
|
|
595
|
+
<!-- /html-only -->
|
|
596
|
+
<!-- react-only -->
|
|
597
|
+
3. **Absolute positioning** - Add `className="absolute w-full h-full"` for overlays
|
|
598
|
+
<!-- /react-only -->
|
|
599
|
+
4. **Test transitions** - Preview to ensure smooth timing
|
|
600
|
+
5. **Combine effects** - Mix opacity, transform, and filter for complex transitions
|
|
601
|
+
<!-- react-only -->
|
|
602
|
+
6. **Extract to components** - Create reusable transition components
|
|
603
|
+
<!-- /react-only -->
|
|
604
|
+
|
|
605
|
+
## See Also
|
|
606
|
+
|
|
607
|
+
- [css-variables.md](references/css-variables.md) - CSS variables reference
|
|
608
|
+
- [timegroup.md](references/timegroup.md) - Timegroup <!-- html-only -->modes and sequencing<!-- /html-only --><!-- react-only -->component reference<!-- /react-only -->
|