@video-editor/shared 0.0.1-beta.9 → 1.0.0-beta.2

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.ts CHANGED
@@ -1,18 +1,33 @@
1
1
  declare interface AudioSegment<T extends ITrackType> extends ISegment<T> {
2
2
  segmentType: T;
3
3
  url: string;
4
+ /** Stable library identity; `url` remains the last-known usable location. */
5
+ assetId?: string;
4
6
  fromTime?: number;
5
7
  volume?: number;
6
8
  fadeInDuration?: number;
7
9
  fadeOutDuration?: number;
8
10
  playRate?: number;
11
+ /**
12
+ * Play the same source window [fromTime, fromTime + (endTime - startTime) * playRate]
13
+ * backwards. `fromTime` still anchors the window start. Default false.
14
+ */
15
+ reversed?: boolean;
9
16
  }
10
17
 
18
+ /**
19
+ * CSS-style cubic-bezier easing: solve x(t) = progress for t, return y(t).
20
+ * Newton iterations with a bisection fallback; no dependencies.
21
+ */
22
+ export declare function cubicBezierEase(x1: number, y1: number, x2: number, y2: number, progress: number): number;
23
+
11
24
  /**
12
25
  * Protocol version constant
13
26
  */
14
27
  export declare const CURRENT_PROTOCOL_VERSION: "1.0.0";
15
28
 
29
+ export declare function easeKeyframeProgress(easing: IKeyframeEasing | undefined, progress: number): number;
30
+
16
31
  declare interface EffectSegment<T extends ITrackType> extends ISegment<T> {
17
32
  segmentType: T;
18
33
  effectId: string;
@@ -50,6 +65,14 @@ export declare interface IBackground {
50
65
  opacity?: number;
51
66
  }
52
67
 
68
+ /** Chroma key (green/blue screen) removal for a visual segment. */
69
+ export declare interface IChromaKey {
70
+ color: string;
71
+ similarity: number;
72
+ smoothness?: number;
73
+ spillSuppress?: number;
74
+ }
75
+
53
76
  export declare interface IDropShadow {
54
77
  color?: string;
55
78
  opacity?: number;
@@ -67,13 +90,15 @@ export declare type IFilterSegment = FilterSegment<'filter'>;
67
90
  declare interface IFramesSegment extends ISegment<'frames'> {
68
91
  type: 'image' | 'video' | '3D';
69
92
  url: string;
93
+ /** Stable library identity; `url` remains the last-known usable location. */
94
+ assetId?: string;
70
95
  transform?: ITransform;
71
96
  opacity?: number;
72
97
  fillMode?: IFillMode;
73
98
  animation?: IAnimation;
74
- transitionIn?: ITransition;
75
- transitionOut?: ITransition;
76
99
  palette?: IPalette;
100
+ mask?: IMask;
101
+ chromaKey?: IChromaKey;
77
102
  background?: `rgba(${number},${number},${number},${number})`;
78
103
  }
79
104
 
@@ -84,6 +109,38 @@ export declare interface IImageFramesSegment extends IFramesSegment {
84
109
  format: 'img' | 'gif';
85
110
  }
86
111
 
112
+ export declare interface IKeyframe {
113
+ /** Timeline time relative to segment.startTime, in ms (not scaled by playRate). */
114
+ timeMs: number;
115
+ value: number;
116
+ /** Easing toward the next keyframe. Defaults to 'linear'. */
117
+ easing?: IKeyframeEasing;
118
+ }
119
+
120
+ export declare type IKeyframeEasing = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | [number, number, number, number];
121
+
122
+ export declare type IKeyframeProperty = 'opacity' | 'position.x' | 'position.y' | 'scale' | 'rotation' | 'volume' | 'intensity';
123
+
124
+ export declare interface IKeyframeTrack {
125
+ property: IKeyframeProperty;
126
+ /** Sorted ascending by timeMs; at least one frame. */
127
+ frames: IKeyframe[];
128
+ }
129
+
130
+ /**
131
+ * Shape mask applied to a visual segment. The mask lives in the segment's own
132
+ * display box: `center` is normalized to [-1, 1] with the origin at the box
133
+ * center (+x right, +y up), `size` is the box-relative full extent in [0, 1].
134
+ */
135
+ export declare interface IMask {
136
+ shape: 'rect' | 'ellipse';
137
+ center: [number, number];
138
+ size: [number, number];
139
+ feather?: number;
140
+ rotation?: number;
141
+ inverse?: boolean;
142
+ }
143
+
87
144
  export declare interface IPalette {
88
145
  temperature: number;
89
146
  hue: number;
@@ -115,6 +172,8 @@ export declare interface ISegment<T extends ITrackType = ITrackType> {
115
172
  endTime: number;
116
173
  segmentType: T;
117
174
  url?: string;
175
+ /** Optional per-property animation curves; see docs/rfcs/0002-keyframe-curves.md. */
176
+ keyframes?: IKeyframeTrack[];
118
177
  extra?: SegmentExtra<T> | null;
119
178
  }
120
179
 
@@ -183,6 +242,18 @@ export declare type ITrack<T extends ITrackType> = {
183
242
  trackId: string;
184
243
  trackType: T;
185
244
  children: TrackTypeMapSegment[T][];
245
+ /**
246
+ * When true, the track's visual output is skipped (renderer draws nothing for
247
+ * its segments). Purely a presentation flag: the segments stay in the protocol
248
+ * and keep participating in timeline layout, duration and export.
249
+ */
250
+ hidden?: boolean;
251
+ /**
252
+ * When true, the track's audio output is skipped (audio segments and the audio
253
+ * of video segments stay silent). Purely a presentation flag: it never mutates
254
+ * per-segment `volume`.
255
+ */
256
+ muted?: boolean;
186
257
  extra?: TrackExtra<T> | null;
187
258
  } & (T extends 'frames' ? {
188
259
  isMain?: boolean;
@@ -202,11 +273,21 @@ export declare interface ITransition {
202
273
  duration: number;
203
274
  }
204
275
 
276
+ export declare interface ITransitionEdge extends ITransition {
277
+ fromSegmentId: string;
278
+ toSegmentId: string;
279
+ }
280
+
205
281
  export declare interface IVideoFramesSegment extends IFramesSegment {
206
282
  type: 'video';
207
283
  fromTime?: number;
208
284
  volume?: number;
209
285
  playRate?: number;
286
+ /**
287
+ * Play the same source window [fromTime, fromTime + (endTime - startTime) * playRate]
288
+ * backwards. `fromTime` still anchors the window start. Default false.
289
+ */
290
+ reversed?: boolean;
210
291
  }
211
292
 
212
293
  /**
@@ -221,14 +302,40 @@ export declare interface IVideoProtocol {
221
302
  height: number;
222
303
  fps: number;
223
304
  tracks: TrackUnion[];
305
+ transitions?: ITransitionEdge[];
224
306
  extra?: ProtocolExtra | null;
225
307
  }
226
308
 
309
+ /**
310
+ * Map an absolute timeline time (ms) onto the source media time (ms).
311
+ *
312
+ * Forward: `fromTime + relMs * rate`
313
+ * Reversed: `fromTime + (span - relMs * rate)` — the same source window
314
+ * `[fromTime, fromTime + span]` read from its end back to its start.
315
+ */
316
+ export declare function mapSourceTimeMs(segment: SourceTimedSegment, timelineMs: number): number;
317
+
318
+ /**
319
+ * Shared source-time mapping helpers.
320
+ *
321
+ * A media segment occupies a timeline window `[startTime, endTime]` and reads a
322
+ * source window `[fromTime, fromTime + sourceSpanMs]`. Every consumer (preview
323
+ * evaluator, transition planner, audio manager, compose pipeline) must agree on
324
+ * this mapping, otherwise preview and export drift apart.
325
+ */
326
+ /**
327
+ * Clamp a play rate into the supported range.
328
+ * Non-finite or missing values fall back to 1.
329
+ */
330
+ export declare function normalizePlayRate(playRate?: number): number;
331
+
227
332
  export declare type ProtocolExtra = ProtocolExtraRegistry extends Record<string, never> ? Record<string, never> : NonNullable<ProtocolExtraRegistry>;
228
333
 
229
334
  export declare interface ProtocolExtraRegistry {
230
335
  }
231
336
 
337
+ export declare function sampleKeyframes(track: IKeyframeTrack, relMs: number): number;
338
+
232
339
  export declare type SegmentExtra<T extends ITrackType> = T extends keyof SegmentExtraRegistry ? NonNullable<SegmentExtraRegistry[T]> : Record<string, never>;
233
340
 
234
341
  export declare interface SegmentExtraRegistry {
@@ -236,14 +343,36 @@ export declare interface SegmentExtraRegistry {
236
343
 
237
344
  export declare type SegmentUnion = TrackTypeMapSegment[ITrackType];
238
345
 
346
+ /**
347
+ * Length of the source window consumed by the segment, in ms.
348
+ * `(endTime - startTime) * playRate`.
349
+ */
350
+ export declare function sourceSpanMs(segment: SourceTimedSegment): number;
351
+
352
+ /** Minimal shape needed to map a timeline time onto a source time. */
353
+ export declare interface SourceTimedSegment {
354
+ startTime: number;
355
+ endTime: number;
356
+ /** Source window start in ms. Defaults to 0. */
357
+ fromTime?: number;
358
+ /** Playback speed multiplier. Defaults to 1. */
359
+ playRate?: number;
360
+ /** Play the same source window backwards. Defaults to false. */
361
+ reversed?: boolean;
362
+ }
363
+
239
364
  declare interface StickerSegment<T extends ITrackType> extends ISegment<T> {
240
365
  segmentType: T;
241
366
  format: 'img' | 'gif';
242
367
  url: string;
368
+ /** Stable library identity; `url` remains the last-known usable location. */
369
+ assetId?: string;
243
370
  fillMode?: IFillMode;
244
371
  animation?: IAnimation;
245
372
  transform?: ITransform;
246
373
  palette?: IPalette;
374
+ mask?: IMask;
375
+ chromaKey?: IChromaKey;
247
376
  }
248
377
 
249
378
  declare interface TextSegment<T extends ITrackType> extends ISegment<T> {
package/dist/index.js CHANGED
@@ -1,46 +1,131 @@
1
- const i = "1.0.0";
2
- function r(e) {
1
+ const S = {
2
+ easeIn: [0.42, 0, 1, 1],
3
+ easeOut: [0, 0, 0.58, 1],
4
+ easeInOut: [0.42, 0, 0.58, 1]
5
+ };
6
+ function E(e, n) {
7
+ const t = e.frames, i = t[0];
8
+ if (!i)
9
+ return Number.NaN;
10
+ if (t.length === 1 || n <= i.timeMs)
11
+ return i.value;
12
+ const r = t[t.length - 1];
13
+ if (n >= r.timeMs)
14
+ return r.value;
15
+ for (let a = 0; a < t.length - 1; a++) {
16
+ const s = t[a], c = t[a + 1];
17
+ if (n < s.timeMs || n > c.timeMs)
18
+ continue;
19
+ const u = c.timeMs - s.timeMs;
20
+ if (u <= 0)
21
+ return c.value;
22
+ const f = (n - s.timeMs) / u;
23
+ return s.value + (c.value - s.value) * p(s.easing, f);
24
+ }
25
+ return r.value;
26
+ }
27
+ function p(e, n) {
28
+ if (!e || e === "linear")
29
+ return n;
30
+ const t = Array.isArray(e) ? e : S[e];
31
+ return t ? d(t[0], t[1], t[2], t[3], n) : n;
32
+ }
33
+ function d(e, n, t, i, r) {
34
+ if (r <= 0)
35
+ return 0;
36
+ if (r >= 1)
37
+ return 1;
38
+ const a = (o) => y(o, e, t), s = (o) => y(o, n, i), c = (o) => v(o, e, t);
39
+ let u = r;
40
+ for (let o = 0; o < 8; o++) {
41
+ const T = a(u) - r;
42
+ if (Math.abs(T) < 1e-6)
43
+ return s(u);
44
+ const M = c(u);
45
+ if (Math.abs(M) < 1e-6)
46
+ break;
47
+ u -= T / M;
48
+ }
49
+ let f = 0, l = 1;
50
+ for (u = r; l - f > 1e-6; )
51
+ a(u) < r ? f = u : l = u, u = (f + l) / 2;
52
+ return s(u);
53
+ }
54
+ function y(e, n, t) {
55
+ const i = 1 - e;
56
+ return 3 * i * i * e * n + 3 * i * e * e * t + e * e * e;
57
+ }
58
+ function v(e, n, t) {
59
+ const i = 1 - e;
60
+ return 3 * i * i * n + 6 * i * e * (t - n) + 3 * e * e * (1 - t);
61
+ }
62
+ const A = 0.1, x = 100;
63
+ function h(e) {
64
+ return typeof e != "number" || !Number.isFinite(e) ? 1 : Math.max(A, Math.min(x, e));
65
+ }
66
+ function m(e) {
67
+ return typeof e != "number" || !Number.isFinite(e) ? 0 : Math.max(0, e);
68
+ }
69
+ function b(e) {
70
+ return Math.max(0, m(e.endTime) - m(e.startTime)) * h(e.playRate);
71
+ }
72
+ function R(e, n) {
73
+ const t = Math.max(0, m(n) - m(e.startTime)), i = m(e.fromTime), r = h(e.playRate);
74
+ if (e.reversed === !0) {
75
+ const a = b(e);
76
+ return Math.max(i, i + Math.max(0, a - t * r));
77
+ }
78
+ return Math.max(0, i + t * r);
79
+ }
80
+ const _ = "1.0.0";
81
+ function I(e) {
3
82
  return e.segmentType === "frames";
4
83
  }
5
- function u(e) {
84
+ function O(e) {
6
85
  return e.segmentType === "frames" && "type" in e && e.type === "video";
7
86
  }
8
- function s(e) {
87
+ function P(e) {
9
88
  return e.segmentType === "text";
10
89
  }
11
- function f(e) {
90
+ function k(e) {
12
91
  return e.segmentType === "sticker";
13
92
  }
14
- function m(e) {
93
+ function z(e) {
15
94
  return e.segmentType === "audio";
16
95
  }
17
- function c(e) {
96
+ function F(e) {
18
97
  return e.segmentType === "effect";
19
98
  }
20
- function o(e) {
99
+ function D(e) {
21
100
  return e.segmentType === "filter";
22
101
  }
23
- function T(e) {
102
+ function Y(e) {
24
103
  return e.endTime - e.startTime;
25
104
  }
26
- function g(e, t) {
27
- return e >= t.startTime && e < t.endTime;
105
+ function g(e, n) {
106
+ return e >= n.startTime && e < n.endTime;
28
107
  }
29
- const n = ["frames", "text", "sticker", "audio", "effect", "filter"];
30
- function a(e) {
31
- return n.includes(e);
108
+ const N = ["frames", "text", "sticker", "audio", "effect", "filter"];
109
+ function C(e) {
110
+ return N.includes(e);
32
111
  }
33
112
  export {
34
- i as CURRENT_PROTOCOL_VERSION,
35
- n as TRACK_TYPES,
36
- T as getSegmentDuration,
37
- m as isAudioSegment,
38
- c as isEffectSegment,
39
- o as isFilterSegment,
40
- r as isFramesSegment,
41
- f as isStickerSegment,
42
- s as isTextSegment,
113
+ _ as CURRENT_PROTOCOL_VERSION,
114
+ N as TRACK_TYPES,
115
+ d as cubicBezierEase,
116
+ p as easeKeyframeProgress,
117
+ Y as getSegmentDuration,
118
+ z as isAudioSegment,
119
+ F as isEffectSegment,
120
+ D as isFilterSegment,
121
+ I as isFramesSegment,
122
+ k as isStickerSegment,
123
+ P as isTextSegment,
43
124
  g as isTimeInSegment,
44
- a as isValidTrackType,
45
- u as isVideoFramesSegment
125
+ C as isValidTrackType,
126
+ O as isVideoFramesSegment,
127
+ R as mapSourceTimeMs,
128
+ h as normalizePlayRate,
129
+ E as sampleKeyframes,
130
+ b as sourceSpanMs
46
131
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@video-editor/shared",
3
3
  "type": "module",
4
- "version": "0.0.1-beta.9",
4
+ "version": "1.0.0-beta.2",
5
5
  "description": "video editor shared libs",
6
6
  "author": "",
7
7
  "license": "ISC",
@@ -20,6 +20,7 @@
20
20
  "dist"
21
21
  ],
22
22
  "scripts": {
23
- "build": "vite build --config vite.config.ts"
23
+ "build": "vite build --config vite.config.ts",
24
+ "test": "vitest run --config ./vitest.config.ts"
24
25
  }
25
26
  }