@twick/live-player 0.14.20 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +49717 -20207
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +49717 -20207
- package/dist/index.mjs.map +1 -1
- package/dist/internal-H4HUGGQY-BTkFZ7_7.mjs +6282 -0
- package/dist/internal-H4HUGGQY-BTkFZ7_7.mjs.map +1 -0
- package/dist/internal-H4HUGGQY-DIx_F8CA.js +6283 -0
- package/dist/internal-H4HUGGQY-DIx_F8CA.js.map +1 -0
- package/package.json +12 -8
- package/dist/internal-CHEF557f.js +0 -2120
- package/dist/internal-CHEF557f.js.map +0 -1
- package/dist/internal-pPYo5Irb.cjs +0 -2121
- package/dist/internal-pPYo5Irb.cjs.map +0 -1
- package/dist/style.css +0 -2
|
@@ -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
|