@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.
@@ -1,4 +1,4 @@
1
- import { P as Project, M as Ms } from './types-CHplD9V5.cjs';
1
+ import { P as Project, M as Ms } from './types-CmS-UIEr.js';
2
2
 
3
3
  /**
4
4
  * Construction context the Editor hands to a playback engine. The
@@ -43,6 +43,39 @@ interface PlaybackEngine {
43
43
  seek(timeMs: Ms): void;
44
44
  /** Free all resources (DOM nodes, decoders, AudioContexts, rAF). */
45
45
  destroy(): void;
46
+ /**
47
+ * Optional. The **output frame rect** — the fixed bounds anything
48
+ * the engine renders is clipped to. The user's keyframe X / Y /
49
+ * scale move the content WITHIN this frame (think picture-in-
50
+ * picture, pan, zoom); anything outside is hidden by the engine.
51
+ *
52
+ * This rect does NOT change with the active transform — it's
53
+ * the stage. The overlay's dashed border is drawn here. Coords
54
+ * relative to `opts.host`. Returns null when no clip is active.
55
+ */
56
+ getOutputFrameRect?(): {
57
+ x: number;
58
+ y: number;
59
+ w: number;
60
+ h: number;
61
+ } | null;
62
+ /**
63
+ * Optional. Return the screen-space CSS-pixel rectangle of the
64
+ * actually-rendered content (the video frame after the active
65
+ * keyframe transform is applied). May extend outside the output
66
+ * frame — the engine clips to the output frame at paint time, but
67
+ * the overlay still wants the geometric rect to position scale
68
+ * handles on the visible content corners.
69
+ *
70
+ * Returns null when no clip is active. Engines that don't expose
71
+ * this leave keyframe handles attached to the output frame instead.
72
+ */
73
+ getFrameRect?(): {
74
+ x: number;
75
+ y: number;
76
+ w: number;
77
+ h: number;
78
+ } | null;
46
79
  /** Fired on each rAF / decoded frame with the current playhead. */
47
80
  onTimeUpdate?: (ms: Ms) => void;
48
81
  /** Fired once when the project's end is reached during playback. */
@@ -1,4 +1,4 @@
1
- import { P as Project, M as Ms } from './types-CHplD9V5.js';
1
+ import { P as Project, M as Ms } from './types-CmS-UIEr.cjs';
2
2
 
3
3
  /**
4
4
  * Construction context the Editor hands to a playback engine. The
@@ -43,6 +43,39 @@ interface PlaybackEngine {
43
43
  seek(timeMs: Ms): void;
44
44
  /** Free all resources (DOM nodes, decoders, AudioContexts, rAF). */
45
45
  destroy(): void;
46
+ /**
47
+ * Optional. The **output frame rect** — the fixed bounds anything
48
+ * the engine renders is clipped to. The user's keyframe X / Y /
49
+ * scale move the content WITHIN this frame (think picture-in-
50
+ * picture, pan, zoom); anything outside is hidden by the engine.
51
+ *
52
+ * This rect does NOT change with the active transform — it's
53
+ * the stage. The overlay's dashed border is drawn here. Coords
54
+ * relative to `opts.host`. Returns null when no clip is active.
55
+ */
56
+ getOutputFrameRect?(): {
57
+ x: number;
58
+ y: number;
59
+ w: number;
60
+ h: number;
61
+ } | null;
62
+ /**
63
+ * Optional. Return the screen-space CSS-pixel rectangle of the
64
+ * actually-rendered content (the video frame after the active
65
+ * keyframe transform is applied). May extend outside the output
66
+ * frame — the engine clips to the output frame at paint time, but
67
+ * the overlay still wants the geometric rect to position scale
68
+ * handles on the visible content corners.
69
+ *
70
+ * Returns null when no clip is active. Engines that don't expose
71
+ * this leave keyframe handles attached to the output frame instead.
72
+ */
73
+ getFrameRect?(): {
74
+ x: number;
75
+ y: number;
76
+ w: number;
77
+ h: number;
78
+ } | null;
46
79
  /** Fired on each rAF / decoded frame with the current playhead. */
47
80
  onTimeUpdate?: (ms: Ms) => void;
48
81
  /** Fired once when the project's end is reached during playback. */
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Milliseconds. All timing in the project is expressed as integer ms to
3
+ * keep JSON serialization unambiguous (no frame-rate coupling in the
4
+ * data model — the renderer can present time as frames if it wants).
5
+ */
6
+ type Ms = number;
7
+ interface MediaSource {
8
+ id: string;
9
+ url: string;
10
+ kind: "video" | "audio";
11
+ /** Optional — probed lazily from the <video> element if absent. */
12
+ duration?: Ms;
13
+ name?: string;
14
+ }
15
+ interface Clip {
16
+ id: string;
17
+ sourceId: string;
18
+ /** Window into the source — `in` inclusive, `out` exclusive. */
19
+ in: Ms;
20
+ out: Ms;
21
+ /** Position on the timeline. */
22
+ start: Ms;
23
+ /**
24
+ * Playback rate. 1 = normal, 2 = 2× speed. Default 1.
25
+ * Persisted in the project JSON so a host can restore exactly.
26
+ */
27
+ speed?: number;
28
+ /**
29
+ * Static base values for the content transform, used when the clip
30
+ * has no keyframes for that property. Pan slides the video inside
31
+ * the FIXED output frame (the dashed border the user sees); scale
32
+ * grows / shrinks the content around the frame center. Anything
33
+ * pushed outside the output frame is clipped — that's how
34
+ * picture-in-picture, pan, and zoom work.
35
+ *
36
+ * `panX`, `panY` are CSS pixels relative to the output frame center.
37
+ * Defaults: panX = 0, panY = 0, scale = 1 (content fills frame).
38
+ */
39
+ panX?: number;
40
+ panY?: number;
41
+ scale?: number;
42
+ /**
43
+ * Per-property keyframe animation. Each keyframe targets one prop
44
+ * (`panX`, `panY`, or `scale`) so the user can animate one axis
45
+ * independently of the others (the standard NLE / CapCut model).
46
+ *
47
+ * Times are clip-local (0 = clip's `in`), so trim and move ops
48
+ * carry keyframes with the clip. Empty array / undefined = use the
49
+ * static base values above. `normalizeProject` keeps it sorted by
50
+ * (prop, time).
51
+ */
52
+ keyframes?: Keyframe[];
53
+ }
54
+ /** Properties on a Clip that can be animated by keyframes. */
55
+ type KeyframeProp = "panX" | "panY" | "scale";
56
+ /**
57
+ * Easing curve that shapes the segment LEAVING this keyframe — i.e.
58
+ * the curve from this keyframe to the next one in time. Matches the
59
+ * "outgoing" easing model in After Effects / Premiere / CapCut so a
60
+ * single dropdown per keyframe is enough.
61
+ *
62
+ * - `linear` — constant rate (default)
63
+ * - `easeIn` — start slow, finish fast (cubic)
64
+ * - `easeOut` — start fast, finish slow (cubic)
65
+ * - `easeInOut` — slow on both ends, fast in the middle (cubic)
66
+ */
67
+ type EasingKind = "linear" | "easeIn" | "easeOut" | "easeInOut";
68
+ /**
69
+ * One pinned value for one property at one moment in clip-local time.
70
+ * Properties without keyframes fall back to the clip's static base
71
+ * value (`Clip.panX` / `panY` / `scale`).
72
+ */
73
+ interface Keyframe {
74
+ id: string;
75
+ /** Which property this keyframe controls. */
76
+ prop: KeyframeProp;
77
+ /** Clip-local time in ms. 0 = clip's `in`. Bounds: [0, clip.out - clip.in]. */
78
+ time: Ms;
79
+ /** The value the property holds at this moment. Same units as the
80
+ * matching static field (CSS px for pan, multiplier for scale). */
81
+ value: number;
82
+ /** Easing curve for the segment leaving THIS keyframe toward the
83
+ * next one. Optional — omitted / undefined = "linear" (back-compat
84
+ * with projects authored before the easing field existed). */
85
+ easing?: EasingKind;
86
+ }
87
+ interface Track {
88
+ id: string;
89
+ kind: "video" | "audio";
90
+ /** Clips on this track. Must be kept sorted by `start` and non-overlapping. */
91
+ clips: Clip[];
92
+ }
93
+ interface Project {
94
+ /** Schema version — bump when breaking the JSON shape. */
95
+ version: 1;
96
+ sources: MediaSource[];
97
+ tracks: Track[];
98
+ /**
99
+ * Project frame rate. Drives keyboard frame-stepping (← / →), the
100
+ * future timecode display, and ffmpeg compilation of keyframe
101
+ * animations. Optional for back-compat — projects without `fps`
102
+ * default to 30, matching consumer NLE convention (CapCut /
103
+ * Premiere project defaults). `normalizeProject` does NOT fill
104
+ * this in, so a missing field stays missing through round-trips.
105
+ */
106
+ fps?: number;
107
+ }
108
+ /**
109
+ * Subset of CSS variables the editor honors. Pass any custom values
110
+ * via `Editor` options; everything is forwarded as `--aicut-*` on the
111
+ * editor's root container, so a host can also override via plain CSS.
112
+ */
113
+ interface Theme {
114
+ brand?: string;
115
+ secondary?: string;
116
+ surface?: string;
117
+ dark?: string;
118
+ muted?: string;
119
+ card?: string;
120
+ success?: string;
121
+ warning?: string;
122
+ info?: string;
123
+ error?: string;
124
+ /** Toolbar / ruler chrome. Background of the editor frame. */
125
+ controlsBg?: string;
126
+ controlsBorder?: string;
127
+ controlsText?: string;
128
+ controlsHover?: string;
129
+ controlsActive?: string;
130
+ /** Letterbox color around the preview video. Defaults to black. */
131
+ previewBg?: string;
132
+ radiusSm?: string;
133
+ radiusMd?: string;
134
+ radiusLg?: string;
135
+ }
136
+
137
+ export type { Clip as C, EasingKind as E, KeyframeProp as K, Ms as M, Project as P, Track as T, MediaSource as a, Theme as b, Keyframe as c };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Milliseconds. All timing in the project is expressed as integer ms to
3
+ * keep JSON serialization unambiguous (no frame-rate coupling in the
4
+ * data model — the renderer can present time as frames if it wants).
5
+ */
6
+ type Ms = number;
7
+ interface MediaSource {
8
+ id: string;
9
+ url: string;
10
+ kind: "video" | "audio";
11
+ /** Optional — probed lazily from the <video> element if absent. */
12
+ duration?: Ms;
13
+ name?: string;
14
+ }
15
+ interface Clip {
16
+ id: string;
17
+ sourceId: string;
18
+ /** Window into the source — `in` inclusive, `out` exclusive. */
19
+ in: Ms;
20
+ out: Ms;
21
+ /** Position on the timeline. */
22
+ start: Ms;
23
+ /**
24
+ * Playback rate. 1 = normal, 2 = 2× speed. Default 1.
25
+ * Persisted in the project JSON so a host can restore exactly.
26
+ */
27
+ speed?: number;
28
+ /**
29
+ * Static base values for the content transform, used when the clip
30
+ * has no keyframes for that property. Pan slides the video inside
31
+ * the FIXED output frame (the dashed border the user sees); scale
32
+ * grows / shrinks the content around the frame center. Anything
33
+ * pushed outside the output frame is clipped — that's how
34
+ * picture-in-picture, pan, and zoom work.
35
+ *
36
+ * `panX`, `panY` are CSS pixels relative to the output frame center.
37
+ * Defaults: panX = 0, panY = 0, scale = 1 (content fills frame).
38
+ */
39
+ panX?: number;
40
+ panY?: number;
41
+ scale?: number;
42
+ /**
43
+ * Per-property keyframe animation. Each keyframe targets one prop
44
+ * (`panX`, `panY`, or `scale`) so the user can animate one axis
45
+ * independently of the others (the standard NLE / CapCut model).
46
+ *
47
+ * Times are clip-local (0 = clip's `in`), so trim and move ops
48
+ * carry keyframes with the clip. Empty array / undefined = use the
49
+ * static base values above. `normalizeProject` keeps it sorted by
50
+ * (prop, time).
51
+ */
52
+ keyframes?: Keyframe[];
53
+ }
54
+ /** Properties on a Clip that can be animated by keyframes. */
55
+ type KeyframeProp = "panX" | "panY" | "scale";
56
+ /**
57
+ * Easing curve that shapes the segment LEAVING this keyframe — i.e.
58
+ * the curve from this keyframe to the next one in time. Matches the
59
+ * "outgoing" easing model in After Effects / Premiere / CapCut so a
60
+ * single dropdown per keyframe is enough.
61
+ *
62
+ * - `linear` — constant rate (default)
63
+ * - `easeIn` — start slow, finish fast (cubic)
64
+ * - `easeOut` — start fast, finish slow (cubic)
65
+ * - `easeInOut` — slow on both ends, fast in the middle (cubic)
66
+ */
67
+ type EasingKind = "linear" | "easeIn" | "easeOut" | "easeInOut";
68
+ /**
69
+ * One pinned value for one property at one moment in clip-local time.
70
+ * Properties without keyframes fall back to the clip's static base
71
+ * value (`Clip.panX` / `panY` / `scale`).
72
+ */
73
+ interface Keyframe {
74
+ id: string;
75
+ /** Which property this keyframe controls. */
76
+ prop: KeyframeProp;
77
+ /** Clip-local time in ms. 0 = clip's `in`. Bounds: [0, clip.out - clip.in]. */
78
+ time: Ms;
79
+ /** The value the property holds at this moment. Same units as the
80
+ * matching static field (CSS px for pan, multiplier for scale). */
81
+ value: number;
82
+ /** Easing curve for the segment leaving THIS keyframe toward the
83
+ * next one. Optional — omitted / undefined = "linear" (back-compat
84
+ * with projects authored before the easing field existed). */
85
+ easing?: EasingKind;
86
+ }
87
+ interface Track {
88
+ id: string;
89
+ kind: "video" | "audio";
90
+ /** Clips on this track. Must be kept sorted by `start` and non-overlapping. */
91
+ clips: Clip[];
92
+ }
93
+ interface Project {
94
+ /** Schema version — bump when breaking the JSON shape. */
95
+ version: 1;
96
+ sources: MediaSource[];
97
+ tracks: Track[];
98
+ /**
99
+ * Project frame rate. Drives keyboard frame-stepping (← / →), the
100
+ * future timecode display, and ffmpeg compilation of keyframe
101
+ * animations. Optional for back-compat — projects without `fps`
102
+ * default to 30, matching consumer NLE convention (CapCut /
103
+ * Premiere project defaults). `normalizeProject` does NOT fill
104
+ * this in, so a missing field stays missing through round-trips.
105
+ */
106
+ fps?: number;
107
+ }
108
+ /**
109
+ * Subset of CSS variables the editor honors. Pass any custom values
110
+ * via `Editor` options; everything is forwarded as `--aicut-*` on the
111
+ * editor's root container, so a host can also override via plain CSS.
112
+ */
113
+ interface Theme {
114
+ brand?: string;
115
+ secondary?: string;
116
+ surface?: string;
117
+ dark?: string;
118
+ muted?: string;
119
+ card?: string;
120
+ success?: string;
121
+ warning?: string;
122
+ info?: string;
123
+ error?: string;
124
+ /** Toolbar / ruler chrome. Background of the editor frame. */
125
+ controlsBg?: string;
126
+ controlsBorder?: string;
127
+ controlsText?: string;
128
+ controlsHover?: string;
129
+ controlsActive?: string;
130
+ /** Letterbox color around the preview video. Defaults to black. */
131
+ previewBg?: string;
132
+ radiusSm?: string;
133
+ radiusMd?: string;
134
+ radiusLg?: string;
135
+ }
136
+
137
+ export type { Clip as C, EasingKind as E, KeyframeProp as K, Ms as M, Project as P, Track as T, MediaSource as a, Theme as b, Keyframe as c };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicut/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Framework-agnostic core for the AiCut video editor — canvas timeline, data model, pluggable PlaybackEngine (HTML5 / Canvas / WebCodecs), plus opt-in 3D lighting picker.",
5
5
  "license": "MIT",
6
6
  "author": "ziqiang <ziqiangytu@gmail.com>",