@twick/live-player 0.14.20 → 0.15.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.
@@ -1,2120 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- class EventDispatcherBase {
5
- constructor() {
6
- this.subscribable = new Subscribable(this);
7
- this.subscribers = /* @__PURE__ */ new Set();
8
- }
9
- /**
10
- * {@inheritDoc Subscribable.subscribe}
11
- */
12
- subscribe(handler) {
13
- this.subscribers.add(handler);
14
- return () => this.unsubscribe(handler);
15
- }
16
- /**
17
- * {@inheritDoc Subscribable.unsubscribe}
18
- */
19
- unsubscribe(handler) {
20
- this.subscribers.delete(handler);
21
- }
22
- /**
23
- * Unsubscribe all subscribers from the event.
24
- */
25
- clear() {
26
- this.subscribers.clear();
27
- }
28
- notifySubscribers(value) {
29
- return [...this.subscribers].map((handler) => handler(value));
30
- }
31
- }
32
- class Subscribable {
33
- constructor(dispatcher) {
34
- this.dispatcher = dispatcher;
35
- }
36
- /**
37
- * Subscribe to the event.
38
- *
39
- * @param handler - The handler to invoke when the event occurs.
40
- *
41
- * @returns A callback function that cancels the subscription.
42
- */
43
- subscribe(handler) {
44
- return this.dispatcher.subscribe(handler);
45
- }
46
- /**
47
- * Unsubscribe from the event.
48
- *
49
- * @param handler - The handler to unsubscribe.
50
- */
51
- unsubscribe(handler) {
52
- this.dispatcher.unsubscribe(handler);
53
- }
54
- }
55
- class AsyncEventDispatcher extends EventDispatcherBase {
56
- async dispatch(value) {
57
- await Promise.all(this.notifySubscribers(value));
58
- }
59
- }
60
- class EventDispatcher extends EventDispatcherBase {
61
- dispatch(value) {
62
- this.notifySubscribers(value);
63
- }
64
- }
65
- class FlagDispatcher extends EventDispatcherBase {
66
- constructor() {
67
- super(...arguments);
68
- this.value = false;
69
- }
70
- /**
71
- * Notify all current and future subscribers.
72
- */
73
- raise() {
74
- if (!this.value) {
75
- this.value = true;
76
- this.notifySubscribers();
77
- }
78
- }
79
- /**
80
- * Stop notifying future subscribers.
81
- */
82
- reset() {
83
- this.value = false;
84
- }
85
- /**
86
- * Are subscribers being notified?
87
- */
88
- isRaised() {
89
- return this.value;
90
- }
91
- subscribe(handler) {
92
- const unsubscribe = super.subscribe(handler);
93
- if (this.value) {
94
- handler();
95
- }
96
- return unsubscribe;
97
- }
98
- }
99
- class ValueDispatcher extends EventDispatcherBase {
100
- /**
101
- * {@inheritDoc SubscribableValueEvent.current}
102
- */
103
- get current() {
104
- return this.value;
105
- }
106
- /**
107
- * Set the current value of this dispatcher.
108
- *
109
- * @remarks
110
- * Setting the value will immediately notify all subscribers.
111
- *
112
- * @param value - The new value.
113
- */
114
- set current(value) {
115
- this.value = value;
116
- this.notifySubscribers(value);
117
- }
118
- /**
119
- * @param value - The initial value.
120
- */
121
- constructor(value) {
122
- super();
123
- this.value = value;
124
- this.subscribable = new SubscribableValueEvent(this);
125
- }
126
- /**
127
- * {@inheritDoc SubscribableValueEvent.subscribe}
128
- */
129
- subscribe(handler, dispatchImmediately = true) {
130
- const unsubscribe = super.subscribe(handler);
131
- if (dispatchImmediately) {
132
- handler(this.value);
133
- }
134
- return unsubscribe;
135
- }
136
- }
137
- class SubscribableValueEvent extends Subscribable {
138
- /**
139
- * Get the most recent value of this dispatcher.
140
- */
141
- get current() {
142
- return this.dispatcher.current;
143
- }
144
- /**
145
- * Subscribe to the event.
146
- *
147
- * Subscribing will immediately invoke the handler with the most recent value.
148
- *
149
- * @param handler - The handler to invoke when the event occurs.
150
- * @param dispatchImmediately - Whether the handler should be immediately
151
- * invoked with the most recent value.
152
- *
153
- * @returns Callback function that cancels the subscription.
154
- */
155
- subscribe(handler, dispatchImmediately = true) {
156
- return this.dispatcher.subscribe(handler, dispatchImmediately);
157
- }
158
- }
159
- function map(from, to, value) {
160
- return from + (to - from) * value;
161
- }
162
- function clamp(min, max, value) {
163
- return value < min ? min : value > max ? max : value;
164
- }
165
- const SceneStack = [];
166
- function useLogger() {
167
- var _a;
168
- return ((_a = SceneStack.at(-1)) == null ? void 0 : _a.logger) ?? console;
169
- }
170
- class DetailedError extends Error {
171
- constructor(props, remarks) {
172
- if (typeof props === "string") {
173
- super(props);
174
- this.remarks = remarks;
175
- } else {
176
- super(props.message);
177
- this.remarks = props.remarks;
178
- this.object = props.object;
179
- this.durationMs = props.durationMs;
180
- this.inspect = props.inspect;
181
- }
182
- }
183
- }
184
- const ThreadStack = [];
185
- function useThread() {
186
- const thread = ThreadStack.at(-1);
187
- if (!thread) {
188
- throw new DetailedError(
189
- "The thread is not available in the current context.",
190
- // language=markdown
191
- `\`useThread()\` can only be called from within generator functions.
192
- It's not available during rendering.`
193
- );
194
- }
195
- return thread;
196
- }
197
- function errorToLog(error) {
198
- return {
199
- message: error.message,
200
- stack: error.stack,
201
- remarks: error.remarks
202
- };
203
- }
204
- function getContext(options, canvas = document.createElement("canvas")) {
205
- const context = canvas.getContext("2d", options);
206
- if (!context) {
207
- throw new Error("Could not create a 2D context.");
208
- }
209
- return context;
210
- }
211
- const RAD2DEG = 180 / Math.PI;
212
- const DEG2RAD = Math.PI / 180;
213
- class Semaphore {
214
- constructor() {
215
- this.resolveCurrent = null;
216
- this.current = null;
217
- }
218
- async acquire() {
219
- while (this.current) {
220
- await this.current;
221
- }
222
- this.current = new Promise((resolve) => {
223
- this.resolveCurrent = resolve;
224
- });
225
- }
226
- release() {
227
- var _a;
228
- this.current = null;
229
- (_a = this.resolveCurrent) == null ? void 0 : _a.call(this);
230
- this.resolveCurrent = null;
231
- }
232
- }
233
- const PlaybackStack = [];
234
- function usePlayback() {
235
- const playback = PlaybackStack.at(-1);
236
- if (!playback) {
237
- throw new Error("The playback is not available in the current context.");
238
- }
239
- return playback;
240
- }
241
- function arcLerp(value, reverse, ratio) {
242
- let flip = reverse;
243
- if (ratio > 1) {
244
- ratio = 1 / ratio;
245
- } else {
246
- flip = !flip;
247
- }
248
- const normalized = flip ? Math.acos(clamp(-1, 1, 1 - value)) : Math.asin(value);
249
- const radians = map(normalized, map(0, Math.PI / 2, value), ratio);
250
- let xValue = Math.sin(radians);
251
- let yValue = 1 - Math.cos(radians);
252
- if (reverse) {
253
- [xValue, yValue] = [yValue, xValue];
254
- }
255
- return { x: xValue, y: yValue };
256
- }
257
- function decorate(fn, ...decorators) {
258
- const target = { [fn.name]: fn };
259
- const descriptor = Object.getOwnPropertyDescriptor(target, fn.name);
260
- if (descriptor) {
261
- for (let i = decorators.length - 1; i >= 0; i--) {
262
- decorators[i](target, fn.name, descriptor);
263
- }
264
- }
265
- }
266
- function threadable(customName) {
267
- return function(_, propertyKey, descriptor) {
268
- descriptor.value.prototype.name = propertyKey;
269
- descriptor.value.prototype.threadable = true;
270
- };
271
- }
272
- function easeInOutCubic(value, from = 0, to = 1) {
273
- value = value < 0.5 ? 4 * value * value * value : 1 - Math.pow(-2 * value + 2, 3) / 2;
274
- return map(from, to, value);
275
- }
276
- decorate(tween, threadable());
277
- function* tween(seconds, onProgress, onEnd) {
278
- const thread = useThread();
279
- const startTime = thread.time();
280
- const endTime = thread.time() + seconds;
281
- onProgress(0, 0);
282
- while (endTime > thread.fixed) {
283
- const time = thread.fixed - startTime;
284
- const value = time / seconds;
285
- if (time > 0) {
286
- onProgress(value, time);
287
- }
288
- yield;
289
- }
290
- thread.time(endTime);
291
- onProgress(1, seconds);
292
- onEnd == null ? void 0 : onEnd(1, seconds);
293
- }
294
- var Direction;
295
- (function(Direction2) {
296
- Direction2[Direction2["Top"] = 4] = "Top";
297
- Direction2[Direction2["Bottom"] = 8] = "Bottom";
298
- Direction2[Direction2["Left"] = 16] = "Left";
299
- Direction2[Direction2["Right"] = 32] = "Right";
300
- })(Direction || (Direction = {}));
301
- var Center;
302
- (function(Center2) {
303
- Center2[Center2["Vertical"] = 1] = "Vertical";
304
- Center2[Center2["Horizontal"] = 2] = "Horizontal";
305
- })(Center || (Center = {}));
306
- var Origin;
307
- (function(Origin2) {
308
- Origin2[Origin2["Middle"] = 3] = "Middle";
309
- Origin2[Origin2["Top"] = 5] = "Top";
310
- Origin2[Origin2["Bottom"] = 9] = "Bottom";
311
- Origin2[Origin2["Left"] = 18] = "Left";
312
- Origin2[Origin2["Right"] = 34] = "Right";
313
- Origin2[Origin2["TopLeft"] = 20] = "TopLeft";
314
- Origin2[Origin2["TopRight"] = 36] = "TopRight";
315
- Origin2[Origin2["BottomLeft"] = 24] = "BottomLeft";
316
- Origin2[Origin2["BottomRight"] = 40] = "BottomRight";
317
- })(Origin || (Origin = {}));
318
- decorate(waitFor, threadable());
319
- function* waitFor(seconds = 0, after) {
320
- const thread = useThread();
321
- const step = usePlayback().framesToSeconds(1);
322
- const targetTime = thread.time() + seconds;
323
- while (targetTime - step > thread.fixed) {
324
- yield;
325
- }
326
- thread.time(targetTime);
327
- if (after) {
328
- yield* after;
329
- }
330
- }
331
- function setTaskName(task, source) {
332
- const prototype = Object.getPrototypeOf(task);
333
- if (!prototype.threadable) {
334
- prototype.threadable = true;
335
- prototype.name = typeof source === "string" ? source : getTaskName(source);
336
- }
337
- }
338
- function getTaskName(task) {
339
- return Object.getPrototypeOf(task).name ?? null;
340
- }
341
- function run(firstArg, runner) {
342
- let task;
343
- if (typeof firstArg === "string") {
344
- task = runner();
345
- setTaskName(task, firstArg);
346
- } else {
347
- task = firstArg();
348
- setTaskName(task, task);
349
- }
350
- return task;
351
- }
352
- class DependencyContext {
353
- static collectPromise(promise, initialValue = null) {
354
- const handle = {
355
- promise,
356
- value: initialValue,
357
- stack: new Error().stack
358
- };
359
- const context = this.collectionStack.at(-1);
360
- if (context) {
361
- handle.owner = context.owner;
362
- }
363
- promise.then((value) => {
364
- handle.value = value;
365
- context == null ? void 0 : context.markDirty();
366
- });
367
- this.promises.push(handle);
368
- return handle;
369
- }
370
- static hasPromises() {
371
- return this.promises.length > 0;
372
- }
373
- static async consumePromises() {
374
- const promises = [...this.promises];
375
- await Promise.all(promises.map((handle) => handle.promise));
376
- this.promises = this.promises.filter((v) => !promises.includes(v));
377
- return promises;
378
- }
379
- constructor(owner) {
380
- this.owner = owner;
381
- this.dependencies = /* @__PURE__ */ new Set();
382
- this.event = new FlagDispatcher();
383
- this.markDirty = () => this.event.raise();
384
- this.invokable = this.invoke.bind(this);
385
- Object.defineProperty(this.invokable, "context", {
386
- value: this
387
- });
388
- Object.defineProperty(this.invokable, "toPromise", {
389
- value: this.toPromise.bind(this)
390
- });
391
- }
392
- invoke() {
393
- }
394
- startCollecting() {
395
- if (DependencyContext.collectionSet.has(this)) {
396
- throw new DetailedError("A circular dependency occurred between signals.", `This can happen when signals reference each other in a loop.
397
- Try using the attached stack trace to locate said loop.`);
398
- }
399
- DependencyContext.collectionSet.add(this);
400
- DependencyContext.collectionStack.push(this);
401
- }
402
- finishCollecting() {
403
- DependencyContext.collectionSet.delete(this);
404
- if (DependencyContext.collectionStack.pop() !== this) {
405
- throw new Error("collectStart/collectEnd was called out of order.");
406
- }
407
- }
408
- clearDependencies() {
409
- this.dependencies.forEach((dep) => dep.unsubscribe(this.markDirty));
410
- this.dependencies.clear();
411
- }
412
- collect() {
413
- const signal = DependencyContext.collectionStack.at(-1);
414
- if (signal) {
415
- signal.dependencies.add(this.event.subscribable);
416
- this.event.subscribe(signal.markDirty);
417
- }
418
- }
419
- dispose() {
420
- this.clearDependencies();
421
- this.event.clear();
422
- this.owner = null;
423
- }
424
- async toPromise() {
425
- do {
426
- await DependencyContext.consumePromises();
427
- this.invokable();
428
- } while (DependencyContext.hasPromises());
429
- return this.invokable;
430
- }
431
- }
432
- DependencyContext.collectionSet = /* @__PURE__ */ new Set();
433
- DependencyContext.collectionStack = [];
434
- DependencyContext.promises = [];
435
- const DEFAULT = Symbol.for("@twick/core/signals/default");
436
- function isReactive(value) {
437
- return typeof value === "function";
438
- }
439
- function modify(value, modification) {
440
- return isReactive(value) ? () => modification(value()) : modification(value);
441
- }
442
- function unwrap(value) {
443
- return isReactive(value) ? value() : value;
444
- }
445
- class SignalContext extends DependencyContext {
446
- constructor(initial, interpolation, owner = void 0, parser = (value) => value, extensions = {}) {
447
- super(owner);
448
- this.initial = initial;
449
- this.interpolation = interpolation;
450
- this.parser = parser;
451
- this.tweening = false;
452
- Object.defineProperty(this.invokable, "reset", {
453
- value: this.reset.bind(this)
454
- });
455
- Object.defineProperty(this.invokable, "save", {
456
- value: this.save.bind(this)
457
- });
458
- Object.defineProperty(this.invokable, "isInitial", {
459
- value: this.isInitial.bind(this)
460
- });
461
- if (this.initial !== void 0) {
462
- this.current = this.initial;
463
- this.markDirty();
464
- if (!isReactive(this.initial)) {
465
- this.last = this.parse(this.initial);
466
- }
467
- }
468
- this.extensions = {
469
- getter: this.getter.bind(this),
470
- setter: this.setter.bind(this),
471
- tweener: this.tweener.bind(this),
472
- ...extensions
473
- };
474
- }
475
- toSignal() {
476
- return this.invokable;
477
- }
478
- parse(value) {
479
- return this.parser(value);
480
- }
481
- set(value) {
482
- this.extensions.setter(value);
483
- return this.owner;
484
- }
485
- setter(value) {
486
- if (value === DEFAULT) {
487
- value = this.initial;
488
- }
489
- if (this.current === value) {
490
- return this.owner;
491
- }
492
- this.current = value;
493
- this.markDirty();
494
- this.clearDependencies();
495
- if (!isReactive(value)) {
496
- this.last = this.parse(value);
497
- }
498
- return this.owner;
499
- }
500
- get() {
501
- return this.extensions.getter();
502
- }
503
- getter() {
504
- var _a;
505
- if (this.event.isRaised() && isReactive(this.current)) {
506
- this.clearDependencies();
507
- this.startCollecting();
508
- try {
509
- this.last = this.parse(this.current());
510
- } catch (e) {
511
- useLogger().error({
512
- ...errorToLog(e),
513
- inspect: (_a = this.owner) == null ? void 0 : _a.key
514
- });
515
- }
516
- this.finishCollecting();
517
- }
518
- this.event.reset();
519
- this.collect();
520
- return this.last;
521
- }
522
- invoke(value, duration, timingFunction = easeInOutCubic, interpolationFunction = this.interpolation) {
523
- if (value === void 0) {
524
- return this.get();
525
- }
526
- if (duration === void 0) {
527
- return this.set(value);
528
- }
529
- const queue = this.createQueue(timingFunction, interpolationFunction);
530
- return queue.to(value, duration);
531
- }
532
- createQueue(defaultTimingFunction, defaultInterpolationFunction) {
533
- const initial = this.get();
534
- const queue = [];
535
- const task = run("animation chain", function* animate() {
536
- while (queue.length > 0) {
537
- yield* queue.shift();
538
- }
539
- });
540
- task.to = (value, duration, timingFunction = defaultTimingFunction, interpolationFunction = defaultInterpolationFunction) => {
541
- defaultTimingFunction = timingFunction;
542
- defaultInterpolationFunction = interpolationFunction;
543
- queue.push(this.tween(value, duration, timingFunction, interpolationFunction));
544
- return task;
545
- };
546
- task.back = (time, timingFunction = defaultTimingFunction, interpolationFunction = defaultInterpolationFunction) => {
547
- defaultTimingFunction = timingFunction;
548
- defaultInterpolationFunction = interpolationFunction;
549
- queue.push(this.tween(initial, time, defaultTimingFunction, defaultInterpolationFunction));
550
- return task;
551
- };
552
- task.wait = (duration) => {
553
- queue.push(waitFor(duration));
554
- return task;
555
- };
556
- task.run = (generator) => {
557
- queue.push(generator);
558
- return task;
559
- };
560
- task.do = (callback) => {
561
- queue.push(run(function* () {
562
- callback();
563
- }));
564
- return task;
565
- };
566
- return task;
567
- }
568
- *tween(value, duration, timingFunction, interpolationFunction) {
569
- if (value === DEFAULT) {
570
- value = this.initial;
571
- }
572
- this.tweening = true;
573
- yield* this.extensions.tweener(value, duration, timingFunction, interpolationFunction);
574
- this.set(value);
575
- this.tweening = false;
576
- }
577
- *tweener(value, duration, timingFunction, interpolationFunction) {
578
- const from = this.get();
579
- yield* tween(duration, (v) => {
580
- this.set(interpolationFunction(from, this.parse(unwrap(value)), timingFunction(v)));
581
- });
582
- }
583
- dispose() {
584
- super.dispose();
585
- this.initial = void 0;
586
- this.current = void 0;
587
- this.last = void 0;
588
- }
589
- /**
590
- * Reset the signal to its initial value (if one has been set).
591
- *
592
- * @example
593
- * ```ts
594
- * const signal = createSignal(7);
595
- *
596
- * signal.reset();
597
- * // same as:
598
- * signal(7);
599
- * ```
600
- */
601
- reset() {
602
- if (this.initial !== void 0) {
603
- this.set(this.initial);
604
- }
605
- return this.owner;
606
- }
607
- /**
608
- * Compute the current value of the signal and immediately set it.
609
- *
610
- * @remarks
611
- * This method can be used to stop the signal from updating while keeping its
612
- * current value.
613
- *
614
- * @example
615
- * ```ts
616
- * signal.save();
617
- * // same as:
618
- * signal(signal());
619
- * ```
620
- */
621
- save() {
622
- return this.set(this.get());
623
- }
624
- /**
625
- * Check if the signal is currently using its initial value.
626
- *
627
- * @example
628
- * ```ts
629
- *
630
- * const signal = createSignal(0);
631
- * signal.isInitial(); // true
632
- *
633
- * signal(5);
634
- * signal.isInitial(); // false
635
- *
636
- * signal(DEFAULT);
637
- * signal.isInitial(); // true
638
- * ```
639
- */
640
- isInitial() {
641
- this.collect();
642
- return this.current === this.initial;
643
- }
644
- /**
645
- * Get the initial value of this signal.
646
- */
647
- getInitial() {
648
- return this.initial;
649
- }
650
- /**
651
- * Get the raw value of this signal.
652
- *
653
- * @remarks
654
- * If the signal was provided with a factory function, the function itself
655
- * will be returned, without invoking it.
656
- *
657
- * This method can be used to create copies of signals.
658
- *
659
- * @example
660
- * ```ts
661
- * const a = createSignal(2);
662
- * const b = createSignal(() => a);
663
- * // b() == 2
664
- *
665
- * const bClone = createSignal(b.raw());
666
- * // bClone() == 2
667
- *
668
- * a(4);
669
- * // b() == 4
670
- * // bClone() == 4
671
- * ```
672
- */
673
- raw() {
674
- return this.current;
675
- }
676
- /**
677
- * Is the signal undergoing a tween?
678
- */
679
- isTweening() {
680
- return this.tweening;
681
- }
682
- }
683
- class CompoundSignalContext extends SignalContext {
684
- constructor(entries, parser, initial, interpolation, owner = void 0, extensions = {}) {
685
- var _a;
686
- super(void 0, interpolation, owner, parser, extensions);
687
- this.entries = entries;
688
- this.signals = [];
689
- this.parser = parser;
690
- for (const entry of entries) {
691
- let key;
692
- let signal;
693
- if (Array.isArray(entry)) {
694
- [key, signal] = entry;
695
- (_a = signal.context).owner ?? (_a.owner = this);
696
- } else {
697
- key = entry;
698
- signal = new SignalContext(modify(initial, (value) => parser(value)[entry]), map, owner ?? this.invokable).toSignal();
699
- }
700
- this.signals.push([key, signal]);
701
- Object.defineProperty(this.invokable, key, { value: signal });
702
- }
703
- }
704
- toSignal() {
705
- return this.invokable;
706
- }
707
- parse(value) {
708
- return this.parser(value);
709
- }
710
- getter() {
711
- return this.parse(Object.fromEntries(this.signals.map(([key, property]) => [key, property()])));
712
- }
713
- setter(value) {
714
- if (isReactive(value)) {
715
- for (const [key, property] of this.signals) {
716
- property(() => this.parser(value())[key]);
717
- }
718
- } else {
719
- const parsed = this.parse(value);
720
- for (const [key, property] of this.signals) {
721
- property(parsed[key]);
722
- }
723
- }
724
- return this.owner;
725
- }
726
- reset() {
727
- for (const [, signal] of this.signals) {
728
- signal.reset();
729
- }
730
- return this.owner;
731
- }
732
- save() {
733
- for (const [, signal] of this.signals) {
734
- signal.save();
735
- }
736
- return this.owner;
737
- }
738
- isInitial() {
739
- for (const [, signal] of this.signals) {
740
- if (!signal.isInitial()) {
741
- return false;
742
- }
743
- }
744
- return true;
745
- }
746
- raw() {
747
- return Object.fromEntries(this.signals.map(([key, property]) => [key, property.context.raw()]));
748
- }
749
- }
750
- const EPSILON = 1e-6;
751
- class Vector2 {
752
- static createSignal(initial, interpolation = Vector2.lerp, owner) {
753
- return new CompoundSignalContext(["x", "y"], (value) => new Vector2(value), initial, interpolation, owner).toSignal();
754
- }
755
- static lerp(from, to, value) {
756
- let valueX;
757
- let valueY;
758
- if (typeof value === "number") {
759
- valueX = valueY = value;
760
- } else {
761
- valueX = value.x;
762
- valueY = value.y;
763
- }
764
- return new Vector2(map(from.x, to.x, valueX), map(from.y, to.y, valueY));
765
- }
766
- static arcLerp(from, to, value, reverse = false, ratio) {
767
- ratio ?? (ratio = from.sub(to).ctg);
768
- return Vector2.lerp(from, to, new Vector2(arcLerp(value, reverse, ratio)));
769
- }
770
- static createArcLerp(reverse, ratio) {
771
- return (from, to, value) => Vector2.arcLerp(from, to, value, reverse, ratio);
772
- }
773
- /**
774
- * Interpolates between two vectors on the polar plane by interpolating
775
- * the angles and magnitudes of the vectors individually.
776
- *
777
- * @param from - The starting vector.
778
- * @param to - The target vector.
779
- * @param value - The t-value of the interpolation.
780
- * @param counterclockwise - Whether the vector should get rotated
781
- * counterclockwise. Defaults to `false`.
782
- * @param origin - The center of rotation. Defaults to the origin.
783
- *
784
- * @remarks
785
- * This function is useful when used in conjunction with {@link rotate} to
786
- * animate an object's position on a circular arc (see examples).
787
- *
788
- * @example
789
- * Animating an object in a circle around the origin
790
- * ```tsx
791
- * circle().position(
792
- * circle().position().rotate(180),
793
- * 1,
794
- * easeInOutCubic,
795
- * Vector2.polarLerp
796
- * );
797
- * ```
798
- * @example
799
- * Rotating an object around the point `[-200, 100]`
800
- * ```ts
801
- * circle().position(
802
- * circle().position().rotate(180, [-200, 100]),
803
- * 1,
804
- * easeInOutCubic,
805
- * Vector2.createPolarLerp(false, [-200, 100]),
806
- * );
807
- * ```
808
- * @example
809
- * Rotating an object counterclockwise around the origin
810
- * ```ts
811
- * circle().position(
812
- * circle().position().rotate(180),
813
- * 1,
814
- * easeInOutCubic,
815
- * Vector2.createPolarLerp(true),
816
- * );
817
- * ```
818
- */
819
- static polarLerp(from, to, value, counterclockwise = false, origin = Vector2.zero) {
820
- from = from.sub(origin);
821
- to = to.sub(origin);
822
- const fromAngle = from.degrees;
823
- let toAngle = to.degrees;
824
- const isCounterclockwise = fromAngle > toAngle;
825
- if (isCounterclockwise !== counterclockwise) {
826
- toAngle = toAngle + (counterclockwise ? -360 : 360);
827
- }
828
- const angle = map(fromAngle, toAngle, value) * DEG2RAD;
829
- const magnitude = map(from.magnitude, to.magnitude, value);
830
- return new Vector2(magnitude * Math.cos(angle) + origin.x, magnitude * Math.sin(angle) + origin.y);
831
- }
832
- /**
833
- * Helper function to create a {@link Vector2.polarLerp} interpolation
834
- * function with additional parameters.
835
- *
836
- * @param counterclockwise - Whether the point should get rotated
837
- * counterclockwise.
838
- * @param center - The center of rotation. Defaults to the origin.
839
- */
840
- static createPolarLerp(counterclockwise = false, center = Vector2.zero) {
841
- return (from, to, value) => Vector2.polarLerp(from, to, value, counterclockwise, new Vector2(center));
842
- }
843
- static fromOrigin(origin) {
844
- const position = new Vector2();
845
- if (origin === Origin.Middle) {
846
- return position;
847
- }
848
- if (origin & Direction.Left) {
849
- position.x = -1;
850
- } else if (origin & Direction.Right) {
851
- position.x = 1;
852
- }
853
- if (origin & Direction.Top) {
854
- position.y = -1;
855
- } else if (origin & Direction.Bottom) {
856
- position.y = 1;
857
- }
858
- return position;
859
- }
860
- static fromScalar(value) {
861
- return new Vector2(value, value);
862
- }
863
- static fromRadians(radians) {
864
- return new Vector2(Math.cos(radians), Math.sin(radians));
865
- }
866
- static fromDegrees(degrees) {
867
- return Vector2.fromRadians(degrees * DEG2RAD);
868
- }
869
- /**
870
- * Return the angle in radians between the vector described by x and y and the
871
- * positive x-axis.
872
- *
873
- * @param x - The x component of the vector.
874
- * @param y - The y component of the vector.
875
- */
876
- static radians(x, y) {
877
- return Math.atan2(y, x);
878
- }
879
- /**
880
- * Return the angle in degrees between the vector described by x and y and the
881
- * positive x-axis.
882
- *
883
- * @param x - The x component of the vector.
884
- * @param y - The y component of the vector.
885
- *
886
- * @remarks
887
- * The returned angle will be between -180 and 180 degrees.
888
- */
889
- static degrees(x, y) {
890
- return Vector2.radians(x, y) * RAD2DEG;
891
- }
892
- static magnitude(x, y) {
893
- return Math.sqrt(x * x + y * y);
894
- }
895
- static squaredMagnitude(x, y) {
896
- return x * x + y * y;
897
- }
898
- static angleBetween(u, v) {
899
- return Math.acos(clamp(-1, 1, u.dot(v) / (u.magnitude * v.magnitude))) * (u.cross(v) >= 0 ? 1 : -1);
900
- }
901
- get width() {
902
- return this.x;
903
- }
904
- set width(value) {
905
- this.x = value;
906
- }
907
- get height() {
908
- return this.y;
909
- }
910
- set height(value) {
911
- this.y = value;
912
- }
913
- get magnitude() {
914
- return Vector2.magnitude(this.x, this.y);
915
- }
916
- get squaredMagnitude() {
917
- return Vector2.squaredMagnitude(this.x, this.y);
918
- }
919
- get normalized() {
920
- return this.scale(1 / Vector2.magnitude(this.x, this.y));
921
- }
922
- get safe() {
923
- return new Vector2(isNaN(this.x) ? 0 : this.x, isNaN(this.y) ? 0 : this.y);
924
- }
925
- get flipped() {
926
- return new Vector2(-this.x, -this.y);
927
- }
928
- get floored() {
929
- return new Vector2(Math.floor(this.x), Math.floor(this.y));
930
- }
931
- get perpendicular() {
932
- return new Vector2(this.y, -this.x);
933
- }
934
- /**
935
- * Return the angle in radians between the vector and the positive x-axis.
936
- */
937
- get radians() {
938
- return Vector2.radians(this.x, this.y);
939
- }
940
- /**
941
- * Return the angle in degrees between the vector and the positive x-axis.
942
- *
943
- * @remarks
944
- * The returned angle will be between -180 and 180 degrees.
945
- */
946
- get degrees() {
947
- return Vector2.degrees(this.x, this.y);
948
- }
949
- get ctg() {
950
- return this.x / this.y;
951
- }
952
- constructor(one, two) {
953
- this.x = 0;
954
- this.y = 0;
955
- if (one === void 0 || one === null) {
956
- return;
957
- }
958
- if (typeof one !== "object") {
959
- this.x = one;
960
- this.y = two ?? one;
961
- return;
962
- }
963
- if (Array.isArray(one)) {
964
- this.x = one[0];
965
- this.y = one[1];
966
- return;
967
- }
968
- if ("width" in one) {
969
- this.x = one.width;
970
- this.y = one.height;
971
- return;
972
- }
973
- this.x = one.x;
974
- this.y = one.y;
975
- }
976
- lerp(to, value) {
977
- return Vector2.lerp(this, to, value);
978
- }
979
- getOriginOffset(origin) {
980
- const offset = Vector2.fromOrigin(origin);
981
- offset.x *= this.x / 2;
982
- offset.y *= this.y / 2;
983
- return offset;
984
- }
985
- scale(value) {
986
- return new Vector2(this.x * value, this.y * value);
987
- }
988
- mul(possibleVector) {
989
- const vector = new Vector2(possibleVector);
990
- return new Vector2(this.x * vector.x, this.y * vector.y);
991
- }
992
- div(possibleVector) {
993
- const vector = new Vector2(possibleVector);
994
- return new Vector2(this.x / vector.x, this.y / vector.y);
995
- }
996
- add(possibleVector) {
997
- const vector = new Vector2(possibleVector);
998
- return new Vector2(this.x + vector.x, this.y + vector.y);
999
- }
1000
- sub(possibleVector) {
1001
- const vector = new Vector2(possibleVector);
1002
- return new Vector2(this.x - vector.x, this.y - vector.y);
1003
- }
1004
- dot(possibleVector) {
1005
- const vector = new Vector2(possibleVector);
1006
- return this.x * vector.x + this.y * vector.y;
1007
- }
1008
- cross(possibleVector) {
1009
- const vector = new Vector2(possibleVector);
1010
- return this.x * vector.y - this.y * vector.x;
1011
- }
1012
- mod(possibleVector) {
1013
- const vector = new Vector2(possibleVector);
1014
- return new Vector2(this.x % vector.x, this.y % vector.y);
1015
- }
1016
- addX(value) {
1017
- return new Vector2(this.x + value, this.y);
1018
- }
1019
- addY(value) {
1020
- return new Vector2(this.x, this.y + value);
1021
- }
1022
- toSymbol() {
1023
- return Vector2.symbol;
1024
- }
1025
- toString() {
1026
- return `Vector2(${this.x}, ${this.y})`;
1027
- }
1028
- toUniform(gl, location) {
1029
- gl.uniform2f(location, this.x, this.y);
1030
- }
1031
- serialize() {
1032
- return { x: this.x, y: this.y };
1033
- }
1034
- /**
1035
- * Check if two vectors are exactly equal to each other.
1036
- *
1037
- * @remarks
1038
- * If you need to compensate for floating point inaccuracies, use the
1039
- * {@link equals} method, instead.
1040
- *
1041
- * @param other - The vector to compare.
1042
- */
1043
- exactlyEquals(other) {
1044
- return this.x === other.x && this.y === other.y;
1045
- }
1046
- /**
1047
- * Check if two vectors are equal to each other.
1048
- *
1049
- * @remarks
1050
- * This method allows passing an allowed error margin when comparing vectors
1051
- * to compensate for floating point inaccuracies. To check if two vectors are
1052
- * exactly equal, use the {@link exactlyEquals} method, instead.
1053
- *
1054
- * @param other - The vector to compare.
1055
- * @param threshold - The allowed error threshold when comparing the vectors.
1056
- */
1057
- equals(other, threshold = EPSILON) {
1058
- return Math.abs(this.x - other.x) <= threshold + Number.EPSILON && Math.abs(this.y - other.y) <= threshold + Number.EPSILON;
1059
- }
1060
- }
1061
- Vector2.symbol = Symbol.for("@twick/core/types/Vector2");
1062
- Vector2.zero = new Vector2();
1063
- Vector2.one = new Vector2(1, 1);
1064
- Vector2.right = new Vector2(1, 0);
1065
- Vector2.left = new Vector2(-1, 0);
1066
- Vector2.up = new Vector2(0, 1);
1067
- Vector2.down = new Vector2(0, -1);
1068
- Vector2.top = new Vector2(0, -1);
1069
- Vector2.bottom = new Vector2(0, 1);
1070
- Vector2.topLeft = new Vector2(-1, -1);
1071
- Vector2.topRight = new Vector2(1, -1);
1072
- Vector2.bottomLeft = new Vector2(-1, 1);
1073
- Vector2.bottomRight = new Vector2(1, 1);
1074
- var PlaybackState;
1075
- (function(PlaybackState2) {
1076
- PlaybackState2[PlaybackState2["Playing"] = 0] = "Playing";
1077
- PlaybackState2[PlaybackState2["Rendering"] = 1] = "Rendering";
1078
- PlaybackState2[PlaybackState2["Paused"] = 2] = "Paused";
1079
- PlaybackState2[PlaybackState2["Presenting"] = 3] = "Presenting";
1080
- })(PlaybackState || (PlaybackState = {}));
1081
- class PlaybackManager {
1082
- constructor() {
1083
- this.frame = 0;
1084
- this.speed = 1;
1085
- this.fps = 30;
1086
- this.duration = 0;
1087
- this.finished = false;
1088
- this.slides = [];
1089
- this.previousScene = null;
1090
- this.state = PlaybackState.Paused;
1091
- this.currentSceneReference = null;
1092
- this.scenes = new ValueDispatcher([]);
1093
- }
1094
- /**
1095
- * Triggered when the active scene changes.
1096
- *
1097
- * @eventProperty
1098
- */
1099
- get onSceneChanged() {
1100
- if (this.currentSceneReference === null) {
1101
- throw new Error("PlaybackManager has not been properly initialized");
1102
- }
1103
- return this.currentSceneReference.subscribable;
1104
- }
1105
- /**
1106
- * Triggered when the scenes get recalculated.
1107
- *
1108
- * @remarks
1109
- * This event indicates that the timing of at least one scene has changed.
1110
- *
1111
- * @eventProperty
1112
- */
1113
- get onScenesRecalculated() {
1114
- return this.scenes.subscribable;
1115
- }
1116
- get currentScene() {
1117
- if (this.currentSceneReference === null) {
1118
- throw new Error("PlaybackManager has not been properly initialized");
1119
- }
1120
- return this.currentSceneReference.current;
1121
- }
1122
- set currentScene(scene) {
1123
- if (!scene) {
1124
- throw new Error("Invalid scene.");
1125
- }
1126
- this.currentSceneReference ?? (this.currentSceneReference = new ValueDispatcher(scene));
1127
- this.currentSceneReference.current = scene;
1128
- }
1129
- setup(scenes) {
1130
- this.scenes.current = scenes;
1131
- this.currentScene = scenes[0];
1132
- }
1133
- async progress() {
1134
- this.finished = await this.next();
1135
- return this.finished;
1136
- }
1137
- async seek(frame) {
1138
- if (frame <= this.frame || this.currentScene.isCached() && this.currentScene.lastFrame < frame) {
1139
- const scene = this.findBestScene(frame);
1140
- if (scene !== this.currentScene) {
1141
- this.currentScene.stopAllMedia();
1142
- this.previousScene = null;
1143
- this.currentScene = scene;
1144
- this.frame = this.currentScene.firstFrame;
1145
- await this.currentScene.reset();
1146
- } else if (this.frame >= frame) {
1147
- this.previousScene = null;
1148
- this.frame = this.currentScene.firstFrame;
1149
- await this.currentScene.reset();
1150
- }
1151
- }
1152
- this.finished = false;
1153
- while (this.frame < frame && !this.finished) {
1154
- this.finished = await this.next();
1155
- }
1156
- return this.finished;
1157
- }
1158
- async reset() {
1159
- this.previousScene = null;
1160
- this.currentScene = this.scenes.current[0];
1161
- this.frame = 0;
1162
- await this.currentScene.reset();
1163
- }
1164
- reload(description) {
1165
- this.scenes.current.forEach((scene) => scene.reload(description));
1166
- }
1167
- async recalculate() {
1168
- this.previousScene = null;
1169
- this.slides = [];
1170
- const speed = this.speed;
1171
- this.frame = 0;
1172
- this.speed = 1;
1173
- const scenes = [];
1174
- try {
1175
- for (const scene of this.scenes.current) {
1176
- await scene.recalculate((frame) => {
1177
- this.frame = frame;
1178
- });
1179
- this.slides.push(...scene.slides.onChanged.current);
1180
- scenes.push(scene);
1181
- }
1182
- } finally {
1183
- this.speed = speed;
1184
- }
1185
- this.scenes.current = scenes;
1186
- this.duration = this.frame;
1187
- }
1188
- async next() {
1189
- if (this.previousScene) {
1190
- await this.previousScene.next();
1191
- if (this.currentScene.isFinished()) {
1192
- this.previousScene = null;
1193
- }
1194
- }
1195
- this.frame += this.speed;
1196
- if (this.currentScene.isFinished()) {
1197
- return true;
1198
- }
1199
- await this.currentScene.next();
1200
- if (this.previousScene && this.currentScene.isAfterTransitionIn()) {
1201
- this.previousScene = null;
1202
- }
1203
- if (this.currentScene.canTransitionOut()) {
1204
- this.previousScene = this.currentScene;
1205
- const nextScene = this.getNextScene(this.previousScene);
1206
- if (nextScene) {
1207
- this.previousScene.stopAllMedia();
1208
- this.currentScene = nextScene;
1209
- await this.currentScene.reset(this.previousScene);
1210
- }
1211
- if (!nextScene || this.currentScene.isAfterTransitionIn()) {
1212
- this.previousScene = null;
1213
- }
1214
- }
1215
- return this.currentScene.isFinished();
1216
- }
1217
- findBestScene(frame) {
1218
- let lastScene = this.scenes.current[0];
1219
- for (const scene of this.scenes.current) {
1220
- if (!scene.isCached() || scene.lastFrame > frame) {
1221
- return scene;
1222
- }
1223
- lastScene = scene;
1224
- }
1225
- return lastScene;
1226
- }
1227
- getNextScene(scene) {
1228
- const scenes = this.scenes.current;
1229
- if (!scene) {
1230
- return scenes[0];
1231
- }
1232
- const index = scenes.findIndex((s) => s === scene);
1233
- if (index < 0) {
1234
- return null;
1235
- }
1236
- return scenes[index + 1] ?? null;
1237
- }
1238
- }
1239
- class PlaybackStatus {
1240
- constructor(playback) {
1241
- this.playback = playback;
1242
- }
1243
- /**
1244
- * Convert seconds to frames using the current framerate.
1245
- *
1246
- * @param seconds - The seconds to convert.
1247
- */
1248
- secondsToFrames(seconds) {
1249
- return Math.ceil(seconds * this.playback.fps);
1250
- }
1251
- /**
1252
- * Convert frames to seconds using the current framerate.
1253
- *
1254
- * @param frames - The frames to convert.
1255
- */
1256
- framesToSeconds(frames) {
1257
- return frames / this.playback.fps;
1258
- }
1259
- get time() {
1260
- return this.framesToSeconds(this.playback.frame);
1261
- }
1262
- get frame() {
1263
- return this.playback.frame;
1264
- }
1265
- get speed() {
1266
- return this.playback.speed;
1267
- }
1268
- get fps() {
1269
- return this.playback.fps;
1270
- }
1271
- get state() {
1272
- return this.playback.state;
1273
- }
1274
- /**
1275
- * The time passed since the last frame in seconds.
1276
- */
1277
- get deltaTime() {
1278
- return this.framesToSeconds(1) * this.speed;
1279
- }
1280
- }
1281
- const SOURCE_URL_REGEX = /^\/\/# sourceURL=(.*)$/gm;
1282
- const INFO_LOG_REGEX = /ERROR: \d+:(\d+): (.*)/g;
1283
- const INFO_TOKEN_REGEX = /^'([^']+)'/;
1284
- const includeWithoutPreprocessor = `
1285
- The \`#include\` directive requires the use of a preprocessor.
1286
-
1287
- Make sure to import the shader from a file:
1288
-
1289
- \`\`\`ts
1290
- import shader from './shader.glsl';
1291
- \`\`\`
1292
-
1293
- Do **NOT** use the raw loader:
1294
-
1295
- \`\`\`ts
1296
- import shader from './shader.glsl?raw';
1297
- \`\`\`
1298
-
1299
- Do **NOT** use \`#include\` in an inline string:
1300
-
1301
- \`\`\`ts
1302
- const shader = \`\\
1303
- #include "example.glsl"
1304
- \`;
1305
- \`\`\`
1306
-
1307
- [Learn more](https://motioncanvas.io/docs/shaders) about working with shaders.
1308
- `;
1309
- class SharedWebGLContext {
1310
- constructor(logger) {
1311
- this.logger = logger;
1312
- this.gl = null;
1313
- this.currentOwner = null;
1314
- this.programLookup = /* @__PURE__ */ new Map();
1315
- }
1316
- borrow(owner) {
1317
- var _a;
1318
- if (this.currentOwner === owner) {
1319
- return this.gl;
1320
- }
1321
- (_a = this.currentOwner) == null ? void 0 : _a.teardown(this.gl);
1322
- this.currentOwner = owner;
1323
- this.currentOwner.setup(this.getGL());
1324
- return this.gl;
1325
- }
1326
- /**
1327
- * Dispose the WebGL context to free up resources.
1328
- */
1329
- dispose() {
1330
- var _a, _b;
1331
- if (!this.gl) {
1332
- return;
1333
- }
1334
- (_a = this.currentOwner) == null ? void 0 : _a.teardown(this.gl);
1335
- this.currentOwner = null;
1336
- this.gl.useProgram(null);
1337
- for (const { program, fragment, vertex } of this.programLookup.values()) {
1338
- this.gl.deleteProgram(program);
1339
- this.gl.deleteShader(fragment);
1340
- this.gl.deleteShader(vertex);
1341
- }
1342
- this.programLookup.clear();
1343
- (_b = this.gl.getExtension("WEBGL_lose_context")) == null ? void 0 : _b.loseContext();
1344
- this.gl.canvas.remove();
1345
- this.gl = null;
1346
- }
1347
- getProgram(fragment, vertex) {
1348
- const key = `${fragment}#${vertex}`;
1349
- if (this.programLookup.has(key)) {
1350
- return this.programLookup.get(key).program;
1351
- }
1352
- const gl = this.getGL();
1353
- const fragmentShader = this.getShader(gl.FRAGMENT_SHADER, fragment);
1354
- const vertexShader = this.getShader(gl.VERTEX_SHADER, vertex);
1355
- if (!fragmentShader || !vertexShader) {
1356
- return null;
1357
- }
1358
- const program = gl.createProgram();
1359
- gl.attachShader(program, fragmentShader);
1360
- gl.attachShader(program, vertexShader);
1361
- gl.linkProgram(program);
1362
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
1363
- this.logger.error({
1364
- message: "Failed to initialize the shader program.",
1365
- remarks: gl.getProgramInfoLog(program) ?? void 0,
1366
- stack: new Error().stack
1367
- });
1368
- gl.deleteProgram(program);
1369
- return null;
1370
- }
1371
- this.programLookup.set(key, {
1372
- program,
1373
- fragment: fragmentShader,
1374
- vertex: vertexShader
1375
- });
1376
- return program;
1377
- }
1378
- getShader(type, source) {
1379
- const gl = this.getGL();
1380
- const shader = gl.createShader(type);
1381
- gl.shaderSource(shader, source);
1382
- gl.compileShader(shader);
1383
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
1384
- const log = gl.getShaderInfoLog(shader);
1385
- logGlslError(this.logger, log, source);
1386
- gl.deleteShader(shader);
1387
- return null;
1388
- }
1389
- return shader;
1390
- }
1391
- getGL() {
1392
- if (this.gl) {
1393
- return this.gl;
1394
- }
1395
- this.gl = document.createElement("canvas").getContext("webgl2", {
1396
- depth: false,
1397
- premultipliedAlpha: false,
1398
- stencil: false,
1399
- powerPreference: "high-performance"
1400
- });
1401
- if (!this.gl) {
1402
- throw new Error("Failed to initialize WebGL.");
1403
- }
1404
- return this.gl;
1405
- }
1406
- }
1407
- function logGlslError(logger, log, source) {
1408
- let sourceUrl = null;
1409
- SOURCE_URL_REGEX.lastIndex = 0;
1410
- const sourceMatch = SOURCE_URL_REGEX.exec(source);
1411
- if (sourceMatch) {
1412
- const url = new URL(sourceMatch[1], window.location.origin);
1413
- url.searchParams.set("t", Date.now().toString());
1414
- sourceUrl = url.toString();
1415
- }
1416
- if (!log) {
1417
- logger.error({
1418
- message: `Unknown shader compilation error.`,
1419
- stack: fakeStackTrace(sourceUrl, 1, 0)
1420
- });
1421
- return null;
1422
- }
1423
- let logged = false;
1424
- let result;
1425
- while (result = INFO_LOG_REGEX.exec(log)) {
1426
- const [, line, message] = result;
1427
- let column = 0;
1428
- const match = message.match(INFO_TOKEN_REGEX);
1429
- if (match) {
1430
- const tokenLine = source.split("\n")[parseInt(line) - 1];
1431
- const index = tokenLine.indexOf(match[1]);
1432
- if (index !== -1) {
1433
- column = index;
1434
- }
1435
- if (match[1] === "include") {
1436
- const line2 = source.split("\n").find((line3) => line3.startsWith("#include"));
1437
- if (line2) {
1438
- logged = true;
1439
- logger.error({
1440
- message: `Shader compilation error: ${message}`,
1441
- remarks: includeWithoutPreprocessor
1442
- });
1443
- break;
1444
- }
1445
- }
1446
- }
1447
- logged = true;
1448
- logger.error({
1449
- message: `Shader compilation error: ${message}`,
1450
- stack: fakeStackTrace(sourceUrl, line, column)
1451
- });
1452
- }
1453
- if (!logged) {
1454
- logger.error({
1455
- message: `Shader compilation error: ${log}`,
1456
- stack: fakeStackTrace(sourceUrl, 1, 0)
1457
- });
1458
- }
1459
- }
1460
- function fakeStackTrace(file, line, column) {
1461
- if (!file) {
1462
- return void 0;
1463
- }
1464
- return navigator.userAgent.toLowerCase().includes("chrome") ? ` at (${file}:${line}:${column})` : `@${file}:${line}:${column}`;
1465
- }
1466
- class Player {
1467
- /**
1468
- * Triggered during each iteration of the update loop when the frame is ready
1469
- * to be rendered.
1470
- *
1471
- * @remarks
1472
- * Player does not perform any rendering on its own. For the animation to be
1473
- * visible, another class must subscribe to this event and perform the
1474
- * rendering itself. {@link Stage} can be used to display the animation.
1475
- *
1476
- * @eventProperty
1477
- */
1478
- get onRender() {
1479
- return this.render.subscribable;
1480
- }
1481
- get onStateChanged() {
1482
- return this.playerState.subscribable;
1483
- }
1484
- get onFrameChanged() {
1485
- return this.frame.subscribable;
1486
- }
1487
- get onDurationChanged() {
1488
- return this.duration.subscribable;
1489
- }
1490
- /**
1491
- * Triggered right after recalculation finishes.
1492
- *
1493
- * @remarks
1494
- * Can be used to provide visual feedback.
1495
- *
1496
- * @eventProperty
1497
- */
1498
- get onRecalculated() {
1499
- return this.recalculated.subscribable;
1500
- }
1501
- get startFrame() {
1502
- return Math.min(this.playback.duration, this.status.secondsToFrames(this.startTime));
1503
- }
1504
- get endFrame() {
1505
- return Math.min(this.playback.duration, this.status.secondsToFrames(this.endTime));
1506
- }
1507
- get finished() {
1508
- return this.playback.finished || this.playback.frame >= this.endFrame;
1509
- }
1510
- constructor(project, settings = {}, initialState = {}, initialFrame = -1) {
1511
- var _a, _b;
1512
- this.project = project;
1513
- this.settings = settings;
1514
- this.initialState = initialState;
1515
- this.initialFrame = initialFrame;
1516
- this.render = new AsyncEventDispatcher();
1517
- this.frame = new ValueDispatcher(0);
1518
- this.duration = new ValueDispatcher(0);
1519
- this.recalculated = new EventDispatcher();
1520
- this.lock = new Semaphore();
1521
- this.startTime = 0;
1522
- this.endTime = Infinity;
1523
- this.requestId = null;
1524
- this.renderTime = 0;
1525
- this.requestedSeek = -1;
1526
- this.requestedRender = false;
1527
- this.requestedRecalculation = true;
1528
- this.active = false;
1529
- this.playerState = new ValueDispatcher({
1530
- loop: true,
1531
- muted: true,
1532
- volume: 1,
1533
- speed: 1,
1534
- ...initialState,
1535
- paused: true
1536
- });
1537
- this.sharedWebGLContext = new SharedWebGLContext(this.project.logger);
1538
- this.requestedSeek = initialFrame;
1539
- this.logger = this.project.logger;
1540
- this.playback = new PlaybackManager();
1541
- this.status = new PlaybackStatus(this.playback);
1542
- this.size = settings.size ?? new Vector2(1920, 1080);
1543
- this.resolutionScale = settings.resolutionScale ?? 1;
1544
- this.startTime = ((_a = settings.range) == null ? void 0 : _a[0]) ?? 0;
1545
- this.endTime = ((_b = settings.range) == null ? void 0 : _b[1]) ?? Infinity;
1546
- this.playback.fps = settings.fps ?? 60;
1547
- const scenes = [];
1548
- for (const description of project.scenes) {
1549
- const scene = new description.klass({
1550
- ...description,
1551
- playback: this.status,
1552
- logger: this.project.logger,
1553
- size: this.size,
1554
- resolutionScale: this.resolutionScale,
1555
- sharedWebGLContext: this.sharedWebGLContext,
1556
- experimentalFeatures: project.experimentalFeatures
1557
- });
1558
- scene.onReloaded.subscribe(() => this.requestRecalculation());
1559
- scene.variables.updateSignals(project.variables ?? {});
1560
- scenes.push(scene);
1561
- }
1562
- this.playback.setup(scenes);
1563
- this.activate();
1564
- }
1565
- async configure(settings) {
1566
- await this.lock.acquire();
1567
- let frame = this.playback.frame;
1568
- let recalculate = false;
1569
- this.startTime = settings.range[0];
1570
- this.endTime = settings.range[1];
1571
- const newFps = Math.max(1, settings.fps);
1572
- if (this.playback.fps !== newFps) {
1573
- const ratio = newFps / this.playback.fps;
1574
- this.playback.fps = newFps;
1575
- frame = Math.floor(frame * ratio);
1576
- recalculate = true;
1577
- }
1578
- if (!settings.size.exactlyEquals(this.size) || settings.resolutionScale !== this.resolutionScale) {
1579
- this.size = settings.size;
1580
- this.resolutionScale = settings.resolutionScale;
1581
- this.playback.reload({
1582
- size: this.size,
1583
- resolutionScale: this.resolutionScale
1584
- });
1585
- }
1586
- this.lock.release();
1587
- if (recalculate) {
1588
- this.playback.reload();
1589
- this.frame.current = frame;
1590
- this.requestRecalculation();
1591
- this.requestedSeek = frame;
1592
- }
1593
- }
1594
- /**
1595
- * Whether the given frame is inside the animation range.
1596
- *
1597
- * @param frame - The frame to check.
1598
- */
1599
- isInRange(frame) {
1600
- return frame >= 0 && frame <= this.playback.duration;
1601
- }
1602
- /**
1603
- * Whether the given frame is inside the user-defined range.
1604
- *
1605
- * @param frame - The frame to check.
1606
- */
1607
- isInUserRange(frame) {
1608
- return frame >= this.startFrame && frame <= this.endFrame;
1609
- }
1610
- requestSeek(value) {
1611
- this.requestedSeek = this.clampRange(value);
1612
- }
1613
- requestPreviousFrame() {
1614
- this.requestedSeek = this.frame.current - this.playback.speed;
1615
- }
1616
- requestNextFrame() {
1617
- this.requestedSeek = this.frame.current + this.playback.speed;
1618
- }
1619
- requestReset() {
1620
- this.requestedSeek = 0;
1621
- }
1622
- requestRender() {
1623
- this.requestedRender = true;
1624
- }
1625
- toggleLoop(value = !this.playerState.current.loop) {
1626
- if (value !== this.playerState.current.loop) {
1627
- this.playerState.current = {
1628
- ...this.playerState.current,
1629
- loop: value
1630
- };
1631
- }
1632
- }
1633
- togglePlayback(value = this.playerState.current.paused) {
1634
- if (value === this.playerState.current.paused) {
1635
- this.playerState.current = {
1636
- ...this.playerState.current,
1637
- paused: !value
1638
- };
1639
- if (value && !this.playerState.current.loop && this.playback.frame === this.playback.duration) {
1640
- this.requestReset();
1641
- }
1642
- }
1643
- }
1644
- toggleAudio(value = this.playerState.current.muted) {
1645
- if (value === this.playerState.current.muted) {
1646
- this.playerState.current = {
1647
- ...this.playerState.current,
1648
- muted: !value
1649
- };
1650
- }
1651
- }
1652
- setAudioVolume(value) {
1653
- const clampedValue = clamp(0, 1, value);
1654
- if (clampedValue !== this.playerState.current.volume) {
1655
- this.playerState.current = {
1656
- ...this.playerState.current,
1657
- volume: clampedValue
1658
- };
1659
- }
1660
- }
1661
- addAudioVolume(value) {
1662
- this.setAudioVolume(this.playerState.current.volume + value);
1663
- }
1664
- setSpeed(value) {
1665
- if (value !== this.playerState.current.speed) {
1666
- this.playback.speed = value;
1667
- this.playback.reload();
1668
- this.playerState.current = {
1669
- ...this.playerState.current,
1670
- speed: value
1671
- };
1672
- this.requestRecalculation();
1673
- }
1674
- }
1675
- setVariables(variables) {
1676
- for (const scene of this.playback.onScenesRecalculated.current) {
1677
- scene.variables.updateSignals(variables);
1678
- }
1679
- }
1680
- /**
1681
- * Activate the player.
1682
- *
1683
- * @remarks
1684
- * A player needs to be active in order for the update loop to run. Each
1685
- * player is active by default.
1686
- */
1687
- activate() {
1688
- this.active = true;
1689
- this.request();
1690
- }
1691
- /**
1692
- * Deactivate the player.
1693
- *
1694
- * @remarks
1695
- * Deactivating the player prevents its update loop from running. This should
1696
- * be done before disposing the player, to prevent it from running in the
1697
- * background.
1698
- *
1699
- * Just pausing the player does not stop the loop.
1700
- */
1701
- deactivate() {
1702
- this.active = false;
1703
- this.sharedWebGLContext.dispose();
1704
- this.playback.currentScene.stopAllMedia();
1705
- if (this.requestId !== null) {
1706
- cancelAnimationFrame(this.requestId);
1707
- this.requestId = null;
1708
- }
1709
- }
1710
- requestRecalculation() {
1711
- this.requestedRecalculation = true;
1712
- this.request();
1713
- }
1714
- async prepare() {
1715
- const state = {
1716
- ...this.playerState.current,
1717
- seek: this.requestedSeek,
1718
- render: this.requestedRender
1719
- };
1720
- this.requestedSeek = -1;
1721
- this.requestedRender = false;
1722
- if (this.requestedRecalculation) {
1723
- if (state.seek < 0) {
1724
- state.seek = this.playback.frame;
1725
- }
1726
- try {
1727
- await this.playback.recalculate();
1728
- this.duration.current = this.playback.frame;
1729
- this.recalculated.dispatch();
1730
- } catch (e) {
1731
- this.requestSeek(state.seek);
1732
- throw e;
1733
- } finally {
1734
- this.requestedRecalculation = false;
1735
- }
1736
- }
1737
- if (!state.loop && this.finished && !state.paused && state.seek < 0 || this.endFrame === this.startFrame) {
1738
- this.togglePlayback(false);
1739
- state.paused = true;
1740
- state.seek = this.endFrame === this.startFrame ? state.seek : this.startFrame;
1741
- }
1742
- if (state.loop && (state.seek > this.endFrame || this.finished && !state.paused) && this.startFrame !== this.endTime) {
1743
- state.seek = this.startFrame;
1744
- }
1745
- return state;
1746
- }
1747
- async run() {
1748
- const state = await this.prepare();
1749
- const previousState = this.playback.state;
1750
- this.playback.state = state.paused ? PlaybackState.Paused : PlaybackState.Playing;
1751
- if (state.seek >= 0 || !this.isInUserRange(this.status.frame)) {
1752
- const seekFrame = state.seek < 0 ? this.status.frame : state.seek;
1753
- const clampedFrame = this.clampRange(seekFrame);
1754
- this.logger.profile("seek time");
1755
- await this.playback.seek(clampedFrame);
1756
- this.logger.profile("seek time");
1757
- } else if (state.paused) {
1758
- if (state.render || state.paused && previousState !== PlaybackState.Paused) {
1759
- await this.render.dispatch();
1760
- }
1761
- this.request();
1762
- return;
1763
- } else if (this.status.frame < this.endFrame) {
1764
- await this.playback.progress();
1765
- }
1766
- if (!state.paused && this.playback.currentScene.slides.isWaiting()) {
1767
- this.togglePlayback(false);
1768
- state.paused = true;
1769
- }
1770
- await this.render.dispatch();
1771
- this.frame.current = this.playback.frame;
1772
- this.request();
1773
- }
1774
- request() {
1775
- if (!this.active)
1776
- return;
1777
- this.requestId ?? (this.requestId = requestAnimationFrame(async (time) => {
1778
- this.requestId = null;
1779
- if (time - this.renderTime >= 1e3 / (this.status.fps + 5)) {
1780
- this.renderTime = time;
1781
- await this.lock.acquire();
1782
- try {
1783
- await this.run();
1784
- } catch (e) {
1785
- this.logger.error(e);
1786
- }
1787
- this.lock.release();
1788
- } else {
1789
- this.request();
1790
- }
1791
- }));
1792
- }
1793
- clampRange(frame) {
1794
- return clamp(this.startFrame, this.endFrame, frame);
1795
- }
1796
- }
1797
- function getFullPreviewSettings(project) {
1798
- return {
1799
- ...project.settings.shared,
1800
- ...project.settings.preview
1801
- };
1802
- }
1803
- class Stage {
1804
- get canvasSize() {
1805
- return this.size.scale(this.resolutionScale);
1806
- }
1807
- constructor() {
1808
- this.background = null;
1809
- this.resolutionScale = 1;
1810
- this.colorSpace = "srgb";
1811
- this.size = Vector2.zero;
1812
- this.finalBuffer = document.createElement("canvas");
1813
- this.currentBuffer = document.createElement("canvas");
1814
- this.previousBuffer = document.createElement("canvas");
1815
- const colorSpace = this.colorSpace;
1816
- this.context = getContext({ colorSpace }, this.finalBuffer);
1817
- this.currentContext = getContext({ colorSpace }, this.currentBuffer);
1818
- this.previousContext = getContext({ colorSpace }, this.previousBuffer);
1819
- }
1820
- configure({ colorSpace = this.colorSpace, size = this.size, resolutionScale = this.resolutionScale, background = this.background }) {
1821
- if (colorSpace !== this.colorSpace) {
1822
- this.colorSpace = colorSpace;
1823
- this.context = getContext({ colorSpace }, this.finalBuffer);
1824
- this.currentContext = getContext({ colorSpace }, this.currentBuffer);
1825
- this.previousContext = getContext({ colorSpace }, this.previousBuffer);
1826
- }
1827
- if (!size.exactlyEquals(this.size) || resolutionScale !== this.resolutionScale) {
1828
- this.resolutionScale = resolutionScale;
1829
- this.size = size;
1830
- this.resizeCanvas(this.context);
1831
- this.resizeCanvas(this.currentContext);
1832
- this.resizeCanvas(this.previousContext);
1833
- }
1834
- this.background = typeof background === "string" ? background : (background == null ? void 0 : background.serialize()) ?? null;
1835
- }
1836
- async render(currentScene, previousScene) {
1837
- const previousOnTop = previousScene ? unwrap(currentScene.previousOnTop) : false;
1838
- if (previousScene) {
1839
- await previousScene.render(this.previousContext);
1840
- }
1841
- await currentScene.render(this.currentContext);
1842
- const size = this.canvasSize;
1843
- this.context.clearRect(0, 0, size.width, size.height);
1844
- if (this.background) {
1845
- this.context.save();
1846
- this.context.fillStyle = this.background;
1847
- this.context.fillRect(0, 0, size.width, size.height);
1848
- this.context.restore();
1849
- }
1850
- if (previousScene && !previousOnTop) {
1851
- this.context.drawImage(this.previousBuffer, 0, 0);
1852
- }
1853
- this.context.drawImage(this.currentBuffer, 0, 0);
1854
- if (previousOnTop) {
1855
- this.context.drawImage(this.previousBuffer, 0, 0);
1856
- }
1857
- }
1858
- resizeCanvas(context) {
1859
- const size = this.canvasSize;
1860
- context.canvas.width = size.width;
1861
- context.canvas.height = size.height;
1862
- }
1863
- }
1864
- const stylesNew = `
1865
- .overlay {
1866
- position: absolute;
1867
- left: 0;
1868
- right: 0;
1869
- top: 0;
1870
- bottom: 0;
1871
- display: flex;
1872
- align-items: center;
1873
- justify-content: center;
1874
- opacity: 0;
1875
- transition: opacity 0.1s;
1876
- z-index: 0;
1877
- }
1878
- .canvas {
1879
- width: 100%;
1880
- display: block;
1881
- opacity: 1;
1882
- transition: opacity 0.1s;
1883
- }
1884
- `;
1885
- const TEMPLATE = `<style>${stylesNew}</style><div class="overlay"></div>`;
1886
- const ID = "twick-player";
1887
- var State;
1888
- (function(State2) {
1889
- State2["Initial"] = "initial";
1890
- State2["Loading"] = "loading";
1891
- State2["Ready"] = "ready";
1892
- State2["Error"] = "error";
1893
- })(State || (State = {}));
1894
- class TwickPlayer extends HTMLElement {
1895
- constructor() {
1896
- super();
1897
- __publicField(this, "root");
1898
- __publicField(this, "canvas");
1899
- __publicField(this, "overlay");
1900
- __publicField(this, "state", State.Initial);
1901
- __publicField(this, "project", null);
1902
- __publicField(this, "player", null);
1903
- __publicField(this, "defaultSettings");
1904
- __publicField(this, "abortController", null);
1905
- __publicField(this, "playing", false);
1906
- __publicField(this, "stage", new Stage());
1907
- __publicField(this, "time", 0);
1908
- __publicField(this, "duration", 0);
1909
- // in frames
1910
- __publicField(this, "looping", true);
1911
- __publicField(this, "volume", 1);
1912
- __publicField(this, "volumeChangeRequested", true);
1913
- /**
1914
- * Triggered by the timeline.
1915
- */
1916
- __publicField(this, "handleSeekTo", (event) => {
1917
- var _a;
1918
- if (!this.project) {
1919
- return;
1920
- }
1921
- const e = event;
1922
- this.time = e.detail;
1923
- (_a = this.player) == null ? void 0 : _a.requestSeek(e.detail * this.player.playback.fps);
1924
- this.volumeChangeRequested = true;
1925
- });
1926
- __publicField(this, "handleVolumeChange", (event) => {
1927
- var _a;
1928
- if (!this.project) {
1929
- return;
1930
- }
1931
- const e = event;
1932
- this.volume = e.detail;
1933
- (_a = this.player) == null ? void 0 : _a.playback.currentScene.adjustVolume(this.volume);
1934
- });
1935
- /**
1936
- * Triggered by the player.
1937
- */
1938
- __publicField(this, "handleFrameChanged", (frame) => {
1939
- var _a;
1940
- if (!this.project || !this.player) {
1941
- return;
1942
- }
1943
- this.time = frame / this.player.playback.fps;
1944
- if (this.volumeChangeRequested || frame === 0) {
1945
- (_a = this.player) == null ? void 0 : _a.playback.currentScene.adjustVolume(this.volume);
1946
- this.volumeChangeRequested = false;
1947
- }
1948
- });
1949
- /**
1950
- * Called on every frame.
1951
- */
1952
- __publicField(this, "render", async () => {
1953
- if (this.player && this.project) {
1954
- await this.stage.render(this.player.playback.currentScene, this.player.playback.previousScene);
1955
- this.dispatchEvent(new CustomEvent("timeupdate", { detail: this.time }));
1956
- const durationInFrames = this.player.playback.duration;
1957
- if (durationInFrames === this.duration) {
1958
- return;
1959
- }
1960
- this.duration = durationInFrames;
1961
- const durationInSeconds = durationInFrames / this.player.playback.fps;
1962
- this.dispatchEvent(new CustomEvent("duration", { detail: durationInSeconds }));
1963
- }
1964
- });
1965
- this.root = this.attachShadow({ mode: "open" });
1966
- this.root.innerHTML = TEMPLATE;
1967
- this.overlay = this.root.querySelector(".overlay");
1968
- this.canvas = this.stage.finalBuffer;
1969
- this.canvas.classList.add("canvas");
1970
- this.root.prepend(this.canvas);
1971
- this.setState(State.Initial);
1972
- }
1973
- static get observedAttributes() {
1974
- return [
1975
- "playing",
1976
- "variables",
1977
- "looping",
1978
- "fps",
1979
- "quality",
1980
- "width",
1981
- "height",
1982
- "volume"
1983
- ];
1984
- }
1985
- get fps() {
1986
- var _a;
1987
- const attr = this.getAttribute("fps");
1988
- return attr ? parseFloat(attr) : ((_a = this.defaultSettings) == null ? void 0 : _a.fps) ?? 60;
1989
- }
1990
- get quality() {
1991
- var _a;
1992
- const attr = this.getAttribute("quality");
1993
- return attr ? parseFloat(attr) : ((_a = this.defaultSettings) == null ? void 0 : _a.resolutionScale) ?? 1;
1994
- }
1995
- get width() {
1996
- var _a;
1997
- const attr = this.getAttribute("width");
1998
- return attr ? parseFloat(attr) : ((_a = this.defaultSettings) == null ? void 0 : _a.size.width) ?? 0;
1999
- }
2000
- get height() {
2001
- var _a;
2002
- const attr = this.getAttribute("height");
2003
- return attr ? parseFloat(attr) : ((_a = this.defaultSettings) == null ? void 0 : _a.size.height) ?? 0;
2004
- }
2005
- get variables() {
2006
- var _a;
2007
- try {
2008
- const attr = this.getAttribute("variables");
2009
- return attr ? JSON.parse(attr) : {};
2010
- } catch {
2011
- (_a = this.project) == null ? void 0 : _a.logger.warn(`Project variables could not be parsed.`);
2012
- return {};
2013
- }
2014
- }
2015
- setProject(project) {
2016
- this.updateProject(project);
2017
- }
2018
- setState(state) {
2019
- this.state = state;
2020
- this.setPlaying(this.playing);
2021
- }
2022
- setPlaying(value) {
2023
- var _a, _b;
2024
- if (this.state === State.Ready && value) {
2025
- (_a = this.player) == null ? void 0 : _a.togglePlayback(true);
2026
- this.playing = true;
2027
- } else {
2028
- (_b = this.player) == null ? void 0 : _b.togglePlayback(false);
2029
- this.playing = false;
2030
- }
2031
- }
2032
- async updateProject(project) {
2033
- var _a, _b, _c, _d, _e;
2034
- const playing = this.playing;
2035
- this.setState(State.Initial);
2036
- (_a = this.abortController) == null ? void 0 : _a.abort();
2037
- this.abortController = new AbortController();
2038
- this.project = project;
2039
- console.log(project);
2040
- this.defaultSettings = getFullPreviewSettings(this.project);
2041
- const player = new Player(this.project);
2042
- player.setVariables(this.variables);
2043
- player.toggleLoop(this.looping);
2044
- (_b = this.player) == null ? void 0 : _b.onRender.unsubscribe(this.render);
2045
- (_c = this.player) == null ? void 0 : _c.onFrameChanged.unsubscribe(this.handleFrameChanged);
2046
- (_d = this.player) == null ? void 0 : _d.togglePlayback(false);
2047
- (_e = this.player) == null ? void 0 : _e.deactivate();
2048
- this.player = player;
2049
- this.updateSettings();
2050
- this.setState(State.Ready);
2051
- this.dispatchEvent(new CustomEvent("playerready", { detail: this.player }));
2052
- this.setPlaying(playing);
2053
- this.player.onRender.subscribe(this.render);
2054
- this.player.onFrameChanged.subscribe(this.handleFrameChanged);
2055
- }
2056
- attributeChangedCallback(name, _, newValue) {
2057
- var _a, _b, _c, _d;
2058
- switch (name) {
2059
- case "playing":
2060
- this.setPlaying(newValue === "true");
2061
- break;
2062
- case "variables":
2063
- (_a = this.player) == null ? void 0 : _a.setVariables(this.variables);
2064
- (_b = this.player) == null ? void 0 : _b.requestSeek(this.player.playback.frame);
2065
- (_c = this.player) == null ? void 0 : _c.playback.reload();
2066
- break;
2067
- case "looping":
2068
- this.looping = newValue === "true";
2069
- (_d = this.player) == null ? void 0 : _d.toggleLoop(newValue === "true");
2070
- break;
2071
- case "fps":
2072
- case "quality":
2073
- case "width":
2074
- case "height":
2075
- this.updateSettings();
2076
- break;
2077
- case "volume":
2078
- this.volume = newValue;
2079
- this.volumeChangeRequested = true;
2080
- }
2081
- }
2082
- /**
2083
- * Runs when the element is removed from the DOM.
2084
- */
2085
- disconnectedCallback() {
2086
- var _a, _b;
2087
- (_a = this.player) == null ? void 0 : _a.deactivate();
2088
- (_b = this.player) == null ? void 0 : _b.onRender.unsubscribe(this.render);
2089
- this.removeEventListener("seekto", this.handleSeekTo);
2090
- this.removeEventListener("volumechange", this.handleVolumeChange);
2091
- }
2092
- /**
2093
- * Runs when the element is added to the DOM.
2094
- */
2095
- connectedCallback() {
2096
- var _a, _b;
2097
- (_a = this.player) == null ? void 0 : _a.activate();
2098
- (_b = this.player) == null ? void 0 : _b.onRender.subscribe(this.render);
2099
- this.addEventListener("seekto", this.handleSeekTo);
2100
- this.addEventListener("volumechange", this.handleVolumeChange);
2101
- }
2102
- updateSettings() {
2103
- var _a;
2104
- if (!this.defaultSettings) {
2105
- return;
2106
- }
2107
- const settings = {
2108
- ...this.defaultSettings,
2109
- size: new Vector2(this.width, this.height),
2110
- resolutionScale: this.quality,
2111
- fps: this.fps
2112
- };
2113
- this.stage.configure(settings);
2114
- (_a = this.player) == null ? void 0 : _a.configure(settings);
2115
- }
2116
- }
2117
- if (!customElements.get(ID)) {
2118
- customElements.define(ID, TwickPlayer);
2119
- }
2120
- //# sourceMappingURL=internal-CHEF557f.js.map