@dojo-video-engine/player 0.0.0-stage → 1.1.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.js ADDED
@@ -0,0 +1,587 @@
1
+ import { inspectScene, parseScene, } from "@dojo-video-engine/schema";
2
+ import { BoundedTextMeasureCache, disposeAssetsAsync, prepareFrame, renderStill, resolveAssets, } from "@dojo-video-engine/renderer-canvas2d";
3
+ import { withCanvas2DResolvedAssets, } from "@dojo-video-engine/renderer-canvas2d/runtime";
4
+ import { ChunkedWebAudioPreview, } from "./audio.js";
5
+ export { ChunkedWebAudioPreview, previewAudioChunkRange, WebAudioPreview, } from "./audio.js";
6
+ /**
7
+ * Maps wall-clock time to scene frames. This is the only place in the
8
+ * playback path where wall-clock time exists: rendering stays a pure function
9
+ * of (scene, frame). The clock is pure given injected timestamps, so playback
10
+ * timing is unit-testable without timers.
11
+ *
12
+ * Frames are integers in [0, durationInFrames). While playing, the frame at
13
+ * time `now` is anchored to the play() position: floor((now − anchorTime) /
14
+ * 1000 × fps) + anchorFrame. Pausing re-anchors; seeking re-anchors while
15
+ * preserving play state.
16
+ */
17
+ export class FrameClock {
18
+ fps;
19
+ durationInFrames;
20
+ loop;
21
+ anchorFrame = 0;
22
+ anchorTime = 0;
23
+ isPlaying = false;
24
+ constructor(options) {
25
+ if (options.fps <= 0 || !Number.isFinite(options.fps)) {
26
+ throw new Error(`FrameClock fps must be a positive number, got ${options.fps}.`);
27
+ }
28
+ if (!Number.isInteger(options.durationInFrames) ||
29
+ options.durationInFrames <= 0) {
30
+ throw new Error(`FrameClock durationInFrames must be a positive integer, got ${options.durationInFrames}.`);
31
+ }
32
+ this.fps = options.fps;
33
+ this.durationInFrames = options.durationInFrames;
34
+ this.loop = options.loop ?? false;
35
+ }
36
+ get playing() {
37
+ return this.isPlaying;
38
+ }
39
+ /** Starts (or restarts) playback at the current frame position. */
40
+ play(now) {
41
+ if (this.isPlaying) {
42
+ return;
43
+ }
44
+ // Playing from the final frame restarts from 0 — the universal
45
+ // player-button expectation.
46
+ if (!this.loop && this.anchorFrame >= this.durationInFrames - 1) {
47
+ this.anchorFrame = 0;
48
+ }
49
+ this.anchorTime = now;
50
+ this.isPlaying = true;
51
+ }
52
+ /** Freezes the clock at the frame visible at `now`. */
53
+ pause(now) {
54
+ if (!this.isPlaying) {
55
+ return;
56
+ }
57
+ this.anchorFrame = this.frameAt(now).frame;
58
+ this.isPlaying = false;
59
+ }
60
+ /** Jumps to a frame (clamped to the scene range), preserving play state. */
61
+ seek(frame, now) {
62
+ this.anchorFrame = Math.min(Math.max(Math.floor(frame), 0), this.durationInFrames - 1);
63
+ this.anchorTime = now;
64
+ }
65
+ /**
66
+ * The frame visible at wall time `now`, and whether non-looping playback
67
+ * has run past the final frame. Calling this never mutates the clock;
68
+ * the caller decides what to do at the end (pause, loop is internal).
69
+ */
70
+ frameAt(now) {
71
+ if (!this.isPlaying) {
72
+ return { frame: this.anchorFrame, ended: false };
73
+ }
74
+ const elapsed = Math.max(0, now - this.anchorTime);
75
+ const advanced = Math.floor((elapsed / 1000) * this.fps) + this.anchorFrame;
76
+ if (advanced < this.durationInFrames) {
77
+ return { frame: advanced, ended: false };
78
+ }
79
+ if (this.loop) {
80
+ return { frame: advanced % this.durationInFrames, ended: false };
81
+ }
82
+ return { frame: this.durationInFrames - 1, ended: true };
83
+ }
84
+ }
85
+ async function waitForPlayerOperation(operation, signal) {
86
+ if (!signal)
87
+ return operation;
88
+ if (signal.aborted)
89
+ throw signal.reason;
90
+ let listener;
91
+ const aborted = new Promise((_resolve, reject) => {
92
+ listener = () => reject(signal.reason instanceof Error
93
+ ? signal.reason
94
+ : new Error("Player operation aborted."));
95
+ signal.addEventListener("abort", listener, { once: true });
96
+ });
97
+ try {
98
+ return await Promise.race([operation, aborted]);
99
+ }
100
+ finally {
101
+ signal.removeEventListener("abort", listener);
102
+ }
103
+ }
104
+ /**
105
+ * A playing/seekable view of a scene on a canvas. Create with createPlayer().
106
+ *
107
+ * The render loop awaits prepareFrame() per displayed frame (video decode),
108
+ * so a slow decode never tears: the player skips to the latest target frame
109
+ * rather than rendering stale intermediates.
110
+ */
111
+ export class Player {
112
+ scene;
113
+ clock;
114
+ context;
115
+ externalRenderFrame;
116
+ assets;
117
+ ownsAssets;
118
+ now;
119
+ requestFrame;
120
+ cancelFrame;
121
+ signal;
122
+ scratchSurfacePool;
123
+ staticDisplayCache;
124
+ renderController = new AbortController();
125
+ unlinkOptionSignal = null;
126
+ listeners = new Map();
127
+ renderedFrame = -1;
128
+ rafHandle = null;
129
+ rendering = false;
130
+ renderQueue = Promise.resolve();
131
+ assetsReleased = false;
132
+ disposed = false;
133
+ disposalPromise = null;
134
+ lastRenderError = null;
135
+ errorListeners = new Set();
136
+ audio = null;
137
+ pendingAudio = null;
138
+ disposedAudio = new WeakSet();
139
+ audioReadyPromise = Promise.resolve();
140
+ textMeasureCache = new BoundedTextMeasureCache();
141
+ onDisposeRequested;
142
+ /** @internal — use createPlayer(). */
143
+ constructor(scene, options, assets, ownsAssets, lifecycle = {}) {
144
+ this.scene = scene;
145
+ this.context = options.context;
146
+ this.externalRenderFrame = options.renderFrame;
147
+ this.assets = assets;
148
+ this.ownsAssets = ownsAssets;
149
+ this.scratchSurfacePool = options.scratchSurfacePool;
150
+ this.staticDisplayCache = options.staticDisplayCache;
151
+ this.onDisposeRequested = lifecycle.onDisposeRequested ?? null;
152
+ this.signal = this.renderController.signal;
153
+ if (options.signal) {
154
+ const abort = () => this.renderController.abort(options.signal?.reason);
155
+ if (options.signal.aborted)
156
+ abort();
157
+ else {
158
+ options.signal.addEventListener("abort", abort, { once: true });
159
+ this.unlinkOptionSignal = () => options.signal?.removeEventListener("abort", abort);
160
+ }
161
+ }
162
+ this.now = options.now ?? (() => performance.now());
163
+ this.requestFrame =
164
+ options.requestFrame ??
165
+ ((callback) => globalThis.requestAnimationFrame(callback));
166
+ this.cancelFrame =
167
+ options.cancelFrame ??
168
+ ((handle) => globalThis.cancelAnimationFrame(handle));
169
+ this.clock = new FrameClock({
170
+ fps: scene.fps,
171
+ durationInFrames: scene.duration,
172
+ loop: options.loop ?? false,
173
+ });
174
+ }
175
+ get playing() {
176
+ return this.clock.playing;
177
+ }
178
+ /** The most recently rendered frame (−1 before the first render). */
179
+ get currentFrame() {
180
+ return this.renderedFrame;
181
+ }
182
+ get loop() {
183
+ return this.clock.loop;
184
+ }
185
+ set loop(value) {
186
+ this.clock.loop = value;
187
+ }
188
+ /** Last asynchronous render-loop error, if playback stopped because of one. */
189
+ get error() {
190
+ return this.lastRenderError;
191
+ }
192
+ onError(listener) {
193
+ this.errorListeners.add(listener);
194
+ return () => this.errorListeners.delete(listener);
195
+ }
196
+ /**
197
+ * Resolves once the audio preview is attached, or once the player knows
198
+ * there will be none (silent scene, unsupported environment, mix failure).
199
+ * The mix is prepared off the critical path, so the first frame paints
200
+ * before sound exists; playback started earlier joins the audio clock the
201
+ * moment it attaches. Await this when audio must be live before play().
202
+ */
203
+ get audioReady() {
204
+ return this.audioReadyPromise;
205
+ }
206
+ on(event, listener) {
207
+ if (!this.listeners.has(event)) {
208
+ this.listeners.set(event, new Set());
209
+ }
210
+ this.listeners.get(event)?.add(listener);
211
+ return () => this.listeners.get(event)?.delete(listener);
212
+ }
213
+ play() {
214
+ this.assertAlive();
215
+ if (this.clock.playing) {
216
+ return;
217
+ }
218
+ this.clock.play(this.now());
219
+ const startFrame = this.clock.frameAt(this.now()).frame;
220
+ this.audio?.start(startFrame / this.scene.fps);
221
+ this.emit("play", this.renderedFrame);
222
+ this.scheduleTick();
223
+ }
224
+ pause() {
225
+ this.assertAlive();
226
+ if (!this.clock.playing) {
227
+ return;
228
+ }
229
+ this.clock.pause(this.now());
230
+ this.audio?.stop();
231
+ this.stopTicking();
232
+ this.emit("pause", this.clock.frameAt(this.now()).frame);
233
+ }
234
+ /** Jumps to a frame and renders it; resolves when the frame is on screen. */
235
+ async seek(frame) {
236
+ this.assertAlive();
237
+ this.clock.seek(frame, this.now());
238
+ const target = this.clock.frameAt(this.now()).frame;
239
+ if (this.clock.playing) {
240
+ this.audio?.start(target / this.scene.fps);
241
+ }
242
+ await this.renderFrame(target);
243
+ }
244
+ /** Stops playback and releases player-owned assets. */
245
+ dispose() {
246
+ if (this.disposed) {
247
+ return;
248
+ }
249
+ this.stopTicking();
250
+ this.disposed = true;
251
+ const notifyDisposeRequested = this.onDisposeRequested;
252
+ this.onDisposeRequested = null;
253
+ notifyDisposeRequested?.();
254
+ this.renderController.abort(typeof DOMException === "function"
255
+ ? new DOMException("Player disposed.", "AbortError")
256
+ : new Error("Player disposed."));
257
+ this.unlinkOptionSignal?.();
258
+ this.unlinkOptionSignal = null;
259
+ this.listeners.clear();
260
+ this.errorListeners.clear();
261
+ if (this.audio)
262
+ this.disposeAudioOnce(this.audio);
263
+ this.audio = null;
264
+ if (this.pendingAudio)
265
+ this.disposeAudioOnce(this.pendingAudio);
266
+ this.pendingAudio = null;
267
+ void this.beginDisposal().catch(() => {
268
+ // Await disposeAsync() when teardown failures must be observed.
269
+ });
270
+ }
271
+ /** Stops playback and waits for audio/render work and owned media teardown. */
272
+ async disposeAsync() {
273
+ this.dispose();
274
+ await this.beginDisposal();
275
+ }
276
+ /** @internal — wired by createPlayer() after load() decides audibility. */
277
+ attachAudio(audio) {
278
+ if (this.pendingAudio === audio)
279
+ this.pendingAudio = null;
280
+ if (this.disposed) {
281
+ this.disposeAudioOnce(audio);
282
+ return;
283
+ }
284
+ this.audio = audio;
285
+ // The mix finished while playback was already running: join it at the
286
+ // current position instead of staying silent until the next play().
287
+ if (this.clock.playing) {
288
+ audio.start(this.clock.frameAt(this.now()).frame / this.scene.fps);
289
+ }
290
+ }
291
+ /** @internal — binds preview preparation to the player lifecycle signal. */
292
+ loadAudio(audio) {
293
+ this.pendingAudio = audio;
294
+ return audio.load(this.scene, this.assets, this.signal);
295
+ }
296
+ /** @internal — clears a preview that resolved silent or failed to load. */
297
+ discardAudio(audio) {
298
+ if (this.pendingAudio === audio)
299
+ this.pendingAudio = null;
300
+ this.disposeAudioOnce(audio);
301
+ }
302
+ disposeAudioOnce(audio) {
303
+ if (this.disposedAudio.has(audio))
304
+ return;
305
+ this.disposedAudio.add(audio);
306
+ audio.dispose();
307
+ }
308
+ /** @internal — wired by createPlayer(). */
309
+ setAudioReady(ready) {
310
+ this.audioReadyPromise = ready;
311
+ }
312
+ /** @internal — first paint from createPlayer(). */
313
+ async renderInitialFrame() {
314
+ await this.renderFrame(0);
315
+ }
316
+ scheduleTick() {
317
+ if (this.rafHandle !== null || this.disposed) {
318
+ return;
319
+ }
320
+ this.rafHandle = this.requestFrame(() => {
321
+ this.rafHandle = null;
322
+ void this.tick().catch((error) => this.handleRenderError(error));
323
+ });
324
+ }
325
+ stopTicking() {
326
+ if (this.rafHandle !== null) {
327
+ this.cancelFrame(this.rafHandle);
328
+ this.rafHandle = null;
329
+ }
330
+ }
331
+ async tick() {
332
+ if (this.disposed || !this.clock.playing) {
333
+ return;
334
+ }
335
+ // Audio hardware is the steadier clock: when the frame clock drifts more
336
+ // than one frame from the audio position, re-anchor the frame clock. A
337
+ // skipped video frame is invisible; skipped audio is not.
338
+ const audioPosition = this.audio?.position();
339
+ if (audioPosition != null) {
340
+ const audioFrame = Math.floor(audioPosition * this.scene.fps);
341
+ const clockFrame = this.clock.frameAt(this.now()).frame;
342
+ if (Math.abs(audioFrame - clockFrame) > 1 &&
343
+ audioFrame < this.clock.durationInFrames) {
344
+ this.clock.seek(audioFrame, this.now());
345
+ }
346
+ }
347
+ const { frame, ended } = this.clock.frameAt(this.now());
348
+ // Loop wrap: the clock jumped backwards, so the audio source (which
349
+ // plays linearly) must restart from the wrapped position.
350
+ if (frame < this.renderedFrame && this.clock.loop) {
351
+ this.audio?.start(frame / this.scene.fps);
352
+ }
353
+ if (frame !== this.renderedFrame) {
354
+ await this.renderFrame(frame);
355
+ }
356
+ if (ended) {
357
+ this.clock.pause(this.now());
358
+ this.audio?.stop();
359
+ this.emit("ended", frame);
360
+ return;
361
+ }
362
+ this.scheduleTick();
363
+ }
364
+ async renderFrame(frame) {
365
+ const task = this.renderQueue
366
+ .catch(() => undefined)
367
+ .then(() => this.performRenderFrame(frame));
368
+ this.renderQueue = task.catch(() => undefined);
369
+ return task;
370
+ }
371
+ async performRenderFrame(frame) {
372
+ if (this.disposed)
373
+ return;
374
+ this.rendering = true;
375
+ try {
376
+ if (this.externalRenderFrame) {
377
+ await waitForPlayerOperation(this.externalRenderFrame(frame, this.signal), this.signal);
378
+ if (this.disposed)
379
+ return;
380
+ this.renderedFrame = frame;
381
+ this.emit("frame", frame);
382
+ return;
383
+ }
384
+ const resolvedScene = this.assets
385
+ ? await waitForPlayerOperation(prepareFrame(this.scene, frame, this.assets, {
386
+ signal: this.signal,
387
+ }), this.signal)
388
+ : undefined;
389
+ if (this.disposed) {
390
+ return;
391
+ }
392
+ renderStill(this.context, this.scene, frame, {
393
+ assets: this.assets,
394
+ resolvedScene,
395
+ textMeasureCache: this.textMeasureCache,
396
+ scratchSurfacePool: this.scratchSurfacePool,
397
+ staticDisplayCache: this.staticDisplayCache,
398
+ });
399
+ this.renderedFrame = frame;
400
+ this.emit("frame", frame);
401
+ }
402
+ catch (error) {
403
+ if (!this.disposed) {
404
+ throw error;
405
+ }
406
+ }
407
+ finally {
408
+ this.rendering = false;
409
+ if (this.disposed) {
410
+ void this.beginDisposal().catch(() => undefined);
411
+ }
412
+ }
413
+ }
414
+ beginDisposal() {
415
+ if (this.disposalPromise)
416
+ return this.disposalPromise;
417
+ const ownedAssetDisposal = this.releaseOwnedAssets();
418
+ this.disposalPromise = (async () => {
419
+ await this.renderQueue.catch(() => undefined);
420
+ await ownedAssetDisposal;
421
+ })();
422
+ return this.disposalPromise;
423
+ }
424
+ async releaseOwnedAssets() {
425
+ if (!this.ownsAssets || !this.assets || this.assetsReleased) {
426
+ return;
427
+ }
428
+ this.assetsReleased = true;
429
+ await disposeAssetsAsync(this.assets);
430
+ }
431
+ handleRenderError(error) {
432
+ if (this.disposed)
433
+ return;
434
+ const normalized = error instanceof Error ? error : new Error(String(error));
435
+ this.lastRenderError = normalized;
436
+ if (this.clock.playing) {
437
+ this.clock.pause(this.now());
438
+ this.audio?.stop();
439
+ }
440
+ this.stopTicking();
441
+ Array.from(this.errorListeners).forEach((listener) => listener(normalized));
442
+ }
443
+ emit(event, frame) {
444
+ const listeners = Array.from(this.listeners.get(event) ?? []);
445
+ for (const listener of listeners) {
446
+ listener(frame);
447
+ }
448
+ }
449
+ assertAlive() {
450
+ if (this.disposed) {
451
+ throw new Error("Player is disposed; create a new one with createPlayer().");
452
+ }
453
+ }
454
+ }
455
+ /**
456
+ * Validates the scene, resolves assets (unless provided), renders frame 0,
457
+ * and returns a ready Player.
458
+ */
459
+ export async function createPlayer(options) {
460
+ return await createPlayerInternal(options);
461
+ }
462
+ async function createPlayerInternal(options, lifecycle = {}) {
463
+ if (options.renderFrame && options.audio !== false) {
464
+ throw new Error("A host-owned frame renderer requires audio:false; audio ownership must be explicit.");
465
+ }
466
+ const scene = parseScene(options.scene);
467
+ const inspection = inspectScene(scene);
468
+ const needsAssets = !options.renderFrame &&
469
+ (Object.keys(scene.assets).length > 0 ||
470
+ inspection.capabilities.hasExtensions);
471
+ const ownsAssets = options.assets === undefined && needsAssets;
472
+ const assets = options.assets ??
473
+ (needsAssets
474
+ ? await resolveAssets(scene, {
475
+ extensions: options.extensions,
476
+ worker: options.worker,
477
+ opaqueExtensionRegistry: options.opaqueExtensionRegistry,
478
+ preferProxy: options.preferProxy ?? true,
479
+ budget: options.budget,
480
+ assetPolicy: options.assetPolicy,
481
+ analysisCache: options.analysisCache,
482
+ fontCache: options.fontCache,
483
+ analyzeWaveforms: options.analyzeWaveforms,
484
+ signal: options.signal,
485
+ })
486
+ : undefined);
487
+ const player = new Player(scene, options, assets, ownsAssets, lifecycle);
488
+ try {
489
+ // Best-effort audio preview: attach only when the scene actually has
490
+ // something audible, so silent scenes never touch AudioContext. The mix
491
+ // runs concurrently with the first paint and attaches whenever it lands —
492
+ // decoding a long soundtrack must never delay the first visible frame.
493
+ if (options.audio !== false) {
494
+ const audio = options.audio ??
495
+ (ChunkedWebAudioPreview.supported()
496
+ ? new ChunkedWebAudioPreview()
497
+ : null);
498
+ if (audio) {
499
+ player.setAudioReady(player
500
+ .loadAudio(audio)
501
+ .then((audible) => {
502
+ if (audible) {
503
+ player.attachAudio(audio);
504
+ }
505
+ else {
506
+ player.discardAudio(audio);
507
+ }
508
+ })
509
+ .catch(() => {
510
+ // Preview audio is best-effort; the export mixes its own.
511
+ player.discardAudio(audio);
512
+ }));
513
+ }
514
+ }
515
+ await player.renderInitialFrame();
516
+ return player;
517
+ }
518
+ catch (error) {
519
+ await player.disposeAsync();
520
+ throw error;
521
+ }
522
+ }
523
+ /**
524
+ * Creates a player that borrows the current prepared Canvas2D runtime state.
525
+ *
526
+ * The compatibility scope stays open until the player is fully disposed, so
527
+ * the runtime cannot replace or release media while a frame/audio task still
528
+ * uses it. A runtime update/disposal or caller abort disposes the player and
529
+ * releases the scope before the newer runtime operation can continue.
530
+ */
531
+ export async function createPlayerFromRuntime(runtime, options) {
532
+ let settleReady = (_player) => undefined;
533
+ let rejectReady = (_error) => undefined;
534
+ let readySettled = false;
535
+ const ready = new Promise((resolve, reject) => {
536
+ settleReady = (player) => {
537
+ if (readySettled)
538
+ return;
539
+ readySettled = true;
540
+ resolve(player);
541
+ };
542
+ rejectReady = (error) => {
543
+ if (readySettled)
544
+ return;
545
+ readySettled = true;
546
+ reject(error);
547
+ };
548
+ });
549
+ const scope = withCanvas2DResolvedAssets(runtime, async ({ assets, scratchSurfacePool, staticDisplayCache, scene, signal, }) => {
550
+ let releaseScope = () => undefined;
551
+ const releaseRequested = new Promise((resolve) => {
552
+ releaseScope = resolve;
553
+ });
554
+ let player;
555
+ const abort = () => player?.dispose();
556
+ signal.addEventListener("abort", abort, { once: true });
557
+ try {
558
+ player = await createPlayerInternal({
559
+ ...options,
560
+ scene,
561
+ assets,
562
+ scratchSurfacePool,
563
+ staticDisplayCache,
564
+ signal,
565
+ }, { onDisposeRequested: releaseScope });
566
+ if (signal.aborted) {
567
+ player.dispose();
568
+ await player.disposeAsync();
569
+ throw signal.reason instanceof Error
570
+ ? signal.reason
571
+ : new Error("Runtime player creation was aborted.");
572
+ }
573
+ settleReady(player);
574
+ await releaseRequested;
575
+ await player.disposeAsync();
576
+ }
577
+ finally {
578
+ signal.removeEventListener("abort", abort);
579
+ if (player && !readySettled) {
580
+ await player.disposeAsync();
581
+ }
582
+ }
583
+ }, { signal: options.signal });
584
+ void scope.catch((error) => rejectReady(error));
585
+ return await ready;
586
+ }
587
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
1
  {
2
2
  "name": "@dojo-video-engine/player",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.1.0",
4
+ "description": "Real-time playback for dojo-video-engine scenes: a deterministic frame clock plus a canvas render loop with play/pause/seek/loop.",
5
+ "keywords": [
6
+ "dojo-video-engine",
7
+ "video",
8
+ "player",
9
+ "playback",
10
+ "canvas"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/PansaLegrand/dojo-video-engine.git",
16
+ "directory": "packages/player"
17
+ },
18
+ "homepage": "https://github.com/PansaLegrand/dojo-video-engine#readme",
19
+ "bugs": "https://github.com/PansaLegrand/dojo-video-engine/issues",
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "!dist/**/*.test.*",
32
+ "!dist/.tsbuildinfo"
33
+ ],
34
+ "sideEffects": false,
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "@dojo-video-engine/renderer-canvas2d": "1.1.0",
43
+ "@dojo-video-engine/export": "1.1.0",
44
+ "@dojo-video-engine/schema": "1.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "vitest": "4.1.12",
48
+ "@dojo-video-engine/core": "1.1.0"
49
+ },
50
+ "scripts": {
51
+ "build": "tsc -p tsconfig.json",
52
+ "test": "vitest run --exclude \"**/dist/**\"",
53
+ "typecheck": "tsc -p tsconfig.json --noEmit",
54
+ "lint": "tsc -p tsconfig.json --noEmit"
55
+ }
6
56
  }