@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.
Files changed (98) hide show
  1. package/dist/index.js +16 -28
  2. package/dist/index.js.map +1 -1
  3. package/dist/skills/editframe-brand-video-generator/README.md +155 -0
  4. package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
  5. package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
  6. package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
  7. package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
  8. package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
  9. package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
  10. package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
  11. package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
  12. package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
  13. package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
  14. package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
  15. package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
  16. package/dist/skills/editframe-composition/SKILL.md +169 -0
  17. package/dist/skills/editframe-composition/references/audio.md +483 -0
  18. package/dist/skills/editframe-composition/references/captions.md +844 -0
  19. package/dist/skills/editframe-composition/references/composition-model.md +73 -0
  20. package/dist/skills/editframe-composition/references/configuration.md +403 -0
  21. package/dist/skills/editframe-composition/references/css-parts.md +105 -0
  22. package/dist/skills/editframe-composition/references/css-variables.md +640 -0
  23. package/dist/skills/editframe-composition/references/entry-points.md +810 -0
  24. package/dist/skills/editframe-composition/references/events.md +499 -0
  25. package/dist/skills/editframe-composition/references/getting-started.md +259 -0
  26. package/dist/skills/editframe-composition/references/hooks.md +234 -0
  27. package/dist/skills/editframe-composition/references/image.md +241 -0
  28. package/dist/skills/editframe-composition/references/r3f.md +580 -0
  29. package/dist/skills/editframe-composition/references/render-api.md +484 -0
  30. package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
  31. package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
  32. package/dist/skills/editframe-composition/references/scripting.md +606 -0
  33. package/dist/skills/editframe-composition/references/sequencing.md +116 -0
  34. package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
  35. package/dist/skills/editframe-composition/references/surface.md +329 -0
  36. package/dist/skills/editframe-composition/references/text.md +627 -0
  37. package/dist/skills/editframe-composition/references/time-model.md +99 -0
  38. package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
  39. package/dist/skills/editframe-composition/references/timegroup.md +457 -0
  40. package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
  41. package/dist/skills/editframe-composition/references/transcription.md +47 -0
  42. package/dist/skills/editframe-composition/references/transitions.md +608 -0
  43. package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
  44. package/dist/skills/editframe-composition/references/video.md +506 -0
  45. package/dist/skills/editframe-composition/references/waveform.md +327 -0
  46. package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
  47. package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
  48. package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
  49. package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
  50. package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
  51. package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
  52. package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
  53. package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
  54. package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
  55. package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
  56. package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
  57. package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
  58. package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
  59. package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
  60. package/dist/skills/editframe-editor-gui/references/play.md +370 -0
  61. package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
  62. package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
  63. package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
  64. package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
  65. package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
  66. package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
  67. package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
  68. package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
  69. package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
  70. package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
  71. package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
  72. package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
  73. package/dist/skills/editframe-motion-design/SKILL.md +101 -0
  74. package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
  75. package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
  76. package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
  77. package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
  78. package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
  79. package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
  80. package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
  81. package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
  82. package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
  83. package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
  84. package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
  85. package/dist/skills/editframe-webhooks/SKILL.md +126 -0
  86. package/dist/skills/editframe-webhooks/references/events.md +382 -0
  87. package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
  88. package/dist/skills/editframe-webhooks/references/security.md +418 -0
  89. package/dist/skills/editframe-webhooks/references/testing.md +409 -0
  90. package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
  91. package/dist/templates/html/AGENTS.md +13 -0
  92. package/dist/templates/react/AGENTS.md +13 -0
  93. package/dist/utils.js +15 -16
  94. package/dist/utils.js.map +1 -1
  95. package/package.json +1 -1
  96. package/tsdown.config.ts +4 -0
  97. package/dist/detectAgent.js +0 -89
  98. package/dist/detectAgent.js.map +0 -1
@@ -0,0 +1,499 @@
1
+ ---
2
+ title: Custom Events
3
+ description: Catalog of all custom DOM events dispatched by Editframe elements for building interactive player and editor UI components.
4
+ type: reference
5
+ nav:
6
+ parent: "Advanced"
7
+ priority: 50
8
+ api:
9
+ events:
10
+ - name: trim-change
11
+ element: ef-trim-handles
12
+ detail: TrimChangeDetail
13
+ description: Fired when trim handles are dragged
14
+
15
+ - name: trim-change-end
16
+ element: ef-trim-handles
17
+ detail: "{ elementId: string, type: 'start' | 'end' | 'region' }"
18
+ description: Fired when trim handle dragging ends
19
+
20
+ - name: bounds-change
21
+ element: ef-transform-handles, ef-resizable-box
22
+ detail: "{ bounds: TransformBounds }"
23
+ description: Fired when element bounds change through transform handles or resize
24
+
25
+ - name: rotation-change
26
+ element: ef-transform-handles
27
+ detail: "{ rotation: number }"
28
+ description: Fired when rotation handle is dragged
29
+
30
+ - name: change
31
+ element: ef-dial
32
+ detail: DialChangeDetail
33
+ description: Fired when dial value changes
34
+
35
+ - name: seek
36
+ element: ef-scrubber
37
+ detail: number (timeMs)
38
+ description: Fired when scrubber position changes
39
+
40
+ - name: scrub-segment-loading
41
+ element: ef-video
42
+ detail: ScrubSegmentLoadingDetail
43
+ description: Fired during scrub track loading for progress indication
44
+
45
+ - name: hierarchy-select
46
+ element: ef-hierarchy
47
+ detail: "{ elementId: string }"
48
+ description: Fired when an element is selected in the hierarchy
49
+
50
+ - name: hierarchy-reorder
51
+ element: ef-hierarchy
52
+ detail: HierarchyReorderDetail
53
+ description: Fired when elements are reordered via drag and drop
54
+
55
+ - name: tree-select
56
+ element: ef-tree
57
+ detail: TreeSelectDetail
58
+ description: Fired when a tree item is selected
59
+
60
+ - name: row-select
61
+ element: ef-timeline-row
62
+ detail: "{ elementId: string, element: Element }"
63
+ description: Fired when a timeline row is clicked
64
+
65
+ - name: row-hover
66
+ element: ef-timeline-row
67
+ detail: "{ element: Element | null }"
68
+ description: Fired when mouse enters or leaves a timeline row
69
+
70
+ - name: track-trim-change
71
+ element: TrackItem (timeline)
72
+ detail: TrimChangeDetail
73
+ description: Fired when timeline track trim handles change
74
+
75
+ - name: selectionchange
76
+ element: SelectionModel (canvas)
77
+ detail: "{ selection: Set<Element> }"
78
+ description: Fired when canvas selection changes
79
+
80
+ - name: activeroottemporalchange
81
+ element: ef-canvas
82
+ detail: "{ activeRootTemporal: Element | null }"
83
+ description: Fired when active root temporal changes
84
+
85
+ - name: readystatechange
86
+ element: EFTemporal elements
87
+ detail: "{ readyState: string }"
88
+ description: Fired when temporal element ready state changes
89
+
90
+ - name: contentchange
91
+ element: EFTemporal elements
92
+ detail: "{}"
93
+ description: Fired when temporal element content changes
94
+
95
+ - name: child-duration-changed
96
+ element: EFMedia elements
97
+ detail: "{ duration: number }"
98
+ description: Fired when child media duration changes
99
+ ---
100
+
101
+ # Custom Events
102
+
103
+ Editframe elements dispatch custom events to enable interactive UI components. Events follow the DOM event bubbling model with `bubbles: true` and `composed: true` to traverse shadow DOM boundaries.
104
+
105
+ ## Event Categories
106
+
107
+ ### Transform & Manipulation Events
108
+
109
+ Events fired during user interactions with transform handles, trim controls, and resize operations.
110
+
111
+ #### trim-change
112
+
113
+ Fired by `ef-trim-handles` when trim handles are dragged. Use this to update element trim values in real-time.
114
+
115
+ ```typescript
116
+ interface TrimChangeDetail {
117
+ elementId: string;
118
+ type: "start" | "end" | "region";
119
+ value: TrimValue;
120
+ }
121
+
122
+ interface TrimValue {
123
+ startMs: number;
124
+ endMs: number;
125
+ }
126
+ ```
127
+
128
+ **Example: Listen to trim changes**
129
+
130
+ ```html live
131
+ <ef-configuration apiHost="https://api.editframe.com">
132
+ <ef-timegroup id="composition" duration="5000" width="1920" height="1080" background="black">
133
+ <ef-video
134
+ id="video1"
135
+ src="https://assets.editframe.com/sample-5s.mp4"
136
+ duration="5000"
137
+ trim-start-ms="500"
138
+ trim-end-ms="500"
139
+ ></ef-video>
140
+ </ef-timegroup>
141
+
142
+ <ef-trim-handles
143
+ element-id="video1"
144
+ intrinsic-duration-ms="5000"
145
+ ></ef-trim-handles>
146
+
147
+ <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
+ });
157
+ </script>
158
+ </ef-configuration>
159
+ ```
160
+
161
+ #### bounds-change
162
+
163
+ Fired by `ef-transform-handles` and `ef-resizable-box` when element bounds change through user interaction.
164
+
165
+ ```typescript
166
+ interface TransformBounds {
167
+ x: number;
168
+ y: number;
169
+ width: number;
170
+ height: number;
171
+ rotation?: number;
172
+ }
173
+ ```
174
+
175
+ **Example: Listen to bounds changes**
176
+
177
+ ```html
178
+ <ef-transform-handles
179
+ .bounds=${{ x: 100, y: 100, width: 200, height: 150 }}
180
+ enable-rotation
181
+ ></ef-transform-handles>
182
+
183
+ <script>
184
+ document.querySelector('ef-transform-handles').addEventListener('bounds-change', (e) => {
185
+ const { bounds } = e.detail;
186
+ console.log('New bounds:', bounds);
187
+
188
+ // Update target element position/size
189
+ targetElement.style.left = `${bounds.x}px`;
190
+ targetElement.style.top = `${bounds.y}px`;
191
+ targetElement.style.width = `${bounds.width}px`;
192
+ targetElement.style.height = `${bounds.height}px`;
193
+ });
194
+ </script>
195
+ ```
196
+
197
+ #### rotation-change
198
+
199
+ Fired by `ef-transform-handles` when the rotation handle is dragged. Provides the new rotation value in degrees.
200
+
201
+ ```typescript
202
+ interface RotationChangeDetail {
203
+ rotation: number; // Degrees (0-360)
204
+ }
205
+ ```
206
+
207
+ #### change (dial)
208
+
209
+ Fired by `ef-dial` when the dial value changes through user interaction. Provides the new angle value.
210
+
211
+ ```typescript
212
+ interface DialChangeDetail {
213
+ value: number; // Degrees (0-360)
214
+ }
215
+ ```
216
+
217
+ **Example: Dial with rotation control**
218
+
219
+ ```html
220
+ <ef-dial value="45"></ef-dial>
221
+
222
+ <script>
223
+ document.querySelector('ef-dial').addEventListener('change', (e) => {
224
+ const { value } = e.detail;
225
+ console.log('Dial rotation:', value, '°');
226
+
227
+ // Apply rotation to element
228
+ targetElement.style.transform = `rotate(${value}deg)`;
229
+ });
230
+ </script>
231
+ ```
232
+
233
+ ### Timeline & Playback Events
234
+
235
+ Events fired during timeline scrubbing, track manipulation, and playback control.
236
+
237
+ #### seek
238
+
239
+ Fired by `ef-scrubber` when the playhead position changes. Detail contains the new time in milliseconds.
240
+
241
+ ```html
242
+ <ef-scrubber target="composition"></ef-scrubber>
243
+
244
+ <script>
245
+ document.querySelector('ef-scrubber').addEventListener('seek', (e) => {
246
+ const timeMs = e.detail;
247
+ console.log('Seek to:', timeMs, 'ms');
248
+ });
249
+ </script>
250
+ ```
251
+
252
+ #### scrub-segment-loading
253
+
254
+ Fired by `ef-video` during scrub track loading to provide progress feedback for UI loading indicators.
255
+
256
+ ```typescript
257
+ interface ScrubSegmentLoadingDetail {
258
+ segmentId: number;
259
+ timeRangeMs: [number, number];
260
+ loaded: number;
261
+ total: number;
262
+ status: "loading" | "loaded";
263
+ }
264
+ ```
265
+
266
+ **Example: Show loading progress**
267
+
268
+ ```html
269
+ <ef-video id="myVideo" src="..."></ef-video>
270
+ <div id="progress" style="display: none;">Loading scrub preview...</div>
271
+
272
+ <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
+ });
284
+ </script>
285
+ ```
286
+
287
+ #### row-select
288
+
289
+ Fired by `ef-timeline-row` when a timeline row is clicked. Used to coordinate selection between timeline and canvas.
290
+
291
+ ```typescript
292
+ interface RowSelectDetail {
293
+ elementId: string;
294
+ element: Element;
295
+ }
296
+ ```
297
+
298
+ #### row-hover
299
+
300
+ Fired by `ef-timeline-row` when mouse enters or leaves a row. Useful for highlighting elements in the preview during timeline hover.
301
+
302
+ ```typescript
303
+ interface RowHoverDetail {
304
+ element: Element | null; // null when mouse leaves
305
+ }
306
+ ```
307
+
308
+ #### track-trim-change
309
+
310
+ Fired by timeline track items when their trim handles change. Bubbles up from the track item to the timeline.
311
+
312
+ ### Selection & Hierarchy Events
313
+
314
+ Events fired when users interact with hierarchy panels, layer lists, or canvas selection tools.
315
+
316
+ #### hierarchy-select
317
+
318
+ Fired by `ef-hierarchy` when an element is selected in the hierarchy panel. Typically used to sync selection with canvas or preview.
319
+
320
+ ```typescript
321
+ interface HierarchySelectDetail {
322
+ elementId: string;
323
+ }
324
+ ```
325
+
326
+ **Example: Sync hierarchy selection with canvas**
327
+
328
+ ```html
329
+ <ef-hierarchy target="composition"></ef-hierarchy>
330
+
331
+ <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
+ </script>
343
+ ```
344
+
345
+ #### hierarchy-reorder
346
+
347
+ Fired by `ef-hierarchy` when elements are reordered via drag and drop. Use this to update the DOM structure.
348
+
349
+ ```typescript
350
+ interface HierarchyReorderDetail {
351
+ sourceId: string;
352
+ targetId: string;
353
+ position: "before" | "after" | "inside";
354
+ }
355
+ ```
356
+
357
+ **Example: Handle reordering**
358
+
359
+ ```html
360
+ <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
+ });
375
+ </script>
376
+ ```
377
+
378
+ #### tree-select
379
+
380
+ Fired by `ef-tree` when a tree item is selected. Generic tree selection event for tree-based UI components.
381
+
382
+ ```typescript
383
+ interface TreeSelectDetail {
384
+ id: string;
385
+ item: any;
386
+ }
387
+ ```
388
+
389
+ #### selectionchange
390
+
391
+ Fired by canvas `SelectionModel` when the set of selected elements changes through user interaction.
392
+
393
+ ```typescript
394
+ interface SelectionChangeDetail {
395
+ selection: Set<Element>;
396
+ }
397
+ ```
398
+
399
+ ### Temporal & Content Events
400
+
401
+ Events fired by temporal elements during initialization, content changes, and state transitions.
402
+
403
+ #### readystatechange
404
+
405
+ Fired by temporal elements (`ef-timegroup`, `ef-video`, `ef-audio`, etc.) when their ready state changes during initialization.
406
+
407
+ ```typescript
408
+ interface ReadyStateChangeDetail {
409
+ readyState: string; // e.g., "loading", "interactive", "complete"
410
+ }
411
+ ```
412
+
413
+ #### contentchange
414
+
415
+ Fired by temporal elements when their content structure changes (children added/removed, attributes modified).
416
+
417
+ #### child-duration-changed
418
+
419
+ Fired by media elements when a child element's duration changes, triggering recalculation of parent duration.
420
+
421
+ ```typescript
422
+ interface ChildDurationChangedDetail {
423
+ duration: number;
424
+ }
425
+ ```
426
+
427
+ #### activeroottemporalchange
428
+
429
+ Fired by `ef-canvas` when the active root temporal element changes. Used to coordinate timeline and canvas state.
430
+
431
+ ```typescript
432
+ interface ActiveRootTemporalChangeDetail {
433
+ activeRootTemporal: Element | null;
434
+ }
435
+ ```
436
+
437
+ ## Event Handling Patterns
438
+
439
+ ### Bubbling and Composed
440
+
441
+ All custom events are dispatched with `bubbles: true` and `composed: true`, allowing them to traverse shadow DOM boundaries and be caught by ancestor elements.
442
+
443
+ ```html
444
+ <div id="app">
445
+ <ef-timeline>
446
+ <ef-timeline-row>
447
+ <!-- Events bubble up from here -->
448
+ </ef-timeline-row>
449
+ </ef-timeline>
450
+ </div>
451
+
452
+ <script>
453
+ // Can listen at any ancestor level
454
+ document.getElementById('app').addEventListener('row-select', (e) => {
455
+ console.log('Row selected:', e.detail.elementId);
456
+ });
457
+ </script>
458
+ ```
459
+
460
+ ### TypeScript Event Types
461
+
462
+ Import event detail types for type-safe event handling:
463
+
464
+ ```typescript
465
+ import type { TrimChangeDetail, DialChangeDetail } from "@editframe/elements";
466
+
467
+ element.addEventListener("trim-change", (e: CustomEvent<TrimChangeDetail>) => {
468
+ const { type, value } = e.detail;
469
+ // TypeScript knows the shape of e.detail
470
+ });
471
+ ```
472
+
473
+ ### Event Coordination
474
+
475
+ Many events are designed to work together for coordinated UI updates:
476
+
477
+ ```typescript
478
+ // Coordinate timeline selection with canvas
479
+ hierarchy.addEventListener('hierarchy-select', (e) => {
480
+ const element = document.getElementById(e.detail.elementId);
481
+ canvas.selectElement(element);
482
+ });
483
+
484
+ // Coordinate canvas selection with transform handles
485
+ canvas.addEventListener('selectionchange', (e) => {
486
+ const selected = Array.from(e.detail.selection)[0];
487
+ if (selected) {
488
+ transformHandles.bounds = getBoundsFromElement(selected);
489
+ }
490
+ });
491
+ ```
492
+
493
+ ## Related
494
+
495
+ - [Trim Handles](/skills/editframe-editor-gui/trim-handles) - Trim handle component
496
+ - [Transform Handles](/skills/editframe-editor-gui/transform-handles) - Transform handle component
497
+ - [Dial](/skills/editframe-editor-gui/dial) - Rotary dial input
498
+ - [Hierarchy](/skills/editframe-editor-gui/hierarchy) - Hierarchy panel component
499
+ - [Timeline](/skills/editframe-editor-gui/timeline) - Timeline editor component