@semio/utils 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,883 @@
1
+ // src/log.ts
2
+ function log(value) {
3
+ console.log(value);
4
+ }
5
+
6
+ // src/namespace.ts
7
+ function getLookup(namespace, id) {
8
+ return `${namespace === "default" ? "default." : `${namespace}.`}${id}`;
9
+ }
10
+ function getNamespace(lookup) {
11
+ if (lookup.includes(".")) {
12
+ return lookup.split(".")[0];
13
+ } else return "default";
14
+ }
15
+ function getId(lookup) {
16
+ if (lookup.includes(".")) {
17
+ return lookup.split(".")[1];
18
+ } else return lookup;
19
+ }
20
+
21
+ // src/player.ts
22
+ function reset(player, stamp) {
23
+ const p = { ...player };
24
+ const nowVal = now();
25
+ p._currentTime = nowVal;
26
+ p._previousTime = nowVal;
27
+ p.stamp = stamp ? stamp : 0;
28
+ return p;
29
+ }
30
+ function now() {
31
+ return (typeof performance === "undefined" ? Date : performance).now();
32
+ }
33
+ function update(player, coldStart) {
34
+ const p = { ...player };
35
+ const duration = p.duration;
36
+ const t = now();
37
+ p._previousTime = coldStart ? t : p._currentTime;
38
+ p._currentTime = t;
39
+ const currentInBounds = p.stamp >= p.bounds[0] && p.stamp <= p.bounds[1];
40
+ const currentViewportCenter = (p.viewport[1] + p.viewport[0]) / 2;
41
+ const nearViewportCenterCurrent = Math.abs(p.stamp - currentViewportCenter) < 0.01;
42
+ const delta = (p._currentTime - p._previousTime) * p.timescale / duration;
43
+ const updatedStamp = p.stamp + delta;
44
+ const [start, end] = currentInBounds ? p.bounds : [0, 1];
45
+ let attachOverride = false;
46
+ if (updatedStamp > end) {
47
+ if (p.playback === "loop") {
48
+ p.stamp = start;
49
+ } else if (p.playback === "bounce") {
50
+ p.stamp = end;
51
+ p.timescale *= -1;
52
+ } else {
53
+ p.stamp = start;
54
+ p.running = false;
55
+ }
56
+ attachOverride = true;
57
+ } else if (currentInBounds && updatedStamp < start) {
58
+ if (p.playback === "loop") {
59
+ p.stamp = start;
60
+ if (p.timescale < 0) {
61
+ p.running = false;
62
+ }
63
+ } else if (p.playback === "bounce") {
64
+ p.stamp = start;
65
+ p.timescale *= -1;
66
+ } else {
67
+ p.stamp = start;
68
+ p.running = false;
69
+ }
70
+ attachOverride = true;
71
+ } else {
72
+ p.stamp = updatedStamp;
73
+ }
74
+ const newNearViewportCenter = Math.abs(p.stamp - currentViewportCenter) < 0.01;
75
+ const boundsInsideViewport = p.viewport[0] <= p.bounds[0] || p.viewport[1] >= p.bounds[1];
76
+ if (p.running && !boundsInsideViewport && (nearViewportCenterCurrent || newNearViewportCenter || attachOverride)) {
77
+ p.viewport = getFittedViewport(p.stamp, p.viewport);
78
+ } else if (p.running && !boundsInsideViewport && !newNearViewportCenter) {
79
+ const oomphOffset = currentViewportCenter < p.stamp ? delta : 0;
80
+ const idealViewport = getFittedViewport(p.stamp + oomphOffset, p.viewport);
81
+ p.viewport = [
82
+ p.viewport[0] * 0.6 + idealViewport[0] * 0.4,
83
+ p.viewport[1] * 0.6 + idealViewport[1] * 0.4
84
+ ];
85
+ }
86
+ return p;
87
+ }
88
+ function setBounds(player, bounds) {
89
+ const p = { ...player };
90
+ p.bounds = bounds;
91
+ return p;
92
+ }
93
+ function setViewport(player, viewport) {
94
+ const p = { ...player };
95
+ p.viewport = viewport;
96
+ return p;
97
+ }
98
+ function play(player, speed) {
99
+ const p = { ...player };
100
+ p.running = true;
101
+ p.timescale = speed ?? 1;
102
+ if (p.playback === "once" && p.stamp === p.bounds[1]) {
103
+ p.stamp = p.bounds[0];
104
+ }
105
+ return p;
106
+ }
107
+ function pause(player) {
108
+ const p = { ...player };
109
+ p.running = false;
110
+ p.timescale = 0;
111
+ return p;
112
+ }
113
+ function seek(player, stamp) {
114
+ const p = reset(player, stamp);
115
+ p.viewport = getFittedViewport(stamp, p.viewport);
116
+ return p;
117
+ }
118
+ function setDuration(player, duration) {
119
+ const p = { ...player };
120
+ p.duration = duration;
121
+ return p;
122
+ }
123
+ function newPlayer() {
124
+ return {
125
+ running: false,
126
+ _previousTime: now(),
127
+ _currentTime: now(),
128
+ stamp: 0,
129
+ timescale: 0,
130
+ bounds: [0, 1],
131
+ playback: "loop",
132
+ viewport: [0, 1],
133
+ duration: 1e3
134
+ };
135
+ }
136
+ var getFittedViewport = (playhead, proposedViewport) => {
137
+ const viewportWidth = proposedViewport[1] - proposedViewport[0];
138
+ const proposedLeft = playhead - viewportWidth / 2;
139
+ const proposedRight = playhead + viewportWidth / 2;
140
+ if (proposedLeft >= 0 && proposedRight <= 1) {
141
+ return [playhead - viewportWidth / 2, playhead + viewportWidth / 2];
142
+ } else if (proposedLeft < 0) {
143
+ return [0, viewportWidth];
144
+ } else {
145
+ return [1 - viewportWidth, 1];
146
+ }
147
+ };
148
+
149
+ // src/player-store.ts
150
+ import { createContext } from "react";
151
+ import { create } from "zustand";
152
+ import { subscribeWithSelector } from "zustand/middleware";
153
+ import { enableMapSet, produce } from "immer";
154
+ import * as THREE from "three";
155
+ THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
156
+ enableMapSet();
157
+ var PlayerSlice = (set) => ({
158
+ player: newPlayer(),
159
+ // Set the duration of the player
160
+ updateDuration: (duration) => {
161
+ set(
162
+ produce((state) => {
163
+ state.player.duration = duration;
164
+ })
165
+ );
166
+ },
167
+ // Set the timescale of the animation playback
168
+ updateTimescale: (speed) => {
169
+ set(
170
+ produce((state) => {
171
+ state.player.timescale = speed;
172
+ })
173
+ );
174
+ },
175
+ // Set the time of the animation
176
+ resetPlayer: (time) => {
177
+ set((state) => ({ player: reset(state.player, time) }));
178
+ },
179
+ // Play the animation
180
+ playPlayer: (speed) => {
181
+ set((state) => ({ player: play(state.player, speed) }));
182
+ },
183
+ // Pause the animation
184
+ pausePlayer: () => {
185
+ set((state) => ({ player: pause(state.player) }));
186
+ },
187
+ // Update the timer
188
+ updatePlayer: (coldStart) => {
189
+ set((state) => ({
190
+ player: update(state.player, coldStart ?? false)
191
+ }));
192
+ },
193
+ // Set the player bounds
194
+ updatePlayerBounds: (start, end) => {
195
+ set((state) => ({
196
+ player: setBounds(state.player, [start, end])
197
+ }));
198
+ },
199
+ updatePlayerBound: (bound, time) => {
200
+ set((state) => {
201
+ const t = time ?? state.player.stamp;
202
+ if (bound === "start" && state.player.bounds[1] <= t) {
203
+ return {
204
+ player: setBounds(state.player, [state.player.bounds[1], t])
205
+ };
206
+ } else if (bound === "end" && state.player.bounds[0] >= t) {
207
+ return {
208
+ player: setBounds(state.player, [t, state.player.bounds[0]])
209
+ };
210
+ } else if (bound === "start") {
211
+ return {
212
+ player: setBounds(state.player, [t, state.player.bounds[1]])
213
+ };
214
+ } else {
215
+ return {
216
+ player: setBounds(state.player, [state.player.bounds[0], t])
217
+ };
218
+ }
219
+ });
220
+ },
221
+ // Set the player viewport
222
+ updatePlayerViewport: (start, end) => {
223
+ set((state) => ({
224
+ player: setViewport(state.player, [start, end])
225
+ }));
226
+ },
227
+ updatePlayerViewportCenter: (time) => {
228
+ set((state) => ({
229
+ player: seek(state.player, time ?? state.player.stamp)
230
+ }));
231
+ },
232
+ updatePlayerViewportBound: (bound, time) => {
233
+ set((state) => {
234
+ if (bound === "start" && state.player.viewport[1] <= time) {
235
+ return {
236
+ player: setViewport(state.player, [state.player.viewport[1], time])
237
+ };
238
+ } else if (bound === "end" && state.player.viewport[0] >= time) {
239
+ return {
240
+ player: setViewport(state.player, [time, state.player.viewport[0]])
241
+ };
242
+ } else if (bound === "start") {
243
+ return {
244
+ player: setViewport(state.player, [time, state.player.viewport[1]])
245
+ };
246
+ } else {
247
+ return {
248
+ player: setViewport(state.player, [state.player.viewport[0], time])
249
+ };
250
+ }
251
+ });
252
+ }
253
+ });
254
+ var usePlayerStore = create()(
255
+ subscribeWithSelector(PlayerSlice)
256
+ );
257
+ var PlayerContext = createContext(null);
258
+
259
+ // src/animated-values.ts
260
+ function instanceOfRawBoolean(object) {
261
+ return typeof object === "boolean";
262
+ }
263
+ function instanceOfRawNumber(object) {
264
+ return typeof object === "number";
265
+ }
266
+ function instanceOfRawString(object) {
267
+ return typeof object === "string";
268
+ }
269
+ function instanceOfRawVector3(object) {
270
+ return object.x !== void 0 && object.y !== void 0 && object.z !== void 0;
271
+ }
272
+ function instanceOfRawVector2(object) {
273
+ return object.x !== void 0 && object.y !== void 0;
274
+ }
275
+ function instanceOfRawEuler(object) {
276
+ return object.x !== void 0 && object.y !== void 0 && object.z !== void 0;
277
+ }
278
+ function instanceOfRawColor(object) {
279
+ return object.r !== void 0 && object.g !== void 0 && object.b !== void 0 || object.h !== void 0 && object.s !== void 0 && object.l !== void 0;
280
+ }
281
+ function instanceOfRawRGB(object) {
282
+ return object.r !== void 0 && object.g !== void 0 && object.b !== void 0;
283
+ }
284
+ function instanceOfRawHSL(object) {
285
+ return object.h !== void 0 && object.s !== void 0 && object.l !== void 0;
286
+ }
287
+ function isRawObject(value) {
288
+ if (instanceOfRawVector3(value) || instanceOfRawVector2(value) || instanceOfRawEuler(value) || instanceOfRawColor(value) || instanceOfRawRGB(value) || instanceOfRawHSL(value))
289
+ return true;
290
+ return false;
291
+ }
292
+
293
+ // src/time.ts
294
+ var numberToDurationString = (duration) => {
295
+ let milliseconds = Math.floor(duration % 1e3 / 10).toString();
296
+ let seconds = Math.floor(duration / 1e3 % 60);
297
+ let minutes = Math.floor(duration / (1e3 * 60) % 60);
298
+ minutes = minutes < 10 ? `0${minutes.toString()}` : minutes;
299
+ seconds = seconds < 10 ? `0${seconds.toString()}` : seconds;
300
+ milliseconds = milliseconds.length === 1 ? `0${milliseconds}` : milliseconds;
301
+ return `${minutes.toString()}:${seconds.toString()}:${milliseconds}`;
302
+ };
303
+
304
+ // src/pairwise.ts
305
+ function pairwise(arr) {
306
+ return arr.slice(1).map((_, i) => [arr[i], arr[i + 1]]);
307
+ }
308
+
309
+ // src/lazy.ts
310
+ import { useState, useEffect } from "react";
311
+ function useLazy(value, timeout) {
312
+ const [lazy, setLazy] = useState(value);
313
+ const [timeoutValue, setTimeoutValue] = useState(null);
314
+ useEffect(() => {
315
+ if (value) {
316
+ setLazy(value);
317
+ if (timeoutValue) {
318
+ clearTimeout(timeoutValue);
319
+ }
320
+ } else {
321
+ const timer = setTimeout(() => {
322
+ setLazy(value);
323
+ setTimeoutValue(timer);
324
+ }, timeout);
325
+ return () => {
326
+ if (timeoutValue) {
327
+ clearTimeout(timeoutValue);
328
+ }
329
+ };
330
+ }
331
+ }, [value, timeout, timeoutValue]);
332
+ return lazy;
333
+ }
334
+
335
+ // src/hexagon.ts
336
+ function getHexagonPath(x, y, size, height) {
337
+ const path = [
338
+ `${x.toString()},${(y - height / 2).toString()}`,
339
+ `${x.toString()},${(y - size / 2).toString()}`,
340
+ `${(x + size * 0.433).toString()},${(y - size / 4).toString()}`,
341
+ `${(x + size * 0.433).toString()},${(y + size / 4).toString()}`,
342
+ `${x.toString()},${(y + size / 2).toString()}`,
343
+ `${x.toString()},${(y + height / 2).toString()}`,
344
+ `${x.toString()},${(y + size / 2).toString()}`,
345
+ `${(x - size * 0.433).toString()},${(y + size / 4).toString()}`,
346
+ `${(x - size * 0.433).toString()},${(y - size / 4).toString()}`,
347
+ `${x.toString()},${(y - size / 2).toString()}`
348
+ ].join("L");
349
+ return `M${path}Z`;
350
+ }
351
+ function getDegenerateHexagonPath(x, y, size, height) {
352
+ const path = [
353
+ `${x.toString()},${(y - height / 2).toString()}`,
354
+ `${x.toString()},${(y - size / 2).toString()}`,
355
+ `${x.toString()},${(y - size / 4).toString()}`,
356
+ `${x.toString()},${(y + size / 4).toString()}`,
357
+ `${x.toString()},${(y + size / 2).toString()}`,
358
+ `${x.toString()},${(y + height / 2).toString()}`,
359
+ `${x.toString()},${(y + size / 2).toString()}`,
360
+ `${x.toString()},${(y + size / 4).toString()}`,
361
+ `${x.toString()},${(y - size / 4).toString()}`,
362
+ `${x.toString()},${(y - size / 2).toString()}`
363
+ ].join("L");
364
+ return `M${path}Z`;
365
+ }
366
+
367
+ // src/closest-frame.ts
368
+ function closestFrame(completion, count) {
369
+ const frameIdx = Math.round(completion * count);
370
+ return frameIdx / count;
371
+ }
372
+
373
+ // src/angles.ts
374
+ var toDegrees = (radians) => radians * (180 / Math.PI);
375
+ var toRadians = (degrees) => degrees * (Math.PI / 180);
376
+
377
+ // src/colors.ts
378
+ import Color from "color";
379
+ var regex = /(\d+),\s*(\d+),\s*(\d+)/;
380
+ var hexToRgba = (hex, alpha2) => {
381
+ const h = hex.replace(/^#/, "");
382
+ let r, g, b;
383
+ if (h.length === 3) {
384
+ r = parseInt(h[0] + h[0], 16);
385
+ g = parseInt(h[1] + h[1], 16);
386
+ b = parseInt(h[2] + h[2], 16);
387
+ } else if (h.length === 6) {
388
+ r = parseInt(h.substring(0, 2), 16);
389
+ g = parseInt(h.substring(2, 4), 16);
390
+ b = parseInt(h.substring(4, 6), 16);
391
+ } else {
392
+ throw new Error("Invalid HEX color.");
393
+ }
394
+ return `rgba(${r.toFixed(0)}, ${g.toFixed(0)}, ${b.toFixed(0)}, ${alpha2.toString()})`;
395
+ };
396
+ var rgbToRgba = (rgb, alpha2) => {
397
+ const result = regex.exec(rgb);
398
+ if (!result) {
399
+ throw new Error("Invalid RGB color.");
400
+ }
401
+ const r = parseInt(result[1]);
402
+ const g = parseInt(result[2]);
403
+ const b = parseInt(result[3]);
404
+ return `rgba(${r.toFixed()}, ${g.toFixed()}, ${b.toFixed()}, ${alpha2.toFixed(2)})`;
405
+ };
406
+ var hslToRgba = (hsl, alpha2) => {
407
+ const result = regex.exec(hsl);
408
+ if (!result) {
409
+ throw new Error("Invalid HSL color.");
410
+ }
411
+ const h = parseInt(result[1]) / 360;
412
+ const s = parseInt(result[2]) / 100;
413
+ const l = parseInt(result[3]) / 100;
414
+ let r, g, b;
415
+ if (s === 0) {
416
+ r = l;
417
+ g = l;
418
+ b = l;
419
+ } else {
420
+ const hue2rgb = (p2, q2, t) => {
421
+ let t1 = t;
422
+ if (t1 < 0) t1 += 1;
423
+ if (t1 > 1) t1 -= 1;
424
+ if (t1 < 1 / 6) return p2 + (q2 - p2) * 6 * t1;
425
+ if (t1 < 1 / 2) return q2;
426
+ if (t1 < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t1) * 6;
427
+ return p2;
428
+ };
429
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
430
+ const p = 2 * l - q;
431
+ r = hue2rgb(p, q, h + 1 / 3);
432
+ g = hue2rgb(p, q, h);
433
+ b = hue2rgb(p, q, h - 1 / 3);
434
+ }
435
+ return `rgba(${Math.round(r * 255).toFixed(0)}, ${Math.round(g * 255).toFixed(0)}, ${Math.round(b * 255).toFixed(0)}, ${alpha2.toString()})`;
436
+ };
437
+ var alpha = (color, opacity) => {
438
+ if (color.startsWith("#")) {
439
+ return hexToRgba(color, opacity);
440
+ } else if (color.startsWith("rgb")) {
441
+ return rgbToRgba(color, opacity);
442
+ } else if (color.startsWith("hsl")) {
443
+ return hslToRgba(color, opacity);
444
+ } else {
445
+ throw new Error("Unsupported color format.");
446
+ }
447
+ };
448
+ function altColor(color, factor) {
449
+ if (factor > 0) {
450
+ return Color(color).lighten(factor).hex();
451
+ } else {
452
+ return Color(color).darken(-1 * factor).hex();
453
+ }
454
+ }
455
+ function hexToRgbArray(color) {
456
+ const c = Color(color);
457
+ return [c.red(), c.green(), c.blue()];
458
+ }
459
+ function rawRGBToHex({ r, g, b }) {
460
+ return Color({ r, g, b }).hex();
461
+ }
462
+ function rawHSLToHex({ h, s, l }) {
463
+ return Color({ h, s, l }).hex();
464
+ }
465
+
466
+ // src/use-deep.ts
467
+ import { useRef } from "react";
468
+ import deepEqual from "deep-equal";
469
+ function useDeepSelector(selector) {
470
+ const prev = useRef();
471
+ return (state) => {
472
+ const next = selector(state);
473
+ return deepEqual(prev.current, next) ? prev.current : prev.current = next;
474
+ };
475
+ }
476
+ function useDeep(initializer, dependencies) {
477
+ const prevValue = useRef();
478
+ const prevDependencies = useRef([]);
479
+ return deepEqual(prevDependencies.current, dependencies) ? prevValue.current : prevValue.current = initializer();
480
+ }
481
+
482
+ // src/use-media-query.ts
483
+ import { useState as useState2, useEffect as useEffect2 } from "react";
484
+ var useMediaQuery = (query) => {
485
+ const [matches, setMatches] = useState2(false);
486
+ useEffect2(() => {
487
+ const mediaQueryList = window.matchMedia(query);
488
+ const documentChangeHandler = () => setMatches(mediaQueryList.matches);
489
+ setMatches(mediaQueryList.matches);
490
+ mediaQueryList.addEventListener("change", documentChangeHandler);
491
+ return () => {
492
+ mediaQueryList.removeEventListener("change", documentChangeHandler);
493
+ };
494
+ }, [query]);
495
+ return matches;
496
+ };
497
+
498
+ // src/json.ts
499
+ function replacer(key, value) {
500
+ if (value instanceof Map) {
501
+ return {
502
+ dataType: "Map",
503
+ value: Array.from(value.entries())
504
+ // or with spread: value: [...value]
505
+ };
506
+ }
507
+ return value;
508
+ }
509
+ function isSerializedMap(value) {
510
+ return typeof value === "object" && value !== null && "dataType" in value && value.dataType === "Map" && Array.isArray(value.value);
511
+ }
512
+ function reviver(key, value) {
513
+ if (isSerializedMap(value)) {
514
+ return new Map(value.value);
515
+ }
516
+ return value;
517
+ }
518
+ function stringifyMapped(value) {
519
+ return JSON.stringify(value, replacer, 2);
520
+ }
521
+ function parseToMapped(json) {
522
+ return JSON.parse(json, reviver);
523
+ }
524
+ function parseJSONFileEvent(event, fn) {
525
+ const files = event.target.files;
526
+ if (files && files.length > 0) {
527
+ const reader = new FileReader();
528
+ reader.onload = (e) => {
529
+ if (e.target?.result) {
530
+ const json = e.target.result;
531
+ const data = parseToMapped(json);
532
+ if (Array.isArray(data)) {
533
+ data.forEach((d) => {
534
+ fn(d);
535
+ });
536
+ } else {
537
+ fn(data);
538
+ }
539
+ }
540
+ };
541
+ reader.readAsText(files[0]);
542
+ }
543
+ }
544
+
545
+ // src/download.ts
546
+ function downloadJSONFile(data, filename) {
547
+ const json = stringifyMapped(data);
548
+ const blob = new Blob([json], { type: "application/json" });
549
+ downloadBlob(blob, filename);
550
+ }
551
+ function downloadBlob(blob, filename) {
552
+ const url = URL.createObjectURL(blob);
553
+ const a = document.createElement("a");
554
+ a.href = url;
555
+ a.download = filename;
556
+ document.body.appendChild(a);
557
+ a.click();
558
+ document.body.removeChild(a);
559
+ URL.revokeObjectURL(url);
560
+ }
561
+
562
+ // src/points-to-path.ts
563
+ function pointsToPath(points, close) {
564
+ if (close) {
565
+ return [
566
+ points.map((p, i) => `${i === 0 ? "M" : "L"} ${p[0].toString()} ${p[1].toString()}`).join(" "),
567
+ " Z"
568
+ ].join(" ");
569
+ } else {
570
+ return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p[0].toString()} ${p[1].toString()}`).join(" ");
571
+ }
572
+ }
573
+
574
+ // src/euler.ts
575
+ function eulerToRotationMatrix(euler) {
576
+ const [z, y, x] = euler;
577
+ const cz = Math.cos(z);
578
+ const sz = Math.sin(z);
579
+ const cy = Math.cos(y);
580
+ const sy = Math.sin(y);
581
+ const cx = Math.cos(x);
582
+ const sx = Math.sin(x);
583
+ return [
584
+ [cz * cy, cz * sy * sx - sz * cx, cz * sy * cx + sz * sx],
585
+ [sz * cy, sz * sy * sx + cz * cx, sz * sy * cx - cz * sx],
586
+ [-sy, cy * sx, cy * cx]
587
+ ];
588
+ }
589
+ function rotationMatrixToAngle(R) {
590
+ const trace = R[0][0] + R[1][1] + R[2][2];
591
+ return Math.acos((trace - 1) / 2);
592
+ }
593
+ function angularDistance(euler1, euler2) {
594
+ const R1 = eulerToRotationMatrix(euler1);
595
+ const R2 = eulerToRotationMatrix(euler2);
596
+ const R12 = [
597
+ [
598
+ R1[0][0] * R2[0][0] + R1[0][1] * R2[1][0] + R1[0][2] * R2[2][0],
599
+ R1[0][0] * R2[0][1] + R1[0][1] * R2[1][1] + R1[0][2] * R2[2][1],
600
+ R1[0][0] * R2[0][2] + R1[0][1] * R2[1][2] + R1[0][2] * R2[2][2]
601
+ ],
602
+ [
603
+ R1[1][0] * R2[0][0] + R1[1][1] * R2[1][0] + R1[1][2] * R2[2][0],
604
+ R1[1][0] * R2[0][1] + R1[1][1] * R2[1][1] + R1[1][2] * R2[2][1],
605
+ R1[1][0] * R2[0][2] + R1[1][1] * R2[1][2] + R1[1][2] * R2[2][2]
606
+ ],
607
+ [
608
+ R1[2][0] * R2[0][0] + R1[2][1] * R2[1][0] + R1[2][2] * R2[2][0],
609
+ R1[2][0] * R2[0][1] + R1[2][1] * R2[1][1] + R1[2][2] * R2[2][1],
610
+ R1[2][0] * R2[0][2] + R1[2][1] * R2[1][2] + R1[2][2] * R2[2][2]
611
+ ]
612
+ ];
613
+ return rotationMatrixToAngle(R12);
614
+ }
615
+
616
+ // src/overlapping-segments.ts
617
+ function overlappingSegments(original) {
618
+ const output = [];
619
+ original.toSorted((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]).forEach(([start, end]) => {
620
+ const lastIndex = output.length - 1;
621
+ if (output.length > 0 && output[lastIndex][1] >= start) {
622
+ output[lastIndex][1] = Math.max(output[lastIndex][1], end);
623
+ } else {
624
+ output.push([start, end]);
625
+ }
626
+ });
627
+ return output;
628
+ }
629
+
630
+ // src/result.ts
631
+ var Result = class _Result {
632
+ constructor(value, error) {
633
+ this.value = value;
634
+ this.error = error;
635
+ }
636
+ /**
637
+ * Creates a new Result instance with a success value
638
+ * @template T The type of the success value
639
+ * @template E The type of the error value
640
+ * @param value The success value
641
+ * @returns A new Result instance containing the success value
642
+ */
643
+ static Ok(value) {
644
+ return new _Result(value);
645
+ }
646
+ /**
647
+ * Creates a new Result instance with an error value
648
+ * @template T The type of the success value
649
+ * @template E The type of the error value
650
+ * @param error The error value
651
+ * @returns A new Result instance containing the error value
652
+ */
653
+ static Err(error) {
654
+ return new _Result(void 0, error);
655
+ }
656
+ /**
657
+ * Creates a new Result instance with an Error created from a string message
658
+ * @template T The type of the success value
659
+ * @param errorMessage The error message string
660
+ * @returns A new Result instance containing an Error with the given message
661
+ */
662
+ static ErrFromStr(errorMessage) {
663
+ const error = new Error(errorMessage);
664
+ return new _Result(void 0, error);
665
+ }
666
+ /**
667
+ * Maps the success value to a new value using the provided function
668
+ * @template U The type of the new success value
669
+ * @param fn The mapping function
670
+ * @returns A new Result with the mapped success value or the original error
671
+ */
672
+ map(fn) {
673
+ return this.isOk() ? _Result.Ok(fn(this.value)) : _Result.Err(this.error);
674
+ }
675
+ /**
676
+ * Maps the error value to a new error using the provided function
677
+ * @template F The type of the new error value
678
+ * @param fn The mapping function
679
+ * @returns A new Result with the mapped error value or the original success value
680
+ */
681
+ mapErr(fn) {
682
+ return this.isOk() ? _Result.Ok(this.value) : _Result.Err(fn(this.error));
683
+ }
684
+ /**
685
+ * Chains a computation that returns a Result
686
+ * @template U The type of the new success value
687
+ * @param fn The function to chain
688
+ * @returns The result of the chained function or the original error
689
+ */
690
+ andThen(fn) {
691
+ return this.isOk() ? fn(this.value) : _Result.Err(this.error);
692
+ }
693
+ /**
694
+ * Applies one of two functions depending on whether the Result is Ok or Err
695
+ * @template U The type of the return value
696
+ * @param ok The function to apply to the success value
697
+ * @param err The function to apply to the error value
698
+ * @returns The result of applying the appropriate function
699
+ */
700
+ match(ok, err) {
701
+ return this.isOk() ? ok(this.value) : err(this.error);
702
+ }
703
+ /**
704
+ * Checks if the Result contains a success value
705
+ * @returns true if the Result contains a success value, false otherwise
706
+ */
707
+ isOk() {
708
+ return this.error === void 0;
709
+ }
710
+ /**
711
+ * Checks if the Result contains an error value
712
+ * @returns true if the Result contains an error value, false otherwise
713
+ */
714
+ isErr() {
715
+ return this.error !== void 0;
716
+ }
717
+ /**
718
+ * Extracts the success value from the Result
719
+ * @throws Error if the Result contains an error value
720
+ * @returns The success value
721
+ */
722
+ unwrap() {
723
+ if (this.isErr()) {
724
+ throw new Error(`Tried to unwrap an Err value${this.error ? `: ${String(this.error)}` : ""}`);
725
+ }
726
+ return this.value;
727
+ }
728
+ /**
729
+ * Returns the success value or a default value if the Result contains an error
730
+ * @param defaultValue The value to return if the Result contains an error
731
+ * @returns The success value or the default value
732
+ */
733
+ unwrapOr(defaultValue) {
734
+ return this.isOk() ? this.value : defaultValue;
735
+ }
736
+ /**
737
+ * Extracts the error value from the Result
738
+ * @throws Error if the Result contains a success value
739
+ * @returns The error value
740
+ */
741
+ unwrapErr() {
742
+ if (this.isOk()) {
743
+ throw new Error("Tried to unwrap an Ok value");
744
+ }
745
+ return this.error;
746
+ }
747
+ /**
748
+ * Converts the Result to a string representation
749
+ * @returns A string representation of the Result
750
+ */
751
+ toString() {
752
+ return this.isOk() ? `Ok(${typeof this.value === "object" ? JSON.stringify(this.value) : String(this.value)})` : `Err(${typeof this.error === "object" ? JSON.stringify(this.error) : String(this.error)})`;
753
+ }
754
+ };
755
+
756
+ // src/progress.ts
757
+ function incrementProgress(progress, message, increment = 1) {
758
+ return {
759
+ ...progress,
760
+ current: progress.current + increment,
761
+ message: message ?? progress.message
762
+ };
763
+ }
764
+ function composeProgress(progresses) {
765
+ let current = 0;
766
+ let total = 0;
767
+ let message = "";
768
+ progresses.forEach((progress) => {
769
+ current += progress.current;
770
+ total += progress.total;
771
+ if (progress.message) {
772
+ message += `${progress.message}
773
+ `;
774
+ }
775
+ });
776
+ message = message.trim();
777
+ return { current, total, message };
778
+ }
779
+ function composeProgressiveResult(progressiveResults, expectedIds) {
780
+ const fullProgress = composeProgress(progressiveResults.map((pr) => pr.progress));
781
+ let fullResult;
782
+ if (progressiveResults.some((res) => res.result?.isErr() ?? true)) {
783
+ fullResult = Result.ErrFromStr("There was an error");
784
+ } else {
785
+ const metas = progressiveResults.flatMap((res) => {
786
+ const innerRes = res.result?.unwrap();
787
+ if (Array.isArray(innerRes)) return innerRes;
788
+ return [innerRes];
789
+ });
790
+ if (expectedIds) {
791
+ const data = expectedIds.map((id) => metas.find((m) => "id" in (m || {}) && m?.id === id));
792
+ if (fullProgress.current >= fullProgress.total && data.some((m) => m === void 0 || m === null)) {
793
+ fullResult = Result.ErrFromStr("Some documents not found");
794
+ } else {
795
+ fullResult = Result.Ok(data);
796
+ }
797
+ } else {
798
+ fullResult = Result.Ok(metas);
799
+ }
800
+ }
801
+ return { result: fullResult, progress: fullProgress };
802
+ }
803
+
804
+ // src/regex.ts
805
+ var EMAIL = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
806
+
807
+ // src/map-deep-equal.ts
808
+ import isDeepEqual from "fast-deep-equal";
809
+ function isMapDeepEqual(map1, map2) {
810
+ if (map1.size !== map2.size) return false;
811
+ for (const [key, value] of map1.entries()) {
812
+ if (!map2.has(key)) return false;
813
+ const otherValue = map2.get(key);
814
+ if (!isDeepEqual(value, otherValue)) {
815
+ return false;
816
+ }
817
+ }
818
+ return true;
819
+ }
820
+ export {
821
+ EMAIL,
822
+ PlayerContext,
823
+ PlayerSlice,
824
+ Result,
825
+ alpha,
826
+ altColor,
827
+ angularDistance,
828
+ closestFrame,
829
+ composeProgress,
830
+ composeProgressiveResult,
831
+ downloadBlob,
832
+ downloadJSONFile,
833
+ eulerToRotationMatrix,
834
+ getDegenerateHexagonPath,
835
+ getHexagonPath,
836
+ getId,
837
+ getLookup,
838
+ getNamespace,
839
+ hexToRgbArray,
840
+ hexToRgba,
841
+ hslToRgba,
842
+ incrementProgress,
843
+ instanceOfRawBoolean,
844
+ instanceOfRawColor,
845
+ instanceOfRawEuler,
846
+ instanceOfRawHSL,
847
+ instanceOfRawNumber,
848
+ instanceOfRawRGB,
849
+ instanceOfRawString,
850
+ instanceOfRawVector2,
851
+ instanceOfRawVector3,
852
+ isMapDeepEqual,
853
+ isRawObject,
854
+ log,
855
+ newPlayer,
856
+ now,
857
+ numberToDurationString,
858
+ overlappingSegments,
859
+ pairwise,
860
+ parseJSONFileEvent,
861
+ parseToMapped,
862
+ pause,
863
+ play,
864
+ pointsToPath,
865
+ rawHSLToHex,
866
+ rawRGBToHex,
867
+ reset,
868
+ rgbToRgba,
869
+ rotationMatrixToAngle,
870
+ seek,
871
+ setBounds,
872
+ setDuration,
873
+ setViewport,
874
+ stringifyMapped,
875
+ toDegrees,
876
+ toRadians,
877
+ update,
878
+ useDeep,
879
+ useDeepSelector,
880
+ useLazy,
881
+ useMediaQuery,
882
+ usePlayerStore
883
+ };