@aicut/core 0.5.0 → 0.6.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.d.cts CHANGED
@@ -1,33 +1,22 @@
1
- import { P as PlaybackEngine, a as PlaybackEngineOptions, b as PlaybackEngineFactory } from './types-DvKlxylu.cjs';
2
- import { M as Ms, P as Project, T as Track, C as Clip, a as MediaSource, b as Theme } from './types-CHplD9V5.cjs';
3
- import { L as Locale } from './i18n-B-DFWgKe.cjs';
4
- export { f as formatLabel, l as localeEn, a as localeZh, m as mergeLocale } from './i18n-B-DFWgKe.cjs';
1
+ import { P as PlaybackEngine, a as PlaybackEngineOptions, b as PlaybackEngineFactory } from './types-CjvRUPtZ.cjs';
2
+ import { M as Ms, P as Project, T as Track, C as Clip, a as MediaSource, b as Theme, K as KeyframeProp, E as EasingKind } from './types-CmS-UIEr.cjs';
3
+ export { c as Keyframe } from './types-CmS-UIEr.cjs';
4
+ import { L as Locale } from './i18n-B24k4XVG.cjs';
5
+ export { f as formatLabel, l as localeEn, a as localeZh, m as mergeLocale } from './i18n-B24k4XVG.cjs';
5
6
 
6
- /**
7
- * Default preview engine — one hidden `<video>` per `MediaSource`,
8
- * "active" video shown for the current playhead. Tick loop drives a
9
- * single video track's playhead, advancing through clips end-to-end.
10
- * When the playhead crosses a clip boundary we pause the outgoing
11
- * video and resume the next at `clip.in`.
12
- *
13
- * Strengths: zero deps, browser-native decode (GPU when available),
14
- * works in every browser today.
15
- *
16
- * Limits: no multi-track compositing (one video visible at a time),
17
- * seek snaps to keyframes (browser controls the decode pipeline), no
18
- * transitions / shaders / filters. See `WebCodecsEngine` for the
19
- * frame-accurate path.
20
- */
21
7
  declare class HtmlVideoEngine implements PlaybackEngine {
22
8
  private host;
23
9
  private mount;
24
- private videos;
10
+ private sources;
25
11
  private project;
26
12
  private currentClipId;
27
13
  private playing;
28
14
  private timeMs;
29
15
  private rafHandle;
30
16
  private lastFrameTs;
17
+ /** Permanent rAF that positions the active wrapper at the output
18
+ * rect + pushes keyframe transform onto the inner video via CSS. */
19
+ private transformRaf;
31
20
  /** Public event hooks — set by Editor. */
32
21
  onTimeUpdate?: (ms: Ms) => void;
33
22
  onEnded?: () => void;
@@ -41,6 +30,37 @@ declare class HtmlVideoEngine implements PlaybackEngine {
41
30
  isPlaying(): boolean;
42
31
  getTime(): Ms;
43
32
  seek(timeMs: Ms): void;
33
+ /**
34
+ * The OUTPUT frame — the fixed stage the rendered video is clipped
35
+ * to. Independent of the keyframe transform. Used by the overlay to
36
+ * draw the dashed border at a stable position.
37
+ */
38
+ getOutputFrameRect(): {
39
+ x: number;
40
+ y: number;
41
+ w: number;
42
+ h: number;
43
+ } | null;
44
+ /**
45
+ * The CONTENT frame — where the transformed video pixels actually
46
+ * land. Equal to the output frame when transform is identity; may
47
+ * extend outside (zoom in) or fit inside (zoom out) when not.
48
+ */
49
+ getFrameRect(): {
50
+ x: number;
51
+ y: number;
52
+ w: number;
53
+ h: number;
54
+ } | null;
55
+ /** Untransformed contain-letterbox rect — the OUTPUT frame. */
56
+ private baseFrameRect;
57
+ /**
58
+ * Permanent rAF that (a) sizes + positions the active wrapper to
59
+ * the output frame, and (b) writes the keyframe transform onto the
60
+ * inner video. Negligible cost — three style writes per frame max.
61
+ */
62
+ private startTransformLoop;
63
+ private applyTransforms;
44
64
  destroy(): void;
45
65
  private syncSources;
46
66
  private activate;
@@ -49,10 +69,7 @@ declare class HtmlVideoEngine implements PlaybackEngine {
49
69
  /**
50
70
  * Find the clip whose timeline range contains `timeMs`, searching
51
71
  * across ALL video tracks. If multiple tracks have a clip at this
52
- * moment, the lowest-index track wins (matches the "Track 1 is
53
- * background" convention used in the auto-split UX — overlapping
54
- * placements would have created a new track on top, but here we
55
- * fall back to the underlying clip).
72
+ * moment, the lowest-index track wins.
56
73
  */
57
74
  private clipAtTime;
58
75
  /** Earliest clip starting at-or-after `timeMs` across all video tracks. */
@@ -107,6 +124,10 @@ declare class CanvasCompositorEngine implements PlaybackEngine {
107
124
  private rafHandle;
108
125
  private lastFrameTs;
109
126
  private paintedFrames;
127
+ /** Output frame rect (no transform) — fixed bounds. */
128
+ private lastOutputRect;
129
+ /** Post-transform content rect. */
130
+ private lastFrameRect;
110
131
  onTimeUpdate?: (ms: Ms) => void;
111
132
  onEnded?: () => void;
112
133
  onError?: (err: Error) => void;
@@ -138,6 +159,18 @@ declare class CanvasCompositorEngine implements PlaybackEngine {
138
159
  * and the seek preview both update when paused.
139
160
  */
140
161
  private paint;
162
+ getOutputFrameRect(): {
163
+ x: number;
164
+ y: number;
165
+ w: number;
166
+ h: number;
167
+ } | null;
168
+ getFrameRect(): {
169
+ x: number;
170
+ y: number;
171
+ w: number;
172
+ h: number;
173
+ } | null;
141
174
  private updateBadge;
142
175
  }
143
176
  /** Factory shorthand for `Editor.create({ playbackEngine })`. */
@@ -194,6 +227,31 @@ interface EditorOptions {
194
227
  * Reasonable range: [120, 480].
195
228
  */
196
229
  timelineHeight?: number;
230
+ /**
231
+ * Per-clip keyframe animation (X / Y / Scale). Off by default; flip
232
+ * `enabled: true` to surface keyframe markers on the timeline and
233
+ * route the canvas / WebCodecs engines through `getEffectiveTransform`
234
+ * when painting. Data is preserved either way — disabling just hides
235
+ * the editing UI and renders identity transforms.
236
+ *
237
+ * HtmlVideoEngine cannot apply per-frame transforms (it shows a raw
238
+ * `<video>`), so keyframes are silently ignored on that engine
239
+ * regardless of this flag. Swap to `CanvasCompositorEngine` or
240
+ * `WebCodecsEngine` for live preview.
241
+ */
242
+ keyframes?: {
243
+ enabled?: boolean;
244
+ };
245
+ /**
246
+ * Show the |◀ / ▶| "jump to clip start / end" toolbar buttons and
247
+ * bind the I / O keyboard shortcuts. Off by default — hosts opt in
248
+ * the same way they do for keyframes. When off the buttons are
249
+ * completely hidden (display: none) so they don't take up toolbar
250
+ * space, and the I / O keys fall through to the page.
251
+ */
252
+ clipEdgeNav?: {
253
+ enabled?: boolean;
254
+ };
197
255
  }
198
256
  interface EditorEventMap {
199
257
  /** Emitted whenever the project mutates. */
@@ -221,6 +279,23 @@ interface EditorEventMap {
221
279
  selectionChange: {
222
280
  clipId: string | null;
223
281
  };
282
+ /** Currently selected keyframe (parent clip + keyframe id), or null.
283
+ * Selecting a keyframe also selects its parent clip — listeners
284
+ * watching `selectionChange` get notified independently. */
285
+ keyframeSelectionChange: {
286
+ target: {
287
+ clipId: string;
288
+ keyframeId: string;
289
+ } | null;
290
+ };
291
+ /** Keyframe-mode toggle changed (Editor.setKeyframesEnabled). */
292
+ keyframesEnabledChange: {
293
+ enabled: boolean;
294
+ };
295
+ /** Jump-to-clip-edge nav toggle changed (Editor.setClipEdgeNavEnabled). */
296
+ clipEdgeNavEnabledChange: {
297
+ enabled: boolean;
298
+ };
224
299
  /** Zoom (px/sec) changed. */
225
300
  scaleChange: {
226
301
  pxPerSec: number;
@@ -297,10 +372,131 @@ interface EditorApi {
297
372
  setSnap(snap: boolean): void;
298
373
  getSelection(): string | null;
299
374
  setSelection(clipId: string | null): void;
375
+ isKeyframesEnabled(): boolean;
376
+ setKeyframesEnabled(enabled: boolean): void;
377
+ isClipEdgeNavEnabled(): boolean;
378
+ setClipEdgeNavEnabled(enabled: boolean): void;
379
+ /** Screen-space CSS-pixel rect of the active rendered frame, post
380
+ * transform, relative to the editor preview. Null when none. */
381
+ getActiveFrameRect(): {
382
+ x: number;
383
+ y: number;
384
+ w: number;
385
+ h: number;
386
+ } | null;
387
+ /** Output frame rect (fixed bounds, no transform). The overlay
388
+ * draws the dashed border here. */
389
+ getActiveOutputFrameRect(): {
390
+ x: number;
391
+ y: number;
392
+ w: number;
393
+ h: number;
394
+ } | null;
395
+ /**
396
+ * Upsert a per-property keyframe at the given clip-local time. If a
397
+ * keyframe for the same `prop` already exists within ~1 frame of
398
+ * `time` it gets its value updated; else a new one is appended.
399
+ * Returns the keyframe's id, or null when the clip can't be found.
400
+ *
401
+ * Defaults: `time` = playhead in clip-local coords; `value` = the
402
+ * currently interpolated value for that prop (so adding doesn't
403
+ * cause a visible jump).
404
+ */
405
+ addKeyframe(clipId: string, prop: KeyframeProp, opts?: {
406
+ time?: Ms;
407
+ value?: number;
408
+ }): string | null;
409
+ removeKeyframe(clipId: string, keyframeId: string): boolean;
410
+ moveKeyframe(clipId: string, keyframeId: string, timeMs: Ms): boolean;
411
+ /** Change one keyframe's value (single number, since each kf is
412
+ * per-property). */
413
+ setKeyframeValue(clipId: string, keyframeId: string, value: number): boolean;
414
+ /**
415
+ * Change one keyframe's outgoing easing curve. Shapes only the
416
+ * segment from this kf to the NEXT kf in time on the same prop.
417
+ * The kf's value is untouched.
418
+ */
419
+ setKeyframeEasing(clipId: string, keyframeId: string, easing: EasingKind): boolean;
420
+ /**
421
+ * Batch-set the outgoing easing on every kf at one moment in time
422
+ * (within the 16ms tolerance that the rest of the API uses) on a
423
+ * single clip. Mirrors the panel's "one dropdown for the moment"
424
+ * UX so all three props (panX / panY / scale) at the selected
425
+ * moment animate with the same curve. Single history entry.
426
+ */
427
+ setKeyframesEasingAtTime(clipId: string, timeMs: Ms, easing: EasingKind): boolean;
428
+ /**
429
+ * CapCut-style auto-record: write `value` for `prop` at the playhead.
430
+ * - If the prop already has keyframes → upsert a keyframe at the
431
+ * playhead with this value.
432
+ * - If the prop has no keyframes → just update the static base
433
+ * (panX / panY / scale on the clip) so the visual changes
434
+ * without committing the user to an animation track yet.
435
+ * Returns true if the project changed.
436
+ */
437
+ setValueAtPlayhead(clipId: string, prop: KeyframeProp, value: number): boolean;
438
+ getSelectedKeyframe(): {
439
+ clipId: string;
440
+ keyframeId: string;
441
+ } | null;
442
+ setSelectedKeyframe(target: {
443
+ clipId: string;
444
+ keyframeId: string;
445
+ } | null): void;
446
+ /**
447
+ * Toolbar-style toggle. If ANY keyframe exists at the playhead time
448
+ * on the selected clip, remove every keyframe at that time (all
449
+ * props). Otherwise, capture one keyframe per prop (panX, panY,
450
+ * scale) at the playhead with the currently interpolated values.
451
+ * Returns true when the project changed.
452
+ */
453
+ toggleKeyframeAtPlayhead(): boolean;
454
+ /**
455
+ * Clear every keyframe AND every static transform value on a clip,
456
+ * restoring the identity pose (panX=0, panY=0, scale=1). Single
457
+ * history entry. */
458
+ resetClipTransform(clipId: string): boolean;
459
+ /**
460
+ * Pin all three transform props (panX, panY, scale) to identity
461
+ * (0, 0, 1) at one specific clip-local time. Upserts on each prop —
462
+ * keyframes that already exist at that time get their values
463
+ * overwritten; props with no kf there get one added. Single history
464
+ * entry. Used by the panel's Reset button when a keyframe is selected.
465
+ */
466
+ resetKeyframesAtTime(clipId: string, timeMs: Ms): boolean;
467
+ /**
468
+ * Move the playhead to a clip edge. "end" intentionally lands 1ms
469
+ * INSIDE the clip (clipEnd - 1) so the playhead remains inside the
470
+ * clip — that lets the user immediately press the keyframe button
471
+ * (or the I/O shortcut) and have it find the right clip + drop a
472
+ * keyframe at clip-local time `duration - 1ms`. Without the -1ms
473
+ * offset the playhead lands on the seam and `toggleKeyframeAtPlayhead`
474
+ * picks the next clip (or none at all).
475
+ * Returns true when the seek actually moved.
476
+ */
477
+ seekToClipEdge(clipId: string, edge: "start" | "end"): boolean;
478
+ /** Convenience for the toolbar: act on the currently-selected clip. */
479
+ seekToSelectedClipEdge(edge: "start" | "end"): boolean;
300
480
  canUndo(): boolean;
301
481
  canRedo(): boolean;
302
482
  undo(): boolean;
303
483
  redo(): boolean;
484
+ /**
485
+ * Open a "drag session". While open, every internal `pushHistory`
486
+ * call captures the pre-session snapshot ONCE — subsequent calls
487
+ * during the same session are no-ops. The session commits a single
488
+ * history entry on `endInteraction()` (or is dropped entirely if
489
+ * the project ended up unchanged). Nestable: nested begin/end pairs
490
+ * count by depth and only the outermost commits.
491
+ *
492
+ * Hosts call this around continuous gestures (drag the preview
493
+ * overlay, scrub a numeric slider, wheel-zoom) so a single user
494
+ * gesture becomes ONE undo entry instead of 30-100. Without this,
495
+ * each pointermove of an overlay drag pushes its own history entry
496
+ * and the user has to mash Cmd+Z that many times to fully undo.
497
+ */
498
+ beginInteraction(): void;
499
+ endInteraction(): void;
304
500
  /**
305
501
  * Bookend slot at the very left of the top toolbar — host appends
306
502
  * its own controls (e.g. an aspect-ratio dropdown). Empty by default
@@ -339,6 +535,13 @@ declare class Editor implements EditorApi {
339
535
  private bus;
340
536
  private history;
341
537
  private selectedClipId;
538
+ private selectedKeyframe;
539
+ private keyframesEnabled;
540
+ private clipEdgeNavEnabled;
541
+ /** Drag-session bookkeeping for ripple-merge undo. See
542
+ * beginInteraction / endInteraction docs on EditorApi. */
543
+ private interactionDepth;
544
+ private interactionStartSnapshot;
342
545
  private pxPerSec;
343
546
  private snap;
344
547
  private locale;
@@ -426,10 +629,74 @@ declare class Editor implements EditorApi {
426
629
  snapMs(timeMs: Ms, ignoreClipId?: string | null): Ms;
427
630
  getSelection(): string | null;
428
631
  setSelection(clipId: string | null): void;
632
+ isKeyframesEnabled(): boolean;
633
+ /**
634
+ * Screen-space CSS-pixel rect of the actively painted frame
635
+ * (post-transform), relative to the editor's preview element.
636
+ * Null when no clip is active, the engine doesn't expose
637
+ * `getFrameRect`, or the rect isn't computed yet. Used by the
638
+ * library's keyframe-editing overlay.
639
+ */
640
+ getActiveFrameRect(): {
641
+ x: number;
642
+ y: number;
643
+ w: number;
644
+ h: number;
645
+ } | null;
646
+ /**
647
+ * Screen-space CSS-pixel rect of the OUTPUT FRAME (the fixed
648
+ * stage that clips the rendered video). Different from
649
+ * `getActiveFrameRect` which includes the keyframe transform —
650
+ * this one stays put as the user drags / scales the content.
651
+ * Used by the overlay to anchor the dashed border + drag body.
652
+ */
653
+ getActiveOutputFrameRect(): {
654
+ x: number;
655
+ y: number;
656
+ w: number;
657
+ h: number;
658
+ } | null;
659
+ setKeyframesEnabled(enabled: boolean): void;
660
+ isClipEdgeNavEnabled(): boolean;
661
+ setClipEdgeNavEnabled(enabled: boolean): void;
662
+ addKeyframe(clipId: string, prop: KeyframeProp, opts?: {
663
+ time?: Ms;
664
+ value?: number;
665
+ }): string | null;
666
+ removeKeyframe(clipId: string, keyframeId: string): boolean;
667
+ moveKeyframe(clipId: string, keyframeId: string, timeMs: Ms): boolean;
668
+ setKeyframeValue(clipId: string, keyframeId: string, value: number): boolean;
669
+ setKeyframeEasing(clipId: string, keyframeId: string, easing: EasingKind): boolean;
670
+ setKeyframesEasingAtTime(clipId: string, timeMs: Ms, easing: EasingKind): boolean;
671
+ setValueAtPlayhead(clipId: string, prop: KeyframeProp, value: number): boolean;
672
+ getSelectedKeyframe(): {
673
+ clipId: string;
674
+ keyframeId: string;
675
+ } | null;
676
+ resetClipTransform(clipId: string): boolean;
677
+ resetKeyframesAtTime(clipId: string, timeMs: Ms): boolean;
678
+ seekToClipEdge(clipId: string, edge: "start" | "end"): boolean;
679
+ seekToSelectedClipEdge(edge: "start" | "end"): boolean;
680
+ toggleKeyframeAtPlayhead(): boolean;
681
+ setSelectedKeyframe(target: {
682
+ clipId: string;
683
+ keyframeId: string;
684
+ } | null): void;
429
685
  canUndo(): boolean;
430
686
  canRedo(): boolean;
431
687
  undo(): boolean;
432
688
  redo(): boolean;
689
+ beginInteraction(): void;
690
+ endInteraction(): void;
691
+ /**
692
+ * Selections (clipId + selectedKeyframe) live OUTSIDE the project
693
+ * snapshot, so undo / redo can leave them pointing at ids that no
694
+ * longer exist. Defend against dangling refs by clearing anything
695
+ * the restored project doesn't actually contain — and emit the
696
+ * paired change events so panels / overlays hide cleanly instead
697
+ * of holding zombie references.
698
+ */
699
+ private reconcileSelectionsWithProject;
433
700
  on<K extends EditorEventName>(event: K, handler: (payload: EditorEventMap[K]) => void): () => void;
434
701
  off<K extends EditorEventName>(event: K, handler: (payload: EditorEventMap[K]) => void): void;
435
702
  destroy(): void;
@@ -441,6 +708,32 @@ declare class Editor implements EditorApi {
441
708
  private handleSourceMetadata;
442
709
  }
443
710
 
711
+ /**
712
+ * The transform a clip's content is rendered with at a given moment.
713
+ * Engines apply this INSIDE a fixed output frame: `panX` / `panY`
714
+ * translate the content (in CSS px), `scale` resizes it around the
715
+ * output frame's center. Anything pushed outside the frame is
716
+ * clipped. Identity = `{ panX: 0, panY: 0, scale: 1 }`.
717
+ */
718
+ interface EffectiveTransform {
719
+ panX: number;
720
+ panY: number;
721
+ scale: number;
722
+ }
723
+ /** Identity transform — no pan, no scaling (content fills the output frame). */
724
+ declare const IDENTITY_TRANSFORM: EffectiveTransform;
725
+ /** True when a transform is effectively identity (within FP slop). */
726
+ declare function isIdentityTransform(t: EffectiveTransform): boolean;
727
+
728
+ /**
729
+ * Effective transform = all three properties evaluated together. The
730
+ * engine applies this to the content inside the fixed output frame:
731
+ * scale around frame center, then translate by (panX, panY).
732
+ */
733
+ declare function getEffectiveTransform(clip: Clip, localMs: Ms): EffectiveTransform;
734
+ /** Same as `getEffectiveTransform` but takes timeline-absolute time. */
735
+ declare function getTransformAtTimelineTime(clip: Clip, timelineMs: Ms): EffectiveTransform;
736
+
444
737
  declare function createEmptyProject(): Project;
445
738
  /**
446
739
  * Defensive normalization — ensures clips on each track are sorted by
@@ -528,6 +821,23 @@ interface TimelineOptions {
528
821
  }) => void;
529
822
  onResizeClip?: (clipId: string, edits: Partial<Pick<Clip, "in" | "out" | "start">>) => void;
530
823
  onChange?: (project: Project) => void;
824
+ /**
825
+ * Hosts wire these to forward keyframe edits to the Editor. The
826
+ * Timeline only paints + hit-tests; mutation goes through these
827
+ * callbacks so the Editor can push history + emit events.
828
+ */
829
+ onSelectKeyframe?: (target: {
830
+ clipId: string;
831
+ keyframeId: string;
832
+ } | null) => void;
833
+ onMoveKeyframe?: (clipId: string, keyframeId: string, timeMs: Ms) => void;
834
+ /** Host-driven state mirror — Editor passes these on every render
835
+ * via `Timeline.setKeyframeState`. */
836
+ keyframesEnabled?: boolean;
837
+ selectedKeyframe?: {
838
+ clipId: string;
839
+ keyframeId: string;
840
+ } | null;
531
841
  /**
532
842
  * Lets the host predict where a drop will actually land — used to
533
843
  * keep the drag-ghost visual honest. The Editor wires this to its
@@ -576,6 +886,8 @@ declare class Timeline {
576
886
  private readOnly;
577
887
  private autoFitEnabled;
578
888
  private locale;
889
+ private keyframesEnabled;
890
+ private selectedKeyframe;
579
891
  private scrollLeft;
580
892
  private scrollTop;
581
893
  private viewportWidth;
@@ -594,6 +906,7 @@ declare class Timeline {
594
906
  private scrollbarDrag;
595
907
  private hoveredClipId;
596
908
  private hoveredTrackIndex;
909
+ private hoveredKeyframe;
597
910
  private hoverCursor;
598
911
  private dropTargetTrackIndex;
599
912
  private snapX;
@@ -690,6 +1003,15 @@ declare class Timeline {
690
1003
  private maybeContinueFade;
691
1004
  private maybeAutoFit;
692
1005
  private buildDrawState;
1006
+ /** Host-pushed state — Editor calls this when its keyframe mode
1007
+ * changes or when a keyframe is selected/deselected externally. */
1008
+ setKeyframeState(state: {
1009
+ enabled?: boolean;
1010
+ selected?: {
1011
+ clipId: string;
1012
+ keyframeId: string;
1013
+ } | null;
1014
+ }): void;
693
1015
  private readStyle;
694
1016
  private attachPointer;
695
1017
  private onPointerDown;
@@ -718,6 +1040,7 @@ declare class Timeline {
718
1040
  */
719
1041
  private maybeStartDragAutoScroll;
720
1042
  private onPointerUp;
1043
+ private attachKeyboard;
721
1044
  private attachWheel;
722
1045
  private attachResize;
723
1046
  private localCoords;
@@ -726,4 +1049,4 @@ declare class Timeline {
726
1049
  private applySnap;
727
1050
  }
728
1051
 
729
- export { CanvasCompositorEngine, type CanvasCompositorEngineOptions, Clip, Editor, type EditorApi, type EditorEventMap, type EditorEventName, type EditorOptions, HEADER_WIDTH, HtmlVideoEngine, Locale, MediaSource, Ms, PlaybackEngine, PlaybackEngineFactory, PlaybackEngineOptions, Project, RULER_HEIGHT, TRACK_HEIGHT, Theme, Timeline, type TimelineOptions, Track, canvasCompositorEngineFactory, createEmptyProject, createId, htmlVideoEngineFactory, normalizeProject, setTimelineMetrics };
1052
+ export { CanvasCompositorEngine, type CanvasCompositorEngineOptions, Clip, EasingKind, Editor, type EditorApi, type EditorEventMap, type EditorEventName, type EditorOptions, type EffectiveTransform, HEADER_WIDTH, HtmlVideoEngine, IDENTITY_TRANSFORM, KeyframeProp, Locale, MediaSource, Ms, PlaybackEngine, PlaybackEngineFactory, PlaybackEngineOptions, Project, RULER_HEIGHT, TRACK_HEIGHT, Theme, Timeline, type TimelineOptions, Track, canvasCompositorEngineFactory, createEmptyProject, createId, getEffectiveTransform, getTransformAtTimelineTime, htmlVideoEngineFactory, isIdentityTransform, normalizeProject, setTimelineMetrics };