@editframe/create 0.51.9 → 0.52.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.
@@ -38,20 +38,26 @@ react:
38
38
  ---
39
39
 
40
40
  <!-- html-only -->
41
+
41
42
  # ef-configuration
43
+
42
44
  <!-- /html-only -->
43
45
  <!-- react-only -->
46
+
44
47
  # Configuration
48
+
45
49
  <!-- /react-only -->
46
50
 
47
51
  Configuration wrapper for media engine selection and API settings.
48
52
 
49
53
  <!-- react-only -->
54
+
50
55
  ## Import
51
56
 
52
57
  ```tsx
53
58
  import { Configuration } from "@editframe/react";
54
59
  ```
60
+
55
61
  <!-- /react-only -->
56
62
 
57
63
  ## Basic Usage
@@ -59,15 +65,21 @@ import { Configuration } from "@editframe/react";
59
65
  Wrap your composition to configure media handling:
60
66
 
61
67
  <!-- html-only -->
68
+
62
69
  ```html
63
70
  <ef-configuration media-engine="cloud">
64
71
  <ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black">
65
- <ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full"></ef-video>
72
+ <ef-video
73
+ src="https://assets.editframe.com/bars-n-tone.mp4"
74
+ class="size-full"
75
+ ></ef-video>
66
76
  </ef-timegroup>
67
77
  </ef-configuration>
68
78
  ```
79
+
69
80
  <!-- /html-only -->
70
81
  <!-- react-only -->
82
+
71
83
  ```tsx
72
84
  // Video.tsx
73
85
  import { Timegroup } from "@editframe/react";
@@ -88,38 +100,50 @@ import { Video } from "./Video";
88
100
  ReactDOM.createRoot(document.getElementById("root")!).render(
89
101
  <Configuration apiHost="https://api.example.com" mediaEngine="local">
90
102
  <TimelineRoot id="root" component={Video} />
91
- </Configuration>
103
+ </Configuration>,
92
104
  );
93
105
  ```
106
+
94
107
  <!-- /react-only -->
95
108
 
96
109
  ## Media Engine Options
97
110
 
98
111
  <!-- html-only -->
112
+
99
113
  The `media-engine` attribute controls how media files are loaded and processed.
114
+
100
115
  <!-- /html-only -->
101
116
  <!-- react-only -->
117
+
102
118
  Controls how media files are loaded and processed. Three options are available:
119
+
103
120
  <!-- /react-only -->
104
121
 
105
122
  ### Cloud Mode (Default)
106
123
 
107
124
  Automatically selects the appropriate engine based on URL:
125
+
108
126
  - Remote URLs (`http://`, `https://`) use JIT transcoding
109
127
  - Local paths use asset engine
110
128
 
111
129
  <!-- html-only -->
130
+
112
131
  ```html live
113
132
  <ef-configuration media-engine="cloud">
114
133
  <ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black">
115
- <ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
134
+ <ef-video
135
+ src="https://assets.editframe.com/bars-n-tone.mp4"
136
+ class="size-full object-contain"
137
+ ></ef-video>
116
138
  </ef-timegroup>
117
139
  </ef-configuration>
118
140
  ```
119
141
 
120
142
  **Use when:** Building production applications with mixed local and remote assets.
143
+
121
144
  <!-- /html-only -->
122
145
  <!-- react-only -->
146
+
123
147
  ```tsx
124
148
  <Configuration mediaEngine="cloud">
125
149
  <Timegroup mode="sequence">
@@ -128,6 +152,7 @@ Automatically selects the appropriate engine based on URL:
128
152
  </Timegroup>
129
153
  </Configuration>
130
154
  ```
155
+
131
156
  <!-- /react-only -->
132
157
 
133
158
  ### Local Mode
@@ -135,6 +160,7 @@ Automatically selects the appropriate engine based on URL:
135
160
  Forces all sources through the local asset engine using `@ef-*` URLs:
136
161
 
137
162
  <!-- html-only -->
163
+
138
164
  ```html
139
165
  <ef-configuration media-engine="local">
140
166
  <ef-timegroup mode="contain" class="w-[720px] h-[480px]">
@@ -144,11 +170,12 @@ Forces all sources through the local asset engine using `@ef-*` URLs:
144
170
  ```
145
171
 
146
172
  **Use when:**
173
+
147
174
  - Development with local files only
148
175
  - Testing without network access
149
176
  - Working with bundled assets
150
- <!-- /html-only -->
151
- <!-- react-only -->
177
+ <!-- /html-only -->
178
+ <!-- react-only -->
152
179
  - All sources use local asset endpoints
153
180
  - No transcoding applied
154
181
  - Best for local development with Vite plugin
@@ -160,6 +187,7 @@ Forces all sources through the local asset engine using `@ef-*` URLs:
160
187
  </Timegroup>
161
188
  </Configuration>
162
189
  ```
190
+
163
191
  <!-- /react-only -->
164
192
 
165
193
  ### JIT Mode
@@ -167,6 +195,7 @@ Forces all sources through the local asset engine using `@ef-*` URLs:
167
195
  Forces all sources through JIT transcoding using `/api/v1/transcode/*` URLs:
168
196
 
169
197
  <!-- html-only -->
198
+
170
199
  ```html
171
200
  <ef-configuration media-engine="jit">
172
201
  <ef-timegroup mode="contain" class="w-[720px] h-[480px]">
@@ -176,11 +205,12 @@ Forces all sources through JIT transcoding using `/api/v1/transcode/*` URLs:
176
205
  ```
177
206
 
178
207
  **Use when:**
208
+
179
209
  - On-demand transcoding needed
180
210
  - Working with incompatible video formats
181
211
  - Development with Editframe Vite plugin
182
- <!-- /html-only -->
183
- <!-- react-only -->
212
+ <!-- /html-only -->
213
+ <!-- react-only -->
184
214
  - All sources are transcoded on-demand
185
215
  - Useful for testing transcoding behavior
186
216
  - May have slower initial load
@@ -192,6 +222,7 @@ Forces all sources through JIT transcoding using `/api/v1/transcode/*` URLs:
192
222
  </Timegroup>
193
223
  </Configuration>
194
224
  ```
225
+
195
226
  <!-- /react-only -->
196
227
 
197
228
  ## API Host Override
@@ -201,10 +232,11 @@ When no `ef-configuration` ancestor is present, all source-based elements (`ef-v
201
232
  Use `ef-configuration` with `api-host` when you need to override that default:
202
233
 
203
234
  <!-- html-only -->
235
+
204
236
  Override the API host for asset resolution in production:
205
237
 
206
238
  ```html
207
- <ef-configuration api-host="https://api.editframe.com">
239
+ <ef-configuration api-host="https://editframe.com">
208
240
  <ef-timegroup mode="contain" class="w-[720px] h-[480px]">
209
241
  <ef-video src="video.mp4" class="size-full"></ef-video>
210
242
  </ef-timegroup>
@@ -212,20 +244,20 @@ Override the API host for asset resolution in production:
212
244
  ```
213
245
 
214
246
  **Use when:**
247
+
215
248
  - Deploying to custom domains
216
249
  - Using proxy servers
217
250
  - Testing against staging environments
218
- <!-- /html-only -->
219
- <!-- react-only -->
220
- Set the API endpoint for transcription and rendering:
251
+ <!-- /html-only -->
252
+ <!-- react-only -->
253
+ Set the API endpoint for transcription and rendering:
221
254
 
222
255
  ```tsx
223
- <Configuration apiHost="https://api.editframe.com">
224
- <Timegroup mode="sequence">
225
- {/* Composition */}
226
- </Timegroup>
256
+ <Configuration apiHost="https://editframe.com">
257
+ <Timegroup mode="sequence">{/* Composition */}</Timegroup>
227
258
  </Configuration>
228
259
  ```
260
+
229
261
  <!-- /react-only -->
230
262
 
231
263
  ## Signing URL
@@ -233,6 +265,7 @@ Set the API endpoint for transcription and rendering:
233
265
  Configure the endpoint for generating signed URLs:
234
266
 
235
267
  <!-- html-only -->
268
+
236
269
  ```html
237
270
  <ef-configuration signing-url="/api/sign-url">
238
271
  <ef-timegroup mode="contain" class="w-[720px] h-[480px]">
@@ -242,35 +275,37 @@ Configure the endpoint for generating signed URLs:
242
275
  ```
243
276
 
244
277
  **Use when:**
278
+
245
279
  - Custom authentication flows
246
280
  - Non-standard URL signing
247
281
  - Backend integration requirements
248
- <!-- /html-only -->
249
- <!-- react-only -->
250
- Defaults to `/@ef-sign-url`:
282
+ <!-- /html-only -->
283
+ <!-- react-only -->
284
+ Defaults to `/@ef-sign-url`:
251
285
 
252
286
  ```tsx
253
287
  <Configuration
254
288
  apiHost="https://api.example.com"
255
289
  signingURL="/custom-signing-endpoint"
256
290
  >
257
- <Timegroup mode="sequence">
258
- {/* Composition */}
259
- </Timegroup>
291
+ <Timegroup mode="sequence">{/* Composition */}</Timegroup>
260
292
  </Configuration>
261
293
  ```
262
294
 
263
295
  The signing URL is used to:
296
+
264
297
  - Generate signed URLs for secure media access
265
298
  - Authenticate transcoding requests
266
299
  - Control access to media files
267
300
 
268
301
  In development, the Vite plugin provides this endpoint automatically.
302
+
269
303
  <!-- /react-only -->
270
304
 
271
305
  ## Development vs Production
272
306
 
273
307
  <!-- html-only -->
308
+
274
309
  ### Local Development Setup
275
310
 
276
311
  Use `local` mode with Vite plugin for fast iteration:
@@ -290,12 +325,17 @@ Use `cloud` mode with custom API host:
290
325
  ```html
291
326
  <ef-configuration media-engine="cloud" api-host="https://api.yourdomain.com">
292
327
  <ef-timegroup mode="contain" class="w-[720px] h-[480px]">
293
- <ef-video src="https://cdn.yourdomain.com/video.mp4" class="size-full"></ef-video>
328
+ <ef-video
329
+ src="https://cdn.yourdomain.com/video.mp4"
330
+ class="size-full"
331
+ ></ef-video>
294
332
  </ef-timegroup>
295
333
  </ef-configuration>
296
334
  ```
335
+
297
336
  <!-- /html-only -->
298
337
  <!-- react-only -->
338
+
299
339
  ```tsx
300
340
  const apiHost = import.meta.env.VITE_API_HOST || "http://localhost:3000";
301
341
  const mediaEngine = import.meta.env.PROD ? "cloud" : "local";
@@ -310,11 +350,13 @@ export const Video = () => {
310
350
  );
311
351
  };
312
352
  ```
353
+
313
354
  <!-- /react-only -->
314
355
 
315
356
  ## Context Provision
316
357
 
317
358
  <!-- html-only -->
359
+
318
360
  `ef-configuration` provides settings via Lit context to all descendant elements. This means you only need one configuration wrapper at the root level:
319
361
 
320
362
  ```html
@@ -327,8 +369,10 @@ export const Video = () => {
327
369
  </ef-timegroup>
328
370
  </ef-configuration>
329
371
  ```
372
+
330
373
  <!-- /html-only -->
331
374
  <!-- react-only -->
375
+
332
376
  If you don't need API features (transcription) or want default settings, you can omit Configuration:
333
377
 
334
378
  ```tsx
@@ -340,18 +384,23 @@ export const Video = () => {
340
384
  );
341
385
  };
342
386
  ```
387
+
343
388
  <!-- /react-only -->
344
389
 
345
390
  ## Multiple Configurations
346
391
 
347
392
  <!-- html-only -->
393
+
348
394
  Nest configurations to override settings for specific subtrees:
349
395
 
350
396
  ```html
351
397
  <ef-configuration media-engine="cloud">
352
398
  <ef-timegroup mode="sequence" class="w-[720px] h-[480px]">
353
399
  <!-- Remote video uses cloud mode -->
354
- <ef-video src="https://cdn.example.com/intro.mp4" class="size-full"></ef-video>
400
+ <ef-video
401
+ src="https://cdn.example.com/intro.mp4"
402
+ class="size-full"
403
+ ></ef-video>
355
404
 
356
405
  <!-- Local videos use local mode -->
357
406
  <ef-configuration media-engine="local">
@@ -362,8 +411,10 @@ Nest configurations to override settings for specific subtrees:
362
411
  ```
363
412
 
364
413
  > **Note:** Inner configurations override outer settings only for their descendants. Settings merge — unspecified attributes inherit from parent configuration.
414
+
365
415
  <!-- /html-only -->
366
416
  <!-- react-only -->
417
+
367
418
  ## Typical Setup
368
419
 
369
420
  ```tsx
@@ -372,11 +423,7 @@ import { Timegroup, Video, Audio } from "@editframe/react";
372
423
 
373
424
  export const VideoComposition = () => {
374
425
  return (
375
- <Timegroup
376
-
377
- mode="sequence"
378
- className="w-[1920px] h-[1080px] bg-black"
379
- >
426
+ <Timegroup mode="sequence" className="w-[1920px] h-[1080px] bg-black">
380
427
  <Timegroup mode="fixed" duration="10s" className="absolute w-full h-full">
381
428
  <Video src="/assets/intro.mp4" className="size-full object-cover" />
382
429
  <Audio src="/assets/music.mp3" volume={0.3} />
@@ -397,7 +444,8 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
397
444
  mediaEngine="local"
398
445
  >
399
446
  <TimelineRoot id="root" component={VideoComposition} />
400
- </Configuration>
447
+ </Configuration>,
401
448
  );
402
449
  ```
450
+
403
451
  <!-- /react-only -->
@@ -128,8 +128,14 @@ interface TrimValue {
128
128
  **Example: Listen to trim changes**
129
129
 
130
130
  ```html live
131
- <ef-configuration apiHost="https://api.editframe.com">
132
- <ef-timegroup id="composition" duration="5000" width="1920" height="1080" background="black">
131
+ <ef-configuration apiHost="https://editframe.com">
132
+ <ef-timegroup
133
+ id="composition"
134
+ duration="5000"
135
+ width="1920"
136
+ height="1080"
137
+ background="black"
138
+ >
133
139
  <ef-video
134
140
  id="video1"
135
141
  src="https://assets.editframe.com/sample-5s.mp4"
@@ -145,15 +151,17 @@ interface TrimValue {
145
151
  ></ef-trim-handles>
146
152
 
147
153
  <script>
148
- document.querySelector('ef-trim-handles').addEventListener('trim-change', (e) => {
149
- const { type, value } = e.detail;
150
- console.log(`Trim ${type}: ${value.startMs}ms - ${value.endMs}ms`);
151
-
152
- // Update video element
153
- const video = document.getElementById('video1');
154
- video.trimStartMs = value.startMs;
155
- video.trimEndMs = value.endMs;
156
- });
154
+ document
155
+ .querySelector("ef-trim-handles")
156
+ .addEventListener("trim-change", (e) => {
157
+ const { type, value } = e.detail;
158
+ console.log(`Trim ${type}: ${value.startMs}ms - ${value.endMs}ms`);
159
+
160
+ // Update video element
161
+ const video = document.getElementById("video1");
162
+ video.trimStartMs = value.startMs;
163
+ video.trimEndMs = value.endMs;
164
+ });
157
165
  </script>
158
166
  </ef-configuration>
159
167
  ```
@@ -220,9 +228,9 @@ interface DialChangeDetail {
220
228
  <ef-dial value="45"></ef-dial>
221
229
 
222
230
  <script>
223
- document.querySelector('ef-dial').addEventListener('change', (e) => {
231
+ document.querySelector("ef-dial").addEventListener("change", (e) => {
224
232
  const { value } = e.detail;
225
- console.log('Dial rotation:', value, '°');
233
+ console.log("Dial rotation:", value, "°");
226
234
 
227
235
  // Apply rotation to element
228
236
  targetElement.style.transform = `rotate(${value}deg)`;
@@ -242,9 +250,9 @@ Fired by `ef-scrubber` when the playhead position changes. Detail contains the n
242
250
  <ef-scrubber target="composition"></ef-scrubber>
243
251
 
244
252
  <script>
245
- document.querySelector('ef-scrubber').addEventListener('seek', (e) => {
253
+ document.querySelector("ef-scrubber").addEventListener("seek", (e) => {
246
254
  const timeMs = e.detail;
247
- console.log('Seek to:', timeMs, 'ms');
255
+ console.log("Seek to:", timeMs, "ms");
248
256
  });
249
257
  </script>
250
258
  ```
@@ -270,17 +278,19 @@ interface ScrubSegmentLoadingDetail {
270
278
  <div id="progress" style="display: none;">Loading scrub preview...</div>
271
279
 
272
280
  <script>
273
- document.getElementById('myVideo').addEventListener('scrub-segment-loading', (e) => {
274
- const { loaded, total, status } = e.detail;
275
- const progressEl = document.getElementById('progress');
276
-
277
- if (status === 'loading') {
278
- progressEl.style.display = 'block';
279
- progressEl.textContent = `Loading ${loaded}/${total}...`;
280
- } else {
281
- progressEl.style.display = 'none';
282
- }
283
- });
281
+ document
282
+ .getElementById("myVideo")
283
+ .addEventListener("scrub-segment-loading", (e) => {
284
+ const { loaded, total, status } = e.detail;
285
+ const progressEl = document.getElementById("progress");
286
+
287
+ if (status === "loading") {
288
+ progressEl.style.display = "block";
289
+ progressEl.textContent = `Loading ${loaded}/${total}...`;
290
+ } else {
291
+ progressEl.style.display = "none";
292
+ }
293
+ });
284
294
  </script>
285
295
  ```
286
296
 
@@ -329,16 +339,18 @@ interface HierarchySelectDetail {
329
339
  <ef-hierarchy target="composition"></ef-hierarchy>
330
340
 
331
341
  <script>
332
- document.querySelector('ef-hierarchy').addEventListener('hierarchy-select', (e) => {
333
- const { elementId } = e.detail;
334
-
335
- // Update canvas selection
336
- const canvas = document.querySelector('ef-canvas');
337
- const element = document.getElementById(elementId);
338
- if (element) {
339
- canvas.selectElement(element);
340
- }
341
- });
342
+ document
343
+ .querySelector("ef-hierarchy")
344
+ .addEventListener("hierarchy-select", (e) => {
345
+ const { elementId } = e.detail;
346
+
347
+ // Update canvas selection
348
+ const canvas = document.querySelector("ef-canvas");
349
+ const element = document.getElementById(elementId);
350
+ if (element) {
351
+ canvas.selectElement(element);
352
+ }
353
+ });
342
354
  </script>
343
355
  ```
344
356
 
@@ -358,20 +370,22 @@ interface HierarchyReorderDetail {
358
370
 
359
371
  ```html
360
372
  <script>
361
- document.querySelector('ef-hierarchy').addEventListener('hierarchy-reorder', (e) => {
362
- const { sourceId, targetId, position } = e.detail;
363
-
364
- const source = document.getElementById(sourceId);
365
- const target = document.getElementById(targetId);
366
-
367
- if (position === 'before') {
368
- target.parentElement.insertBefore(source, target);
369
- } else if (position === 'after') {
370
- target.parentElement.insertBefore(source, target.nextSibling);
371
- } else if (position === 'inside') {
372
- target.appendChild(source);
373
- }
374
- });
373
+ document
374
+ .querySelector("ef-hierarchy")
375
+ .addEventListener("hierarchy-reorder", (e) => {
376
+ const { sourceId, targetId, position } = e.detail;
377
+
378
+ const source = document.getElementById(sourceId);
379
+ const target = document.getElementById(targetId);
380
+
381
+ if (position === "before") {
382
+ target.parentElement.insertBefore(source, target);
383
+ } else if (position === "after") {
384
+ target.parentElement.insertBefore(source, target.nextSibling);
385
+ } else if (position === "inside") {
386
+ target.appendChild(source);
387
+ }
388
+ });
375
389
  </script>
376
390
  ```
377
391
 
@@ -451,8 +465,8 @@ All custom events are dispatched with `bubbles: true` and `composed: true`, allo
451
465
 
452
466
  <script>
453
467
  // Can listen at any ancestor level
454
- document.getElementById('app').addEventListener('row-select', (e) => {
455
- console.log('Row selected:', e.detail.elementId);
468
+ document.getElementById("app").addEventListener("row-select", (e) => {
469
+ console.log("Row selected:", e.detail.elementId);
456
470
  });
457
471
  </script>
458
472
  ```
@@ -476,13 +490,13 @@ Many events are designed to work together for coordinated UI updates:
476
490
 
477
491
  ```typescript
478
492
  // Coordinate timeline selection with canvas
479
- hierarchy.addEventListener('hierarchy-select', (e) => {
493
+ hierarchy.addEventListener("hierarchy-select", (e) => {
480
494
  const element = document.getElementById(e.detail.elementId);
481
495
  canvas.selectElement(element);
482
496
  });
483
497
 
484
498
  // Coordinate canvas selection with transform handles
485
- canvas.addEventListener('selectionchange', (e) => {
499
+ canvas.addEventListener("selectionchange", (e) => {
486
500
  const selected = Array.from(e.detail.selection)[0];
487
501
  if (selected) {
488
502
  transformHandles.bounds = getBoundsFromElement(selected);
@@ -34,7 +34,7 @@ Access the data inside the composition with `getRenderData()`:
34
34
 
35
35
  const data = getRenderData();
36
36
  if (data) {
37
- document.querySelector('ef-text').textContent = data.title;
37
+ document.querySelector("ef-text").textContent = data.title;
38
38
  }
39
39
  </script>
40
40
  ```
@@ -47,15 +47,15 @@ The browser path uses the WebCodecs API for video encoding and FFmpeg.wasm for m
47
47
 
48
48
  ```html
49
49
  <script type="module">
50
- const timegroup = document.querySelector('ef-timegroup');
50
+ const timegroup = document.querySelector("ef-timegroup");
51
51
 
52
52
  await timegroup.renderToVideo({
53
53
  fps: 30,
54
- codec: 'avc',
55
- filename: 'export.mp4',
54
+ codec: "avc",
55
+ filename: "export.mp4",
56
56
  onProgress: (progress) => {
57
57
  console.log(`${Math.round(progress.progress * 100)}%`);
58
- }
58
+ },
59
59
  });
60
60
  </script>
61
61
  ```
@@ -64,7 +64,7 @@ Browser support: Chrome 94+, Edge 94+, Safari 16.4+. Check availability at runti
64
64
 
65
65
  ```html
66
66
  <script type="module">
67
- const supported = 'VideoEncoder' in window && 'VideoDecoder' in window;
67
+ const supported = "VideoEncoder" in window && "VideoDecoder" in window;
68
68
  </script>
69
69
  ```
70
70
 
@@ -76,7 +76,7 @@ The cloud path uploads the composition bundle to a server, which processes it wi
76
76
 
77
77
  ```bash
78
78
  # POST composition bundle to render API
79
- curl -X POST https://api.editframe.com/v1/renders \
79
+ curl -X POST https://editframe.com/v1/renders \
80
80
  -H "Authorization: Bearer $API_KEY" \
81
81
  -F "bundle=@composition.tgz"
82
82
  ```
@@ -85,16 +85,16 @@ Results are delivered via webhook or polling. The cloud path is suited for produ
85
85
 
86
86
  ## Comparison
87
87
 
88
- | Aspect | CLI (Playwright) | Browser (WebCodecs) | Cloud (API) |
89
- |--------|-------------------|---------------------|-------------|
90
- | Runs in | Local machine | User's browser | Remote server |
91
- | Encoding | Server-side FFmpeg | WebCodecs + FFmpeg.wasm | Server-side FFmpeg |
92
- | Audio muxing | Automatic | Automatic | Automatic |
93
- | Dynamic data | `--data` flag | JavaScript state | Request payload |
94
- | Progress feedback | Terminal output | `onProgress` callback | Webhook / polling |
95
- | Browser required | Playwright (headless) | User's browser | None (server-side) |
96
- | Codec control | Full FFmpeg options | Browser-supported codecs | Full FFmpeg options |
97
- | Concurrent renders | Limited by local CPU | One per tab | Scales with infrastructure |
88
+ | Aspect | CLI (Playwright) | Browser (WebCodecs) | Cloud (API) |
89
+ | ------------------ | --------------------- | ------------------------ | -------------------------- |
90
+ | Runs in | Local machine | User's browser | Remote server |
91
+ | Encoding | Server-side FFmpeg | WebCodecs + FFmpeg.wasm | Server-side FFmpeg |
92
+ | Audio muxing | Automatic | Automatic | Automatic |
93
+ | Dynamic data | `--data` flag | JavaScript state | Request payload |
94
+ | Progress feedback | Terminal output | `onProgress` callback | Webhook / polling |
95
+ | Browser required | Playwright (headless) | User's browser | None (server-side) |
96
+ | Codec control | Full FFmpeg options | Browser-supported codecs | Full FFmpeg options |
97
+ | Concurrent renders | Limited by local CPU | One per tab | Scales with infrastructure |
98
98
 
99
99
  ## Architecture Differences
100
100
 
@@ -7,9 +7,9 @@
7
7
  "start": "editframe preview"
8
8
  },
9
9
  "dependencies": {
10
- "@editframe/cli": "0.51.9",
11
- "@editframe/elements": "0.51.9",
12
- "@editframe/vite-plugin": "0.51.9",
10
+ "@editframe/cli": "0.52.1",
11
+ "@editframe/elements": "0.52.1",
12
+ "@editframe/vite-plugin": "0.52.1",
13
13
  "@tailwindcss/vite": "^4.0.0",
14
14
  "tailwindcss": "^4.0.0",
15
15
  "vite": "^8.0.0",
@@ -1,15 +1,12 @@
1
1
  import { withEditframe } from "@editframe/nextjs-plugin";
2
2
 
3
- // Ensure ffprobe/ffmpeg are reachable — Homebrew installs to /opt/homebrew/bin
4
- process.env.PATH = `/opt/homebrew/bin:${process.env.PATH}`;
5
-
6
3
  /** @type {import('next').NextConfig} */
7
4
  const nextConfig = {};
8
5
 
9
6
  export default withEditframe(
10
7
  {
11
- root: "./public",
12
- cacheRoot: "./cache",
8
+ root: "./src",
9
+ cacheRoot: "./src/assets/cache",
13
10
  },
14
11
  nextConfig,
15
12
  );
@@ -7,9 +7,9 @@
7
7
  "dev": "next dev"
8
8
  },
9
9
  "dependencies": {
10
- "@editframe/elements": "0.51.9",
11
- "@editframe/nextjs-plugin": "0.51.9",
12
- "@editframe/react": "0.51.9",
10
+ "@editframe/elements": "0.52.1",
11
+ "@editframe/nextjs-plugin": "0.52.1",
12
+ "@editframe/react": "0.52.1",
13
13
  "next": "^16.0.0",
14
14
  "react": "^19.0.0",
15
15
  "react-dom": "^19.0.0"
@@ -5,11 +5,7 @@ export const metadata: Metadata = {
5
5
  title: "Editframe Project",
6
6
  };
7
7
 
8
- export default function RootLayout({
9
- children,
10
- }: {
11
- children: React.ReactNode;
12
- }) {
8
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
13
9
  return (
14
10
  <html lang="en">
15
11
  <body>{children}</body>
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Timegroup, Text } from "@editframe/react";
3
+ import { Timegroup, Video } from "@editframe/react";
4
4
 
5
5
  export default function Home() {
6
6
  return (
@@ -13,15 +13,9 @@ export default function Home() {
13
13
  background: "#0f172a",
14
14
  }}
15
15
  >
16
- <Timegroup
17
- workbench
18
- mode="sequence"
19
- style={{ width: "1920px", height: "1080px" }}
20
- >
16
+ <Timegroup workbench mode="sequence" style={{ width: "1920px", height: "1080px" }}>
21
17
  {/* Add your composition here */}
22
18
  <Timegroup
23
- mode="fixed"
24
- duration="5s"
25
19
  style={{
26
20
  position: "absolute",
27
21
  width: "100%",
@@ -32,9 +26,7 @@ export default function Home() {
32
26
  background: "black",
33
27
  }}
34
28
  >
35
- <Text duration="5s" style={{ color: "white", fontSize: "4rem" }}>
36
- Your video starts here
37
- </Text>
29
+ <Video src="https://assets.editframe.com/bars-n-tone.mp4" />
38
30
  </Timegroup>
39
31
  </Timegroup>
40
32
  </main>
@@ -7,9 +7,9 @@
7
7
  "start": "editframe preview"
8
8
  },
9
9
  "dependencies": {
10
- "@editframe/cli": "0.51.9",
11
- "@editframe/react": "0.51.9",
12
- "@editframe/vite-plugin": "0.51.9",
10
+ "@editframe/cli": "0.52.1",
11
+ "@editframe/react": "0.52.1",
12
+ "@editframe/vite-plugin": "0.52.1",
13
13
  "@tailwindcss/vite": "^4.0.0",
14
14
  "@vitejs/plugin-react": "^6.0.0",
15
15
  "tailwindcss": "^4.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/create",
3
- "version": "0.51.9",
3
+ "version": "0.52.1",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "create-editframe": "dist/index.js"