@editframe/create 0.44.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.
- 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,580 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: React Three Fiber Integration
|
|
3
|
+
description: Integrate React Three Fiber 3D scenes into Editframe compositions with frame-accurate scrubbing and video export support.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Advanced"
|
|
7
|
+
priority: 20
|
|
8
|
+
api:
|
|
9
|
+
components:
|
|
10
|
+
- name: OffscreenCompositionCanvas
|
|
11
|
+
description: R3F canvas that renders in a web worker via OffscreenCanvas
|
|
12
|
+
props:
|
|
13
|
+
- name: worker
|
|
14
|
+
type: Worker
|
|
15
|
+
required: true
|
|
16
|
+
description: Web worker that will handle R3F rendering
|
|
17
|
+
- name: fallback
|
|
18
|
+
type: React.ReactNode
|
|
19
|
+
description: Fallback content for browsers without OffscreenCanvas support
|
|
20
|
+
- name: containerStyle
|
|
21
|
+
type: React.CSSProperties
|
|
22
|
+
description: Extra styles for the container div
|
|
23
|
+
- name: containerClassName
|
|
24
|
+
type: string
|
|
25
|
+
description: Extra className for the container div
|
|
26
|
+
- name: canvasProps
|
|
27
|
+
type: CanvasProps
|
|
28
|
+
description: Canvas props to forward to R3F Canvas (shadows, dpr, gl, camera, scene, etc.)
|
|
29
|
+
- name: CompositionCanvas
|
|
30
|
+
description: R3F canvas that renders on the main thread with timeline synchronization
|
|
31
|
+
props:
|
|
32
|
+
- name: children
|
|
33
|
+
type: React.ReactNode
|
|
34
|
+
required: true
|
|
35
|
+
description: R3F scene content
|
|
36
|
+
- name: containerStyle
|
|
37
|
+
type: React.CSSProperties
|
|
38
|
+
description: Extra styles for the container div
|
|
39
|
+
- name: containerClassName
|
|
40
|
+
type: string
|
|
41
|
+
description: Extra className for the container div
|
|
42
|
+
- name: gl
|
|
43
|
+
type: object
|
|
44
|
+
description: WebGL renderer options (automatically includes preserveDrawingBuffer)
|
|
45
|
+
hooks:
|
|
46
|
+
- name: useCompositionTime
|
|
47
|
+
signature: "useCompositionTime(): { timeMs: number; durationMs: number }"
|
|
48
|
+
description: Hook to read current composition time inside an R3F scene
|
|
49
|
+
returns: "{ timeMs, durationMs }"
|
|
50
|
+
functions:
|
|
51
|
+
- name: renderOffscreen
|
|
52
|
+
signature: "renderOffscreen(children: React.ReactNode): void"
|
|
53
|
+
description: Worker-side entry point for offscreen R3F rendering
|
|
54
|
+
returns: void
|
|
55
|
+
react:
|
|
56
|
+
generate: true
|
|
57
|
+
componentName: "React Three Fiber Integration"
|
|
58
|
+
importPath: "@editframe/react/r3f"
|
|
59
|
+
nav:
|
|
60
|
+
parent: "Advanced / 3D Integration"
|
|
61
|
+
priority: 80
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
# React Three Fiber Integration
|
|
65
|
+
|
|
66
|
+
<!-- html-only -->
|
|
67
|
+
Editframe provides first-class integration with React Three Fiber (R3F) for rendering 3D scenes in video compositions. Import from `@editframe/react/r3f` to access components and utilities for synchronizing Three.js animations with your timeline.
|
|
68
|
+
<!-- /html-only -->
|
|
69
|
+
<!-- react-only -->
|
|
70
|
+
Editframe provides first-class integration with React Three Fiber (R3F) for rendering 3D scenes in video compositions.
|
|
71
|
+
<!-- /react-only -->
|
|
72
|
+
|
|
73
|
+
## Import
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import {
|
|
77
|
+
CompositionCanvas,
|
|
78
|
+
OffscreenCompositionCanvas,
|
|
79
|
+
useCompositionTime
|
|
80
|
+
} from "@editframe/react/r3f";
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## CompositionCanvas
|
|
84
|
+
|
|
85
|
+
<!-- html-only -->
|
|
86
|
+
Renders a React Three Fiber scene on the main thread with automatic timeline synchronization.
|
|
87
|
+
<!-- /html-only -->
|
|
88
|
+
<!-- react-only -->
|
|
89
|
+
Main-thread R3F canvas that automatically synchronizes with Editframe's timeline.
|
|
90
|
+
<!-- /react-only -->
|
|
91
|
+
|
|
92
|
+
### Basic Usage
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { Timegroup } from "@editframe/react";
|
|
96
|
+
import { CompositionCanvas, useCompositionTime } from "@editframe/react/r3f";
|
|
97
|
+
import { Box } from "@react-three/drei";
|
|
98
|
+
|
|
99
|
+
function RotatingBox() {
|
|
100
|
+
const { timeMs } = useCompositionTime();
|
|
101
|
+
const rotation = (timeMs / 1000) * Math.PI * 2; // Full rotation per second
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Box rotation={[0, rotation, 0]}>
|
|
105
|
+
<meshStandardMaterial color="orange" />
|
|
106
|
+
</Box>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const Video = () => {
|
|
111
|
+
return (
|
|
112
|
+
<Timegroup mode="fixed" duration="5s" className="w-[1920px] h-[1080px]">
|
|
113
|
+
<CompositionCanvas shadows>
|
|
114
|
+
<ambientLight intensity={0.5} />
|
|
115
|
+
<pointLight position={[10, 10, 10]} />
|
|
116
|
+
<RotatingBox />
|
|
117
|
+
</CompositionCanvas>
|
|
118
|
+
</Timegroup>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Features
|
|
124
|
+
|
|
125
|
+
- **Automatic Time Sync:** Integrates with `ef-timegroup`'s `addFrameTask` to synchronize 3D animations with your timeline
|
|
126
|
+
- **Deterministic Rendering:** Uses `frameloop="demand"` for frame-by-frame rendering during video export
|
|
127
|
+
- **WebGL Sync:** Calls `gl.finish()` after each frame to ensure all GPU commands complete before capture
|
|
128
|
+
- **Preserves Drawing Buffer:** Automatically sets `preserveDrawingBuffer: true` for video export
|
|
129
|
+
|
|
130
|
+
<!-- react-only -->
|
|
131
|
+
### Timeline Synchronization
|
|
132
|
+
|
|
133
|
+
`CompositionCanvas` automatically:
|
|
134
|
+
- Registers with parent `<Timegroup>` via `addFrameTask`
|
|
135
|
+
- Updates 3D scene on every frame
|
|
136
|
+
- Provides current time via `useCompositionTime()` hook
|
|
137
|
+
- Ensures deterministic frame-by-frame rendering
|
|
138
|
+
<!-- /react-only -->
|
|
139
|
+
|
|
140
|
+
### useCompositionTime Hook
|
|
141
|
+
|
|
142
|
+
Access the current composition time inside your R3F scene:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
function AnimatedSphere() {
|
|
146
|
+
const { timeMs, durationMs } = useCompositionTime();
|
|
147
|
+
const progress = timeMs / durationMs; // 0 to 1
|
|
148
|
+
const scale = 1 + Math.sin(progress * Math.PI * 2) * 0.5;
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<mesh scale={[scale, scale, scale]}>
|
|
152
|
+
<sphereGeometry args={[1, 32, 32]} />
|
|
153
|
+
<meshStandardMaterial color="hotpink" />
|
|
154
|
+
</mesh>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
<!-- react-only -->
|
|
160
|
+
**Returns:**
|
|
161
|
+
- `timeMs` - Current time in milliseconds (relative to this timegroup)
|
|
162
|
+
- `durationMs` - Total duration in milliseconds
|
|
163
|
+
<!-- /react-only -->
|
|
164
|
+
|
|
165
|
+
### Custom WebGL Options
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<CompositionCanvas
|
|
169
|
+
shadows
|
|
170
|
+
gl={{
|
|
171
|
+
antialias: true,
|
|
172
|
+
alpha: true,
|
|
173
|
+
// preserveDrawingBuffer is automatically added
|
|
174
|
+
}}
|
|
175
|
+
camera={{ position: [0, 0, 5], fov: 75 }}
|
|
176
|
+
<!-- react-only -->
|
|
177
|
+
scene={{ background: new THREE.Color("#000000") }}
|
|
178
|
+
<!-- /react-only -->
|
|
179
|
+
>
|
|
180
|
+
{/* Scene content */}
|
|
181
|
+
</CompositionCanvas>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
<!-- react-only -->
|
|
185
|
+
**Note:** `preserveDrawingBuffer: true` is automatically set for video export compatibility.
|
|
186
|
+
|
|
187
|
+
### Styling
|
|
188
|
+
|
|
189
|
+
The canvas fills its container absolutely:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
<Timegroup mode="fixed" duration="10s" className="w-[1920px] h-[1080px] bg-black">
|
|
193
|
+
<CompositionCanvas
|
|
194
|
+
containerClassName="rounded-lg"
|
|
195
|
+
containerStyle={{ border: "2px solid white" }}
|
|
196
|
+
>
|
|
197
|
+
{/* Scene */}
|
|
198
|
+
</CompositionCanvas>
|
|
199
|
+
</Timegroup>
|
|
200
|
+
```
|
|
201
|
+
<!-- /react-only -->
|
|
202
|
+
|
|
203
|
+
## OffscreenCompositionCanvas
|
|
204
|
+
|
|
205
|
+
Renders a React Three Fiber scene in a **web worker** using OffscreenCanvas. This keeps the main thread free and enables rendering to continue even when the browser tab is hidden.
|
|
206
|
+
|
|
207
|
+
### Worker Setup
|
|
208
|
+
|
|
209
|
+
Create a worker file:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// scene-worker.ts
|
|
213
|
+
import { renderOffscreen } from "@editframe/react/r3f";
|
|
214
|
+
import { useCompositionTime } from "@editframe/react/r3f";
|
|
215
|
+
import { Box } from "@react-three/drei";
|
|
216
|
+
|
|
217
|
+
function Scene() {
|
|
218
|
+
const { timeMs } = useCompositionTime();
|
|
219
|
+
const rotation = (timeMs / 1000) * Math.PI;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<>
|
|
223
|
+
<ambientLight intensity={0.5} />
|
|
224
|
+
<pointLight position={[10, 10, 10]} />
|
|
225
|
+
<Box rotation={[0, rotation, 0]}>
|
|
226
|
+
<meshStandardMaterial color="cyan" />
|
|
227
|
+
</Box>
|
|
228
|
+
</>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
renderOffscreen(<Scene />);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Component Usage
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { Timegroup } from "@editframe/react";
|
|
239
|
+
import { OffscreenCompositionCanvas } from "@editframe/react/r3f";
|
|
240
|
+
|
|
241
|
+
const worker = new Worker(
|
|
242
|
+
new URL('./scene-worker.ts', import.meta.url),
|
|
243
|
+
{ type: 'module' }
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
export const Video = () => {
|
|
247
|
+
return (
|
|
248
|
+
<Timegroup mode="fixed" duration="10s" className="w-[1920px] h-[1080px]">
|
|
249
|
+
<OffscreenCompositionCanvas
|
|
250
|
+
worker={worker}
|
|
251
|
+
canvasProps={{ shadows: true, dpr: [1, 2] }}
|
|
252
|
+
fallback={
|
|
253
|
+
<div className="flex items-center justify-center w-full h-full">
|
|
254
|
+
<p>OffscreenCanvas not supported</p>
|
|
255
|
+
</div>
|
|
256
|
+
}
|
|
257
|
+
/>
|
|
258
|
+
</Timegroup>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Features
|
|
264
|
+
|
|
265
|
+
- **Web Worker Rendering:** All R3F rendering happens in a separate thread
|
|
266
|
+
- **Background Tab Resilience:** Continues rendering when the browser tab is hidden
|
|
267
|
+
- **Zero-Copy Transfer:** Uses ImageBitmap transfer for efficient pixel data
|
|
268
|
+
- **Automatic Sync:** Integrates with `addFrameTask` for frame-by-frame rendering
|
|
269
|
+
- **Safari Fallback:** Shows fallback content when OffscreenCanvas is unavailable
|
|
270
|
+
|
|
271
|
+
<!-- html-only -->
|
|
272
|
+
### Worker Protocol
|
|
273
|
+
|
|
274
|
+
The worker communicates via structured messages:
|
|
275
|
+
|
|
276
|
+
**Main → Worker:**
|
|
277
|
+
```typescript
|
|
278
|
+
{
|
|
279
|
+
type: 'renderFrame',
|
|
280
|
+
timeMs: number,
|
|
281
|
+
durationMs: number,
|
|
282
|
+
requestId: number
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Worker → Main:**
|
|
287
|
+
```typescript
|
|
288
|
+
{
|
|
289
|
+
type: 'frameRendered',
|
|
290
|
+
requestId: number,
|
|
291
|
+
bitmap: ImageBitmap // Transferred, not copied
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
<!-- /html-only -->
|
|
295
|
+
|
|
296
|
+
### When to Use OffscreenCanvas vs CompositionCanvas
|
|
297
|
+
|
|
298
|
+
**Use OffscreenCompositionCanvas when:**
|
|
299
|
+
- Complex 3D scenes with heavy computation
|
|
300
|
+
- Long render times where main thread responsiveness matters
|
|
301
|
+
- Need guaranteed rendering in background tabs
|
|
302
|
+
- Rendering multiple compositions simultaneously
|
|
303
|
+
|
|
304
|
+
**Use CompositionCanvas when:**
|
|
305
|
+
- Simple 3D scenes
|
|
306
|
+
- Browser compatibility is critical (Safari support)
|
|
307
|
+
- Debugging (easier to inspect in main thread)
|
|
308
|
+
- Using Three.js features incompatible with workers
|
|
309
|
+
<!-- react-only -->
|
|
310
|
+
- Interactive preview with controls
|
|
311
|
+
<!-- /react-only -->
|
|
312
|
+
|
|
313
|
+
<!-- react-only -->
|
|
314
|
+
### Browser Support
|
|
315
|
+
|
|
316
|
+
- **Chrome:** Full support
|
|
317
|
+
- **Firefox:** Full support
|
|
318
|
+
- **Edge:** Full support
|
|
319
|
+
- **Safari:** Not supported (use `fallback` prop)
|
|
320
|
+
|
|
321
|
+
Use the `fallback` prop to provide alternative content for Safari:
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
<OffscreenCompositionCanvas
|
|
325
|
+
worker={worker}
|
|
326
|
+
fallback={
|
|
327
|
+
<CompositionCanvas>
|
|
328
|
+
<MyScene />
|
|
329
|
+
</CompositionCanvas>
|
|
330
|
+
}
|
|
331
|
+
/>
|
|
332
|
+
```
|
|
333
|
+
<!-- /react-only -->
|
|
334
|
+
|
|
335
|
+
## Advanced: <!-- html-only -->Custom<!-- /html-only --><!-- react-only -->Complex<!-- /react-only --> Animations
|
|
336
|
+
|
|
337
|
+
<!-- html-only -->
|
|
338
|
+
Combine `useCompositionTime` with Three.js for complex animations:
|
|
339
|
+
<!-- /html-only -->
|
|
340
|
+
|
|
341
|
+
### Particle System
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
<!-- react-only -->
|
|
345
|
+
import { useRef, useEffect } from "react";
|
|
346
|
+
import { useCompositionTime } from "@editframe/react/r3f";
|
|
347
|
+
import * as THREE from "three";
|
|
348
|
+
|
|
349
|
+
<!-- /react-only -->
|
|
350
|
+
function ParticleSystem() {
|
|
351
|
+
const { timeMs, durationMs } = useCompositionTime();
|
|
352
|
+
const meshRef = useRef<THREE.InstancedMesh>(null);
|
|
353
|
+
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
if (!meshRef.current) return;
|
|
356
|
+
|
|
357
|
+
const count = 1000;
|
|
358
|
+
const dummy = new THREE.Object3D();
|
|
359
|
+
const progress = timeMs / durationMs;
|
|
360
|
+
|
|
361
|
+
for (let i = 0; i < count; i++) {
|
|
362
|
+
const t = progress + (i / count) * 0.1;
|
|
363
|
+
const angle = t * Math.PI * 2;
|
|
364
|
+
const radius = 5 + Math.sin(t * 10) * 2;
|
|
365
|
+
|
|
366
|
+
dummy.position.set(
|
|
367
|
+
Math.cos(angle) * radius,
|
|
368
|
+
Math.sin(t * 5) * 3,
|
|
369
|
+
Math.sin(angle) * radius
|
|
370
|
+
);
|
|
371
|
+
dummy.rotation.set(t * Math.PI, t * Math.PI * 2, 0);
|
|
372
|
+
dummy.updateMatrix();
|
|
373
|
+
|
|
374
|
+
meshRef.current.setMatrixAt(i, dummy.matrix);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
meshRef.current.instanceMatrix.needsUpdate = true;
|
|
378
|
+
}, [timeMs, durationMs]);
|
|
379
|
+
|
|
380
|
+
return (
|
|
381
|
+
<instancedMesh ref={meshRef} args={[undefined, undefined, 1000]}>
|
|
382
|
+
<sphereGeometry args={[0.1, 16, 16]} />
|
|
383
|
+
<meshStandardMaterial color="white" />
|
|
384
|
+
</instancedMesh>
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
<!-- react-only -->
|
|
390
|
+
### Camera Animation
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
import { useThree } from "@react-three/fiber";
|
|
394
|
+
import { useCompositionTime } from "@editframe/react/r3f";
|
|
395
|
+
import { useEffect } from "react";
|
|
396
|
+
|
|
397
|
+
function CameraRig() {
|
|
398
|
+
const { camera } = useThree();
|
|
399
|
+
const { timeMs } = useCompositionTime();
|
|
400
|
+
|
|
401
|
+
useEffect(() => {
|
|
402
|
+
const t = timeMs / 1000;
|
|
403
|
+
camera.position.x = Math.sin(t) * 5;
|
|
404
|
+
camera.position.z = Math.cos(t) * 5;
|
|
405
|
+
camera.lookAt(0, 0, 0);
|
|
406
|
+
}, [timeMs, camera]);
|
|
407
|
+
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Material Animation
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
function AnimatedMaterial() {
|
|
416
|
+
const { timeMs } = useCompositionTime();
|
|
417
|
+
const materialRef = useRef<THREE.MeshStandardMaterial>(null);
|
|
418
|
+
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
if (!materialRef.current) return;
|
|
421
|
+
const hue = (timeMs / 1000) % 1;
|
|
422
|
+
materialRef.current.color.setHSL(hue, 1, 0.5);
|
|
423
|
+
}, [timeMs]);
|
|
424
|
+
|
|
425
|
+
return (
|
|
426
|
+
<mesh>
|
|
427
|
+
<boxGeometry />
|
|
428
|
+
<meshStandardMaterial ref={materialRef} />
|
|
429
|
+
</mesh>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Integration with @react-three/drei
|
|
435
|
+
|
|
436
|
+
Use Drei helpers with Editframe:
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
import { OrbitControls, Environment, ContactShadows } from "@react-three/drei";
|
|
440
|
+
import { CompositionCanvas, useCompositionTime } from "@editframe/react/r3f";
|
|
441
|
+
|
|
442
|
+
function Scene() {
|
|
443
|
+
const { timeMs } = useCompositionTime();
|
|
444
|
+
|
|
445
|
+
return (
|
|
446
|
+
<>
|
|
447
|
+
<OrbitControls enableZoom={false} />
|
|
448
|
+
<Environment preset="sunset" />
|
|
449
|
+
<ContactShadows opacity={0.5} />
|
|
450
|
+
|
|
451
|
+
<Box position={[0, Math.sin(timeMs / 500), 0]} />
|
|
452
|
+
</>
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export const Video = () => {
|
|
457
|
+
return (
|
|
458
|
+
<Timegroup mode="fixed" duration="10s" className="w-[1920px] h-[1080px]">
|
|
459
|
+
<CompositionCanvas>
|
|
460
|
+
<Scene />
|
|
461
|
+
</CompositionCanvas>
|
|
462
|
+
</Timegroup>
|
|
463
|
+
);
|
|
464
|
+
};
|
|
465
|
+
```
|
|
466
|
+
<!-- /react-only -->
|
|
467
|
+
|
|
468
|
+
## Rendering to Video
|
|
469
|
+
|
|
470
|
+
3D scenes render to video just like any other Editframe element:
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
import { Timegroup } from "@editframe/react";
|
|
474
|
+
import { CompositionCanvas } from "@editframe/react/r3f";
|
|
475
|
+
|
|
476
|
+
export const Video = () => {
|
|
477
|
+
return (
|
|
478
|
+
<Timegroup
|
|
479
|
+
mode="fixed"
|
|
480
|
+
duration="10s"
|
|
481
|
+
className="w-[1920px] h-[1080px]"
|
|
482
|
+
>
|
|
483
|
+
<CompositionCanvas>
|
|
484
|
+
{/* Your 3D scene */}
|
|
485
|
+
</CompositionCanvas>
|
|
486
|
+
</Timegroup>
|
|
487
|
+
);
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// Render with CLI
|
|
491
|
+
// npx editframe render ./src/Video.tsx
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
The R3F integration ensures:
|
|
495
|
+
1. Each frame renders synchronously at the correct timeline position
|
|
496
|
+
2. WebGL finishes all commands before frame capture
|
|
497
|
+
3. Deterministic output regardless of playback state
|
|
498
|
+
4. Proper integration with Editframe's rendering pipeline
|
|
499
|
+
|
|
500
|
+
## Browser Support
|
|
501
|
+
|
|
502
|
+
- **CompositionCanvas:** All modern browsers (Chrome, Firefox, Safari, Edge)
|
|
503
|
+
- **OffscreenCompositionCanvas:** Chrome, Firefox, Edge (Safari does not support OffscreenCanvas)
|
|
504
|
+
|
|
505
|
+
<!-- react-only -->
|
|
506
|
+
## Performance Tips
|
|
507
|
+
|
|
508
|
+
1. **Memoize scene components** to avoid unnecessary re-renders:
|
|
509
|
+
```tsx
|
|
510
|
+
const Scene = React.memo(() => {
|
|
511
|
+
const { timeMs } = useCompositionTime();
|
|
512
|
+
// ...
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
2. **Use instancing** for many identical objects:
|
|
517
|
+
```tsx
|
|
518
|
+
<instancedMesh args={[geometry, material, count]} />
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
3. **Limit geometry complexity** during rendering:
|
|
522
|
+
```tsx
|
|
523
|
+
<sphereGeometry args={[1, 16, 16]} /> {/* Lower segments */}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
4. **Disable antialiasing** if not needed:
|
|
527
|
+
```tsx
|
|
528
|
+
<CompositionCanvas gl={{ antialias: false }}>
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Troubleshooting
|
|
532
|
+
|
|
533
|
+
### Scene appears black
|
|
534
|
+
**Problem:** Missing lights or incorrect camera setup.
|
|
535
|
+
|
|
536
|
+
**Solution:**
|
|
537
|
+
```tsx
|
|
538
|
+
<CompositionCanvas>
|
|
539
|
+
<ambientLight intensity={0.5} />
|
|
540
|
+
<pointLight position={[10, 10, 10]} />
|
|
541
|
+
{/* Your scene */}
|
|
542
|
+
</CompositionCanvas>
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Animation stutters during export
|
|
546
|
+
**Problem:** Animations using `useFrame` RAF loop.
|
|
547
|
+
|
|
548
|
+
**Solution:** Use `useCompositionTime()` instead:
|
|
549
|
+
```tsx
|
|
550
|
+
// Don't use useFrame for time-based animations
|
|
551
|
+
useFrame((state) => {
|
|
552
|
+
mesh.rotation.y += 0.01;
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// Use useCompositionTime
|
|
556
|
+
const { timeMs } = useCompositionTime();
|
|
557
|
+
mesh.rotation.y = timeMs / 1000;
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Worker fails to load
|
|
561
|
+
**Problem:** Incorrect worker URL or module type.
|
|
562
|
+
|
|
563
|
+
**Solution:**
|
|
564
|
+
```tsx
|
|
565
|
+
// Correct
|
|
566
|
+
const worker = new Worker(
|
|
567
|
+
new URL('./worker.ts', import.meta.url),
|
|
568
|
+
{ type: 'module' }
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
// Wrong
|
|
572
|
+
const worker = new Worker('./worker.ts');
|
|
573
|
+
```
|
|
574
|
+
<!-- /react-only -->
|
|
575
|
+
|
|
576
|
+
## Related
|
|
577
|
+
|
|
578
|
+
- [timegroup.md](references/timegroup.md) - Timeline container <!-- html-only -->element<!-- /html-only --><!-- react-only -->component<!-- /react-only -->
|
|
579
|
+
- [render-to-video.md](references/render-to-video.md) - Rendering compositions to video
|
|
580
|
+
- [scripting.md](references/scripting.md) - Programmatic element control
|