@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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ export declare class FrameBuffer {
2
+ #private;
3
+ /**
4
+ * @param capacity Maximum number of frames held. When pushing a new
5
+ * frame would exceed this, the earliest frame is
6
+ * closed and dropped.
7
+ */
8
+ constructor(capacity: number);
9
+ /** Current capacity. Fixed at construction. */
10
+ get capacity(): number;
11
+ /** Current number of buffered frames. */
12
+ get size(): number;
13
+ /** Active sequence ID. Frames pushed with a different ID are closed + dropped. */
14
+ get sequenceId(): number;
15
+ /**
16
+ * Advance the sequence ID — closes and drops any buffered frames whose
17
+ * ID doesn't match. Called after seek / setSource so stale in-flight
18
+ * frames from the worker land into a freshly-invalidated buffer.
19
+ */
20
+ setSequenceId(id: number): void;
21
+ /**
22
+ * Insert a frame (sorted by time). If `sequenceId` doesn't match the
23
+ * current, the frame is closed and dropped immediately. If capacity
24
+ * is exceeded, the earliest buffered frame is closed and dropped.
25
+ */
26
+ push(time: number, frame: VideoFrame, sequenceId: number): void;
27
+ /**
28
+ * Return the frame whose time is the latest `<= time`. Caller must
29
+ * not close it — the buffer owns it. Returns null if no buffered
30
+ * frame qualifies (buffer empty, or playhead is before all frames).
31
+ */
32
+ peekAt(time: number): VideoFrame | null;
33
+ /**
34
+ * Seconds of frames currently buffered ahead of `time`. Zero if the
35
+ * buffer is empty or the playhead is past the latest frame.
36
+ */
37
+ aheadSec(time: number): number;
38
+ /**
39
+ * Close and drop every frame whose time is strictly before
40
+ * `targetTime - keepBackSec`. The keepBack window holds a small
41
+ * tail in case the presenter's wall clock drifts slightly behind
42
+ * the requested playhead.
43
+ */
44
+ prune(targetTime: number, keepBackSec?: number): void;
45
+ /** Close and drop every frame. The buffer is empty but still usable. */
46
+ clear(): void;
47
+ /** Same as clear(); reserved for symmetry with other engine components. */
48
+ dispose(): void;
49
+ }
50
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"AAyBA,qBAAa,WAAW;;IAKtB;;;;OAIG;gBACS,QAAQ,EAAE,MAAM;IAK5B,+CAA+C;IAC/C,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,yCAAyC;IACzC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,kFAAkF;IAClF,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAa/B;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAuB/D;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IASvC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAM9B;;;;;OAKG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,SAAO,GAAG,IAAI;IAQnD,wEAAwE;IACxE,KAAK,IAAI,IAAI;IAKb,2EAA2E;IAC3E,OAAO,IAAI,IAAI;CAGhB"}
package/dist/buffer.js ADDED
@@ -0,0 +1,137 @@
1
+ // FrameBuffer — bounded sorted collection of VideoFrames.
2
+ //
3
+ // Holds frames received from the worker, indexed by composition time.
4
+ // The presenter calls `peekAt(time)` to get the frame to draw; the
5
+ // engine periodically calls `prune(time)` to evict frames behind the
6
+ // playhead and `setSequenceId(n)` to invalidate everything after a
7
+ // seek / setSource.
8
+ //
9
+ // ─── VideoFrame.close() discipline (best practice from SPRINT.md) ───
10
+ // VideoFrames hold GPU memory until close()'d. Every pathway that
11
+ // drops a frame from this buffer calls close() exactly once:
12
+ // - Capacity overflow → close the evicted frame
13
+ // - Stale sequence ID at push → close immediately, don't insert
14
+ // - Stale sequence ID at setSequenceId → close all existing
15
+ // - prune() → close all frames before the cutoff
16
+ // - clear() / dispose() → close everything
17
+ // Consumers of peekAt() never close — the buffer owns the frame; the
18
+ // consumer just reads its pixels.
19
+ export class FrameBuffer {
20
+ #capacity;
21
+ #frames = [];
22
+ #currentSequenceId = 0;
23
+ /**
24
+ * @param capacity Maximum number of frames held. When pushing a new
25
+ * frame would exceed this, the earliest frame is
26
+ * closed and dropped.
27
+ */
28
+ constructor(capacity) {
29
+ if (capacity <= 0)
30
+ throw new Error('FrameBuffer capacity must be > 0');
31
+ this.#capacity = capacity;
32
+ }
33
+ /** Current capacity. Fixed at construction. */
34
+ get capacity() {
35
+ return this.#capacity;
36
+ }
37
+ /** Current number of buffered frames. */
38
+ get size() {
39
+ return this.#frames.length;
40
+ }
41
+ /** Active sequence ID. Frames pushed with a different ID are closed + dropped. */
42
+ get sequenceId() {
43
+ return this.#currentSequenceId;
44
+ }
45
+ /**
46
+ * Advance the sequence ID — closes and drops any buffered frames whose
47
+ * ID doesn't match. Called after seek / setSource so stale in-flight
48
+ * frames from the worker land into a freshly-invalidated buffer.
49
+ */
50
+ setSequenceId(id) {
51
+ this.#currentSequenceId = id;
52
+ const kept = [];
53
+ for (const f of this.#frames) {
54
+ if (f.sequenceId === id) {
55
+ kept.push(f);
56
+ }
57
+ else {
58
+ f.frame.close();
59
+ }
60
+ }
61
+ this.#frames = kept;
62
+ }
63
+ /**
64
+ * Insert a frame (sorted by time). If `sequenceId` doesn't match the
65
+ * current, the frame is closed and dropped immediately. If capacity
66
+ * is exceeded, the earliest buffered frame is closed and dropped.
67
+ */
68
+ push(time, frame, sequenceId) {
69
+ if (sequenceId !== this.#currentSequenceId) {
70
+ frame.close();
71
+ return;
72
+ }
73
+ const entry = { time, frame, sequenceId };
74
+ // Insert sorted. List is small (cap is ~30); linear scan beats binary.
75
+ let inserted = false;
76
+ for (let i = 0; i < this.#frames.length; i++) {
77
+ if (this.#frames[i].time > time) {
78
+ this.#frames.splice(i, 0, entry);
79
+ inserted = true;
80
+ break;
81
+ }
82
+ }
83
+ if (!inserted)
84
+ this.#frames.push(entry);
85
+ while (this.#frames.length > this.#capacity) {
86
+ const evicted = this.#frames.shift();
87
+ evicted?.frame.close();
88
+ }
89
+ }
90
+ /**
91
+ * Return the frame whose time is the latest `<= time`. Caller must
92
+ * not close it — the buffer owns it. Returns null if no buffered
93
+ * frame qualifies (buffer empty, or playhead is before all frames).
94
+ */
95
+ peekAt(time) {
96
+ for (let i = this.#frames.length - 1; i >= 0; i--) {
97
+ if (this.#frames[i].time <= time) {
98
+ return this.#frames[i].frame;
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ /**
104
+ * Seconds of frames currently buffered ahead of `time`. Zero if the
105
+ * buffer is empty or the playhead is past the latest frame.
106
+ */
107
+ aheadSec(time) {
108
+ if (this.#frames.length === 0)
109
+ return 0;
110
+ const lastTime = this.#frames[this.#frames.length - 1].time;
111
+ return Math.max(0, lastTime - time);
112
+ }
113
+ /**
114
+ * Close and drop every frame whose time is strictly before
115
+ * `targetTime - keepBackSec`. The keepBack window holds a small
116
+ * tail in case the presenter's wall clock drifts slightly behind
117
+ * the requested playhead.
118
+ */
119
+ prune(targetTime, keepBackSec = 0.05) {
120
+ const cutoff = targetTime - keepBackSec;
121
+ while (this.#frames.length > 0 && this.#frames[0].time < cutoff) {
122
+ const evicted = this.#frames.shift();
123
+ evicted?.frame.close();
124
+ }
125
+ }
126
+ /** Close and drop every frame. The buffer is empty but still usable. */
127
+ clear() {
128
+ for (const f of this.#frames)
129
+ f.frame.close();
130
+ this.#frames = [];
131
+ }
132
+ /** Same as clear(); reserved for symmetry with other engine components. */
133
+ dispose() {
134
+ this.clear();
135
+ }
136
+ }
137
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { Unsubscribe } from './types.js';
2
+ /**
3
+ * Snapshot of the clock's current state. Delivered to subscribers on
4
+ * any state change (play / pause / seek). `position` is the composition
5
+ * time at the moment of the change — not the live playhead. Use
6
+ * `clock.now()` for the live value.
7
+ */
8
+ export interface ClockState {
9
+ playing: boolean;
10
+ position: number;
11
+ }
12
+ export declare class TransportClock {
13
+ #private;
14
+ /**
15
+ * @param audioContext The precision time source. The clock does not
16
+ * own the context — the caller is responsible for
17
+ * its lifecycle.
18
+ * @param initialTime Composition time to start at, in seconds.
19
+ * Default `0`. Clamped to `>= 0`.
20
+ */
21
+ constructor(audioContext: AudioContext, initialTime?: number);
22
+ /** True while the playhead is advancing. */
23
+ get playing(): boolean;
24
+ /**
25
+ * Current composition time, in seconds. Computed on demand from the
26
+ * AudioContext clock — call any time, get the live value. Returns the
27
+ * last held position when paused.
28
+ */
29
+ now(): number;
30
+ /**
31
+ * Resume advancing the playhead from its current position. No-op if
32
+ * already playing or disposed. Resumes the AudioContext if needed —
33
+ * some browsers start it suspended until a user gesture.
34
+ *
35
+ * Resolves once the state has been broadcast to subscribers; awaiting
36
+ * `play()` guarantees `playing === true` is visible to listeners.
37
+ */
38
+ play(): Promise<void>;
39
+ /**
40
+ * Stop advancing. The playhead holds at the current position.
41
+ * No-op if already paused or disposed.
42
+ */
43
+ pause(): void;
44
+ /**
45
+ * Jump the playhead to `time` (seconds, clamped to `>= 0`). Preserves
46
+ * play / pause state. Notifies subscribers so consumers tied to the
47
+ * old position (frame buffer, audio sources) can invalidate.
48
+ */
49
+ seek(time: number): void;
50
+ /**
51
+ * Subscribe to state changes. Fires once immediately with the current
52
+ * state, then again on every play / pause / seek. Returns an unsubscribe
53
+ * function. Listener exceptions are caught and logged, never propagated
54
+ * back to the caller of `play / pause / seek`.
55
+ */
56
+ subscribe(listener: (state: ClockState) => void): Unsubscribe;
57
+ /**
58
+ * Detach all subscribers and mark the clock disposed. Does not close
59
+ * the AudioContext (the caller owns its lifecycle). Idempotent.
60
+ */
61
+ dispose(): void;
62
+ }
63
+ //# sourceMappingURL=clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAc;;IAQzB;;;;;;OAMG;gBACS,YAAY,EAAE,YAAY,EAAE,WAAW,SAAI;IAKvD,4CAA4C;IAC5C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,GAAG,IAAI,MAAM;IAKb;;;;;;;OAOG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;OAGG;IACH,KAAK,IAAI,IAAI;IAUb;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAUxB;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,WAAW;IAS7D;;;OAGG;IACH,OAAO,IAAI,IAAI;CAuChB"}
package/dist/clock.js ADDED
@@ -0,0 +1,161 @@
1
+ // TransportClock — the composition playhead.
2
+ //
3
+ // The clock represents *composition time* — "where is the playhead in
4
+ // this Source?". Its underlying time source is `AudioContext.currentTime`
5
+ // because that's the highest-precision monotonic clock the browser
6
+ // exposes (sample-accurate, audio-thread-priority, doesn't drift).
7
+ //
8
+ // The AudioContext is treated as a clock substrate, not as "the audio
9
+ // player". A composition with zero `audio` elements still uses the
10
+ // same context as its clock source — it just doesn't schedule any
11
+ // audio sources on it. See SPRINT.md § "Audio is just an element".
12
+ //
13
+ // Internal model:
14
+ // - When PAUSED: `now()` returns `#anchorPosition` (the held position).
15
+ // - When PLAYING: `now()` returns
16
+ // `#anchorPosition + (ctx.currentTime - #anchorCtxTime)`.
17
+ //
18
+ // Every transition (play / pause / seek) re-anchors the pair so the
19
+ // linear mapping above stays correct without per-tick state.
20
+ export class TransportClock {
21
+ #ctx;
22
+ #playing = false;
23
+ #anchorPosition;
24
+ #anchorCtxTime = 0;
25
+ #listeners = new Set();
26
+ #disposed = false;
27
+ /**
28
+ * @param audioContext The precision time source. The clock does not
29
+ * own the context — the caller is responsible for
30
+ * its lifecycle.
31
+ * @param initialTime Composition time to start at, in seconds.
32
+ * Default `0`. Clamped to `>= 0`.
33
+ */
34
+ constructor(audioContext, initialTime = 0) {
35
+ this.#ctx = audioContext;
36
+ this.#anchorPosition = Math.max(0, initialTime);
37
+ }
38
+ /** True while the playhead is advancing. */
39
+ get playing() {
40
+ return this.#playing;
41
+ }
42
+ /**
43
+ * Current composition time, in seconds. Computed on demand from the
44
+ * AudioContext clock — call any time, get the live value. Returns the
45
+ * last held position when paused.
46
+ */
47
+ now() {
48
+ if (!this.#playing)
49
+ return this.#anchorPosition;
50
+ return this.#anchorPosition + (this.#ctx.currentTime - this.#anchorCtxTime);
51
+ }
52
+ /**
53
+ * Resume advancing the playhead from its current position. No-op if
54
+ * already playing or disposed. Resumes the AudioContext if needed —
55
+ * some browsers start it suspended until a user gesture.
56
+ *
57
+ * Resolves once the state has been broadcast to subscribers; awaiting
58
+ * `play()` guarantees `playing === true` is visible to listeners.
59
+ */
60
+ async play() {
61
+ if (this.#disposed)
62
+ throw new Error('TransportClock is disposed');
63
+ if (this.#playing)
64
+ return;
65
+ if (this.#ctx.state === 'suspended') {
66
+ await this.#ctx.resume();
67
+ }
68
+ // Re-check after the await — disposed / paused could have changed.
69
+ if (this.#disposed)
70
+ return;
71
+ if (this.#playing)
72
+ return;
73
+ this.#anchorCtxTime = this.#ctx.currentTime;
74
+ this.#playing = true;
75
+ this.#notify();
76
+ }
77
+ /**
78
+ * Stop advancing. The playhead holds at the current position.
79
+ * No-op if already paused or disposed.
80
+ */
81
+ pause() {
82
+ if (this.#disposed)
83
+ return;
84
+ if (!this.#playing)
85
+ return;
86
+ // Snapshot the live position *before* flipping the playing flag —
87
+ // `now()` reads it via the playing-branch formula.
88
+ this.#anchorPosition = this.now();
89
+ this.#playing = false;
90
+ this.#notify();
91
+ }
92
+ /**
93
+ * Jump the playhead to `time` (seconds, clamped to `>= 0`). Preserves
94
+ * play / pause state. Notifies subscribers so consumers tied to the
95
+ * old position (frame buffer, audio sources) can invalidate.
96
+ */
97
+ seek(time) {
98
+ if (this.#disposed)
99
+ return;
100
+ this.#anchorPosition = Math.max(0, time);
101
+ if (this.#playing) {
102
+ // Re-anchor so the playing-branch formula continues from `time`.
103
+ this.#anchorCtxTime = this.#ctx.currentTime;
104
+ }
105
+ this.#notify();
106
+ }
107
+ /**
108
+ * Subscribe to state changes. Fires once immediately with the current
109
+ * state, then again on every play / pause / seek. Returns an unsubscribe
110
+ * function. Listener exceptions are caught and logged, never propagated
111
+ * back to the caller of `play / pause / seek`.
112
+ */
113
+ subscribe(listener) {
114
+ if (this.#disposed)
115
+ return () => { };
116
+ this.#listeners.add(listener);
117
+ this.#deliver(listener);
118
+ return () => {
119
+ this.#listeners.delete(listener);
120
+ };
121
+ }
122
+ /**
123
+ * Detach all subscribers and mark the clock disposed. Does not close
124
+ * the AudioContext (the caller owns its lifecycle). Idempotent.
125
+ */
126
+ dispose() {
127
+ if (this.#disposed)
128
+ return;
129
+ this.#disposed = true;
130
+ this.#playing = false;
131
+ this.#listeners.clear();
132
+ }
133
+ // ── Internal ────────────────────────────────────────────────────────
134
+ #notify() {
135
+ const state = {
136
+ playing: this.#playing,
137
+ position: this.now(),
138
+ };
139
+ for (const listener of this.#listeners) {
140
+ this.#deliverState(listener, state);
141
+ }
142
+ }
143
+ #deliver(listener) {
144
+ this.#deliverState(listener, {
145
+ playing: this.#playing,
146
+ position: this.now(),
147
+ });
148
+ }
149
+ #deliverState(listener, state) {
150
+ try {
151
+ listener(state);
152
+ }
153
+ catch (err) {
154
+ // One buggy subscriber shouldn't break the clock for other
155
+ // subscribers or for the caller of play/pause/seek.
156
+ // eslint-disable-next-line no-console
157
+ console.error('[TransportClock] subscriber threw:', err);
158
+ }
159
+ }
160
+ }
161
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import type { Source } from '@clipkit/protocol';
2
+ import { type AudioLevels } from './audio.js';
3
+ import type { BufferStatus, EngineStats, PlaybackEngineOptions, Unsubscribe } from './types.js';
4
+ export declare class PlaybackEngine {
5
+ #private;
6
+ source: Source;
7
+ duration: number;
8
+ readonly ready: Promise<void>;
9
+ get playing(): boolean;
10
+ get time(): number;
11
+ constructor(options: PlaybackEngineOptions);
12
+ play(): Promise<void>;
13
+ pause(): void;
14
+ seek(time: number): void;
15
+ /**
16
+ * Frame-quantized transport step (the editor's prev/next-frame
17
+ * buttons). Pauses playback and seeks to the frame `frames` away
18
+ * from the current one (negative steps back), clamped to the
19
+ * composition. Quantization math is shared via frame-math.ts.
20
+ */
21
+ stepFrame(frames?: number): void;
22
+ /**
23
+ * Render ONE export-quality still at `time` (motion blur included
24
+ * when the source configures it) off the playback path, returned as
25
+ * an ImageBitmap. `width` downscales preserving aspect — thumbnail
26
+ * strips and scrub-hover previews stay cheap to transfer. Requests
27
+ * serialize behind frame production in the worker.
28
+ */
29
+ renderFrameAt(time: number, options?: {
30
+ width?: number;
31
+ }): Promise<ImageBitmap>;
32
+ setSource(source: Source): Promise<void>;
33
+ /**
34
+ * Toggle interactive (edit) mode. While `true`, the engine produces
35
+ * only one frame at the current playhead on each `setSource` —
36
+ * no look-ahead buffering. Use during drag/resize/rotate operations
37
+ * so live mutation dispatches don't queue dozens of doomed frames.
38
+ * Set back to `false` to resume normal buffered playback.
39
+ */
40
+ /**
41
+ * Apply partial updates to existing elements without re-sending the
42
+ * full source. The fast path for live drag / resize / rotate
43
+ * dispatches:
44
+ *
45
+ * - Worker applies patches via Object.assign to its in-memory source
46
+ * - No `runtime.preload()` (assets unchanged)
47
+ * - No audio scheduling
48
+ * - Tiny message payload (~50 bytes vs full source's KBs)
49
+ *
50
+ * Caller passes both the new source (so this.source stays in sync as
51
+ * the diff baseline for the next tick) and the patches to send to
52
+ * the worker. We never mutate — the source from the store is
53
+ * Immer-frozen and that's fine; we just swap the reference.
54
+ *
55
+ * Patches should be for visual/spatial fields only — time/track/
56
+ * duration changes affect frame-buffer alignment and should go
57
+ * through `setSource`. The Editor's source-diff function decides
58
+ * which path to use.
59
+ */
60
+ patchElements(nextSource: Source, patches: ReadonlyArray<{
61
+ id: string;
62
+ patch: Record<string, unknown>;
63
+ }>): void;
64
+ /** When true, playback wraps to 0 at the end instead of pausing. */
65
+ /**
66
+ * PREVIEW-ONLY per-element audio gains (the mixer's mute/solo).
67
+ * Multiplies on top of authored volume; never written into the
68
+ * Source — the lens rule's engine half. Unlisted ids reset to 1.
69
+ */
70
+ setPreviewGains(gains: Readonly<Record<string, number>>): void;
71
+ /** Mixer meter levels (0..1 peaks); zeros before audio init. */
72
+ getAudioLevels(): AudioLevels;
73
+ setLoop(value: boolean): void;
74
+ /**
75
+ * Current transport time, in seconds. Reads the clock directly —
76
+ * advances continuously during playback regardless of how often
77
+ * onTime emits. UI elements that need 60Hz-smooth motion (the
78
+ * timeline playhead) read this on every rAF tick instead of
79
+ * subscribing to the store's playback.time (which is throttled
80
+ * to 100ms).
81
+ */
82
+ get currentTime(): number;
83
+ /**
84
+ * Snapshot of presenter / worker / buffer health for the in-app
85
+ * diagnostic HUD. All values are derived from sliding windows the
86
+ * engine already maintains for instrumentation; this is a cheap
87
+ * read intended to be polled at ~4Hz by a UI overlay.
88
+ */
89
+ getStats(): EngineStats;
90
+ /** Zero out starvation count + latency windows. Useful at play start. */
91
+ resetStats(): void;
92
+ setInteractive(value: boolean): void;
93
+ onTime(listener: (time: number) => void): Unsubscribe;
94
+ onPlayingChange(listener: (playing: boolean) => void): Unsubscribe;
95
+ onError(listener: (error: Error) => void): Unsubscribe;
96
+ onBufferStatus(listener: (status: BufferStatus) => void): Unsubscribe;
97
+ dispose(): void;
98
+ }
99
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,mBAAmB,CAAC;AAIzD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9D,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AAqCpB,qBAAa,cAAc;;IAGzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,IAAI,IAAI,MAAM,CAEjB;gBA4GW,OAAO,EAAE,qBAAqB;IAkDpC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B,KAAK,IAAI,IAAI;IASb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQxB;;;;;OAKG;IACH,SAAS,CAAC,MAAM,SAAI,GAAG,IAAI;IAO3B;;;;;;OAMG;IACG,aAAa,CACjB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/B,OAAO,CAAC,WAAW,CAAC;IAgBjB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqD9C;;;;;;OAMG;IACH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GACrE,IAAI;IAsBP,oEAAoE;IACpE;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;IAK9D,gEAAgE;IAChE,cAAc,IAAI,WAAW;IAI7B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI7B;;;;;;;OAOG;IACH,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED;;;;;OAKG;IACH,QAAQ,IAAI,WAAW;IAsDvB,yEAAyE;IACzE,UAAU,IAAI,IAAI;IAalB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAcpC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,WAAW;IAOrD,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,WAAW;IAOlE,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,WAAW;IAOtD,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,WAAW;IASrE,OAAO,IAAI,IAAI;CA+mBhB"}