@kieransimkin/dancemoves 3.1.23 → 3.2.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/README.md +3 -0
- package/docs/audio-recording-playback.md +56 -0
- package/lib/build-manifest.json +11 -11
- package/lib/dancemoves.min.js +3 -3
- package/lib/index.cjs +242 -63
- package/lib/index.d.ts +5 -1
- package/lib/index.mjs +242 -63
- package/lib/wordpress.js +3 -3
- package/package.json +1 -1
- package/readme.txt +2 -2
package/lib/index.mjs
CHANGED
|
@@ -1032,7 +1032,7 @@ function install2(__dmScope) {
|
|
|
1032
1032
|
return;
|
|
1033
1033
|
var instances = /* @__PURE__ */ new Map();
|
|
1034
1034
|
var serial2 = 0;
|
|
1035
|
-
function
|
|
1035
|
+
function finite3(value, fallback) {
|
|
1036
1036
|
value = Number(value);
|
|
1037
1037
|
return Number.isFinite(value) ? value : fallback;
|
|
1038
1038
|
}
|
|
@@ -1086,8 +1086,8 @@ function install2(__dmScope) {
|
|
|
1086
1086
|
rect = bounds.getBoundingClientRect();
|
|
1087
1087
|
}
|
|
1088
1088
|
function apply(x, y, reason) {
|
|
1089
|
-
latestX = clamp(
|
|
1090
|
-
latestY = clamp(
|
|
1089
|
+
latestX = clamp(finite3(x, 0), -1, 1);
|
|
1090
|
+
latestY = clamp(finite3(y, 0), -1, 1);
|
|
1091
1091
|
__dmScope.setStyle(state.root.style, "--dance-moves-x", latestX.toFixed(4));
|
|
1092
1092
|
__dmScope.setStyle(state.root.style, "--dance-moves-y", latestY.toFixed(4));
|
|
1093
1093
|
__dmScope.dataset(state.root, "danceMovesPointer", reason || "active");
|
|
@@ -1178,13 +1178,13 @@ function install2(__dmScope) {
|
|
|
1178
1178
|
var audio = playbackElement(options.audio, state.root.querySelector("audio"));
|
|
1179
1179
|
if (!audio)
|
|
1180
1180
|
throw new Error("DanceMovesEffects pulse requires an audio element");
|
|
1181
|
-
var ticks = Math.max(1, Math.round(
|
|
1181
|
+
var ticks = Math.max(1, Math.round(finite3(options.ticks, 16)));
|
|
1182
1182
|
var className = String(options.className || "dance-moves-playing");
|
|
1183
1183
|
var prefix = String(options.propertyPrefix || "--dance-moves-pulse").replace(/-+$/, "");
|
|
1184
1184
|
function sync() {
|
|
1185
|
-
var rate = Math.max(0.01,
|
|
1185
|
+
var rate = Math.max(0.01, finite3(audio.playbackRate, 1));
|
|
1186
1186
|
var duration = motion.durationMilliseconds(ticks) / 1e3 / rate;
|
|
1187
|
-
var phase = -(
|
|
1187
|
+
var phase = -(finite3(audio.currentTime, 0) / rate % duration);
|
|
1188
1188
|
__dmScope.setStyle(state.root.style, prefix + "-duration", duration.toFixed(6) + "s");
|
|
1189
1189
|
__dmScope.setStyle(state.root.style, prefix + "-delay", phase.toFixed(6) + "s");
|
|
1190
1190
|
__dmScope.dataset(state.root, "danceMovesPulse", state.reduced.matches || state.forced.matches ? "inactive" : audio.paused ? "paused" : "playing");
|
|
@@ -1223,7 +1223,7 @@ function install2(__dmScope) {
|
|
|
1223
1223
|
var state = commonState(options, "cue-class");
|
|
1224
1224
|
var cue = String(options.cue || "*");
|
|
1225
1225
|
var className = String(options.className || "dance-moves-cue-active");
|
|
1226
|
-
var durationTicks = Math.max(1, Math.round(
|
|
1226
|
+
var durationTicks = Math.max(1, Math.round(finite3(options.durationTicks, 16)));
|
|
1227
1227
|
var timer = 0, count = 0;
|
|
1228
1228
|
function clear(reason) {
|
|
1229
1229
|
if (timer)
|
|
@@ -1279,16 +1279,16 @@ function install2(__dmScope) {
|
|
|
1279
1279
|
if (!audio)
|
|
1280
1280
|
throw new Error("DanceMovesEffects cueTimeline requires an audio element");
|
|
1281
1281
|
var cues = (Array.isArray(options.cues) ? options.cues : []).map(function(cue, index) {
|
|
1282
|
-
var time =
|
|
1282
|
+
var time = finite3(cue && cue.time, NaN);
|
|
1283
1283
|
if (!Number.isFinite(time) || time < 0)
|
|
1284
1284
|
throw new TypeError("DanceMovesEffects cueTimeline cue time must be a non-negative number");
|
|
1285
1285
|
return Object.freeze({ id: String(cue.id || "cue-" + index), time, end: Number.isFinite(Number(cue.end)) ? Number(cue.end) : null, data: cue.data });
|
|
1286
1286
|
}).sort(function(a, b) {
|
|
1287
1287
|
return a.time - b.time;
|
|
1288
1288
|
});
|
|
1289
|
-
var tolerance = Math.max(0,
|
|
1290
|
-
var maxCrossingGap = Math.max(0.05,
|
|
1291
|
-
var fired = /* @__PURE__ */ new Set(), frame = 0, previous =
|
|
1289
|
+
var tolerance = Math.max(0, finite3(options.seekLandingTolerance, 0.05));
|
|
1290
|
+
var maxCrossingGap = Math.max(0.05, finite3(options.maxCrossingGap, 1.25));
|
|
1291
|
+
var fired = /* @__PURE__ */ new Set(), frame = 0, previous = finite3(audio.currentTime, 0), status = "idle", generation = 0, previousWall = 0;
|
|
1292
1292
|
function blocked() {
|
|
1293
1293
|
return document2.hidden || state.reduced.matches || state.forced.matches;
|
|
1294
1294
|
}
|
|
@@ -1298,7 +1298,7 @@ function install2(__dmScope) {
|
|
|
1298
1298
|
});
|
|
1299
1299
|
}
|
|
1300
1300
|
function publish(reason, extra) {
|
|
1301
|
-
var time =
|
|
1301
|
+
var time = finite3(audio.currentTime, 0);
|
|
1302
1302
|
__dmScope.dataset(state.root, "danceMovesCueTimeline", reason);
|
|
1303
1303
|
if (typeof options.render === "function")
|
|
1304
1304
|
options.render({ root: state.root, audio, time, previousTime: previous, reason, playing: !audio.paused && !audio.ended && !blocked(), active: activeAt(time), generation, detail: extra || null });
|
|
@@ -1308,10 +1308,10 @@ function install2(__dmScope) {
|
|
|
1308
1308
|
return;
|
|
1309
1309
|
fired.add(cue.id);
|
|
1310
1310
|
if (typeof options.onCue === "function")
|
|
1311
|
-
options.onCue({ root: state.root, audio, cue, time:
|
|
1311
|
+
options.onCue({ root: state.root, audio, cue, time: finite3(audio.currentTime, cue.time), reason, generation });
|
|
1312
1312
|
}
|
|
1313
1313
|
function rebuild(time, reason, allowLanding) {
|
|
1314
|
-
time = Math.max(0,
|
|
1314
|
+
time = Math.max(0, finite3(time, 0));
|
|
1315
1315
|
generation += 1;
|
|
1316
1316
|
fired.clear();
|
|
1317
1317
|
cues.forEach(function(cue) {
|
|
@@ -1337,7 +1337,7 @@ function install2(__dmScope) {
|
|
|
1337
1337
|
frame = 0;
|
|
1338
1338
|
if (audio.paused || audio.ended || blocked())
|
|
1339
1339
|
return stop(audio.ended ? "ended" : blocked() ? "inactive" : "paused");
|
|
1340
|
-
var now = Math.max(0,
|
|
1340
|
+
var now = Math.max(0, finite3(audio.currentTime, previous));
|
|
1341
1341
|
var delta = now - previous;
|
|
1342
1342
|
if (delta < -1e-3 || delta > maxCrossingGap)
|
|
1343
1343
|
rebuild(now, "discontinuity", false);
|
|
@@ -1346,8 +1346,8 @@ function install2(__dmScope) {
|
|
|
1346
1346
|
if (previous < cue.time && now >= cue.time)
|
|
1347
1347
|
fire(cue, "crossing");
|
|
1348
1348
|
});
|
|
1349
|
-
var wallDelta = previousWall ? Math.min(0.25, Math.max(0, (
|
|
1350
|
-
previousWall =
|
|
1349
|
+
var wallDelta = previousWall ? Math.min(0.25, Math.max(0, (finite3(wallNow, previousWall) - previousWall) / 1e3)) : 0;
|
|
1350
|
+
previousWall = finite3(wallNow, previousWall);
|
|
1351
1351
|
previous = now;
|
|
1352
1352
|
status = "playing";
|
|
1353
1353
|
publish("frame", { deltaSeconds: wallDelta });
|
|
@@ -1356,7 +1356,7 @@ function install2(__dmScope) {
|
|
|
1356
1356
|
function start(reason) {
|
|
1357
1357
|
if (frame || audio.paused || audio.ended || blocked())
|
|
1358
1358
|
return publish(blocked() ? "inactive" : audio.ended ? "ended" : "paused");
|
|
1359
|
-
previous = Math.max(0,
|
|
1359
|
+
previous = Math.max(0, finite3(audio.currentTime, 0));
|
|
1360
1360
|
previousWall = 0;
|
|
1361
1361
|
status = reason || "playing";
|
|
1362
1362
|
publish(status);
|
|
@@ -1420,7 +1420,7 @@ function install2(__dmScope) {
|
|
|
1420
1420
|
start,
|
|
1421
1421
|
stop,
|
|
1422
1422
|
snapshot: function() {
|
|
1423
|
-
return { id: state.id, type: "cue-timeline", status, time:
|
|
1423
|
+
return { id: state.id, type: "cue-timeline", status, time: finite3(audio.currentTime, 0), previousTime: previous, generation, fired: Array.from(fired), active: activeAt(finite3(audio.currentTime, 0)).map(function(cue) {
|
|
1424
1424
|
return cue.id;
|
|
1425
1425
|
}) };
|
|
1426
1426
|
},
|
|
@@ -1443,28 +1443,28 @@ function install2(__dmScope) {
|
|
|
1443
1443
|
if (!target)
|
|
1444
1444
|
throw new Error("DanceMovesEffects spritePlayback requires a target element");
|
|
1445
1445
|
var frameMap = Array.isArray(options.frameMap) && options.frameMap.length ? options.frameMap.map(function(value) {
|
|
1446
|
-
value = Math.floor(
|
|
1446
|
+
value = Math.floor(finite3(value, -1));
|
|
1447
1447
|
if (value < 0)
|
|
1448
1448
|
throw new TypeError("DanceMovesEffects spritePlayback frameMap values must be non-negative integers");
|
|
1449
1449
|
return value;
|
|
1450
1450
|
}) : null;
|
|
1451
|
-
var frameCount = frameMap ? frameMap.length : Math.max(1, Math.round(
|
|
1452
|
-
var columns = Math.max(1, Math.round(
|
|
1453
|
-
var framesPerRow = clamp(Math.round(
|
|
1454
|
-
var columnOffset = clamp(Math.round(
|
|
1455
|
-
var rowOffset = Math.max(0, Math.round(
|
|
1456
|
-
var cycleTicks = Math.max(1, Math.round(
|
|
1457
|
-
var phaseOffsetSeconds =
|
|
1458
|
-
var staticFrame = clamp(Math.round(
|
|
1451
|
+
var frameCount = frameMap ? frameMap.length : Math.max(1, Math.round(finite3(options.frameCount, 1)));
|
|
1452
|
+
var columns = Math.max(1, Math.round(finite3(options.columns, frameCount)));
|
|
1453
|
+
var framesPerRow = clamp(Math.round(finite3(options.framesPerRow, columns)), 1, columns);
|
|
1454
|
+
var columnOffset = clamp(Math.round(finite3(options.columnOffset, 0)), 0, columns - framesPerRow);
|
|
1455
|
+
var rowOffset = Math.max(0, Math.round(finite3(options.rowOffset, 0)));
|
|
1456
|
+
var cycleTicks = Math.max(1, Math.round(finite3(options.cycleTicks, 32)));
|
|
1457
|
+
var phaseOffsetSeconds = finite3(options.phaseOffsetSeconds, 0);
|
|
1458
|
+
var staticFrame = clamp(Math.round(finite3(options.staticFrame, 0)), 0, frameCount - 1);
|
|
1459
1459
|
var prefix = String(options.propertyPrefix || "--dance-moves-sprite").replace(/-+$/, "");
|
|
1460
1460
|
if (prefix.slice(0, 2) !== "--")
|
|
1461
1461
|
prefix = "--" + prefix.replace(/^-+/, "");
|
|
1462
1462
|
var tiers = Array.isArray(options.qualityTiers) && options.qualityTiers.length ? options.qualityTiers.map(String) : ["full", "constrained", "minimal"];
|
|
1463
1463
|
var suppliedFps = Array.isArray(options.qualityFramesPerSecond) ? options.qualityFramesPerSecond : [60, 30, 15];
|
|
1464
1464
|
var qualityFps = tiers.map(function(_, index) {
|
|
1465
|
-
return Math.max(1,
|
|
1465
|
+
return Math.max(1, finite3(suppliedFps[index], suppliedFps[suppliedFps.length - 1] || 15));
|
|
1466
1466
|
});
|
|
1467
|
-
var qualityIndex = clamp(Math.round(
|
|
1467
|
+
var qualityIndex = clamp(Math.round(finite3(options.initialQuality, 0)), 0, tiers.length - 1);
|
|
1468
1468
|
var frame = 0, status = "idle", lastWall = -Infinity, renders = 0, latest = null;
|
|
1469
1469
|
function blocked() {
|
|
1470
1470
|
return document2.hidden || state.reduced.matches || state.forced.matches;
|
|
@@ -1474,8 +1474,8 @@ function install2(__dmScope) {
|
|
|
1474
1474
|
return { sourceFrame, column: sourceFrame % columns, row: Math.floor(sourceFrame / columns) };
|
|
1475
1475
|
}
|
|
1476
1476
|
function calculate(reason, staticFallback) {
|
|
1477
|
-
var cycleSeconds = Math.max(1e-3,
|
|
1478
|
-
var time = Math.max(0,
|
|
1477
|
+
var cycleSeconds = Math.max(1e-3, finite3(motion.durationMilliseconds(cycleTicks), 1) / 1e3);
|
|
1478
|
+
var time = Math.max(0, finite3(audio.currentTime, 0));
|
|
1479
1479
|
var phase = ((time - phaseOffsetSeconds) % cycleSeconds + cycleSeconds) % cycleSeconds / cycleSeconds;
|
|
1480
1480
|
var localFrame = staticFallback ? staticFrame : Math.min(frameCount - 1, Math.floor(phase * frameCount + 1e-9));
|
|
1481
1481
|
var mapped = mappedFrame(localFrame);
|
|
@@ -1530,8 +1530,8 @@ function install2(__dmScope) {
|
|
|
1530
1530
|
if (audio.paused || audio.ended || blocked())
|
|
1531
1531
|
return stop(audio.ended ? "ended" : blocked() ? "inactive" : "paused", audio.ended || blocked());
|
|
1532
1532
|
var minimumInterval = 1e3 / qualityFps[qualityIndex];
|
|
1533
|
-
if (!Number.isFinite(lastWall) ||
|
|
1534
|
-
lastWall =
|
|
1533
|
+
if (!Number.isFinite(lastWall) || finite3(wallNow, lastWall) - lastWall >= minimumInterval - 0.01) {
|
|
1534
|
+
lastWall = finite3(wallNow, lastWall);
|
|
1535
1535
|
status = "playing";
|
|
1536
1536
|
publish("frame", false);
|
|
1537
1537
|
}
|
|
@@ -1562,7 +1562,7 @@ function install2(__dmScope) {
|
|
|
1562
1562
|
}
|
|
1563
1563
|
function setQuality(value, reason) {
|
|
1564
1564
|
var named = typeof value === "string" ? tiers.indexOf(value) : -1;
|
|
1565
|
-
qualityIndex = named >= 0 ? named : clamp(Math.round(
|
|
1565
|
+
qualityIndex = named >= 0 ? named : clamp(Math.round(finite3(value, qualityIndex)), 0, tiers.length - 1);
|
|
1566
1566
|
lastWall = -Infinity;
|
|
1567
1567
|
publish(reason || "quality-change", audio.ended || blocked());
|
|
1568
1568
|
}
|
|
@@ -1616,7 +1616,7 @@ function install2(__dmScope) {
|
|
|
1616
1616
|
},
|
|
1617
1617
|
setQuality,
|
|
1618
1618
|
snapshot: function() {
|
|
1619
|
-
return { id: state.id, type: "sprite-playback", status, time:
|
|
1619
|
+
return { id: state.id, type: "sprite-playback", status, time: finite3(audio.currentTime, 0), frame: latest ? latest.frame : null, localFrame: latest ? latest.localFrame : null, column: latest ? latest.column : null, row: latest ? latest.row : null, phase: latest ? latest.phase : null, cycleTicks, cycleSeconds: latest ? latest.cycleSeconds : null, qualityTier: tiers[qualityIndex], qualityIndex, renders, running: Boolean(frame) };
|
|
1620
1620
|
},
|
|
1621
1621
|
teardown: function() {
|
|
1622
1622
|
stop("teardown", true);
|
|
@@ -1683,8 +1683,8 @@ function install2(__dmScope) {
|
|
|
1683
1683
|
popover.appendChild(viewport);
|
|
1684
1684
|
__dmScope.dataset(popover, "danceMovesLyricStage", "ready");
|
|
1685
1685
|
__dmScope.setStyle(popover.style, "--dance-moves-lyric-progress", "0");
|
|
1686
|
-
var travelTicks = Math.max(1, Math.round(
|
|
1687
|
-
var defaultCueTicks = Math.max(1, Math.round(
|
|
1686
|
+
var travelTicks = Math.max(1, Math.round(finite3(options.travelTicks, 32)));
|
|
1687
|
+
var defaultCueTicks = Math.max(1, Math.round(finite3(options.cueDurationTicks, 32)));
|
|
1688
1688
|
var latest = null, phase = "idle", progress = 0, frame = 0, wakeTimer = 0, cueTimer = 0, cueCleanup = null, cueCount = 0;
|
|
1689
1689
|
var lyricEffects = [];
|
|
1690
1690
|
var slots = Object.freeze({ previous, current, next, viewport, track });
|
|
@@ -1733,7 +1733,7 @@ function install2(__dmScope) {
|
|
|
1733
1733
|
publish(reason || value);
|
|
1734
1734
|
}
|
|
1735
1735
|
function setProgress(value) {
|
|
1736
|
-
progress = clamp(
|
|
1736
|
+
progress = clamp(finite3(value, 0), 0, 1);
|
|
1737
1737
|
__dmScope.setStyle(popover.style, "--dance-moves-lyric-progress", progress.toFixed(5));
|
|
1738
1738
|
}
|
|
1739
1739
|
function copyLyrics(detail) {
|
|
@@ -1750,7 +1750,7 @@ function install2(__dmScope) {
|
|
|
1750
1750
|
var cleanup = typeof result === "function" ? result : typeof result.cleanup === "function" ? result.cleanup : null;
|
|
1751
1751
|
if (!cleanup)
|
|
1752
1752
|
return;
|
|
1753
|
-
var durationTicks = result && typeof result === "object" ? Math.max(1, Math.round(
|
|
1753
|
+
var durationTicks = result && typeof result === "object" ? Math.max(1, Math.round(finite3(result.durationTicks, 64))) : 64;
|
|
1754
1754
|
var record = { cleanup, timer: 0 };
|
|
1755
1755
|
record.timer = window2.setTimeout(function() {
|
|
1756
1756
|
lyricEffects = lyricEffects.filter(function(item) {
|
|
@@ -1776,7 +1776,7 @@ function install2(__dmScope) {
|
|
|
1776
1776
|
setProgress(0);
|
|
1777
1777
|
return setPhase("waiting", "no-next-line");
|
|
1778
1778
|
}
|
|
1779
|
-
var now = Math.max(0,
|
|
1779
|
+
var now = Math.max(0, finite3(audio.currentTime, 0));
|
|
1780
1780
|
if (now < windowRange.start)
|
|
1781
1781
|
return reconcile("frame-before-window");
|
|
1782
1782
|
if (now >= windowRange.end) {
|
|
@@ -1806,7 +1806,7 @@ function install2(__dmScope) {
|
|
|
1806
1806
|
setProgress(0);
|
|
1807
1807
|
return setPhase("waiting", reason || "no-next-line");
|
|
1808
1808
|
}
|
|
1809
|
-
var now = Math.max(0,
|
|
1809
|
+
var now = Math.max(0, finite3(audio.currentTime, 0));
|
|
1810
1810
|
if (now >= windowRange.end) {
|
|
1811
1811
|
setProgress(1);
|
|
1812
1812
|
return setPhase("arrived", reason || "arrived");
|
|
@@ -1821,7 +1821,7 @@ function install2(__dmScope) {
|
|
|
1821
1821
|
wakeTimer = window2.setTimeout(function() {
|
|
1822
1822
|
wakeTimer = 0;
|
|
1823
1823
|
tick();
|
|
1824
|
-
}, Math.max(0, (windowRange.start - now) * 1e3 / Math.max(0.01,
|
|
1824
|
+
}, Math.max(0, (windowRange.start - now) * 1e3 / Math.max(0.01, finite3(audio.playbackRate, 1))));
|
|
1825
1825
|
}
|
|
1826
1826
|
function onLyric(detail) {
|
|
1827
1827
|
var previousDetail = latest;
|
|
@@ -1876,7 +1876,7 @@ function install2(__dmScope) {
|
|
|
1876
1876
|
else if (result && typeof result === "object") {
|
|
1877
1877
|
if (typeof result.cleanup === "function")
|
|
1878
1878
|
cueCleanup = result.cleanup;
|
|
1879
|
-
durationTicks = Math.max(1, Math.round(
|
|
1879
|
+
durationTicks = Math.max(1, Math.round(finite3(result.durationTicks, defaultCueTicks)));
|
|
1880
1880
|
}
|
|
1881
1881
|
cueTimer = window2.setTimeout(function() {
|
|
1882
1882
|
clearCue("complete");
|
|
@@ -1948,16 +1948,16 @@ function install2(__dmScope) {
|
|
|
1948
1948
|
var hazardSources = Array.isArray(options.hazardSources) ? options.hazardSources.filter(Boolean).map(String) : [];
|
|
1949
1949
|
if (!shipSources.length || !hazardSources.length)
|
|
1950
1950
|
throw new Error("DanceMovesEffects cooperativeArena requires ship and hazard sources");
|
|
1951
|
-
var shipCount = clamp(Math.round(
|
|
1952
|
-
var hazardCount = clamp(Math.round(
|
|
1953
|
-
var speed = clamp(
|
|
1951
|
+
var shipCount = clamp(Math.round(finite3(options.shipCount, 3)), 2, 12);
|
|
1952
|
+
var hazardCount = clamp(Math.round(finite3(options.hazardCount, 8)), 3, 48);
|
|
1953
|
+
var speed = clamp(finite3(options.speed, 1), 0.35, 2.4);
|
|
1954
1954
|
var inlineTransform = options.inlineTransform === true;
|
|
1955
|
-
var bpm = Math.max(1,
|
|
1956
|
-
var shotIntervalTicks = clamp(Math.round(
|
|
1955
|
+
var bpm = Math.max(1, finite3(options.bpm, motion.bpm || 120));
|
|
1956
|
+
var shotIntervalTicks = clamp(Math.round(finite3(options.shotIntervalTicks, 32)), 4, 256);
|
|
1957
1957
|
var shotIntervalSeconds = motion.durationMilliseconds ? motion.durationMilliseconds(shotIntervalTicks, bpm) / 1e3 : shotIntervalTicks * 60 / (bpm * 16);
|
|
1958
|
-
var burstDurationSeconds = clamp(
|
|
1959
|
-
var shipHitboxScale = clamp(
|
|
1960
|
-
var hazardHitboxScale = clamp(
|
|
1958
|
+
var burstDurationSeconds = clamp(finite3(options.burstDurationBeats, 1.5), 0.1, 8) * 60 / bpm;
|
|
1959
|
+
var shipHitboxScale = clamp(finite3(options.shipHitboxScale, 1), 0.4, 1);
|
|
1960
|
+
var hazardHitboxScale = clamp(finite3(options.hazardHitboxScale, 1), 0.4, 1);
|
|
1961
1961
|
var removers = state.removers, ships = [], hazards = [], shots = [], bursts = [], burstTimers = [];
|
|
1962
1962
|
var activeShips = shipCount, activeHazards = hazardCount;
|
|
1963
1963
|
var width = 1, height = 1, frame = 0, last = 0, elapsed = 0, nextShot = 0, hits = 0;
|
|
@@ -2289,7 +2289,7 @@ function install2(__dmScope) {
|
|
|
2289
2289
|
reconcile(reason || "manual");
|
|
2290
2290
|
},
|
|
2291
2291
|
setDensity: function(nextShips, nextHazards) {
|
|
2292
|
-
var shipsNext = clamp(Math.round(
|
|
2292
|
+
var shipsNext = clamp(Math.round(finite3(nextShips, activeShips)), 2, shipCount), hazardsNext = clamp(Math.round(finite3(nextHazards, activeHazards)), 3, hazardCount);
|
|
2293
2293
|
if (shipsNext === activeShips && hazardsNext === activeHazards)
|
|
2294
2294
|
return;
|
|
2295
2295
|
activeShips = shipsNext;
|
|
@@ -2332,12 +2332,12 @@ function install2(__dmScope) {
|
|
|
2332
2332
|
options = options || {};
|
|
2333
2333
|
var state = commonState(options, "quality");
|
|
2334
2334
|
var tiers = Array.isArray(options.tiers) && options.tiers.length ? options.tiers.map(String) : ["full", "constrained", "minimal"];
|
|
2335
|
-
var index = clamp(Math.round(
|
|
2336
|
-
var sampleMs = Math.max(800,
|
|
2337
|
-
var poorWindows = Math.max(2, Math.round(
|
|
2338
|
-
var healthyWindows = Math.max(3, Math.round(
|
|
2339
|
-
var downgradeRatio = clamp(
|
|
2340
|
-
var recoveryRatio = clamp(
|
|
2335
|
+
var index = clamp(Math.round(finite3(options.initial, 0)), 0, tiers.length - 1);
|
|
2336
|
+
var sampleMs = Math.max(800, finite3(options.sampleMilliseconds, 1600));
|
|
2337
|
+
var poorWindows = Math.max(2, Math.round(finite3(options.poorWindows, 2)));
|
|
2338
|
+
var healthyWindows = Math.max(3, Math.round(finite3(options.healthyWindows, 5)));
|
|
2339
|
+
var downgradeRatio = clamp(finite3(options.downgradeRatio, 0.72), 0.2, 0.95);
|
|
2340
|
+
var recoveryRatio = clamp(finite3(options.recoveryRatio, 0.9), downgradeRatio, 1);
|
|
2341
2341
|
var frame = 0, frames = 0, start = 0, reference = 0, poor = 0, healthy = 0, lastShift = 0, running = true;
|
|
2342
2342
|
var preferenceLimited = false, tierBeforePreference = index;
|
|
2343
2343
|
function publish(reason, sample) {
|
|
@@ -2381,12 +2381,12 @@ function install2(__dmScope) {
|
|
|
2381
2381
|
poor = 0;
|
|
2382
2382
|
healthy = 0;
|
|
2383
2383
|
}
|
|
2384
|
-
if (poor >= poorWindows && index < tiers.length - 1 && now - lastShift >=
|
|
2384
|
+
if (poor >= poorWindows && index < tiers.length - 1 && now - lastShift >= finite3(options.downgradeCooldownMilliseconds, 5e3)) {
|
|
2385
2385
|
index += 1;
|
|
2386
2386
|
poor = 0;
|
|
2387
2387
|
lastShift = now;
|
|
2388
2388
|
publish("sustained-low-fps", { fps });
|
|
2389
|
-
} else if (healthy >= healthyWindows && index > 0 && now - lastShift >=
|
|
2389
|
+
} else if (healthy >= healthyWindows && index > 0 && now - lastShift >= finite3(options.recoveryCooldownMilliseconds, 12e3)) {
|
|
2390
2390
|
index -= 1;
|
|
2391
2391
|
healthy = 0;
|
|
2392
2392
|
lastShift = now;
|
|
@@ -2425,7 +2425,7 @@ function install2(__dmScope) {
|
|
|
2425
2425
|
id: state.id,
|
|
2426
2426
|
type: "quality",
|
|
2427
2427
|
setTier: function(value, reason) {
|
|
2428
|
-
index = clamp(Math.round(
|
|
2428
|
+
index = clamp(Math.round(finite3(value, index)), 0, tiers.length - 1);
|
|
2429
2429
|
publish(reason || "manual");
|
|
2430
2430
|
},
|
|
2431
2431
|
snapshot: function() {
|
|
@@ -6403,6 +6403,184 @@ function installPlayback(scope, api, host = scope.document.defaultView) {
|
|
|
6403
6403
|
});
|
|
6404
6404
|
}
|
|
6405
6405
|
|
|
6406
|
+
// .build/modules/recordings.mjs
|
|
6407
|
+
var WASM = "AGFzbQEAAAABDwJgAAF/YAZ/f39/f38BfAMDAgABBQUBAQKAQAYIAX8BQYCIBAsHKgMGbWVtb3J5AgAKdGFibGVfYmFzZQAAEHNhbXBsZV9yZWNvcmRpbmcAAQpvAggAQYCIhIAAC2QCAXwBfkQAAAAAAAD4fyEGAkAgAEUNACABQQFIDQAgAkEBSA0AIAVBAEgNACAFIAJPDQAgBKwgA6x9IgdCAFMNACAHIAGtWg0AIAAgB6cgAmxBA3RqIAVBA3RqKwMAIQYLIAYL";
|
|
6408
|
+
var MAX_VALUES = 8388608;
|
|
6409
|
+
var MAX_BYTES = 64 * 1024 * 1024;
|
|
6410
|
+
var modulePromise;
|
|
6411
|
+
var finite2 = (n, label) => {
|
|
6412
|
+
if (typeof n !== "number" || !Number.isFinite(n)) throw new TypeError(label + " must be finite");
|
|
6413
|
+
return n;
|
|
6414
|
+
};
|
|
6415
|
+
function validateRecording(input) {
|
|
6416
|
+
if (!input || input.format !== "dancerudiments.recording" || input.schema_version !== 1 || input.pips_per_beat !== 64 || input.sample_dtype !== "float64") throw new TypeError("Expected dancerudiments.recording v1, float64, 64 pips per beat");
|
|
6417
|
+
if (typeof input.name !== "string" || !input.name.length || input.name.length > 128) throw new TypeError("Recording name is required");
|
|
6418
|
+
const dimensions = input.dimensions;
|
|
6419
|
+
if (!Array.isArray(dimensions) || !dimensions.length || dimensions.length > 64 || new Set(dimensions).size !== dimensions.length || dimensions.some((d) => typeof d !== "string" || !/^[a-z][a-z0-9_]{0,127}$/.test(d))) throw new TypeError("Recording requires 1..64 unique named dimensions");
|
|
6420
|
+
const c = input.clock;
|
|
6421
|
+
if (!c || finite2(c.bpm, "Recording BPM") <= 0 || !["confirmed", "estimated"].includes(c.bpm_status) || !["unverified", "estimated", "supplied"].includes(c.phase_status) || typeof c.bpm_source !== "string" || !c.bpm_source.trim()) throw new TypeError("Recording clock requires BPM and provenance");
|
|
6422
|
+
finite2(c.beat_zero_seconds, "Beat zero");
|
|
6423
|
+
if (!Number.isInteger(c.start_pip) || c.start_pip < -2147483648) throw new RangeError("Invalid recording start pip");
|
|
6424
|
+
const rows = input.samples;
|
|
6425
|
+
if (!Array.isArray(rows) || !rows.length || rows.length * dimensions.length > MAX_VALUES || c.start_pip + rows.length > 2147483647) throw new RangeError("Recording exceeds bounded sample limits");
|
|
6426
|
+
const values = new Float64Array(rows.length * dimensions.length);
|
|
6427
|
+
rows.forEach((row, i) => {
|
|
6428
|
+
if (!Array.isArray(row) || row.length !== dimensions.length) throw new TypeError("Recording sample dimensions differ");
|
|
6429
|
+
row.forEach((v, j) => {
|
|
6430
|
+
finite2(v, "Sample");
|
|
6431
|
+
if (Math.abs(v) > 1) throw new RangeError("Recording samples must be in [-1,1]");
|
|
6432
|
+
values[i * dimensions.length + j] = v;
|
|
6433
|
+
});
|
|
6434
|
+
});
|
|
6435
|
+
return Object.freeze({ name: input.name, dimensions: Object.freeze([...dimensions]), count: rows.length, clock: Object.freeze({ ...c }), values });
|
|
6436
|
+
}
|
|
6437
|
+
async function samplerFromData(data) {
|
|
6438
|
+
if (!modulePromise) modulePromise = WebAssembly.compile(Uint8Array.from(atob(WASM), (c) => c.charCodeAt(0))).catch((error) => {
|
|
6439
|
+
modulePromise = null;
|
|
6440
|
+
throw error;
|
|
6441
|
+
});
|
|
6442
|
+
const api = (await WebAssembly.instantiate(await modulePromise, {})).exports;
|
|
6443
|
+
const base = api.table_base(), pages = Math.ceil((base + data.values.byteLength - api.memory.buffer.byteLength) / 65536);
|
|
6444
|
+
if (pages > 0) api.memory.grow(pages);
|
|
6445
|
+
new Float64Array(api.memory.buffer, base, data.values.length).set(data.values);
|
|
6446
|
+
return Object.freeze({ ...data, sample(pip) {
|
|
6447
|
+
if (!Number.isInteger(pip) || pip < data.clock.start_pip || pip >= data.clock.start_pip + data.count) throw new RangeError("Position is outside the non-looping recording");
|
|
6448
|
+
return data.dimensions.map((_, axis) => api.sample_recording(base, data.count, data.dimensions.length, data.clock.start_pip, pip, axis));
|
|
6449
|
+
} });
|
|
6450
|
+
}
|
|
6451
|
+
function createRecordingService(scope, rudiments, config) {
|
|
6452
|
+
const handles = /* @__PURE__ */ new Map();
|
|
6453
|
+
async function load(url2) {
|
|
6454
|
+
if (scope.disposed) throw new Error("DanceMoves mount is destroyed");
|
|
6455
|
+
const response = await scope.window.fetch(url2);
|
|
6456
|
+
if (!response.ok) throw new Error("Recording request failed: " + response.status);
|
|
6457
|
+
if (Number(response.headers?.get("content-length")) > MAX_BYTES) throw new RangeError("Recording exceeds 64 MiB");
|
|
6458
|
+
let text;
|
|
6459
|
+
if (response.body?.getReader) {
|
|
6460
|
+
const reader = response.body.getReader(), chunks = [];
|
|
6461
|
+
let size = 0;
|
|
6462
|
+
for (; ; ) {
|
|
6463
|
+
const { done, value } = await reader.read();
|
|
6464
|
+
if (done) break;
|
|
6465
|
+
size += value.byteLength;
|
|
6466
|
+
if (size > MAX_BYTES) {
|
|
6467
|
+
await reader.cancel();
|
|
6468
|
+
throw new RangeError("Recording exceeds 64 MiB");
|
|
6469
|
+
}
|
|
6470
|
+
chunks.push(value);
|
|
6471
|
+
}
|
|
6472
|
+
const bytes = new Uint8Array(size);
|
|
6473
|
+
let offset = 0;
|
|
6474
|
+
for (const chunk of chunks) {
|
|
6475
|
+
bytes.set(chunk, offset);
|
|
6476
|
+
offset += chunk.length;
|
|
6477
|
+
}
|
|
6478
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
6479
|
+
} else {
|
|
6480
|
+
text = await response.text();
|
|
6481
|
+
if (new TextEncoder().encode(text).length > MAX_BYTES) throw new RangeError("Recording exceeds 64 MiB");
|
|
6482
|
+
}
|
|
6483
|
+
const input = JSON.parse(text);
|
|
6484
|
+
validateRecording(input);
|
|
6485
|
+
return input;
|
|
6486
|
+
}
|
|
6487
|
+
function animate(options = {}) {
|
|
6488
|
+
if (scope.disposed) throw new Error("DanceMoves mount is destroyed");
|
|
6489
|
+
if (typeof options.id !== "string" || !options.id.trim() || handles.has(options.id)) throw new TypeError("Recording controller requires a unique id");
|
|
6490
|
+
if (typeof options.render !== "function") throw new TypeError("Recording render callback is required");
|
|
6491
|
+
if (!options.audio) throw new TypeError("Recording playback requires an audio/player source");
|
|
6492
|
+
if (["rate", "phasePips", "clock", "bpm"].some((k) => Object.hasOwn(options, k))) throw new TypeError("Recording clock, rate and origin come from its capture");
|
|
6493
|
+
const data = validateRecording(options.recording);
|
|
6494
|
+
if (Math.abs(data.clock.bpm - config.bpm) > 1e-9) throw new RangeError("Recording BPM does not match the authoritative page BPM");
|
|
6495
|
+
let inner = null, sampler = null, destroyed = false, enabled = options.enabled !== false, paused = false, status = "loading", error = null, last = null;
|
|
6496
|
+
const output = (frame, values, pip, reason) => {
|
|
6497
|
+
if (destroyed) return;
|
|
6498
|
+
last = { ...frame, rudiment: null, recording: data.name, dimensions: data.dimensions, values, position: { x: values[0] || 0, y: values[1] || 0, z: values[2] || 0 }, pip, positionPips: pip, loopProgress: null, reason };
|
|
6499
|
+
options.render(last);
|
|
6500
|
+
};
|
|
6501
|
+
const handle = {
|
|
6502
|
+
id: options.id,
|
|
6503
|
+
ready: null,
|
|
6504
|
+
setEnabled(value) {
|
|
6505
|
+
if (typeof value !== "boolean") throw new TypeError("enabled must be boolean");
|
|
6506
|
+
enabled = value;
|
|
6507
|
+
inner?.setEnabled(value);
|
|
6508
|
+
},
|
|
6509
|
+
pause() {
|
|
6510
|
+
paused = true;
|
|
6511
|
+
inner?.pause();
|
|
6512
|
+
},
|
|
6513
|
+
resume() {
|
|
6514
|
+
paused = false;
|
|
6515
|
+
inner?.resume();
|
|
6516
|
+
},
|
|
6517
|
+
refresh() {
|
|
6518
|
+
inner?.refresh();
|
|
6519
|
+
},
|
|
6520
|
+
destroy() {
|
|
6521
|
+
if (destroyed) return;
|
|
6522
|
+
inner?.destroy();
|
|
6523
|
+
inner = null;
|
|
6524
|
+
sampler = null;
|
|
6525
|
+
destroyed = true;
|
|
6526
|
+
status = "destroyed";
|
|
6527
|
+
handles.delete(options.id);
|
|
6528
|
+
},
|
|
6529
|
+
snapshot() {
|
|
6530
|
+
const state = inner?.snapshot() ?? null;
|
|
6531
|
+
return { id: options.id, type: "recording", recording: data.name, status: !destroyed && ["hidden", "offscreen", "paused", "seeking"].includes(state?.status) ? state.status : status, error, destroyed, enabled, paused, pip: last?.pip ?? null, dimensions: data.dimensions, count: data.count, clock: data.clock, inner: state };
|
|
6532
|
+
}
|
|
6533
|
+
};
|
|
6534
|
+
handle.teardown = handle.destroy;
|
|
6535
|
+
handles.set(options.id, handle);
|
|
6536
|
+
handle.ready = samplerFromData(data).then(async (native) => {
|
|
6537
|
+
if (destroyed || scope.disposed) return handle;
|
|
6538
|
+
sampler = native;
|
|
6539
|
+
inner = rudiments.animate({
|
|
6540
|
+
id: options.id,
|
|
6541
|
+
root: options.root,
|
|
6542
|
+
target: options.target,
|
|
6543
|
+
audio: options.audio,
|
|
6544
|
+
clock: "audio",
|
|
6545
|
+
rudiment: "circle",
|
|
6546
|
+
rate: 1,
|
|
6547
|
+
phasePips: 0,
|
|
6548
|
+
amplitude: 0,
|
|
6549
|
+
css: false,
|
|
6550
|
+
renderEveryFrame: true,
|
|
6551
|
+
offscreen: options.offscreen !== false,
|
|
6552
|
+
enabled,
|
|
6553
|
+
render(frame) {
|
|
6554
|
+
if (destroyed) return;
|
|
6555
|
+
const neutral = ["disabled", "reduced-motion", "forced-colors"].includes(frame.reason), precise = (frame.sourceBeats - data.clock.beat_zero_seconds * data.clock.bpm / 60) * 64;
|
|
6556
|
+
const pip = Math.floor(precise + 1e-8), outside = pip < data.clock.start_pip || pip >= data.clock.start_pip + data.count;
|
|
6557
|
+
status = neutral ? frame.reason : outside ? "outside-recording" : frame.reason;
|
|
6558
|
+
const values = neutral || outside ? data.dimensions.map(() => 0) : sampler.sample(pip);
|
|
6559
|
+
output(frame, values, pip, status);
|
|
6560
|
+
}
|
|
6561
|
+
});
|
|
6562
|
+
if (paused) inner.pause();
|
|
6563
|
+
await inner.ready;
|
|
6564
|
+
return handle;
|
|
6565
|
+
}).catch((failure) => {
|
|
6566
|
+
error = String(failure.message || failure);
|
|
6567
|
+
status = "error";
|
|
6568
|
+
inner?.destroy();
|
|
6569
|
+
inner = null;
|
|
6570
|
+
sampler = null;
|
|
6571
|
+
if (handles.get(options.id) === handle) handles.delete(options.id);
|
|
6572
|
+
throw failure;
|
|
6573
|
+
});
|
|
6574
|
+
return handle;
|
|
6575
|
+
}
|
|
6576
|
+
scope.onDispose(() => {
|
|
6577
|
+
for (const handle of [...handles.values()]) handle.destroy();
|
|
6578
|
+
});
|
|
6579
|
+
return Object.freeze({ load, animate, get: (id) => handles.get(id) || null, destroyAll: () => {
|
|
6580
|
+
for (const h of [...handles.values()]) h.destroy();
|
|
6581
|
+
}, snapshot: () => ({ native: "DanceRudiments 0.3.0 recording C++/WASM", instances: [...handles.values()].map((h) => h.snapshot()) }) });
|
|
6582
|
+
}
|
|
6583
|
+
|
|
6406
6584
|
// .build/modules/child-playback.mjs
|
|
6407
6585
|
var PROTOCOL = "dancemoves.child-playback.v1";
|
|
6408
6586
|
var EVENTS = /* @__PURE__ */ new Set(["snapshot", "loadedmetadata", "durationchange", "play", "playing", "pause", "ended", "seeking", "seeked", "ratechange", "timeupdate", "waiting", "error"]);
|
|
@@ -6827,7 +7005,7 @@ function installChildPlayback(scope, api, host) {
|
|
|
6827
7005
|
}
|
|
6828
7006
|
|
|
6829
7007
|
// .build/modules/version.mjs
|
|
6830
|
-
var VERSION = "3.
|
|
7008
|
+
var VERSION = "3.2.0";
|
|
6831
7009
|
|
|
6832
7010
|
// .build/modules/index.mjs
|
|
6833
7011
|
var mounted = /* @__PURE__ */ new WeakMap();
|
|
@@ -6880,6 +7058,7 @@ function createDanceMoves(options = {}) {
|
|
|
6880
7058
|
config,
|
|
6881
7059
|
effects: w.DanceMovesEffects,
|
|
6882
7060
|
rudiments: w.DanceMovesRudiments,
|
|
7061
|
+
recordings: createRecordingService(scope, w.DanceMovesRudiments, config),
|
|
6883
7062
|
orientationCore: w.KSEpkOrientationCore,
|
|
6884
7063
|
getOrientation: () => w.__ksEpkOrientationRuntime || null,
|
|
6885
7064
|
getClay: () => w.DanceMovesClayStars || null,
|