@replayablejs/devtools 0.1.0-alpha.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.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/dist/disabled-stats-DrzL4cm1.js +12 -0
  4. package/dist/disabled-stats-DrzL4cm1.js.map +1 -0
  5. package/dist/end-card-trigger-q4ww_XP2.d.ts +8 -0
  6. package/dist/endcard-trigger/disabled.d.ts +7 -0
  7. package/dist/endcard-trigger/disabled.js +10 -0
  8. package/dist/endcard-trigger/disabled.js.map +1 -0
  9. package/dist/endcard-trigger/enabled.d.ts +7 -0
  10. package/dist/endcard-trigger/enabled.js +68 -0
  11. package/dist/endcard-trigger/enabled.js.map +1 -0
  12. package/dist/index.d.ts +13 -0
  13. package/dist/index.js +22 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/install-devtools-interaction-1Flxw89C.js +61 -0
  16. package/dist/install-devtools-interaction-1Flxw89C.js.map +1 -0
  17. package/dist/sound-control/disabled.d.ts +7 -0
  18. package/dist/sound-control/disabled.js +10 -0
  19. package/dist/sound-control/disabled.js.map +1 -0
  20. package/dist/sound-control/enabled.d.ts +7 -0
  21. package/dist/sound-control/enabled.js +91 -0
  22. package/dist/sound-control/enabled.js.map +1 -0
  23. package/dist/sound-control-D8U9dP87.d.ts +9 -0
  24. package/dist/stats/disabled.d.ts +7 -0
  25. package/dist/stats/disabled.js +10 -0
  26. package/dist/stats/disabled.js.map +1 -0
  27. package/dist/stats/enabled.d.ts +7 -0
  28. package/dist/stats/enabled.js +1081 -0
  29. package/dist/stats/enabled.js.map +1 -0
  30. package/dist/stats/webgl/disabled.d.ts +6 -0
  31. package/dist/stats/webgl/disabled.js +10 -0
  32. package/dist/stats/webgl/disabled.js.map +1 -0
  33. package/dist/stats/webgl/enabled.d.ts +14 -0
  34. package/dist/stats/webgl/enabled.js +62 -0
  35. package/dist/stats/webgl/enabled.js.map +1 -0
  36. package/dist/stats-CMNxuMXo.d.ts +13 -0
  37. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Replayable contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @replayablejs/devtools
2
+
3
+ Provide optional stats, sound controls and an endcard trigger for development previews.
4
+
5
+ Part of [Replayable](https://github.com/replayablejs/replayable) **0.1.0-alpha.0**.
6
+ APIs may change during the alpha series.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pnpm add @replayablejs/devtools@0.1.0-alpha.0
12
+ ```
13
+
14
+ ## Public surface
15
+
16
+ `createStats`, `createSoundControl`, `createEndCardTrigger` and their returned control types.
17
+
18
+ [Usage and reference](https://github.com/replayablejs/replayable/blob/main/docs/reference/devtools.md).
19
+ The package manifest defines supported import paths; internal source files are not public APIs.
20
+
21
+ ## Development
22
+
23
+ From the repository root, install with `pnpm install --frozen-lockfile` and build dependencies
24
+ with `pnpm build`. Run `pnpm --filter @replayablejs/devtools test` for this package's tests.
25
+
26
+ ## Peer dependencies
27
+
28
+ - `@replayablejs/runtime`: `workspace:*`
29
+
30
+ Workspace ranges are converted to package versions when packed.
31
+
32
+ ## License
33
+
34
+ Original code is [MIT licensed](https://github.com/replayablejs/replayable/blob/main/LICENSE). Bundled third-party resources retain
35
+ their accompanying license terms.
@@ -0,0 +1,12 @@
1
+ //#region src/stats/disabled-stats.ts
2
+ /** Shared inert controls: disabled stats allocate no DOM or subscriptions. */
3
+ const disabledStats = {
4
+ show: doNothing,
5
+ hide: doNothing,
6
+ destroy: doNothing
7
+ };
8
+ function doNothing() {}
9
+ //#endregion
10
+ export { disabledStats as t };
11
+
12
+ //# sourceMappingURL=disabled-stats-DrzL4cm1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled-stats-DrzL4cm1.js","names":[],"sources":["../src/stats/disabled-stats.ts"],"sourcesContent":["import type { Stats } from '#types/stats.js';\n\n/** Shared inert controls: disabled stats allocate no DOM or subscriptions. */\nexport const disabledStats: Stats = {\n show: doNothing,\n hide: doNothing,\n destroy: doNothing,\n};\n\nfunction doNothing(): void {}\n"],"mappings":";;AAGA,MAAa,gBAAuB;CAClC,MAAM;CACN,MAAM;CACN,SAAS;AACX;AAEA,SAAS,YAAkB,CAAC"}
@@ -0,0 +1,8 @@
1
+ //#region src/types/end-card-trigger.d.ts
2
+ /** Cleanup for the development-only skip shortcut and button. */
3
+ interface EndCardTrigger {
4
+ destroy(this: void): void;
5
+ }
6
+ //#endregion
7
+ export { EndCardTrigger as t };
8
+ //# sourceMappingURL=end-card-trigger-q4ww_XP2.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { t as EndCardTrigger } from "../end-card-trigger-q4ww_XP2.js";
2
+ //#region src/endcard-trigger/disabled.d.ts
3
+ /** Production imports no runtime, DOM, styles, or keyboard listeners. */
4
+ declare function createEndCardTrigger(): EndCardTrigger;
5
+ //#endregion
6
+ export { createEndCardTrigger };
7
+ //# sourceMappingURL=disabled.d.ts.map
@@ -0,0 +1,10 @@
1
+ //#region src/endcard-trigger/disabled.ts
2
+ const disabledTrigger = { destroy() {} };
3
+ /** Production imports no runtime, DOM, styles, or keyboard listeners. */
4
+ function createEndCardTrigger() {
5
+ return disabledTrigger;
6
+ }
7
+ //#endregion
8
+ export { createEndCardTrigger };
9
+
10
+ //# sourceMappingURL=disabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled.js","names":[],"sources":["../../src/endcard-trigger/disabled.ts"],"sourcesContent":["import type { EndCardTrigger } from '#types/end-card-trigger.js';\n\nconst disabledTrigger: EndCardTrigger = { destroy(): void {} };\n\n/** Production imports no runtime, DOM, styles, or keyboard listeners. */\nexport function createEndCardTrigger(): EndCardTrigger {\n return disabledTrigger;\n}\n"],"mappings":";AAEA,MAAM,kBAAkC,EAAE,UAAgB,CAAC,EAAE;;AAG7D,SAAgB,uBAAuC;CACrD,OAAO;AACT"}
@@ -0,0 +1,7 @@
1
+ import { t as EndCardTrigger } from "../end-card-trigger-q4ww_XP2.js";
2
+ //#region src/create-end-card-trigger.d.ts
3
+ /** Install after ready and scene creation, so skipping follows normal completion listeners. */
4
+ declare function createEndCardTrigger(): EndCardTrigger;
5
+ //#endregion
6
+ export { createEndCardTrigger };
7
+ //# sourceMappingURL=enabled.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { t as installDevtoolsInteraction } from "../install-devtools-interaction-1Flxw89C.js";
2
+ import { createEndCardTrigger as createEndCardTrigger$1 } from "./disabled.js";
3
+ import { playable } from "@replayablejs/runtime";
4
+ //#region src/endcard-trigger/skip-button.css?inline
5
+ var skip_button_default = ".replayable-skip{top:max(8px, env(safe-area-inset-top,0px));right:max(8px, env(safe-area-inset-right,0px));z-index:2147483647;color:#fff;appearance:none;cursor:pointer;touch-action:manipulation;-webkit-user-select:none;user-select:none;background:0 0;border:0;border-radius:50%;place-items:center;width:44px;height:44px;padding:0;display:grid;position:fixed}.replayable-skip:before{content:\"\";background:#0000008c;border:1px solid #ffffffa6;border-radius:50%;position:absolute;inset:8px;box-shadow:0 1px 4px #0003}.replayable-skip__arrow{background:currentColor;border-radius:1px;width:10px;height:2px;margin-right:4px;position:relative}.replayable-skip__arrow:before{content:\"\";background:currentColor;border-radius:1px;width:2px;height:12px;position:absolute;top:-5px;right:-5px}.replayable-skip__arrow:after{content:\"\";border-top:2px solid;border-right:2px solid;width:6px;height:6px;position:absolute;top:-3px;right:0;transform:rotate(45deg)}.replayable-skip:active:before{background:#000000bf}.replayable-skip:focus-visible{outline-offset:2px;outline:2px solid #fff}\n";
6
+ //#endregion
7
+ //#region src/endcard-trigger/create-skip-button.ts
8
+ /** DOM-only control, independent of stats, canvas, and the renderer. */
9
+ function createSkipButton(onSkip) {
10
+ const button = document.createElement("button");
11
+ button.type = "button";
12
+ button.className = "replayable-skip";
13
+ const arrow = document.createElement("span");
14
+ arrow.className = "replayable-skip__arrow";
15
+ arrow.setAttribute("aria-hidden", "true");
16
+ button.append(arrow);
17
+ button.title = "Skip to endcard (Escape)";
18
+ button.setAttribute("aria-label", "Skip to endcard");
19
+ button.setAttribute("role", "button");
20
+ const style = document.createElement("style");
21
+ style.textContent = skip_button_default;
22
+ document.head.append(style);
23
+ document.body.append(button);
24
+ const removeInteraction = installDevtoolsInteraction(button, onSkip);
25
+ return { destroy };
26
+ /** Remove capture listeners before detaching their target. */
27
+ function destroy() {
28
+ removeInteraction();
29
+ button.remove();
30
+ style.remove();
31
+ }
32
+ }
33
+ //#endregion
34
+ //#region src/create-end-card-trigger.ts
35
+ /** Install after ready and scene creation, so skipping follows normal completion listeners. */
36
+ function createEndCardTrigger() {
37
+ if (!playable.config.devtools.endCardTrigger) return createEndCardTrigger$1();
38
+ if (playable.state.completion !== void 0) return createEndCardTrigger$1();
39
+ const button = createSkipButton(skip);
40
+ const removeCompletion = playable.on("complete", destroy);
41
+ window.addEventListener("keydown", handleKeyDown, true);
42
+ let destroyed = false;
43
+ return { destroy };
44
+ /** Normal completion owns timers, scene transitions, and host notifications. */
45
+ function skip() {
46
+ if (!destroyed && playable.state.visible) playable.complete("skip");
47
+ }
48
+ /** Ignore held keys and text editing; this shortcut must not interfere with an editor. */
49
+ function handleKeyDown(event) {
50
+ const target = event.target;
51
+ if (event.key !== "Escape" || event.repeat || event.isComposing || event.ctrlKey || event.altKey || event.metaKey || event.shiftKey || target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select") !== null)) return;
52
+ event.preventDefault();
53
+ event.stopImmediatePropagation();
54
+ skip();
55
+ }
56
+ /** Completion removes both entry points; repeated explicit cleanup is safe. */
57
+ function destroy() {
58
+ if (destroyed) return;
59
+ destroyed = true;
60
+ window.removeEventListener("keydown", handleKeyDown, true);
61
+ removeCompletion();
62
+ button.destroy();
63
+ }
64
+ }
65
+ //#endregion
66
+ export { createEndCardTrigger };
67
+
68
+ //# sourceMappingURL=enabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enabled.js","names":["styles","createDisabledTrigger"],"sources":["../../src/endcard-trigger/skip-button.css?inline","../../src/endcard-trigger/create-skip-button.ts","../../src/create-end-card-trigger.ts"],"sourcesContent":[".replayable-skip {\n position: fixed;\n top: max(8px, env(safe-area-inset-top, 0px));\n right: max(8px, env(safe-area-inset-right, 0px));\n z-index: 2147483647;\n display: grid;\n place-items: center;\n width: 44px;\n height: 44px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: #ffffff;\n appearance: none;\n cursor: pointer;\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n}\n\n/* A compact visible circle inside a larger, forgiving touch target. */\n.replayable-skip::before {\n content: '';\n position: absolute;\n inset: 8px;\n border: 1px solid rgb(255 255 255 / 65%);\n border-radius: 50%;\n background: rgb(0 0 0 / 55%);\n box-shadow: 0 1px 4px rgb(0 0 0 / 20%);\n}\n\n.replayable-skip__arrow {\n position: relative;\n width: 10px;\n height: 2px;\n margin-right: 4px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.replayable-skip__arrow::before {\n content: '';\n position: absolute;\n top: -5px;\n right: -5px;\n width: 2px;\n height: 12px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.replayable-skip__arrow::after {\n content: '';\n position: absolute;\n top: -3px;\n right: 0;\n width: 6px;\n height: 6px;\n border-top: 2px solid currentColor;\n border-right: 2px solid currentColor;\n transform: rotate(45deg);\n}\n\n.replayable-skip:active::before {\n background: rgb(0 0 0 / 75%);\n}\n\n.replayable-skip:focus-visible {\n outline: 2px solid #ffffff;\n outline-offset: 2px;\n}\n","import type { EndCardTrigger } from '#types/end-card-trigger.js';\n\nimport { installDevtoolsInteraction } from '../interaction/install-devtools-interaction.js';\n\nimport styles from './skip-button.css?inline';\n\n/** DOM-only control, independent of stats, canvas, and the renderer. */\nexport function createSkipButton(onSkip: () => void): EndCardTrigger {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'replayable-skip';\n const arrow = document.createElement('span');\n arrow.className = 'replayable-skip__arrow';\n arrow.setAttribute('aria-hidden', 'true');\n button.append(arrow);\n button.title = 'Skip to endcard (Escape)';\n button.setAttribute('aria-label', 'Skip to endcard');\n button.setAttribute('role', 'button');\n const style = document.createElement('style');\n style.textContent = styles;\n document.head.append(style);\n document.body.append(button);\n const removeInteraction = installDevtoolsInteraction(button, onSkip);\n\n return { destroy };\n\n /** Remove capture listeners before detaching their target. */\n function destroy(): void {\n removeInteraction();\n button.remove();\n style.remove();\n }\n}\n","import { playable } from '@replayablejs/runtime';\n\nimport type { EndCardTrigger } from '#types/end-card-trigger.js';\n\nimport { createSkipButton } from './endcard-trigger/create-skip-button.js';\nimport { createEndCardTrigger as createDisabledTrigger } from './endcard-trigger/disabled.js';\n\n/** Install after ready and scene creation, so skipping follows normal completion listeners. */\nexport function createEndCardTrigger(): EndCardTrigger {\n if (!playable.config.devtools.endCardTrigger) {\n return createDisabledTrigger();\n }\n // The state getter enforces readiness before allocating DOM or subscriptions.\n const state = playable.state;\n if (state.completion !== undefined) {\n return createDisabledTrigger();\n }\n\n const button = createSkipButton(skip);\n const removeCompletion = playable.on('complete', destroy);\n window.addEventListener('keydown', handleKeyDown, true);\n let destroyed = false;\n\n return { destroy };\n\n /** Normal completion owns timers, scene transitions, and host notifications. */\n function skip(): void {\n if (!destroyed && playable.state.visible) {\n playable.complete('skip');\n }\n }\n\n /** Ignore held keys and text editing; this shortcut must not interfere with an editor. */\n function handleKeyDown(event: KeyboardEvent): void {\n const target = event.target;\n if (\n event.key !== 'Escape' ||\n event.repeat ||\n event.isComposing ||\n event.ctrlKey ||\n event.altKey ||\n event.metaKey ||\n event.shiftKey ||\n (target instanceof HTMLElement &&\n (target.isContentEditable || target.closest('input, textarea, select') !== null))\n ) {\n return;\n }\n event.preventDefault();\n event.stopImmediatePropagation();\n skip();\n }\n\n /** Completion removes both entry points; repeated explicit cleanup is safe. */\n function destroy(): void {\n if (destroyed) {\n return;\n }\n destroyed = true;\n window.removeEventListener('keydown', handleKeyDown, true);\n removeCompletion();\n button.destroy();\n }\n}\n"],"mappings":";;;;AAAA,IAAA,sBAAA;;;;ACOA,SAAgB,iBAAiB,QAAoC;CACnE,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,OAAO;CACd,OAAO,YAAY;CACnB,MAAM,QAAQ,SAAS,cAAc,MAAM;CAC3C,MAAM,YAAY;CAClB,MAAM,aAAa,eAAe,MAAM;CACxC,OAAO,OAAO,KAAK;CACnB,OAAO,QAAQ;CACf,OAAO,aAAa,cAAc,iBAAiB;CACnD,OAAO,aAAa,QAAQ,QAAQ;CACpC,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,cAAcA;CACpB,SAAS,KAAK,OAAO,KAAK;CAC1B,SAAS,KAAK,OAAO,MAAM;CAC3B,MAAM,oBAAoB,2BAA2B,QAAQ,MAAM;CAEnE,OAAO,EAAE,QAAQ;;CAGjB,SAAS,UAAgB;EACvB,kBAAkB;EAClB,OAAO,OAAO;EACd,MAAM,OAAO;CACf;AACF;;;;ACxBA,SAAgB,uBAAuC;CACrD,IAAI,CAAC,SAAS,OAAO,SAAS,gBAC5B,OAAOC,uBAAsB;CAI/B,IADc,SAAS,MACb,eAAe,KAAA,GACvB,OAAOA,uBAAsB;CAG/B,MAAM,SAAS,iBAAiB,IAAI;CACpC,MAAM,mBAAmB,SAAS,GAAG,YAAY,OAAO;CACxD,OAAO,iBAAiB,WAAW,eAAe,IAAI;CACtD,IAAI,YAAY;CAEhB,OAAO,EAAE,QAAQ;;CAGjB,SAAS,OAAa;EACpB,IAAI,CAAC,aAAa,SAAS,MAAM,SAC/B,SAAS,SAAS,MAAM;CAE5B;;CAGA,SAAS,cAAc,OAA4B;EACjD,MAAM,SAAS,MAAM;EACrB,IACE,MAAM,QAAQ,YACd,MAAM,UACN,MAAM,eACN,MAAM,WACN,MAAM,UACN,MAAM,WACN,MAAM,YACL,kBAAkB,gBAChB,OAAO,qBAAqB,OAAO,QAAQ,yBAAyB,MAAM,OAE7E;EAEF,MAAM,eAAe;EACrB,MAAM,yBAAyB;EAC/B,KAAK;CACP;;CAGA,SAAS,UAAgB;EACvB,IAAI,WACF;EAEF,YAAY;EACZ,OAAO,oBAAoB,WAAW,eAAe,IAAI;EACzD,iBAAiB;EACjB,OAAO,QAAQ;CACjB;AACF"}
@@ -0,0 +1,13 @@
1
+ import { t as EndCardTrigger } from "./end-card-trigger-q4ww_XP2.js";
2
+ import { t as SoundControl } from "./sound-control-D8U9dP87.js";
3
+ import { t as Stats } from "./stats-CMNxuMXo.js";
4
+ //#region src/index.d.ts
5
+ /** Creates development stats after playable readiness. */
6
+ declare const createStats: () => Stats;
7
+ /** Creates the optional development endcard trigger. */
8
+ declare const createEndCardTrigger: () => EndCardTrigger;
9
+ /** Creates the optional development sound control. */
10
+ declare const createSoundControl: () => SoundControl;
11
+ //#endregion
12
+ export { type EndCardTrigger, type SoundControl, type Stats, createEndCardTrigger, createSoundControl, createStats };
13
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import { createEndCardTrigger as createEndCardTrigger$1 } from "#endcard-trigger";
2
+ import { createSoundControl as createSoundControl$1 } from "#sound-control";
3
+ import { createStats as createStats$1 } from "#stats";
4
+ //#region src/index.ts
5
+ /**
6
+ * Optional renderer-independent development tools for Replayable playables.
7
+ *
8
+ * Tools allocate subscriptions and DOM only when explicitly created after
9
+ * await playable.ready(). The build pipeline selects disabled entries for production.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ /** Creates development stats after playable readiness. */
14
+ const createStats = createStats$1;
15
+ /** Creates the optional development endcard trigger. */
16
+ const createEndCardTrigger = createEndCardTrigger$1;
17
+ /** Creates the optional development sound control. */
18
+ const createSoundControl = createSoundControl$1;
19
+ //#endregion
20
+ export { createEndCardTrigger, createSoundControl, createStats };
21
+
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["selectedCreateStats","selectedCreateEndCardTrigger","selectedCreateSoundControl"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Optional renderer-independent development tools for Replayable playables.\n *\n * Tools allocate subscriptions and DOM only when explicitly created after\n * await playable.ready(). The build pipeline selects disabled entries for production.\n *\n * @packageDocumentation\n */\n\nimport { createEndCardTrigger as selectedCreateEndCardTrigger } from '#endcard-trigger';\nimport { createSoundControl as selectedCreateSoundControl } from '#sound-control';\nimport { createStats as selectedCreateStats } from '#stats';\nimport type { EndCardTrigger } from '#types/end-card-trigger.js';\nimport type { SoundControl } from '#types/sound-control.js';\nimport type { Stats } from '#types/stats.js';\n\n// Explicit public signatures keep build-only selection aliases out of emitted declarations.\n// The selected function references remain unchanged, preserving production tree-shaking.\n/** Creates development stats after playable readiness. */\nexport const createStats: () => Stats = selectedCreateStats;\n/** Creates the optional development endcard trigger. */\nexport const createEndCardTrigger: () => EndCardTrigger = selectedCreateEndCardTrigger;\n/** Creates the optional development sound control. */\nexport const createSoundControl: () => SoundControl = selectedCreateSoundControl;\nexport type { SoundControl, EndCardTrigger, Stats };\n"],"mappings":";;;;;;;;;;;;;AAmBA,MAAa,cAA2BA;;AAExC,MAAa,uBAA6CC;;AAE1D,MAAa,qBAAyCC"}
@@ -0,0 +1,61 @@
1
+ //#region src/interaction/install-devtools-interaction.ts
2
+ /** Includes compatibility mouse events so a touch cannot leak into gameplay twice. */
3
+ const DEVTOOLS_INPUT_EVENTS = [
4
+ "pointerdown",
5
+ "pointermove",
6
+ "pointerup",
7
+ "pointercancel",
8
+ "mousedown",
9
+ "mousemove",
10
+ "mouseup",
11
+ "touchstart",
12
+ "touchmove",
13
+ "touchend",
14
+ "touchcancel",
15
+ "click",
16
+ "dblclick",
17
+ "contextmenu",
18
+ "keydown",
19
+ "keyup"
20
+ ];
21
+ /**
22
+ * Keeps development-control input out of gameplay. Runtime observes document capture,
23
+ * so interception must happen earlier, at window capture—not on the card.
24
+ * Only events whose composed path contains this shell are intercepted.
25
+ */
26
+ function installDevtoolsInteraction(shell, onActivate) {
27
+ for (const event of DEVTOOLS_INPUT_EVENTS) window.addEventListener(event, handleInput, {
28
+ capture: true,
29
+ passive: false
30
+ });
31
+ return removeListeners;
32
+ /** Removes the same handlers and capture registrations installed by this instance. */
33
+ function removeListeners() {
34
+ for (const event of DEVTOOLS_INPUT_EVENTS) window.removeEventListener(event, handleInput, true);
35
+ }
36
+ /** Stops gameplay propagation, then applies only the matching control action. */
37
+ function handleInput(event) {
38
+ if (!shouldIntercept(event)) return;
39
+ if (event instanceof KeyboardEvent && event.key === "Escape") return;
40
+ event.stopImmediatePropagation();
41
+ if (event.type === "click") {
42
+ event.preventDefault();
43
+ onActivate();
44
+ } else if (event instanceof KeyboardEvent) handleKeyboardInput(event);
45
+ else if (event.type === "contextmenu") event.preventDefault();
46
+ }
47
+ /** Hidden or unavailable shells must not intercept input, nor may events outside this shell. */
48
+ function shouldIntercept(event) {
49
+ return !shell.hidden && shell.hasAttribute("role") && event.composedPath().includes(shell);
50
+ }
51
+ /** Enter and Space activate once per press; keyup and repeats must not activate again. */
52
+ function handleKeyboardInput(event) {
53
+ if (event.key !== "Enter" && event.key !== " ") return;
54
+ event.preventDefault();
55
+ if (event.type === "keydown" && !event.repeat) onActivate();
56
+ }
57
+ }
58
+ //#endregion
59
+ export { installDevtoolsInteraction as t };
60
+
61
+ //# sourceMappingURL=install-devtools-interaction-1Flxw89C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-devtools-interaction-1Flxw89C.js","names":[],"sources":["../src/interaction/install-devtools-interaction.ts"],"sourcesContent":["/** Includes compatibility mouse events so a touch cannot leak into gameplay twice. */\nconst DEVTOOLS_INPUT_EVENTS = [\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointercancel',\n 'mousedown',\n 'mousemove',\n 'mouseup',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'click',\n 'dblclick',\n 'contextmenu',\n 'keydown',\n 'keyup',\n] as const;\n\n/**\n * Keeps development-control input out of gameplay. Runtime observes document capture,\n * so interception must happen earlier, at window capture—not on the card.\n * Only events whose composed path contains this shell are intercepted.\n */\nexport function installDevtoolsInteraction(shell: HTMLElement, onActivate: () => void): () => void {\n for (const event of DEVTOOLS_INPUT_EVENTS) {\n window.addEventListener(event, handleInput, { capture: true, passive: false });\n }\n\n return removeListeners;\n\n /** Removes the same handlers and capture registrations installed by this instance. */\n function removeListeners(): void {\n for (const event of DEVTOOLS_INPUT_EVENTS) {\n window.removeEventListener(event, handleInput, true);\n }\n }\n\n /** Stops gameplay propagation, then applies only the matching control action. */\n function handleInput(event: Event): void {\n if (!shouldIntercept(event)) {\n return;\n }\n // Let the global development Escape shortcut work while a control is focused.\n if (event instanceof KeyboardEvent && event.key === 'Escape') {\n return;\n }\n event.stopImmediatePropagation();\n\n // Do not cancel touchstart/pointerdown: the browser must still produce the\n // click for a tap. Activating on click avoids counting its compatibility mouse\n // events as additional taps. CSS touch-action prevents scrolling here.\n if (event.type === 'click') {\n event.preventDefault();\n onActivate();\n } else if (event instanceof KeyboardEvent) {\n handleKeyboardInput(event);\n } else if (event.type === 'contextmenu') {\n event.preventDefault();\n }\n }\n\n /** Hidden or unavailable shells must not intercept input, nor may events outside this shell. */\n function shouldIntercept(event: Event): boolean {\n return !shell.hidden && shell.hasAttribute('role') && event.composedPath().includes(shell);\n }\n\n /** Enter and Space activate once per press; keyup and repeats must not activate again. */\n function handleKeyboardInput(event: KeyboardEvent): void {\n if (event.key !== 'Enter' && event.key !== ' ') {\n return;\n }\n\n event.preventDefault();\n if (event.type === 'keydown' && !event.repeat) {\n onActivate();\n }\n }\n}\n"],"mappings":";;AACA,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAOA,SAAgB,2BAA2B,OAAoB,YAAoC;CACjG,KAAK,MAAM,SAAS,uBAClB,OAAO,iBAAiB,OAAO,aAAa;EAAE,SAAS;EAAM,SAAS;CAAM,CAAC;CAG/E,OAAO;;CAGP,SAAS,kBAAwB;EAC/B,KAAK,MAAM,SAAS,uBAClB,OAAO,oBAAoB,OAAO,aAAa,IAAI;CAEvD;;CAGA,SAAS,YAAY,OAAoB;EACvC,IAAI,CAAC,gBAAgB,KAAK,GACxB;EAGF,IAAI,iBAAiB,iBAAiB,MAAM,QAAQ,UAClD;EAEF,MAAM,yBAAyB;EAK/B,IAAI,MAAM,SAAS,SAAS;GAC1B,MAAM,eAAe;GACrB,WAAW;EACb,OAAO,IAAI,iBAAiB,eAC1B,oBAAoB,KAAK;OACpB,IAAI,MAAM,SAAS,eACxB,MAAM,eAAe;CAEzB;;CAGA,SAAS,gBAAgB,OAAuB;EAC9C,OAAO,CAAC,MAAM,UAAU,MAAM,aAAa,MAAM,KAAK,MAAM,aAAa,CAAC,CAAC,SAAS,KAAK;CAC3F;;CAGA,SAAS,oBAAoB,OAA4B;EACvD,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KACzC;EAGF,MAAM,eAAe;EACrB,IAAI,MAAM,SAAS,aAAa,CAAC,MAAM,QACrC,WAAW;CAEf;AACF"}
@@ -0,0 +1,7 @@
1
+ import { t as SoundControl } from "../sound-control-D8U9dP87.js";
2
+ //#region src/sound-control/disabled.d.ts
3
+ /** Production never loads the control's UI, icons, or runtime subscriptions. */
4
+ declare function createSoundControl(): SoundControl;
5
+ //#endregion
6
+ export { createSoundControl };
7
+ //# sourceMappingURL=disabled.d.ts.map
@@ -0,0 +1,10 @@
1
+ //#region src/sound-control/disabled.ts
2
+ const disabledSoundControl = { destroy() {} };
3
+ /** Production never loads the control's UI, icons, or runtime subscriptions. */
4
+ function createSoundControl() {
5
+ return disabledSoundControl;
6
+ }
7
+ //#endregion
8
+ export { createSoundControl };
9
+
10
+ //# sourceMappingURL=disabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled.js","names":[],"sources":["../../src/sound-control/disabled.ts"],"sourcesContent":["import type { SoundControl } from '#types/sound-control.js';\n\nconst disabledSoundControl: SoundControl = { destroy(): void {} };\n\n/** Production never loads the control's UI, icons, or runtime subscriptions. */\nexport function createSoundControl(): SoundControl {\n return disabledSoundControl;\n}\n"],"mappings":";AAEA,MAAM,uBAAqC,EAAE,UAAgB,CAAC,EAAE;;AAGhE,SAAgB,qBAAmC;CACjD,OAAO;AACT"}
@@ -0,0 +1,7 @@
1
+ import { t as SoundControl } from "../sound-control-D8U9dP87.js";
2
+ //#region src/create-sound-control.d.ts
3
+ /** Creates a development-only audio toggle after await playable.ready(). */
4
+ declare function createSoundControl(): SoundControl;
5
+ //#endregion
6
+ export { createSoundControl };
7
+ //# sourceMappingURL=enabled.d.ts.map
@@ -0,0 +1,91 @@
1
+ import { t as installDevtoolsInteraction } from "../install-devtools-interaction-1Flxw89C.js";
2
+ import { createSoundControl as createSoundControl$1 } from "./disabled.js";
3
+ import { playable } from "@replayablejs/runtime";
4
+ //#region src/sound-control/assets/sound-off.png
5
+ var sound_off_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAB2BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIj4KICAgICAgICAgPHBob3Rvc2hvcDpJQ0NQcm9maWxlPnNSR0IgSUVDNjE5NjYtMi4xPC9waG90b3Nob3A6SUNDUHJvZmlsZT4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxOC0xMS0yMFQxMTozNToyOCswMjowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTgtMTEtMjBUMTE6MzE6NTUrMDI6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxOC0xMS0yMFQxMTozNToyOCswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3BuZzwvZGM6Zm9ybWF0PgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6OWY0ZWUxZjAtZWI0My03YzRhLTgyNzItMzBmZWFhZjU0YWU2PC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTgtMTEtMjBUMTE6MzE6NTUrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6OWY0ZWUxZjAtZWI0My03YzRhLTgyNzItMzBmZWFhZjU0YWU2PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNyZWF0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8eG1wTU06SW5zdGFuY2VJRD54bXAuaWlkOjlmNGVlMWYwLWViNDMtN2M0YS04MjcyLTMwZmVhYWY1NGFlNjwveG1wTU06SW5zdGFu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";
6
+ //#endregion
7
+ //#region src/sound-control/assets/sound-on.png
8
+ var sound_on_default = "data:image/png;base64,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";
9
+ //#endregion
10
+ //#region src/sound-control/sound-button.css?inline
11
+ var sound_button_default = ".replayable-sound{z-index:2147483647;appearance:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;cursor:pointer;touch-action:manipulation;-webkit-user-select:none;user-select:none;background:0 0;border:0;border-radius:50%;place-items:center;width:max(44px,8vmin);height:max(44px,8vmin);padding:0;display:grid;position:fixed;bottom:1vmin;right:1vmin}.replayable-sound[hidden]{display:none}.replayable-sound img{pointer-events:none;width:8vmin;height:8vmin;display:block}.replayable-sound:active img{scale:.94}.replayable-sound:focus-visible{outline-offset:2px;outline:2px solid #fff}\n";
12
+ //#endregion
13
+ //#region src/sound-control/create-sound-button.ts
14
+ /** Mounts renderer-independent UI with the examples' existing sound artwork. */
15
+ function createSoundButton(onToggle) {
16
+ const button = document.createElement("button");
17
+ button.type = "button";
18
+ button.className = "replayable-sound";
19
+ button.setAttribute("role", "button");
20
+ const icon = document.createElement("img");
21
+ icon.alt = "";
22
+ icon.draggable = false;
23
+ button.append(icon);
24
+ const style = document.createElement("style");
25
+ style.textContent = sound_button_default;
26
+ document.head.append(style);
27
+ document.body.append(button);
28
+ const removeInteraction = installDevtoolsInteraction(button, onToggle);
29
+ return {
30
+ update,
31
+ setVisible,
32
+ destroy
33
+ };
34
+ /** Keep the icon and accessible action synchronized without replacing the image node. */
35
+ function update(muted) {
36
+ icon.src = muted ? sound_off_default : sound_on_default;
37
+ button.setAttribute("aria-pressed", String(muted));
38
+ button.setAttribute("aria-label", muted ? "Unmute sound" : "Mute sound");
39
+ button.title = muted ? "Unmute sound" : "Mute sound";
40
+ }
41
+ function setVisible(visible) {
42
+ button.hidden = !visible;
43
+ }
44
+ /** Remove capture listeners before detaching their target. */
45
+ function destroy() {
46
+ removeInteraction();
47
+ button.remove();
48
+ style.remove();
49
+ }
50
+ }
51
+ //#endregion
52
+ //#region src/create-sound-control.ts
53
+ /** Creates a development-only audio toggle after await playable.ready(). */
54
+ function createSoundControl() {
55
+ if (!playable.config.devtools.soundControl || !playable.config.audio) return createSoundControl$1();
56
+ const { visible } = playable.state;
57
+ const button = createSoundButton(toggleSound);
58
+ button.update(playable.audio.muted);
59
+ button.setVisible(visible);
60
+ const removeAudioListener = playable.on("audiochange", handleAudioChange);
61
+ const removeVisibilityListener = playable.on("visibilitychange", handleVisibilityChange);
62
+ let destroyed = false;
63
+ return { destroy };
64
+ /** Synchronous on the trusted click; never overrides host permission or queues sound. */
65
+ function toggleSound() {
66
+ if (!destroyed && playable.state.visible) {
67
+ playable.audio.setMuted(!playable.audio.muted);
68
+ handleAudioChange();
69
+ }
70
+ }
71
+ /** Show the user's mute preference, not temporary host restrictions or loading state. */
72
+ function handleAudioChange() {
73
+ button.update(playable.audio.muted);
74
+ }
75
+ /** Keep the control available on the endcard, but not while the playable is hidden. */
76
+ function handleVisibilityChange() {
77
+ button.setVisible(playable.state.visible);
78
+ }
79
+ /** Unsubscribe before detaching DOM; repeated cleanup is harmless. */
80
+ function destroy() {
81
+ if (destroyed) return;
82
+ destroyed = true;
83
+ removeAudioListener();
84
+ removeVisibilityListener();
85
+ button.destroy();
86
+ }
87
+ }
88
+ //#endregion
89
+ export { createSoundControl };
90
+
91
+ //# sourceMappingURL=enabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enabled.js","names":["styles","soundOff","soundOn","createDisabledControl"],"sources":["../../src/sound-control/assets/sound-off.png","../../src/sound-control/assets/sound-on.png","../../src/sound-control/sound-button.css?inline","../../src/sound-control/create-sound-button.ts","../../src/create-sound-control.ts"],"sourcesContent":["\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAB2BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIj4KICAgICAgICAgPHBob3Rvc2hvcDpJQ0NQcm9maWxlPnNSR0IgSUVDNjE5NjYtMi4xPC9waG90b3Nob3A6SUNDUHJvZmlsZT4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxOC0xMS0yMFQxMTozNToyOCswMjowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTgtMTEtMjBUMTE6MzE6NTUrMDI6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxOC0xMS0yMFQxMTozNToyOCswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3BuZzwvZGM6Zm9ybWF0PgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6OWY0ZWUxZjAtZWI0My03YzRhLTgyNzItMzBmZWFhZjU0YWU2PC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTgtMTEtMjBUMTE6MzE6NTUrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6OWY0ZWUxZjAtZWI0My03YzRhLTgyNzItMzBmZWFhZjU0YWU2PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNyZWF0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8eG1wTU06SW5zdGFuY2VJRD54bXAuaWlkOjlmNGVlMWYwLWViNDMtN2M0YS04MjcyLTMwZmVhYWY1NGFlNjwveG1wTU06SW5zdGFu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\"","\"data:image/png;base64,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\"",".replayable-sound {\n position: fixed;\n right: 1vmin;\n bottom: 1vmin;\n z-index: 2147483647;\n display: grid;\n place-items: center;\n width: max(44px, 8vmin);\n height: max(44px, 8vmin);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n appearance: none;\n /* Devtools mounts outside the runtime shell and owns its browser interaction styling. */\n -webkit-tap-highlight-color: transparent;\n -webkit-touch-callout: none;\n cursor: pointer;\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.replayable-sound[hidden] {\n display: none;\n}\n\n.replayable-sound img {\n display: block;\n width: 8vmin;\n height: 8vmin;\n pointer-events: none;\n}\n\n.replayable-sound:active img {\n scale: 0.94;\n}\n\n.replayable-sound:focus-visible {\n outline: 2px solid #ffffff;\n outline-offset: 2px;\n}\n","import type { SoundButton } from '#types/sound-button.js';\n\nimport { installDevtoolsInteraction } from '../interaction/install-devtools-interaction.js';\nimport soundOff from './assets/sound-off.png';\nimport soundOn from './assets/sound-on.png';\n\nimport styles from './sound-button.css?inline';\n\n/** Mounts renderer-independent UI with the examples' existing sound artwork. */\nexport function createSoundButton(onToggle: () => void): SoundButton {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'replayable-sound';\n button.setAttribute('role', 'button');\n const icon = document.createElement('img');\n icon.alt = '';\n icon.draggable = false;\n button.append(icon);\n const style = document.createElement('style');\n style.textContent = styles;\n document.head.append(style);\n document.body.append(button);\n const removeInteraction = installDevtoolsInteraction(button, onToggle);\n\n return { update, setVisible, destroy };\n\n /** Keep the icon and accessible action synchronized without replacing the image node. */\n function update(muted: boolean): void {\n icon.src = muted ? soundOff : soundOn;\n button.setAttribute('aria-pressed', String(muted));\n button.setAttribute('aria-label', muted ? 'Unmute sound' : 'Mute sound');\n button.title = muted ? 'Unmute sound' : 'Mute sound';\n }\n\n function setVisible(visible: boolean): void {\n button.hidden = !visible;\n }\n\n /** Remove capture listeners before detaching their target. */\n function destroy(): void {\n removeInteraction();\n button.remove();\n style.remove();\n }\n}\n","import { playable } from '@replayablejs/runtime';\n\nimport type { SoundControl } from '#types/sound-control.js';\n\nimport { createSoundButton } from './sound-control/create-sound-button.js';\nimport { createSoundControl as createDisabledControl } from './sound-control/disabled.js';\n\n/** Creates a development-only audio toggle after await playable.ready(). */\nexport function createSoundControl(): SoundControl {\n if (!playable.config.devtools.soundControl || !playable.config.audio) {\n return createDisabledControl();\n }\n\n // Enforce readiness before allocating DOM or subscriptions.\n const { visible } = playable.state;\n const button = createSoundButton(toggleSound);\n button.update(playable.audio.muted);\n button.setVisible(visible);\n const removeAudioListener = playable.on('audiochange', handleAudioChange);\n const removeVisibilityListener = playable.on('visibilitychange', handleVisibilityChange);\n let destroyed = false;\n\n return { destroy };\n\n /** Synchronous on the trusted click; never overrides host permission or queues sound. */\n function toggleSound(): void {\n if (!destroyed && playable.state.visible) {\n playable.audio.setMuted(!playable.audio.muted);\n // setMuted changes the user preference; audiochange reports host audio state.\n handleAudioChange();\n }\n }\n\n /** Show the user's mute preference, not temporary host restrictions or loading state. */\n function handleAudioChange(): void {\n button.update(playable.audio.muted);\n }\n\n /** Keep the control available on the endcard, but not while the playable is hidden. */\n function handleVisibilityChange(): void {\n button.setVisible(playable.state.visible);\n }\n\n /** Unsubscribe before detaching DOM; repeated cleanup is harmless. */\n function destroy(): void {\n if (destroyed) {\n return;\n }\n destroyed = true;\n removeAudioListener();\n removeVisibilityListener();\n button.destroy();\n }\n}\n"],"mappings":";;;;AAAA,IAAA,oBAAA;;;ACAA,IAAA,mBAAA;;;ACAA,IAAA,uBAAA;;;;ACSA,SAAgB,kBAAkB,UAAmC;CACnE,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,OAAO;CACd,OAAO,YAAY;CACnB,OAAO,aAAa,QAAQ,QAAQ;CACpC,MAAM,OAAO,SAAS,cAAc,KAAK;CACzC,KAAK,MAAM;CACX,KAAK,YAAY;CACjB,OAAO,OAAO,IAAI;CAClB,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,cAAcA;CACpB,SAAS,KAAK,OAAO,KAAK;CAC1B,SAAS,KAAK,OAAO,MAAM;CAC3B,MAAM,oBAAoB,2BAA2B,QAAQ,QAAQ;CAErE,OAAO;EAAE;EAAQ;EAAY;CAAQ;;CAGrC,SAAS,OAAO,OAAsB;EACpC,KAAK,MAAM,QAAQC,oBAAWC;EAC9B,OAAO,aAAa,gBAAgB,OAAO,KAAK,CAAC;EACjD,OAAO,aAAa,cAAc,QAAQ,iBAAiB,YAAY;EACvE,OAAO,QAAQ,QAAQ,iBAAiB;CAC1C;CAEA,SAAS,WAAW,SAAwB;EAC1C,OAAO,SAAS,CAAC;CACnB;;CAGA,SAAS,UAAgB;EACvB,kBAAkB;EAClB,OAAO,OAAO;EACd,MAAM,OAAO;CACf;AACF;;;;ACpCA,SAAgB,qBAAmC;CACjD,IAAI,CAAC,SAAS,OAAO,SAAS,gBAAgB,CAAC,SAAS,OAAO,OAC7D,OAAOC,qBAAsB;CAI/B,MAAM,EAAE,YAAY,SAAS;CAC7B,MAAM,SAAS,kBAAkB,WAAW;CAC5C,OAAO,OAAO,SAAS,MAAM,KAAK;CAClC,OAAO,WAAW,OAAO;CACzB,MAAM,sBAAsB,SAAS,GAAG,eAAe,iBAAiB;CACxE,MAAM,2BAA2B,SAAS,GAAG,oBAAoB,sBAAsB;CACvF,IAAI,YAAY;CAEhB,OAAO,EAAE,QAAQ;;CAGjB,SAAS,cAAoB;EAC3B,IAAI,CAAC,aAAa,SAAS,MAAM,SAAS;GACxC,SAAS,MAAM,SAAS,CAAC,SAAS,MAAM,KAAK;GAE7C,kBAAkB;EACpB;CACF;;CAGA,SAAS,oBAA0B;EACjC,OAAO,OAAO,SAAS,MAAM,KAAK;CACpC;;CAGA,SAAS,yBAA+B;EACtC,OAAO,WAAW,SAAS,MAAM,OAAO;CAC1C;;CAGA,SAAS,UAAgB;EACvB,IAAI,WACF;EAEF,YAAY;EACZ,oBAAoB;EACpB,yBAAyB;EACzB,OAAO,QAAQ;CACjB;AACF"}
@@ -0,0 +1,9 @@
1
+ //#region src/types/sound-control.d.ts
2
+ /** Development audio toggle. Runtime retains ownership of the mute preference. */
3
+ interface SoundControl {
4
+ /** Removes the button, styles, and runtime/input subscriptions. Safe to call again. */
5
+ destroy(): void;
6
+ }
7
+ //#endregion
8
+ export { SoundControl as t };
9
+ //# sourceMappingURL=sound-control-D8U9dP87.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { t as Stats } from "../stats-CMNxuMXo.js";
2
+ //#region src/stats/create-disabled-stats.d.ts
3
+ /** Disabled entry imports no runtime, measurement, presentation, or graph dependencies. */
4
+ declare function createStats(): Stats;
5
+ //#endregion
6
+ export { createStats };
7
+ //# sourceMappingURL=disabled.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { t as disabledStats } from "../disabled-stats-DrzL4cm1.js";
2
+ //#region src/stats/create-disabled-stats.ts
3
+ /** Disabled entry imports no runtime, measurement, presentation, or graph dependencies. */
4
+ function createStats() {
5
+ return disabledStats;
6
+ }
7
+ //#endregion
8
+ export { createStats };
9
+
10
+ //# sourceMappingURL=disabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled.js","names":[],"sources":["../../src/stats/create-disabled-stats.ts"],"sourcesContent":["import type { Stats } from '#types/stats.js';\n\nimport { disabledStats } from './disabled-stats.js';\n\n/** Disabled entry imports no runtime, measurement, presentation, or graph dependencies. */\nexport function createStats(): Stats {\n return disabledStats;\n}\n"],"mappings":";;;AAKA,SAAgB,cAAqB;CACnC,OAAO;AACT"}
@@ -0,0 +1,7 @@
1
+ import { t as Stats } from "../stats-CMNxuMXo.js";
2
+ //#region src/create-stats.d.ts
3
+ /** Creates optional development stats after await playable.ready(). */
4
+ declare function createStats(): Stats;
5
+ //#endregion
6
+ export { createStats };
7
+ //# sourceMappingURL=enabled.d.ts.map