@clipkit/playback 1.0.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/worker.js ADDED
@@ -0,0 +1,336 @@
1
+ // Frame-producer worker.
2
+ //
3
+ // Runs ClipkitRuntime against an internally-owned OffscreenCanvas.
4
+ // Listens for protocol messages from the engine on the main thread,
5
+ // produces VideoFrames, and transfers them back via postMessage's
6
+ // transfer list (zero-copy).
7
+ //
8
+ // The worker is intentionally simple — no scheduling, no buffer logic,
9
+ // no cancellation tracking. It's a pure "produce a frame at this time"
10
+ // RPC service. All timing intelligence lives in the engine; stale-frame
11
+ // filtering lives in the engine. See worker-protocol.ts.
12
+ //
13
+ // ─── WebGPU/WebGL2 best practices ───────────────────────────────────
14
+ // - OffscreenCanvas is created here, never transferred in (the spec
15
+ // compliant way to run WebGPU/WebGL2 in a worker)
16
+ // - VideoFrame is the cross-thread primitive; transfer list is zero-copy
17
+ // - Backend negotiation (WebGPU → WebGL2 fallback) runs inside this
18
+ // worker, not on the main thread
19
+ // - Device-loss handling: punted to Phase 5 (engine wiring) — needs
20
+ // coordination with the engine to re-init silently
21
+ // - Visibility-aware production: punted to Phase 5 — the engine pauses
22
+ // produce calls when the document is hidden; the worker doesn't need
23
+ // to know
24
+ import { ClipkitRuntime } from '@clipkit/runtime';
25
+ let runtime = null;
26
+ let canvas = null;
27
+ let disposed = false;
28
+ /**
29
+ * EMA of one blur sample's TRUE render cost in ms — drives the
30
+ * adaptive sample count for live-playback motion blur. CPU submit
31
+ * times lie (the GPU pipelines the work and a heavy scene can cost
32
+ * 20× what the submit suggests), so this is fed by periodic measured
33
+ * frames that drain the GPU via runtime.gpuFinish(). Seeded
34
+ * pessimistically; corrects within one measured frame.
35
+ */
36
+ let liveSampleCostMs = 4;
37
+ /** Blurred frames produced since the last true-cost measurement. */
38
+ let blurFramesSinceMeasure = Infinity; // ∞ → measure the very first one
39
+ /** Per-frame render budget for live blur (ms) — ~realtime at 30fps with headroom. */
40
+ const LIVE_BLUR_BUDGET_MS = 22;
41
+ /** Drain the pipeline and re-measure true cost every N blurred frames. */
42
+ const BLUR_MEASURE_INTERVAL = 10;
43
+ /**
44
+ * The source currently loaded into the runtime. Held so we can apply
45
+ * incremental patches (via `patchElements`) without round-tripping the
46
+ * whole source on every drag tick.
47
+ */
48
+ let currentSource = null;
49
+ function send(message, transfer = []) {
50
+ self.postMessage(message, transfer);
51
+ }
52
+ function sendError(err) {
53
+ const message = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
54
+ send({ type: 'error', message });
55
+ }
56
+ async function handleInit(source, backend) {
57
+ const width = source.width ?? 1920;
58
+ const height = source.height ?? 1080;
59
+ canvas = new OffscreenCanvas(width, height);
60
+ runtime = new ClipkitRuntime(canvas);
61
+ const ok = await runtime.init({ backend });
62
+ if (!ok) {
63
+ send({
64
+ type: 'error',
65
+ message: `Runtime init failed for backend="${backend}". WebGPU and WebGL2 both unavailable in this worker.`,
66
+ });
67
+ runtime = null;
68
+ canvas = null;
69
+ return;
70
+ }
71
+ const api = runtime.api;
72
+ if (!api) {
73
+ send({ type: 'error', message: 'Runtime init reported success but api is null.' });
74
+ return;
75
+ }
76
+ currentSource = source;
77
+ runtime.load(source);
78
+ await runtime.preload();
79
+ reportVideoFallbacks(source);
80
+ send({
81
+ type: 'ready',
82
+ activeApi: api,
83
+ width,
84
+ height,
85
+ timeOrigin: performance.timeOrigin,
86
+ });
87
+ }
88
+ /**
89
+ * Tell the engine which video URLs the runtime could NOT self-decode
90
+ * (WebCodecs path failed) so it can pump frames from the main thread
91
+ * for just those. Empty list = all videos decode in-worker.
92
+ */
93
+ function reportVideoFallbacks(source) {
94
+ if (!runtime)
95
+ return;
96
+ const urls = new Set();
97
+ collectVideoUrls(source.elements, urls);
98
+ const fallbacks = [];
99
+ for (const url of urls) {
100
+ if (!runtime.hasVideoAsset(url))
101
+ fallbacks.push(url);
102
+ }
103
+ send({ type: 'videoFallback', urls: fallbacks });
104
+ }
105
+ function collectVideoUrls(elements, out) {
106
+ for (const el of elements) {
107
+ if (el.type === 'video' && typeof el.source === 'string' && el.source) {
108
+ out.add(el.source);
109
+ }
110
+ else if (el.type === 'group') {
111
+ collectVideoUrls(el.elements, out);
112
+ }
113
+ }
114
+ }
115
+ async function handleSetSource(source) {
116
+ if (!runtime || !canvas)
117
+ return;
118
+ const w = source.width ?? canvas.width;
119
+ const h = source.height ?? canvas.height;
120
+ if (canvas.width !== w || canvas.height !== h) {
121
+ canvas.width = w;
122
+ canvas.height = h;
123
+ }
124
+ currentSource = source;
125
+ runtime.load(source);
126
+ await runtime.preload();
127
+ reportVideoFallbacks(source);
128
+ }
129
+ /**
130
+ * Apply patches to the current source in place, then re-load (without
131
+ * preload — assets unchanged). Skips the costly preload step that
132
+ * full setSource does. Used for live drag/resize dispatches.
133
+ */
134
+ function handlePatchElements(patches) {
135
+ if (!runtime || !canvas || !currentSource)
136
+ return;
137
+ for (const { id, patch } of patches) {
138
+ const el = findById(currentSource.elements, id);
139
+ if (el)
140
+ Object.assign(el, patch);
141
+ }
142
+ runtime.load(currentSource);
143
+ }
144
+ function findById(elements, id) {
145
+ for (const el of elements) {
146
+ if (el.id === id)
147
+ return el;
148
+ if (el.type === 'group') {
149
+ const nested = findById(el.elements, id);
150
+ if (nested)
151
+ return nested;
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ async function handleProduce(time, sequenceId, quality) {
157
+ if (!runtime || !canvas)
158
+ return;
159
+ // Measure each sub-step so the main-thread HUD can show where the
160
+ // budget goes. `performance.mark` calls are wrapped in try/catch
161
+ // because not all browsers accept the `detail` argument; the
162
+ // numeric timings (sent in the frame message) work everywhere.
163
+ const t0 = performance.now();
164
+ try {
165
+ performance.mark('ck.worker.frame.start', { detail: { time } });
166
+ }
167
+ catch {
168
+ /* noop */
169
+ }
170
+ // Decode + upload the exact video frames this composition time needs
171
+ // (WebCodecs path). No-op for sources without frameSource-backed
172
+ // videos. Produce calls are serialized via produceChain below, so an
173
+ // await here can't interleave uploads between two frames.
174
+ await runtime.prepareVideoFrames(time);
175
+ const tPrep = performance.now();
176
+ let blurSamplesUsed = 0;
177
+ const mb = currentSource?.motion_blur;
178
+ const mbSamples = mb
179
+ ? Math.max(1, Math.min(32, Math.round(typeof mb.samples === 'number' ? mb.samples : 8)))
180
+ : 1;
181
+ if (quality === 'final') {
182
+ // Export-accurate frame: full supersampling. Falls back to a plain
183
+ // frame when the source has no motion_blur.
184
+ runtime.renderFinalFrame(time);
185
+ }
186
+ else if (mbSamples > 1) {
187
+ // Live playback: blurred with as many samples as the frame budget
188
+ // affords on this machine, so the effect the export will have is
189
+ // visible while playing — lighter on heavy scenes / slow hardware,
190
+ // near-full elsewhere, never at the cost of realtime.
191
+ const affordable = Math.max(2, Math.min(mbSamples, Math.floor(LIVE_BLUR_BUDGET_MS / Math.max(0.25, liveSampleCostMs))));
192
+ blurSamplesUsed = affordable;
193
+ if (blurFramesSinceMeasure >= BLUR_MEASURE_INTERVAL) {
194
+ // Measured frame: drain the GPU so the timing covers the real
195
+ // shader cost, not just the CPU submit. ~2/sec — the drain stall
196
+ // is the price of a budget that tracks scene weight (fractal
197
+ // noise ×16 samples saturated the GPU while submit times looked
198
+ // idle).
199
+ const t = performance.now();
200
+ runtime.renderFinalFrame(time, affordable);
201
+ await runtime.gpuFinish();
202
+ const costPerSample = (performance.now() - t) / affordable;
203
+ liveSampleCostMs = liveSampleCostMs * 0.5 + costPerSample * 0.5;
204
+ blurFramesSinceMeasure = 0;
205
+ }
206
+ else {
207
+ runtime.renderFinalFrame(time, affordable);
208
+ blurFramesSinceMeasure += 1;
209
+ }
210
+ }
211
+ else {
212
+ runtime.frame(time);
213
+ }
214
+ const t1 = performance.now();
215
+ try {
216
+ performance.mark('ck.worker.frame.end', { detail: { time } });
217
+ performance.mark('ck.worker.videoframe.start', { detail: { time } });
218
+ }
219
+ catch {
220
+ /* noop */
221
+ }
222
+ // Construct a VideoFrame from the OffscreenCanvas's current pixels.
223
+ // `timestamp` is in microseconds per the spec; we encode composition
224
+ // time so consumers can match frames to playhead positions.
225
+ const frame = new VideoFrame(canvas, {
226
+ timestamp: Math.round(time * 1_000_000),
227
+ });
228
+ const t2 = performance.now();
229
+ try {
230
+ performance.mark('ck.worker.videoframe.end', { detail: { time } });
231
+ }
232
+ catch {
233
+ /* noop */
234
+ }
235
+ const sentAt = performance.now();
236
+ send({
237
+ type: 'frame',
238
+ time,
239
+ sequenceId,
240
+ frame,
241
+ timings: {
242
+ frameMs: t1 - tPrep,
243
+ prepareMs: tPrep - t0,
244
+ blurSamples: blurSamplesUsed,
245
+ videoFrameMs: t2 - t1,
246
+ workerTotalMs: performance.now() - t0,
247
+ sentAt,
248
+ },
249
+ }, [frame]);
250
+ }
251
+ /**
252
+ * One export-quality still → ImageBitmap. Runs behind produceChain
253
+ * (the caller chains it) so video-frame uploads never interleave.
254
+ */
255
+ async function handleStill(time, requestId, width) {
256
+ if (!runtime || !canvas) {
257
+ send({ type: 'stillError', requestId, message: 'worker not initialized' });
258
+ return;
259
+ }
260
+ try {
261
+ await runtime.prepareVideoFrames(time);
262
+ // Export-accurate: full motion-blur supersampling when configured.
263
+ runtime.renderFinalFrame(time);
264
+ const opts = {};
265
+ if (width && width > 0 && width < canvas.width) {
266
+ opts.resizeWidth = Math.round(width);
267
+ opts.resizeHeight = Math.round((canvas.height / canvas.width) * width);
268
+ opts.resizeQuality = 'high';
269
+ }
270
+ const bitmap = await createImageBitmap(canvas, opts);
271
+ send({ type: 'stillResult', requestId, time, bitmap }, [bitmap]);
272
+ }
273
+ catch (err) {
274
+ send({
275
+ type: 'stillError',
276
+ requestId,
277
+ message: err instanceof Error ? `${err.name}: ${err.message}` : String(err),
278
+ });
279
+ }
280
+ }
281
+ function handleDispose() {
282
+ if (disposed)
283
+ return;
284
+ disposed = true;
285
+ runtime?.dispose();
286
+ runtime = null;
287
+ canvas = null;
288
+ currentSource = null;
289
+ }
290
+ /**
291
+ * Serializes produce work. handleProduce awaits video decode, and
292
+ * `self.onmessage` fires per message regardless of pending awaits — two
293
+ * unserialized produces would interleave texture uploads and render
294
+ * frame A with frame B's video pixels.
295
+ */
296
+ let produceChain = Promise.resolve();
297
+ self.onmessage = async (event) => {
298
+ if (disposed)
299
+ return;
300
+ const msg = event.data;
301
+ try {
302
+ switch (msg.type) {
303
+ case 'init':
304
+ await handleInit(msg.source, msg.backend);
305
+ return;
306
+ case 'setSource':
307
+ await handleSetSource(msg.source);
308
+ return;
309
+ case 'patchElements':
310
+ handlePatchElements(msg.patches);
311
+ return;
312
+ case 'produce':
313
+ produceChain = produceChain
314
+ .then(() => handleProduce(msg.time, msg.sequenceId, msg.quality))
315
+ .catch(sendError);
316
+ return;
317
+ case 'still':
318
+ produceChain = produceChain
319
+ .then(() => handleStill(msg.time, msg.requestId, msg.width))
320
+ .catch(sendError);
321
+ return;
322
+ case 'videoFrame':
323
+ // Main-thread pump fallback (non-MP4 / no WebCodecs): upload
324
+ // into the texture the video renderer samples.
325
+ runtime?.pushExternalVideoFrame(msg.url, msg.bitmap);
326
+ return;
327
+ case 'dispose':
328
+ handleDispose();
329
+ return;
330
+ }
331
+ }
332
+ catch (err) {
333
+ sendError(err);
334
+ }
335
+ };
336
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,EAAE;AACF,mEAAmE;AACnE,oEAAoE;AACpE,kEAAkE;AAClE,6BAA6B;AAC7B,EAAE;AACF,uEAAuE;AACvE,uEAAuE;AACvE,wEAAwE;AACxE,yDAAyD;AACzD,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,oDAAoD;AACpD,yEAAyE;AACzE,oEAAoE;AACpE,mCAAmC;AACnC,oEAAoE;AACpE,qDAAqD;AACrD,uEAAuE;AACvE,uEAAuE;AACvE,YAAY;AAEZ,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASlD,IAAI,OAAO,GAA0B,IAAI,CAAC;AAC1C,IAAI,MAAM,GAA2B,IAAI,CAAC;AAC1C,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB;;;;;;;GAOG;AACH,IAAI,gBAAgB,GAAG,CAAC,CAAC;AACzB,oEAAoE;AACpE,IAAI,sBAAsB,GAAG,QAAQ,CAAC,CAAC,iCAAiC;AACxE,qFAAqF;AACrF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,0EAA0E;AAC1E,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACjC;;;;GAIG;AACH,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC,SAAS,IAAI,CAAC,OAA4B,EAAE,WAA2B,EAAE;IACvE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,MAA0C,EAC1C,OAAqC;IAErC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC;IACrC,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,IAAI,CAAC;YACH,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,oCAAoC,OAAO,uDAAuD;SAC5G,CAAC,CAAC;QACH,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;QACd,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gDAAgD,EAAE,CAAC,CAAC;QACnF,OAAO;IACT,CAAC;IACD,aAAa,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC;QACH,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,GAAG;QACd,KAAK;QACL,MAAM;QACN,UAAU,EAAE,WAAW,CAAC,UAAU;KACnC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,gBAAgB,CAAC,QAA4B,EAAE,GAAgB;IACtE,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,EAAE,CAAC,MAAM,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACtE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/B,gBAAgB,CAAC,EAAE,CAAC,QAA8B,EAAE,GAAG,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,MAA0C;IAE1C,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM;QAAE,OAAO;IAChC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;IACvC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;IACzC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACjB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,aAAa,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAC1B,OAAsE;IAEtE,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa;QAAE,OAAO;IAClD,KAAK,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,EAAE;YAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,QAAQ,CAAC,QAA4B,EAAE,EAAU;IACxD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAC5B,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,QAA8B,EAAE,EAAE,CAAC,CAAC;YAC/D,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,IAAY,EACZ,UAAkB,EAClB,OAA8B;IAE9B,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM;QAAE,OAAO;IAChC,kEAAkE;IAClE,iEAAiE;IACjE,6DAA6D;IAC7D,+DAA+D;IAC/D,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,qEAAqE;IACrE,iEAAiE;IACjE,qEAAqE;IACrE,0DAA0D;IAC1D,MAAM,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEhC,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,aAAa,EAAE,WAAW,CAAC;IACtC,MAAM,SAAS,GAAG,EAAE;QAClB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC,CAAC;IACN,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,mEAAmE;QACnE,4CAA4C;QAC5C,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACzB,kEAAkE;QAClE,iEAAiE;QACjE,mEAAmE;QACnE,sDAAsD;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,CACxF,CAAC;QACF,eAAe,GAAG,UAAU,CAAC;QAC7B,IAAI,sBAAsB,IAAI,qBAAqB,EAAE,CAAC;YACpD,8DAA8D;YAC9D,iEAAiE;YACjE,6DAA6D;YAC7D,gEAAgE;YAChE,SAAS;YACT,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAC5B,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC3C,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;YAC1B,MAAM,aAAa,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;YAC3D,gBAAgB,GAAG,gBAAgB,GAAG,GAAG,GAAG,aAAa,GAAG,GAAG,CAAC;YAChE,sBAAsB,GAAG,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC3C,sBAAsB,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9D,WAAW,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,oEAAoE;IACpE,qEAAqE;IACrE,4DAA4D;IAC5D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE;QACnC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,SAAS,CAAC;KACxC,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACjC,IAAI,CACF;QACE,IAAI,EAAE,OAAO;QACb,IAAI;QACJ,UAAU;QACV,KAAK;QACL,OAAO,EAAE;YACP,OAAO,EAAE,EAAE,GAAG,KAAK;YACnB,SAAS,EAAE,KAAK,GAAG,EAAE;YACrB,WAAW,EAAE,eAAe;YAC5B,YAAY,EAAE,EAAE,GAAG,EAAE;YACrB,aAAa,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE;YACrC,MAAM;SACP;KACF,EACD,CAAC,KAAK,CAAC,CACR,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,WAAW,CACxB,IAAY,EACZ,SAAiB,EACjB,KAAc;IAEd,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACvC,mEAAmE;QACnE,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAuB,EAAE,CAAC;QACpC,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;YAC/C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;YACvE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC9B,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,IAAI,EAAE,YAAY;YAClB,SAAS;YACT,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SAC5E,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,aAAa;IACpB,IAAI,QAAQ;QAAE,OAAO;IACrB,QAAQ,GAAG,IAAI,CAAC;IAChB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,OAAO,GAAG,IAAI,CAAC;IACf,MAAM,GAAG,IAAI,CAAC;IACd,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,IAAI,YAAY,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAEpD,IAAI,CAAC,SAAS,GAAG,KAAK,EAAE,KAAwC,EAAiB,EAAE;IACjF,IAAI,QAAQ;QAAE,OAAO;IACrB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,MAAM;gBACT,MAAM,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC1C,OAAO;YACT,KAAK,WAAW;gBACd,MAAM,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClC,OAAO;YACT,KAAK,eAAe;gBAClB,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACjC,OAAO;YACT,KAAK,SAAS;gBACZ,YAAY,GAAG,YAAY;qBACxB,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;qBAChE,KAAK,CAAC,SAAS,CAAC,CAAC;gBACpB,OAAO;YACT,KAAK,OAAO;gBACV,YAAY,GAAG,YAAY;qBACxB,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;qBAC3D,KAAK,CAAC,SAAS,CAAC,CAAC;gBACpB,OAAO;YACT,KAAK,YAAY;gBACf,6DAA6D;gBAC7D,+CAA+C;gBAC/C,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBACrD,OAAO;YACT,KAAK,SAAS;gBACZ,aAAa,EAAE,CAAC;gBAChB,OAAO;QACX,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;AACH,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@clipkit/playback",
3
+ "version": "1.0.0",
4
+ "description": "Clipkit playback engine — TransportClock, worker-based renderer, frame ring buffer, and WebAudio scheduling. Drives the playground, the editor SDK preview, and any embedded Clipkit player.",
5
+ "license": "Apache-2.0",
6
+ "repository": { "type": "git", "url": "git+https://github.com/clipkit-video/clipkit.git", "directory": "packages/playback" },
7
+ "homepage": "https://clipkit.dev",
8
+ "bugs": "https://github.com/clipkit-video/clipkit/issues",
9
+ "type": "module",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "dev": "tsc --watch",
26
+ "typecheck": "tsc --noEmit",
27
+ "clean": "rm -rf dist"
28
+ },
29
+ "dependencies": {
30
+ "@clipkit/runtime": "^1.0.0",
31
+ "@clipkit/protocol": "^1.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "^5.7.3"
35
+ }
36
+ }