@video-editor/shared 0.0.1-beta.9 → 1.0.0-beta.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.
package/dist/index.d.ts CHANGED
@@ -6,13 +6,26 @@ declare interface AudioSegment<T extends ITrackType> extends ISegment<T> {
6
6
  fadeInDuration?: number;
7
7
  fadeOutDuration?: number;
8
8
  playRate?: number;
9
+ /**
10
+ * Play the same source window [fromTime, fromTime + (endTime - startTime) * playRate]
11
+ * backwards. `fromTime` still anchors the window start. Default false.
12
+ */
13
+ reversed?: boolean;
9
14
  }
10
15
 
16
+ /**
17
+ * CSS-style cubic-bezier easing: solve x(t) = progress for t, return y(t).
18
+ * Newton iterations with a bisection fallback; no dependencies.
19
+ */
20
+ export declare function cubicBezierEase(x1: number, y1: number, x2: number, y2: number, progress: number): number;
21
+
11
22
  /**
12
23
  * Protocol version constant
13
24
  */
14
25
  export declare const CURRENT_PROTOCOL_VERSION: "1.0.0";
15
26
 
27
+ export declare function easeKeyframeProgress(easing: IKeyframeEasing | undefined, progress: number): number;
28
+
16
29
  declare interface EffectSegment<T extends ITrackType> extends ISegment<T> {
17
30
  segmentType: T;
18
31
  effectId: string;
@@ -50,6 +63,14 @@ export declare interface IBackground {
50
63
  opacity?: number;
51
64
  }
52
65
 
66
+ /** Chroma key (green/blue screen) removal for a visual segment. */
67
+ export declare interface IChromaKey {
68
+ color: string;
69
+ similarity: number;
70
+ smoothness?: number;
71
+ spillSuppress?: number;
72
+ }
73
+
53
74
  export declare interface IDropShadow {
54
75
  color?: string;
55
76
  opacity?: number;
@@ -71,9 +92,9 @@ declare interface IFramesSegment extends ISegment<'frames'> {
71
92
  opacity?: number;
72
93
  fillMode?: IFillMode;
73
94
  animation?: IAnimation;
74
- transitionIn?: ITransition;
75
- transitionOut?: ITransition;
76
95
  palette?: IPalette;
96
+ mask?: IMask;
97
+ chromaKey?: IChromaKey;
77
98
  background?: `rgba(${number},${number},${number},${number})`;
78
99
  }
79
100
 
@@ -84,6 +105,38 @@ export declare interface IImageFramesSegment extends IFramesSegment {
84
105
  format: 'img' | 'gif';
85
106
  }
86
107
 
108
+ export declare interface IKeyframe {
109
+ /** Timeline time relative to segment.startTime, in ms (not scaled by playRate). */
110
+ timeMs: number;
111
+ value: number;
112
+ /** Easing toward the next keyframe. Defaults to 'linear'. */
113
+ easing?: IKeyframeEasing;
114
+ }
115
+
116
+ export declare type IKeyframeEasing = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | [number, number, number, number];
117
+
118
+ export declare type IKeyframeProperty = 'opacity' | 'position.x' | 'position.y' | 'scale' | 'rotation' | 'volume' | 'intensity';
119
+
120
+ export declare interface IKeyframeTrack {
121
+ property: IKeyframeProperty;
122
+ /** Sorted ascending by timeMs; at least one frame. */
123
+ frames: IKeyframe[];
124
+ }
125
+
126
+ /**
127
+ * Shape mask applied to a visual segment. The mask lives in the segment's own
128
+ * display box: `center` is normalized to [-1, 1] with the origin at the box
129
+ * center (+x right, +y up), `size` is the box-relative full extent in [0, 1].
130
+ */
131
+ export declare interface IMask {
132
+ shape: 'rect' | 'ellipse';
133
+ center: [number, number];
134
+ size: [number, number];
135
+ feather?: number;
136
+ rotation?: number;
137
+ inverse?: boolean;
138
+ }
139
+
87
140
  export declare interface IPalette {
88
141
  temperature: number;
89
142
  hue: number;
@@ -115,6 +168,8 @@ export declare interface ISegment<T extends ITrackType = ITrackType> {
115
168
  endTime: number;
116
169
  segmentType: T;
117
170
  url?: string;
171
+ /** Optional per-property animation curves; see docs/rfcs/0002-keyframe-curves.md. */
172
+ keyframes?: IKeyframeTrack[];
118
173
  extra?: SegmentExtra<T> | null;
119
174
  }
120
175
 
@@ -183,6 +238,18 @@ export declare type ITrack<T extends ITrackType> = {
183
238
  trackId: string;
184
239
  trackType: T;
185
240
  children: TrackTypeMapSegment[T][];
241
+ /**
242
+ * When true, the track's visual output is skipped (renderer draws nothing for
243
+ * its segments). Purely a presentation flag: the segments stay in the protocol
244
+ * and keep participating in timeline layout, duration and export.
245
+ */
246
+ hidden?: boolean;
247
+ /**
248
+ * When true, the track's audio output is skipped (audio segments and the audio
249
+ * of video segments stay silent). Purely a presentation flag: it never mutates
250
+ * per-segment `volume`.
251
+ */
252
+ muted?: boolean;
186
253
  extra?: TrackExtra<T> | null;
187
254
  } & (T extends 'frames' ? {
188
255
  isMain?: boolean;
@@ -202,11 +269,21 @@ export declare interface ITransition {
202
269
  duration: number;
203
270
  }
204
271
 
272
+ export declare interface ITransitionEdge extends ITransition {
273
+ fromSegmentId: string;
274
+ toSegmentId: string;
275
+ }
276
+
205
277
  export declare interface IVideoFramesSegment extends IFramesSegment {
206
278
  type: 'video';
207
279
  fromTime?: number;
208
280
  volume?: number;
209
281
  playRate?: number;
282
+ /**
283
+ * Play the same source window [fromTime, fromTime + (endTime - startTime) * playRate]
284
+ * backwards. `fromTime` still anchors the window start. Default false.
285
+ */
286
+ reversed?: boolean;
210
287
  }
211
288
 
212
289
  /**
@@ -221,14 +298,40 @@ export declare interface IVideoProtocol {
221
298
  height: number;
222
299
  fps: number;
223
300
  tracks: TrackUnion[];
301
+ transitions?: ITransitionEdge[];
224
302
  extra?: ProtocolExtra | null;
225
303
  }
226
304
 
305
+ /**
306
+ * Map an absolute timeline time (ms) onto the source media time (ms).
307
+ *
308
+ * Forward: `fromTime + relMs * rate`
309
+ * Reversed: `fromTime + (span - relMs * rate)` — the same source window
310
+ * `[fromTime, fromTime + span]` read from its end back to its start.
311
+ */
312
+ export declare function mapSourceTimeMs(segment: SourceTimedSegment, timelineMs: number): number;
313
+
314
+ /**
315
+ * Shared source-time mapping helpers.
316
+ *
317
+ * A media segment occupies a timeline window `[startTime, endTime]` and reads a
318
+ * source window `[fromTime, fromTime + sourceSpanMs]`. Every consumer (preview
319
+ * evaluator, transition planner, audio manager, compose pipeline) must agree on
320
+ * this mapping, otherwise preview and export drift apart.
321
+ */
322
+ /**
323
+ * Clamp a play rate into the supported range.
324
+ * Non-finite or missing values fall back to 1.
325
+ */
326
+ export declare function normalizePlayRate(playRate?: number): number;
327
+
227
328
  export declare type ProtocolExtra = ProtocolExtraRegistry extends Record<string, never> ? Record<string, never> : NonNullable<ProtocolExtraRegistry>;
228
329
 
229
330
  export declare interface ProtocolExtraRegistry {
230
331
  }
231
332
 
333
+ export declare function sampleKeyframes(track: IKeyframeTrack, relMs: number): number;
334
+
232
335
  export declare type SegmentExtra<T extends ITrackType> = T extends keyof SegmentExtraRegistry ? NonNullable<SegmentExtraRegistry[T]> : Record<string, never>;
233
336
 
234
337
  export declare interface SegmentExtraRegistry {
@@ -236,6 +339,24 @@ export declare interface SegmentExtraRegistry {
236
339
 
237
340
  export declare type SegmentUnion = TrackTypeMapSegment[ITrackType];
238
341
 
342
+ /**
343
+ * Length of the source window consumed by the segment, in ms.
344
+ * `(endTime - startTime) * playRate`.
345
+ */
346
+ export declare function sourceSpanMs(segment: SourceTimedSegment): number;
347
+
348
+ /** Minimal shape needed to map a timeline time onto a source time. */
349
+ export declare interface SourceTimedSegment {
350
+ startTime: number;
351
+ endTime: number;
352
+ /** Source window start in ms. Defaults to 0. */
353
+ fromTime?: number;
354
+ /** Playback speed multiplier. Defaults to 1. */
355
+ playRate?: number;
356
+ /** Play the same source window backwards. Defaults to false. */
357
+ reversed?: boolean;
358
+ }
359
+
239
360
  declare interface StickerSegment<T extends ITrackType> extends ISegment<T> {
240
361
  segmentType: T;
241
362
  format: 'img' | 'gif';
@@ -244,6 +365,8 @@ declare interface StickerSegment<T extends ITrackType> extends ISegment<T> {
244
365
  animation?: IAnimation;
245
366
  transform?: ITransform;
246
367
  palette?: IPalette;
368
+ mask?: IMask;
369
+ chromaKey?: IChromaKey;
247
370
  }
248
371
 
249
372
  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.1",
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
  }