@zylem/game-lib 0.8.9 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +7 -1
  2. package/dist/api/game-lib.api.json +37952 -19547
  3. package/dist/api/game-lib.api.md +1302 -7
  4. package/dist/api/game-lib.d.ts +1696 -3
  5. package/dist/api/game-lib.typedoc.json +174596 -76562
  6. package/dist/audio.d.ts +193 -1
  7. package/dist/audio.js +1 -1
  8. package/dist/bridge.d.ts +17 -2
  9. package/dist/bridge.js +1 -1
  10. package/dist/catalog.js +1 -1
  11. package/dist/chunk-2PFNNGTV.js +1 -0
  12. package/dist/chunk-2XMG3NJS.js +1 -0
  13. package/dist/chunk-4CZZZCFB.js +9 -0
  14. package/dist/chunk-7CBJKE42.js +1 -0
  15. package/dist/{chunk-CBUQBP2U.js → chunk-BQRMYLYD.js} +1 -1
  16. package/dist/chunk-FZNEWOC5.js +1 -0
  17. package/dist/chunk-GPCSX3M6.js +1 -0
  18. package/dist/chunk-K3NNXZIJ.js +1 -0
  19. package/dist/{chunk-JNFFTNMH.js → chunk-KSEP7AUF.js} +1 -1
  20. package/dist/{chunk-7JSZEEAE.js → chunk-LI43BZQN.js} +1 -1
  21. package/dist/chunk-NVVLLWIM.js +1 -0
  22. package/dist/chunk-QGIYILYI.js +1 -0
  23. package/dist/chunk-SHDHPDOV.js +24 -0
  24. package/dist/chunk-STVEILJJ.js +1 -0
  25. package/dist/chunk-SWDNK4GG.js +1 -0
  26. package/dist/chunk-UUOPT2N4.js +1 -0
  27. package/dist/chunk-VMXSE3EC.js +0 -0
  28. package/dist/{chunk-EYDC2PMO.js → chunk-VSFULLND.js} +1 -1
  29. package/dist/chunk-YNX3Q3CL.js +1 -0
  30. package/dist/chunk-ZZO4CKRU.js +1 -0
  31. package/dist/cinematics.d.ts +279 -0
  32. package/dist/cinematics.js +1 -0
  33. package/dist/core.d.ts +124 -10
  34. package/dist/core.js +1 -1
  35. package/dist/cutscene-definition-C479fkei.d.ts +509 -0
  36. package/dist/debug.d.ts +1 -0
  37. package/dist/debug.js +1 -1
  38. package/dist/{entity-type-map-D6BeAdvg.d.ts → entity-type-map-CrsrKT8c.d.ts} +12 -3
  39. package/dist/entity.d.ts +2 -1
  40. package/dist/entity.js +1 -1
  41. package/dist/game-D8KTP3fD.d.ts +652 -0
  42. package/dist/game-default-JV3Q6JAL.js +1 -0
  43. package/dist/graphics.d.ts +1 -1
  44. package/dist/graphics.js +1 -1
  45. package/dist/public.d.ts +12 -6
  46. package/dist/public.js +1 -1
  47. package/dist/schema/cutscene.schema.json +782 -0
  48. package/dist/schema/song.schema.json +430 -0
  49. package/dist/schema.d.ts +2 -0
  50. package/dist/schema.js +1 -1
  51. package/dist/selection-bounds-BKmSo9aG.d.ts +50 -0
  52. package/dist/song-definition-rEKksP0B.d.ts +263 -0
  53. package/dist/song-player-7QPLFLAS.js +1 -0
  54. package/dist/{game-DyKbOeck.d.ts → stage-CAPlk_cN.d.ts} +146 -647
  55. package/dist/web-components.d.ts +5 -3
  56. package/dist/web-components.js +1 -1
  57. package/dist/{zylem-camera-DZTpPOiD.d.ts → zylem-camera-CYDtrVgi.d.ts} +134 -102
  58. package/package.json +11 -4
  59. package/dist/chunk-34MYRTRP.js +0 -9
  60. package/dist/chunk-AXJTUVGC.js +0 -24
  61. package/dist/chunk-BWOZF5YK.js +0 -1
  62. package/dist/chunk-EVMLNMGU.js +0 -1
  63. package/dist/chunk-G3TBBZUI.js +0 -1
  64. package/dist/chunk-J6KD2G6F.js +0 -1
  65. package/dist/chunk-X7T7QRYP.js +0 -1
  66. package/dist/chunk-YVWDCZNT.js +0 -1
  67. package/dist/chunk-ZRT3ZQVH.js +0 -1
  68. package/dist/game-default-6YXFFZ2Q.js +0 -1
  69. /package/dist/{chunk-MSCVL5OK.js → chunk-ELQN62PQ.js} +0 -0
@@ -1,11 +1,12 @@
1
- import { G as Game, D as DeviceProfile } from './game-DyKbOeck.js';
1
+ import { G as Game, D as DeviceProfile } from './game-D8KTP3fD.js';
2
2
  import { v as DebugTools } from './debug-state-Cg3f5FB6.js';
3
3
  import './base-node-life-cycle-BK9xebT9.js';
4
4
  import 'three';
5
5
  import './stage-transition-CmGpV4tc.js';
6
6
  import './game-interfaces-vF5sRi1n.js';
7
7
  import './base-node-idopiSw5.js';
8
- import './entity-type-map-D6BeAdvg.js';
8
+ import './stage-CAPlk_cN.js';
9
+ import './entity-type-map-CrsrKT8c.js';
9
10
  import './entity-XqvuWgPm.js';
10
11
  import '@zylem/behaviors/core';
11
12
  import './simulation-body-zQw-emOr.js';
@@ -15,10 +16,11 @@ import 'three/webgpu';
15
16
  import './collision-builder-BckxkdmA.js';
16
17
  import './events.js';
17
18
  import 'mitt';
19
+ import './selection-bounds-BKmSo9aG.js';
18
20
  import './entity-BIf_a4dl.js';
19
21
  import '@zylem/behaviors/particle-emitter';
20
22
  import 'three/addons/lines/webgpu/Line2.js';
21
- import './zylem-camera-DZTpPOiD.js';
23
+ import './zylem-camera-CYDtrVgi.js';
22
24
  import '@zylem/bridge';
23
25
  import './default-controls-CAKJ5zlo.js';
24
26
 
@@ -1 +1 @@
1
- import{a}from"./chunk-34MYRTRP.js";import"./chunk-EVMLNMGU.js";import"./chunk-WOT6VMZA.js";export{a as ZylemGameElement};
1
+ import{a}from"./chunk-4CZZZCFB.js";import"./chunk-GPCSX3M6.js";import"./chunk-WOT6VMZA.js";export{a as ZylemGameElement};
@@ -1,11 +1,120 @@
1
- import { Object3D, Vector2, Scene, Camera, Vector3, Quaternion, RenderTarget, Texture } from 'three';
1
+ import { Vector3, Quaternion, Object3D, Vector2, Scene, Camera, RenderTarget, Texture } from 'three';
2
2
  import { S as StageEntity } from './entity-BIf_a4dl.js';
3
3
  import { WebGPURenderer, RenderPipeline } from 'three/webgpu';
4
4
  import { R as ResolvedStageTransition } from './stage-transition-CmGpV4tc.js';
5
5
 
6
+ /**
7
+ * Represents a full camera pose: position, rotation, projection params, and optional lookAt.
8
+ * This is the canonical data structure that flows through the camera pipeline.
9
+ */
10
+ interface CameraPose {
11
+ position: Vector3;
12
+ rotation: Quaternion;
13
+ fov?: number;
14
+ zoom?: number;
15
+ near?: number;
16
+ far?: number;
17
+ /** When set, the camera orients to look at this point (takes priority over rotation). */
18
+ lookAt?: Vector3;
19
+ }
20
+ /**
21
+ * An additive delta applied on top of a CameraPose.
22
+ * Used by CameraActions to apply transient offsets (shake, recoil, etc.).
23
+ */
24
+ interface PoseDelta {
25
+ position?: Vector3;
26
+ rotation?: Quaternion;
27
+ fov?: number;
28
+ zoom?: number;
29
+ }
30
+ /**
31
+ * Minimal transform representation for pipeline targets.
32
+ */
33
+ interface TransformLike {
34
+ position: Vector3;
35
+ rotation?: Quaternion;
36
+ }
37
+ /**
38
+ * Per-frame context passed to every pipeline module (perspectives, behaviors, actions).
39
+ */
40
+ interface CameraContext {
41
+ /** Frame delta time in seconds. */
42
+ dt: number;
43
+ /** Elapsed time in seconds since camera started updating. */
44
+ time: number;
45
+ /** Current viewport dimensions and aspect ratio. */
46
+ viewport: {
47
+ width: number;
48
+ height: number;
49
+ aspect: number;
50
+ };
51
+ /** Named targets the camera can track. 'primary' is targets[0] by convention. */
52
+ targets: Record<string, TransformLike>;
53
+ }
54
+ /** Which Three.js camera a perspective commits onto. */
55
+ type CameraProjection = 'perspective' | 'orthographic';
56
+ /**
57
+ * A perspective produces the base camera pose each frame.
58
+ * Exactly one perspective is active per camera at a time.
59
+ */
60
+ interface CameraPerspective {
61
+ id: string;
62
+ /**
63
+ * Projection the Three.js camera must use. When omitted, the runtime keeps
64
+ * a perspective camera. Orthographic perspectives set this so a runtime
65
+ * switch replaces the camera instance.
66
+ */
67
+ projection?: CameraProjection;
68
+ /** Compute the raw desired pose for this frame given the current context. */
69
+ getBasePose(ctx: CameraContext): CameraPose;
70
+ /** Optional defaults for smoothing and other pipeline settings. */
71
+ defaults?: {
72
+ damping?: number;
73
+ };
74
+ }
75
+ /**
76
+ * Behaviors modify the desired pose each frame.
77
+ * They are keyed by name (idempotent add) and sorted by priority.
78
+ */
79
+ interface CameraBehavior {
80
+ /** Receive current context and pose, return a modified pose. */
81
+ update(ctx: CameraContext, pose: CameraPose): CameraPose;
82
+ /** Called when the behavior is attached to the pipeline. */
83
+ onAttach?(ctx: CameraContext): void;
84
+ /** Called when the behavior is removed from the pipeline. */
85
+ onDetach?(ctx: CameraContext): void;
86
+ /** Sort order: lower runs first. Default 0. */
87
+ priority?: number;
88
+ /** When false, the behavior is skipped during the pipeline run. */
89
+ enabled?: boolean;
90
+ }
91
+ /**
92
+ * Actions are transient effects that apply additive deltas (screenshake, recoil, etc.).
93
+ * They self-expire when isDone() returns true and are automatically removed.
94
+ */
95
+ interface CameraAction {
96
+ /** Return the additive delta for this frame. */
97
+ update(ctx: CameraContext): PoseDelta;
98
+ /** Return true when the action has completed and should be removed. */
99
+ isDone(ctx: CameraContext): boolean;
100
+ /** Sort order for action application. Default 0. */
101
+ priority?: number;
102
+ }
103
+ /**
104
+ * Debug snapshot returned by pipeline.getState().
105
+ */
106
+ interface CameraPipelineState {
107
+ perspectiveId: string | null;
108
+ desiredPose: CameraPose | null;
109
+ finalPose: CameraPose | null;
110
+ activeBehaviors: string[];
111
+ activeActionCount: number;
112
+ }
113
+
6
114
  declare const Perspectives: {
7
115
  readonly FirstPerson: "first-person";
8
116
  readonly ThirdPerson: "third-person";
117
+ readonly SecondPerson: "second-person";
9
118
  readonly Isometric: "isometric";
10
119
  readonly Flat2D: "flat-2d";
11
120
  readonly Fixed2D: "fixed-2d";
@@ -129,6 +238,12 @@ declare class RendererManager {
129
238
  * replacement for the old `EffectComposer` + `RenderPass`.
130
239
  */
131
240
  setupPostProcessing(scene: Scene, camera: Camera): void;
241
+ /**
242
+ * Point an already-built post-processing pass at a replacement camera.
243
+ * No-ops when post-processing has not been set up; the next setup call
244
+ * receives whatever camera the stage passes in.
245
+ */
246
+ rebindPostProcessingCamera(camera: Camera): void;
132
247
  /** Whether a stage transition is currently in flight. */
133
248
  get transitionActive(): boolean;
134
249
  /**
@@ -137,6 +252,14 @@ declare class RendererManager {
137
252
  * its pipeline is set up. Call before tearing down the outgoing stage.
138
253
  */
139
254
  beginSnapshotTransition(resolved: ResolvedStageTransition, scene: Scene, camera: Camera): void;
255
+ /**
256
+ * Blend from the current picture into the frames that follow without
257
+ * changing stage: snapshot the outgoing frame, then rebuild the pipeline
258
+ * so the blend is composed immediately. Used by cutscene scene changes
259
+ * and any in-stage "cut" the game wants to soften. Move the camera right
260
+ * after calling this so the snapshot shows the outgoing shot.
261
+ */
262
+ beginInStageTransition(resolved: ResolvedStageTransition, scene: Scene, camera: Camera): void;
140
263
  /**
141
264
  * Complete the active transition immediately: rebuild the normal
142
265
  * pipeline, release transition resources, and fire `onComplete`.
@@ -224,106 +347,6 @@ declare class RendererManager {
224
347
  dispose(): void;
225
348
  }
226
349
 
227
- /**
228
- * Represents a full camera pose: position, rotation, projection params, and optional lookAt.
229
- * This is the canonical data structure that flows through the camera pipeline.
230
- */
231
- interface CameraPose {
232
- position: Vector3;
233
- rotation: Quaternion;
234
- fov?: number;
235
- zoom?: number;
236
- near?: number;
237
- far?: number;
238
- /** When set, the camera orients to look at this point (takes priority over rotation). */
239
- lookAt?: Vector3;
240
- }
241
- /**
242
- * An additive delta applied on top of a CameraPose.
243
- * Used by CameraActions to apply transient offsets (shake, recoil, etc.).
244
- */
245
- interface PoseDelta {
246
- position?: Vector3;
247
- rotation?: Quaternion;
248
- fov?: number;
249
- zoom?: number;
250
- }
251
- /**
252
- * Minimal transform representation for pipeline targets.
253
- */
254
- interface TransformLike {
255
- position: Vector3;
256
- rotation?: Quaternion;
257
- }
258
- /**
259
- * Per-frame context passed to every pipeline module (perspectives, behaviors, actions).
260
- */
261
- interface CameraContext {
262
- /** Frame delta time in seconds. */
263
- dt: number;
264
- /** Elapsed time in seconds since camera started updating. */
265
- time: number;
266
- /** Current viewport dimensions and aspect ratio. */
267
- viewport: {
268
- width: number;
269
- height: number;
270
- aspect: number;
271
- };
272
- /** Named targets the camera can track. 'primary' is targets[0] by convention. */
273
- targets: Record<string, TransformLike>;
274
- }
275
- /**
276
- * A perspective produces the base camera pose each frame.
277
- * Exactly one perspective is active per camera at a time.
278
- */
279
- interface CameraPerspective {
280
- id: string;
281
- /** Compute the raw desired pose for this frame given the current context. */
282
- getBasePose(ctx: CameraContext): CameraPose;
283
- /** Optional defaults for smoothing and other pipeline settings. */
284
- defaults?: {
285
- damping?: number;
286
- };
287
- }
288
- /**
289
- * Behaviors modify the desired pose each frame.
290
- * They are keyed by name (idempotent add) and sorted by priority.
291
- */
292
- interface CameraBehavior {
293
- /** Receive current context and pose, return a modified pose. */
294
- update(ctx: CameraContext, pose: CameraPose): CameraPose;
295
- /** Called when the behavior is attached to the pipeline. */
296
- onAttach?(ctx: CameraContext): void;
297
- /** Called when the behavior is removed from the pipeline. */
298
- onDetach?(ctx: CameraContext): void;
299
- /** Sort order: lower runs first. Default 0. */
300
- priority?: number;
301
- /** When false, the behavior is skipped during the pipeline run. */
302
- enabled?: boolean;
303
- }
304
- /**
305
- * Actions are transient effects that apply additive deltas (screenshake, recoil, etc.).
306
- * They self-expire when isDone() returns true and are automatically removed.
307
- */
308
- interface CameraAction {
309
- /** Return the additive delta for this frame. */
310
- update(ctx: CameraContext): PoseDelta;
311
- /** Return true when the action has completed and should be removed. */
312
- isDone(ctx: CameraContext): boolean;
313
- /** Sort order for action application. Default 0. */
314
- priority?: number;
315
- }
316
- /**
317
- * Debug snapshot returned by pipeline.getState().
318
- */
319
- interface CameraPipelineState {
320
- perspectiveId: string | null;
321
- desiredPose: CameraPose | null;
322
- finalPose: CameraPose | null;
323
- activeBehaviors: string[];
324
- activeActionCount: number;
325
- }
326
-
327
350
  /**
328
351
  * CameraPipeline runs a deterministic per-frame update:
329
352
  *
@@ -589,10 +612,19 @@ declare class ZylemCamera {
589
612
  * Apply the final pipeline pose to the Three.js camera.
590
613
  */
591
614
  private commitPose;
615
+ /**
616
+ * Install a perspective and replace the Three.js camera when its projection
617
+ * kind differs from the live one. Pose is copied across; orbit controls and
618
+ * post-processing are rebound to the new instance.
619
+ */
620
+ applyPerspective(type: PerspectiveType, perspective: CameraPerspective): void;
621
+ private ensureProjection;
592
622
  /**
593
623
  * Create a Three.js camera based on perspective type.
594
624
  */
595
625
  private createCameraForPerspective;
626
+ private createPerspectiveCamera;
627
+ private createOrthographicCamera;
596
628
  }
597
629
 
598
- export { type CameraPose as C, type PerspectiveType as P, RendererManager as R, type TransformLike as T, type Viewport as V, type ZylemPostEffect as Z, Perspectives as a, type ZylemRenderer as b, type PoseDelta as c, type CameraContext as d, type CameraPerspective as e, type CameraBehavior as f, type CameraAction as g, type CameraPipelineState as h, isWebGPUSupported as i, CameraPipeline as j, ZylemCamera as k };
630
+ export { type CameraPose as C, type PerspectiveType as P, RendererManager as R, type TransformLike as T, type Viewport as V, type ZylemPostEffect as Z, Perspectives as a, type ZylemRenderer as b, type PoseDelta as c, type CameraContext as d, type CameraPerspective as e, type CameraBehavior as f, type CameraAction as g, type CameraPipelineState as h, isWebGPUSupported as i, type CameraProjection as j, CameraPipeline as k, ZylemCamera as l };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zylem/game-lib",
3
- "version": "0.8.9",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "description": "A powerful and easy-to-use framework for creating simple 3D digital interactive applications using TypeScript.",
6
6
  "license": "MIT",
@@ -33,6 +33,10 @@
33
33
  "types": "./dist/audio.d.ts",
34
34
  "import": "./dist/audio.js"
35
35
  },
36
+ "./cinematics": {
37
+ "types": "./dist/cinematics.d.ts",
38
+ "import": "./dist/cinematics.js"
39
+ },
36
40
  "./globals": {
37
41
  "types": "./dist/globals.d.ts",
38
42
  "import": "./dist/globals.js"
@@ -89,7 +93,9 @@
89
93
  "./schema/stage": "./dist/schema/stage.schema.json",
90
94
  "./schema/game-config": "./dist/schema/game-config.schema.json",
91
95
  "./schema/stage-config": "./dist/schema/stage-config.schema.json",
92
- "./schema/input-config": "./dist/schema/input-config.schema.json"
96
+ "./schema/input-config": "./dist/schema/input-config.schema.json",
97
+ "./schema/song": "./dist/schema/song.schema.json",
98
+ "./schema/cutscene": "./dist/schema/cutscene.schema.json"
93
99
  },
94
100
  "keywords": [
95
101
  "game",
@@ -110,6 +116,7 @@
110
116
  "@sinclair/typebox": "^0.34.52",
111
117
  "@types/howler": "^2.2.13",
112
118
  "@zylem/behaviors": "^0.8.8",
119
+ "@zylem/bridge": "^0.9.0",
113
120
  "comlink": "^4.4.2",
114
121
  "howler": "^2.2.4",
115
122
  "idb-keyval": "^6.2.6",
@@ -117,9 +124,9 @@
117
124
  "nanoid": "^5.1.16",
118
125
  "stats.js": "^0.17.0",
119
126
  "three": "^0.185.1",
127
+ "tone": "^15.1.22",
120
128
  "typescript-fsm": "^1.6.0",
121
- "valtio": "^2.1.8",
122
- "@zylem/bridge": "^0.8.9"
129
+ "valtio": "^2.1.8"
123
130
  },
124
131
  "peerDependencies": {
125
132
  "howler": "^2.2.4",
@@ -1,9 +0,0 @@
1
- import{d as s,h as o,j as a}from"./chunk-EVMLNMGU.js";import{announceBridgeReady as c}from"@zylem/bridge";var n=class r extends HTMLElement{_game=null;_state={};container;resizeObserver=null;_viewportProfile="auto";static HOST_CONFIG_MARKER=Symbol("zylem:host-config");constructor(){super(),this.attachShadow({mode:"open"});let e=document.createElement("style");e.textContent=`
2
- :host {
3
- display: block;
4
- width: 100%;
5
- height: 100%;
6
- min-width: 0;
7
- min-height: 0;
8
- }
9
- `,this.container=document.createElement("div"),this.container.style.width="100%",this.container.style.height="100%",this.container.style.position="relative",this.container.style.outline="none",this.container.tabIndex=0,this.shadowRoot.append(e,this.container)}focus(){this.container.focus()}connectedCallback(){typeof ResizeObserver<"u"&&!this.resizeObserver&&(this.resizeObserver=new ResizeObserver(()=>{this.syncDisplayRuntime()}),this.resizeObserver.observe(this)),this.syncDisplayRuntime()}set game(e){this._game&&this._game.dispose(),this._game=e,this.attachHostContainer(e),this.syncDisplayRuntime(),e.start(),c(this)}get game(){return this._game}set state(e){this._state=e,this.syncDebugState(),this.syncToolbarState()}get state(){return this._state}set viewportProfile(e){let t=e==="mobile"||e==="desktop"?e:"auto";this._viewportProfile!==t&&(this._viewportProfile=t,this.syncDisplayRuntime())}get viewportProfile(){return this._viewportProfile}static get observedAttributes(){return["viewport-profile"]}attributeChangedCallback(e,t,i){e==="viewport-profile"&&(this.viewportProfile=i??"auto")}syncDebugState(){let e=this._state.gameState?.debugFlag;e!==void 0&&(s.enabled=e)}syncToolbarState(){let{tool:e,paused:t}=this._state.toolbarState??{};e!==void 0&&a(e),t!==void 0&&o(t)}disconnectedCallback(){this.resizeObserver?.disconnect(),this.resizeObserver=null,this._game&&(this._game.dispose(),this._game=null)}attachHostContainer(e){let t=r.HOST_CONFIG_MARKER,i=e.options.find(l=>!!l?.[t]);if(i){i.container=this.container;return}e.options.push({container:this.container,[t]:!0})}syncDisplayRuntime(){if(!this._game)return;let e=this.getBoundingClientRect(),t=Math.round(e.width||this.clientWidth||0),i=Math.round(e.height||this.clientHeight||0);this._game.setDisplayRuntime({deviceProfile:this._viewportProfile,viewportSize:t>0&&i>0?{width:t,height:i}:void 0})}};customElements.define("zylem-game",n);export{n as a};
@@ -1,24 +0,0 @@
1
- import{b as ye,d as G,j as Me,u as L,v as E}from"./chunk-BWOZF5YK.js";import{b as Be}from"./chunk-7GYFZKK7.js";import{b as y}from"./chunk-Q2YDBMVY.js";import{b as Re,c as Te}from"./chunk-EYDC2PMO.js";import{c as Ce,e as xe,f as Ge}from"./chunk-2HSR5XDQ.js";import{b as $,c as Se,d as W,e as j,g as we}from"./chunk-G3TBBZUI.js";import{d as g,g as fe,h as K}from"./chunk-EVMLNMGU.js";import{k as Ie}from"./chunk-7JSZEEAE.js";import{a as Q,t as ee}from"./chunk-KP6DLLJO.js";import{j as Ee}from"./chunk-6FGXC4T6.js";import{a as ve,b}from"./chunk-AIQ6IVT5.js";import{c as S}from"./chunk-D2PATZCC.js";import{c as pe,d as C,e as de,h as ce,i as me,j as he,k as J,l as x,m as ge}from"./chunk-4QLJUQSJ.js";import{j as q}from"./chunk-7WRQ2UAN.js";import{g as be}from"./chunk-PCFF4LLO.js";import{l as v}from"./chunk-UG22Z42P.js";function Fe(){return{pressed:!1,released:!1,held:0}}function Xe(){return{value:0,held:0}}function k(a){let e=new Map;if(!a)return e;for(let[t,n]of Object.entries(a)){if(!n||n.length===0)continue;let i=[];for(let o of n){let[r,s]=(o||"").split(".");if(!r||!s)continue;let l=r.toLowerCase(),u=s.toLowerCase();if(l==="buttons"){let p={a:"A",b:"B",x:"X",y:"Y",start:"Start",select:"Select",l:"L",r:"R"}[u];p&&i.push({category:"buttons",property:p})}else if(l==="directions"){let p={up:"Up",down:"Down",left:"Left",right:"Right"}[u];p&&i.push({category:"directions",property:p})}else if(l==="shoulders"){let p={ltrigger:"LTrigger",rtrigger:"RTrigger"}[u];p&&i.push({category:"shoulders",property:p})}else if(l==="axes"){let p={left:{property:"Horizontal",direction:-1},right:{property:"Horizontal",direction:1},up:{property:"Vertical",direction:-1},down:{property:"Vertical",direction:1},secondaryleft:{property:"SecondaryHorizontal",direction:-1},secondaryright:{property:"SecondaryHorizontal",direction:1},secondaryup:{property:"SecondaryVertical",direction:-1},secondarydown:{property:"SecondaryVertical",direction:1}}[u];p&&i.push({category:"axes",property:p.property,axisDirection:p.direction})}}i.length>0&&e.set(t,i)}return e}function d(a,e){return!a&&!e?Fe():a?e?{pressed:a.pressed||e.pressed,released:a.released||e.released,held:a.held+e.held}:{...a}:{...e}}function f(a,e){return!a&&!e?Xe():a?e?{value:a.value+e.value,held:a.held+e.held}:{...a}:{...e}}var w=class{keyStates=new Map;keyButtonStates=new Map;analogStates=new Map;compiledMapping;includeDefaultBase=!0;onKeyDown=({key:e})=>this.keyStates.set(e,!0);onKeyUp=({key:e})=>this.keyStates.set(e,!1);constructor(e,t){this.includeDefaultBase=t?.includeDefaultBase??!0,this.compiledMapping=k(e??null),window.addEventListener("keydown",this.onKeyDown),window.addEventListener("keyup",this.onKeyUp)}dispose(){window.removeEventListener("keydown",this.onKeyDown),window.removeEventListener("keyup",this.onKeyUp),this.keyStates.clear(),this.keyButtonStates.clear(),this.analogStates.clear()}isKeyPressed(e){return this.keyStates.get(e)||!1}handleButtonState(e,t){let n=this.keyButtonStates.get(e);n||(n={pressed:!1,released:!1,held:0},this.keyButtonStates.set(e,n));let i=this.isKeyPressed(e);return n.pressed=i&&n.held===0,n.released=!i&&n.held>0,n.held=i?n.held+t:0,n}handleAnalogState(e,t,n){let i=`${e}:${t}`,o=this.analogStates.get(i);return o||(o={value:0,held:0},this.analogStates.set(i,o)),o.value=this.getAxisValue(e,t),o.held=o.value!==0?o.held+n:0,o}applyCustomMapping(e,t){if(this.compiledMapping.size===0)return e;let n=new Map;for(let[i,o]of this.compiledMapping.entries()){let r=null;for(let s of o)if(s.category==="axes")n.has(s.property)||n.set(s.property,0),this.isKeyPressed(i)&&n.set(s.property,n.get(s.property)+s.axisDirection);else{r||(r=this.handleButtonState(i,t));let l=e[s.category]??={};l[s.property]=d(l[s.property],r)}}if(n.size>0){e.axes||(e.axes={});for(let[i,o]of n.entries()){let r=`custom:${i}`,s=this.analogStates.get(r);s||(s={value:0,held:0},this.analogStates.set(r,s)),s.value=o,s.held=o!==0?s.held+t:0,e.axes[i]=f(e.axes[i],s)}}return e}getInput(e){let t={};return this.includeDefaultBase&&(t.buttons={A:this.handleButtonState("z",e),B:this.handleButtonState("x",e),X:this.handleButtonState("a",e),Y:this.handleButtonState("s",e),Start:this.handleButtonState(" ",e),Select:this.handleButtonState("Enter",e),L:this.handleButtonState("q",e),R:this.handleButtonState("e",e)},t.directions={Up:this.handleButtonState("ArrowUp",e),Down:this.handleButtonState("ArrowDown",e),Left:this.handleButtonState("ArrowLeft",e),Right:this.handleButtonState("ArrowRight",e)},t.shoulders={LTrigger:this.handleButtonState("Q",e),RTrigger:this.handleButtonState("E",e)}),this.applyCustomMapping(t,e)}getName(){return"keyboard"}getAxisValue(e,t){return(this.isKeyPressed(t)?1:0)-(this.isKeyPressed(e)?1:0)}isConnected(){return!0}};var D=class{gamepadIndex;connected=!1;buttonStates={};analogStates={};onConnected=e=>{e.gamepad.index===this.gamepadIndex&&(this.connected=!0)};onDisconnected=e=>{e.gamepad.index===this.gamepadIndex&&(this.connected=!1)};constructor(e){this.gamepadIndex=e,window.addEventListener("gamepadconnected",this.onConnected),window.addEventListener("gamepaddisconnected",this.onDisconnected)}dispose(){window.removeEventListener("gamepadconnected",this.onConnected),window.removeEventListener("gamepaddisconnected",this.onDisconnected),this.buttonStates={},this.analogStates={}}handleButtonState(e,t,n){let i=this.buttonStates[e];i||(i={pressed:!1,released:!1,held:0},this.buttonStates[e]=i);let o=t.buttons[e].pressed;return i.pressed=o&&i.held===0,i.released=!o&&i.held>0,i.held=o?i.held+n:0,i}handleAnalogState(e,t,n){let i=this.analogStates[e];return i||(i={value:0,held:0},this.analogStates[e]=i),i.value=t.axes[e],i.held=i.value!==0?i.held+n:0,i}getInput(e){let t=navigator.getGamepads()[this.gamepadIndex];return t?{buttons:{A:this.handleButtonState(0,t,e),B:this.handleButtonState(1,t,e),X:this.handleButtonState(2,t,e),Y:this.handleButtonState(3,t,e),Start:this.handleButtonState(9,t,e),Select:this.handleButtonState(8,t,e),L:this.handleButtonState(4,t,e),R:this.handleButtonState(5,t,e)},directions:{Up:this.handleButtonState(12,t,e),Down:this.handleButtonState(13,t,e),Left:this.handleButtonState(14,t,e),Right:this.handleButtonState(15,t,e)},axes:{Horizontal:this.handleAnalogState(0,t,e),Vertical:this.handleAnalogState(1,t,e),SecondaryHorizontal:this.handleAnalogState(2,t,e),SecondaryVertical:this.handleAnalogState(3,t,e)},shoulders:{LTrigger:this.handleButtonState(6,t,e),RTrigger:this.handleButtonState(7,t,e)}}:{}}getName(){return`gamepad-${this.gamepadIndex+1}`}isConnected(){return this.connected}};import{subscribe as Ye}from"valtio/vanilla";var Ze=.002;function A(a,e,t){return Math.max(e,Math.min(t,a))}function Je(a){if(a instanceof HTMLCanvasElement)return a;let e=a.querySelector("canvas");if(e instanceof HTMLCanvasElement)return e;for(let t of a.querySelectorAll("*")){let n=t.shadowRoot;if(!n)continue;let i=n.querySelector("canvas");if(i instanceof HTMLCanvasElement)return i}return null}var R=class{buttonStates=new Map;analogStates=new Map;compiledMapping;movementX=0;movementY=0;pointerX=.5;pointerY=.5;pointerCenterX=0;pointerCenterY=0;mouseButtonDown=new Set;sensitivity;usePointerLock;lookMode;isLocked=!1;targetElement;debugUnsubscribe=null;updatePointerPosition(e,t){this.pointerX=e/window.innerWidth,this.pointerY=t/window.innerHeight;let n=Je(this.targetElement);if(n){let i=n.getBoundingClientRect();if(i.width>0&&i.height>0){let o=i.left+i.width/2,r=i.top+i.height/2;this.pointerCenterX=A((e-o)/(i.width/2),-1,1),this.pointerCenterY=A((t-r)/(i.height/2),-1,1);return}}this.pointerCenterX=A((this.pointerX-.5)*2,-1,1),this.pointerCenterY=A((this.pointerY-.5)*2,-1,1)}onMouseMove=e=>{this.updatePointerPosition(e.clientX,e.clientY),!(g.enabled||this.lookMode==="screenCenter")&&(this.movementX+=e.movementX,this.movementY+=e.movementY)};onMouseDown=e=>{let t=e.target;t instanceof HTMLCanvasElement&&this.targetElement.contains(t)&&(this.mouseButtonDown.add(e.button),this.usePointerLock&&!this.isLocked&&!g.enabled&&this.targetElement.requestPointerLock())};onMouseUp=e=>{this.mouseButtonDown.delete(e.button)};onContextMenu=e=>{e.preventDefault()};onPointerLockChange=()=>{this.isLocked=document.pointerLockElement===this.targetElement};constructor(e,t){this.sensitivity=e?.sensitivity??Ze,this.lookMode=e?.lookMode??"delta",this.usePointerLock=e?.pointerLock??!1,this.compiledMapping=k(e?.mapping??null),this.targetElement=t??document.body,window.addEventListener("mousemove",this.onMouseMove),this.targetElement.addEventListener("mousedown",this.onMouseDown),this.targetElement.addEventListener("mouseup",this.onMouseUp),this.targetElement.addEventListener("contextmenu",this.onContextMenu),this.usePointerLock&&(document.addEventListener("pointerlockchange",this.onPointerLockChange),this.debugUnsubscribe=Ye(g,()=>{g.enabled&&document.pointerLockElement===this.targetElement&&document.exitPointerLock()}))}dispose(){window.removeEventListener("mousemove",this.onMouseMove),this.targetElement.removeEventListener("mousedown",this.onMouseDown),this.targetElement.removeEventListener("mouseup",this.onMouseUp),this.targetElement.removeEventListener("contextmenu",this.onContextMenu),document.removeEventListener("pointerlockchange",this.onPointerLockChange),this.debugUnsubscribe?.(),this.debugUnsubscribe=null,this.isLocked&&document.exitPointerLock(),this.buttonStates.clear(),this.analogStates.clear(),this.mouseButtonDown.clear(),this.movementX=0,this.movementY=0}handleMouseButton(e,t){let n=this.buttonStates.get(e);n||(n={pressed:!1,released:!1,held:0},this.buttonStates.set(e,n));let i=this.mouseButtonDown.has(e);return n.pressed=i&&n.held===0,n.released=!i&&n.held>0,n.held=i?n.held+t:0,n}handleMovementAxis(e,t){let n=this.analogStates.get(e);n||(n={value:0,held:0},this.analogStates.set(e,n));let i=e==="x"?this.movementX:this.movementY;return n.value=Math.max(-1,Math.min(1,i*this.sensitivity)),n.held=n.value!==0?n.held+t:0,n}applyCustomMapping(e,t){if(this.compiledMapping.size===0)return e;let n=new Map,i={leftbutton:()=>this.handleMouseButton(0,t),rightbutton:()=>this.handleMouseButton(2,t),middlebutton:()=>this.handleMouseButton(1,t)};for(let[o,r]of this.compiledMapping.entries()){let s=o.toLowerCase();for(let l of r)if(l.category==="axes")n.has(l.property)||n.set(l.property,0),s==="movex"?n.set(l.property,n.get(l.property)+Math.max(-1,Math.min(1,this.movementX*this.sensitivity))*l.axisDirection):s==="movey"?n.set(l.property,n.get(l.property)+Math.max(-1,Math.min(1,this.movementY*this.sensitivity))*l.axisDirection):s in i&&this.mouseButtonDown.has(this.buttonIndexForAction(s))&&n.set(l.property,n.get(l.property)+l.axisDirection);else{let u=i[s];if(u){let m=u();if(m){let p=e[l.category]??={};p[l.property]=d(p[l.property],m)}}}}if(n.size>0){e.axes||(e.axes={});for(let[o,r]of n.entries()){let s=`custom:${o}`,l=this.analogStates.get(s);l||(l={value:0,held:0},this.analogStates.set(s,l)),l.value=Math.max(-1,Math.min(1,r)),l.held=r!==0?l.held+t:0,e.axes[o]=f(e.axes[o],l)}}return e}buttonIndexForAction(e){switch(e){case"leftbutton":return 0;case"middlebutton":return 1;case"rightbutton":return 2;default:return-1}}getInput(e){g.enabled&&(this.movementX=0,this.movementY=0);let t={value:0,held:0},n=this.lookMode==="delta",i={axes:{Horizontal:t,Vertical:t,SecondaryHorizontal:n?this.handleMovementAxis("x",e):t,SecondaryVertical:n?this.handleMovementAxis("y",e):t},shoulders:{LTrigger:this.handleMouseButton(0,e),RTrigger:this.handleMouseButton(2,e)},pointer:{x:this.pointerX,y:this.pointerY,centerX:this.pointerCenterX,centerY:this.pointerCenterY}};return this.movementX=0,this.movementY=0,this.applyCustomMapping(i,e)}getName(){return"mouse"}isConnected(){return!0}};function T(a={}){if(typeof window>"u"||typeof navigator>"u")return!1;let e=navigator.userAgent,t=/android/i.test(e)||/iPad|iPhone|iPod/.test(e),n="ontouchstart"in window||navigator.maxTouchPoints>0,i=typeof window.matchMedia=="function"?window.matchMedia("(pointer: coarse)").matches:!1,o=a.viewportSize?.width??window.innerWidth??0,r=a.viewportSize?.height??window.innerHeight??0,s=Math.max(o,r),l=s===0||s<=1024;return a.allowViewportOnly&&a.viewportSize?l:t||(n||i)&&l}var Ke=["A","B","X","Y","Start","Select","L","R","LTrigger","RTrigger","Up","Down","Left","Right"],$e=new Set(["flex","flexGrow","flexShrink","fontWeight","lineHeight","opacity","order","zIndex","zoom"]),We={A:{size:72,label:"A",position:{right:98,bottom:44}},B:{size:72,label:"B",position:{right:24,bottom:108}},X:{size:72,label:"X",position:{right:172,bottom:108}},Y:{size:72,label:"Y",position:{right:98,bottom:172}},Start:{size:64,label:"Start",position:{left:"50%",top:24,transform:"translateX(28px)"}},Select:{size:64,label:"Select",position:{left:"50%",top:24,transform:"translateX(-108px)"}},L:{size:62,label:"L",position:{left:28,bottom:184}},R:{size:62,label:"R",position:{right:236,bottom:184}},LTrigger:{size:76,label:"LT",position:{left:24,top:24}},RTrigger:{size:76,label:"RT",position:{right:24,top:24}},Up:{enabled:!1,size:64,label:"Up"},Down:{enabled:!1,size:64,label:"Down"},Left:{enabled:!1,size:64,label:"Left"},Right:{enabled:!1,size:64,label:"Right"}},je={left:{size:140,thumbSize:58,maxDistance:44,deadzone:.12,directionThreshold:.34,horizontalAxis:"Horizontal",verticalAxis:"Vertical",emitDirections:!0,position:{left:24,bottom:24}},right:{size:140,thumbSize:58,maxDistance:44,deadzone:.12,directionThreshold:.34,horizontalAxis:"SecondaryHorizontal",verticalAxis:"SecondaryVertical",emitDirections:!1,position:{right:24,bottom:236}}},M=class{config;targetElement;buttonStates=new Map;analogStates=new Map;buttons=new Map;joysticks=new Map;rootElement=null;enabled=!1;onPointerMove=e=>{for(let t of this.joysticks.values())t.pointerId===e.pointerId&&(this.consumeEvent(e),this.updateJoystickFromPoint(t,e.clientX,e.clientY))};onPointerUp=e=>{for(let t of this.buttons.values())t.pointerId===e.pointerId&&(this.consumeEvent(e),this.releaseButton(t));for(let t of this.joysticks.values())t.pointerId===e.pointerId&&(this.consumeEvent(e),this.releaseJoystick(t))};onWindowBlur=()=>{for(let e of this.buttons.values())this.releaseButton(e);for(let e of this.joysticks.values())this.releaseJoystick(e)};constructor(e,t){this.config=e??{},this.targetElement=t??document.body,this.enabled=this.resolveEnabledState(),this.enabled&&(this.mountControls(),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp),window.addEventListener("pointercancel",this.onPointerUp),window.addEventListener("blur",this.onWindowBlur))}getInput(e){if(!this.enabled)return{};let t={};for(let n of this.buttons.values()){let i=this.handleButtonState(`button:${n.slot}`,n.pointerId!==null,e);this.assignButtonState(t,this.resolveButtonTarget(n.slot),i)}for(let n of this.joysticks.values()){let i=this.handleAnalogState(`joystick:${n.id}:x`,n.valueX,e),o=this.handleAnalogState(`joystick:${n.id}:y`,n.valueY,e);this.assignAxisState(t,n.config.horizontalAxis,i),this.assignAxisState(t,n.config.verticalAxis,o),n.config.emitDirections&&(this.assignButtonState(t,this.resolveButtonTarget("Left"),this.handleButtonState(`joystick:${n.id}:left`,n.valueX<=-n.config.directionThreshold,e)),this.assignButtonState(t,this.resolveButtonTarget("Right"),this.handleButtonState(`joystick:${n.id}:right`,n.valueX>=n.config.directionThreshold,e)),this.assignButtonState(t,this.resolveButtonTarget("Up"),this.handleButtonState(`joystick:${n.id}:up`,n.valueY<=-n.config.directionThreshold,e)),this.assignButtonState(t,this.resolveButtonTarget("Down"),this.handleButtonState(`joystick:${n.id}:down`,n.valueY>=n.config.directionThreshold,e)))}return t}getName(){return"virtual-touch"}isConnected(){return this.enabled}dispose(){window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),window.removeEventListener("pointercancel",this.onPointerUp),window.removeEventListener("blur",this.onWindowBlur),this.rootElement?.remove(),this.rootElement=null,this.buttons.clear(),this.joysticks.clear(),this.buttonStates.clear(),this.analogStates.clear()}resolveEnabledState(){return typeof window>"u"||typeof document>"u"?!1:this.config.enabled===!0?!0:this.config.enabled===!1?!1:T()}mountControls(){this.rootElement=document.createElement("div"),this.rootElement.className="zylem-virtual-touch",this.rootElement.dataset.zylemTouchRoot="true",this.rootElement.style.position="absolute",this.rootElement.style.inset="0",this.rootElement.style.pointerEvents="none",this.rootElement.style.touchAction="none",this.rootElement.style.userSelect="none",this.rootElement.style.WebkitUserSelect="none",this.rootElement.style.WebkitTouchCallout="none",this.rootElement.style.color="rgba(245, 247, 255, 0.96)",this.rootElement.style.zIndex="20",this.appendClassName(this.rootElement,this.config.className),B(this.rootElement,this.config.style),this.rootElement.addEventListener("contextmenu",e=>e.preventDefault());for(let[e,t]of this.resolveButtons())this.rootElement.appendChild(this.createButton(e,t));for(let[e,t]of this.resolveJoysticks())this.rootElement.appendChild(this.createJoystick(e,t));this.targetElement.appendChild(this.rootElement)}resolveButtons(){if(this.config.buttons===!1)return[];let e=this.config.buttons,t=[];for(let n of Ke){let i=We[n],o=e?.[n];if(o===!1)continue;let r={...i,...o??{},style:{...i.style,...o?.style},position:{...i.position,...o?.position},label:o?.label??i.label??n,size:o?.size??i.size??72};r.enabled!==!1&&t.push([n,r])}return t}resolveJoysticks(){if(this.config.joysticks===!1)return[];let e=this.config.joysticks,t=[];for(let n of["left","right"]){let i=je[n],o=e?.[n];if(o===!1)continue;let r={...i,...o??{},style:{...i.style,...o?.style},position:{...i.position,...o?.position},svg:{...i.svg,...o?.svg},size:o?.size??i.size??140,thumbSize:o?.thumbSize??i.thumbSize??58,maxDistance:o?.maxDistance??i.maxDistance??44,deadzone:o?.deadzone??i.deadzone??.12,directionThreshold:o?.directionThreshold??i.directionThreshold??.34,horizontalAxis:o?.horizontalAxis??i.horizontalAxis??"Horizontal",verticalAxis:o?.verticalAxis??i.verticalAxis??"Vertical",emitDirections:o?.emitDirections??i.emitDirections??!1};r.enabled!==!1&&t.push([n,r])}return t}createButton(e,t){let n=document.createElement("button"),i=document.createElement("div");n.type="button",n.ariaLabel=t.label,n.className=`zylem-virtual-touch__button zylem-virtual-touch__button--${e}`,n.dataset.zylemTouchButton=e,n.dataset.active="false",n.style.position="absolute",n.style.width=`${t.size}px`,n.style.height=`${t.size}px`,n.style.padding="0",n.style.margin="0",n.style.border="0",n.style.background="transparent",n.style.pointerEvents="auto",n.style.touchAction="none",n.style.cursor="pointer",n.style.appearance="none",n.style.outline="none",n.style.userSelect="none",n.style.WebkitTapHighlightColor="transparent",B(n,t.position),B(n,t.style),this.appendClassName(n,t.className),i.className="zylem-virtual-touch__button-content",i.style.width="100%",i.style.height="100%",i.style.pointerEvents="none",i.style.transform="scale(1)",i.style.transformOrigin="center",i.style.transition="transform 120ms ease, opacity 120ms ease",i.style.opacity="0.92",i.innerHTML=t.svg??Qe(t.label),n.appendChild(i),n.addEventListener("pointerdown",r=>{if(!Pe(r))return;let s=this.buttons.get(e);!s||s.pointerId!==null||(this.consumeEvent(r),s.pointerId=r.pointerId,this.updateButtonVisual(s,!0))});let o={slot:e,config:t,element:n,content:i,pointerId:null};return this.buttons.set(e,o),n}createJoystick(e,t){let n=document.createElement("div"),i=document.createElement("div"),o=document.createElement("div");n.className=`zylem-virtual-touch__joystick zylem-virtual-touch__joystick--${e}`,n.dataset.zylemTouchJoystick=e,n.dataset.active="false",n.style.position="absolute",n.style.width=`${t.size}px`,n.style.height=`${t.size}px`,n.style.pointerEvents="auto",n.style.touchAction="none",n.style.userSelect="none",B(n,t.position),B(n,t.style),this.appendClassName(n,t.className),i.className="zylem-virtual-touch__joystick-base",i.style.position="absolute",i.style.inset="0",i.style.pointerEvents="none",i.style.opacity="0.88",i.style.transition="opacity 120ms ease",i.innerHTML=t.svg?.base??et(),o.className="zylem-virtual-touch__joystick-thumb",o.style.position="absolute",o.style.left="50%",o.style.top="50%",o.style.width=`${t.thumbSize}px`,o.style.height=`${t.thumbSize}px`,o.style.pointerEvents="none",o.style.transform="translate(-50%, -50%) translate(0px, 0px)",o.style.transition="transform 60ms linear, opacity 120ms ease",o.style.opacity="0.94",o.innerHTML=t.svg?.thumb??tt(),n.append(i,o);let r={id:e,config:t,element:n,base:i,thumb:o,pointerId:null,centerX:0,centerY:0,rawX:0,rawY:0,valueX:0,valueY:0};return this.joysticks.set(e,r),n.addEventListener("pointerdown",s=>{if(!Pe(s))return;let l=this.joysticks.get(e);if(!l||l.pointerId!==null)return;this.consumeEvent(s);let u=l.element.getBoundingClientRect();l.pointerId=s.pointerId,l.centerX=u.left+u.width/2,l.centerY=u.top+u.height/2,this.updateJoystickVisual(l,!0),this.updateJoystickFromPoint(l,s.clientX,s.clientY)}),n}handleButtonState(e,t,n){let i=this.buttonStates.get(e);return i||(i={pressed:!1,released:!1,held:0},this.buttonStates.set(e,i)),i.pressed=t&&i.held===0,i.released=!t&&i.held>0,i.held=t?i.held+n:0,i}handleAnalogState(e,t,n){let i=this.analogStates.get(e);return i||(i={value:0,held:0},this.analogStates.set(e,i)),i.value=t,i.held=t!==0?i.held+n:0,i}assignAxisState(e,t,n){e.axes||(e.axes={}),e.axes[t]=f(e.axes[t],n)}assignButtonState(e,t,n){if(t.category==="buttons"){e.buttons??={},e.buttons[t.property]=d(e.buttons[t.property],n);return}if(t.category==="directions"){e.directions??={},e.directions[t.property]=d(e.directions[t.property],n);return}e.shoulders??={},e.shoulders[t.property]=d(e.shoulders[t.property],n)}resolveButtonTarget(e){switch(e){case"LTrigger":case"RTrigger":return{category:"shoulders",property:e};case"Up":case"Down":case"Left":case"Right":return{category:"directions",property:e};default:return{category:"buttons",property:e}}}updateJoystickFromPoint(e,t,n){let i=t-e.centerX,o=n-e.centerY,r=Math.hypot(i,o),s=e.config.maxDistance,l=r>s&&r>0?s/r:1;e.rawX=i*l,e.rawY=o*l;let u=qe(e.rawX/s,e.rawY/s,e.config.deadzone);e.valueX=u.x,e.valueY=u.y,e.thumb.style.transform=`translate(-50%, -50%) translate(${e.rawX}px, ${e.rawY}px)`}releaseButton(e){e.pointerId=null,this.updateButtonVisual(e,!1)}releaseJoystick(e){e.pointerId=null,e.rawX=0,e.rawY=0,e.valueX=0,e.valueY=0,e.thumb.style.transform="translate(-50%, -50%) translate(0px, 0px)",this.updateJoystickVisual(e,!1)}updateButtonVisual(e,t){e.element.dataset.active=String(t),e.content.style.transform=t?"scale(0.94)":"scale(1)",e.content.style.opacity=t?"1":"0.92"}updateJoystickVisual(e,t){e.element.dataset.active=String(t),e.base.style.opacity=t?"1":"0.88",e.thumb.style.opacity=t?"1":"0.94"}consumeEvent(e){e.cancelable&&e.preventDefault(),e.stopPropagation()}appendClassName(e,t){t&&(e.className=`${e.className} ${t}`.trim())}};function B(a,e){if(e)for(let[t,n]of Object.entries(e)){if(n==null)continue;let i=typeof n=="number"&&!$e.has(t)?`${n}px`:String(n);t.includes("-")?a.style.setProperty(t,i):a.style[t]=i}}function qe(a,e,t){let n=Math.hypot(a,e);if(n===0||n<=t)return{x:0,y:0};let o=Math.min(1,(n-t)/Math.max(1-t,1e-4))/n;return{x:a*o,y:e*o}}function Qe(a){let e=nt(a);return`
2
- <svg viewBox="0 0 100 100" width="100%" height="100%" aria-hidden="true">
3
- <circle cx="50" cy="50" r="45" fill="rgba(12,18,24,0.72)" stroke="currentColor" stroke-width="4" />
4
- <circle cx="50" cy="50" r="34" fill="rgba(255,255,255,0.06)" stroke="rgba(255,255,255,0.12)" stroke-width="1.5" />
5
- <text
6
- x="50"
7
- y="56"
8
- text-anchor="middle"
9
- font-family="ui-sans-serif, system-ui, sans-serif"
10
- font-size="${e.length>2?24:34}"
11
- font-weight="700"
12
- fill="currentColor"
13
- >${e}</text>
14
- </svg>
15
- `}function et(){return`
16
- <svg viewBox="0 0 140 140" width="100%" height="100%" aria-hidden="true">
17
- <circle cx="70" cy="70" r="62" fill="rgba(10,16,20,0.64)" stroke="currentColor" stroke-width="4" />
18
- <circle cx="70" cy="70" r="40" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.12)" stroke-width="1.5" />
19
- </svg>
20
- `}function tt(){return`
21
- <svg viewBox="0 0 64 64" width="100%" height="100%" aria-hidden="true">
22
- <circle cx="32" cy="32" r="28" fill="rgba(22,30,38,0.9)" stroke="currentColor" stroke-width="3.5" />
23
- </svg>
24
- `}function nt(a){return a.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}function Pe(a){return a.pointerType==="touch"}var z=class{inputMap=new Map;currentInputs={};previousInputs={};targetElement;mouseTargetElement;constructor(e,t){this.targetElement=t?.targetElement,this.mouseTargetElement=t?.mouseTargetElement??t?.targetElement;let n=this.buildPlayerEntries(e);for(let{player:i,config:o,gamepadIndex:r,isP1:s}of n)this.addConfigurableProviders(i,o,s),this.addInputProvider(i,new D(r))}configure(e){let t=this.buildPlayerEntries(e);for(let{player:n,config:i,isP1:o}of t){let s=(this.inputMap.get(n)??[]).filter(l=>l instanceof w||l instanceof R||l instanceof M?(l.dispose(),!1):!0);this.inputMap.set(n,[...this.createConfigurableProviders(i,o),...s])}}addInputProvider(e,t){this.inputMap.has(e)||this.inputMap.set(e,[]),this.inputMap.get(e)?.push(t)}dispose(){for(let e of this.inputMap.values())for(let t of e)t.dispose?.();this.inputMap.clear(),this.currentInputs={},this.previousInputs={}}getInputs(e){let t={};return this.inputMap.forEach((n,i)=>{let o=`p${i}`,r=n.reduce((s,l)=>{let u=l.getInput(e);return this.mergeInputs(s,u)},{});t[o]={playerNumber:i,...r}}),t}buildPlayerEntries(e){return[{player:1,config:e?.p1,gamepadIndex:0,isP1:!0},{player:2,config:e?.p2,gamepadIndex:1,isP1:!1},{player:3,config:e?.p3,gamepadIndex:2,isP1:!1},{player:4,config:e?.p4,gamepadIndex:3,isP1:!1},{player:5,config:e?.p5,gamepadIndex:4,isP1:!1},{player:6,config:e?.p6,gamepadIndex:5,isP1:!1},{player:7,config:e?.p7,gamepadIndex:6,isP1:!1},{player:8,config:e?.p8,gamepadIndex:7,isP1:!1}]}addConfigurableProviders(e,t,n){for(let i of this.createConfigurableProviders(t,n))this.addInputProvider(e,i)}createConfigurableProviders(e,t){let n=[];if(e?.key){let i=e.includeDefaults??t;n.push(new w(e.key,{includeDefaultBase:i}))}else t&&n.push(new w);return e?.mouse&&n.push(new R(e.mouse,this.mouseTargetElement)),e?.touch&&n.push(new M(e.touch,this.targetElement)),n}mergeInputs(e,t){return{buttons:{A:d(e.buttons?.A,t.buttons?.A),B:d(e.buttons?.B,t.buttons?.B),X:d(e.buttons?.X,t.buttons?.X),Y:d(e.buttons?.Y,t.buttons?.Y),Start:d(e.buttons?.Start,t.buttons?.Start),Select:d(e.buttons?.Select,t.buttons?.Select),L:d(e.buttons?.L,t.buttons?.L),R:d(e.buttons?.R,t.buttons?.R)},directions:{Up:d(e.directions?.Up,t.directions?.Up),Down:d(e.directions?.Down,t.directions?.Down),Left:d(e.directions?.Left,t.directions?.Left),Right:d(e.directions?.Right,t.directions?.Right)},axes:{Horizontal:f(e.axes?.Horizontal,t.axes?.Horizontal),Vertical:f(e.axes?.Vertical,t.axes?.Vertical),SecondaryHorizontal:f(e.axes?.SecondaryHorizontal,t.axes?.SecondaryHorizontal),SecondaryVertical:f(e.axes?.SecondaryVertical,t.axes?.SecondaryVertical)},shoulders:{LTrigger:d(e.shoulders?.LTrigger,t.shoulders?.LTrigger),RTrigger:d(e.shoulders?.RTrigger,t.shoulders?.RTrigger)},pointer:t.pointer??e.pointer}}};var V=class{_previousTime;_currentTime;_startTime;_delta;_elapsed;_timescale;_document;_pageVisibilityHandler;constructor(){this._previousTime=0,this._currentTime=0,this._startTime=te(),this._delta=0,this._elapsed=0,this._timescale=1,this._document=null,this._pageVisibilityHandler=null}connect(e){this._document=e,e.hidden!==void 0&&(this._pageVisibilityHandler=it.bind(this),e.addEventListener("visibilitychange",this._pageVisibilityHandler,!1))}disconnect(){this._pageVisibilityHandler!==null&&(this._document.removeEventListener("visibilitychange",this._pageVisibilityHandler),this._pageVisibilityHandler=null),this._document=null}getDelta(){return this._delta/1e3}getElapsed(){return this._elapsed/1e3}getTimescale(){return this._timescale}setTimescale(e){return this._timescale=e,this}reset(){return this._currentTime=te()-this._startTime,this}dispose(){this.disconnect()}update(e){return this._pageVisibilityHandler!==null&&this._document.hidden===!0?this._delta=0:(this._previousTime=this._currentTime,this._currentTime=(e!==void 0?e:te())-this._startTime,this._delta=(this._currentTime-this._previousTime)*this._timescale,this._elapsed+=this._delta),this}};function te(){return performance.now()}function it(){this._document.hidden===!1&&this.reset()}var I={FourByThree:1.3333333333333333,SixteenByNine:1.7777777777777777,NineBySixteen:.5625,TwentyOneByNine:2.3333333333333335,OneByOne:1},H=class{container;canvas;aspectRatio;onResize;handleResizeBound;resizeObserver=null;constructor(e){this.container=e.container,this.canvas=e.canvas,this.aspectRatio=(typeof e.aspectRatio=="number",e.aspectRatio),this.onResize=e.onResize,this.handleResizeBound=this.apply.bind(this)}attach(){window.addEventListener("resize",this.handleResizeBound),typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(this.handleResizeBound),this.resizeObserver.observe(this.container)),this.apply()}detach(){window.removeEventListener("resize",this.handleResizeBound),this.resizeObserver?.disconnect(),this.resizeObserver=null}measure(){let e=this.container.getBoundingClientRect(),t=Math.round(e.width||this.container.clientWidth||0),n=Math.round(e.height||this.container.clientHeight||0);if(t>0&&n>0){if(t/n>this.aspectRatio){let u=n;return{width:Math.round(u*this.aspectRatio),height:u}}let s=t,l=Math.round(s/this.aspectRatio);return{width:s,height:l}}if(t>0){let r=t,s=Math.round(r/this.aspectRatio);return{width:r,height:s}}if(n>0){let r=n;return{width:Math.round(r*this.aspectRatio),height:r}}let i=window.innerWidth,o=Math.round(i/this.aspectRatio);return{width:i,height:o}}apply(){let{width:e,height:t}=this.measure();this.canvas.style.width=`${e}px`,this.canvas.style.height=`${t}px`,this.onResize?.(e,t)}};var Le={NES:{displayAspect:1.3333333333333333,resolutions:[{key:"256x240",width:256,height:240,notes:"Standard NTSC; effective 240p."}]},SNES:{displayAspect:1.3333333333333333,resolutions:[{key:"256x224",width:256,height:224,notes:"Common 240p-equivalent mode."},{key:"512x448",width:512,height:448,notes:"Hi-res interlaced (480i)."}]},N64:{displayAspect:1.3333333333333333,resolutions:[{key:"320x240",width:320,height:240,notes:"Common 240p mode."},{key:"640x480",width:640,height:480,notes:"Higher resolution (480i)."}]},PS1:{displayAspect:1.3333333333333333,resolutions:[{key:"320x240",width:320,height:240,notes:"Progressive 240p common."},{key:"640x480",width:640,height:480,notes:"Interlaced 480i for higher detail."}]},PS2:{displayAspect:1.3333333333333333,resolutions:[{key:"640x480",width:640,height:480,notes:"480i/480p baseline."},{key:"720x480",width:720,height:480,notes:"480p (widescreen capable in some titles)."},{key:"1280x720",width:1280,height:720,notes:"720p (select titles)."}]},PS5:{displayAspect:1.7777777777777777,resolutions:[{key:"720x480",width:720,height:480,notes:"Legacy compatibility."},{key:"1280x720",width:1280,height:720,notes:"720p."},{key:"1920x1080",width:1920,height:1080,notes:"1080p."},{key:"2560x1440",width:2560,height:1440,notes:"1440p."},{key:"3840x2160",width:3840,height:2160,notes:"4K (up to 120Hz)."},{key:"7680x4320",width:7680,height:4320,notes:"8K (limited)."}]},XboxOne:{displayAspect:1.7777777777777777,resolutions:[{key:"1280x720",width:1280,height:720,notes:"720p (original)."},{key:"1920x1080",width:1920,height:1080,notes:"1080p (original)."},{key:"3840x2160",width:3840,height:2160,notes:"4K UHD (S/X models)."}]},MobilePortrait:{displayAspect:.5625,resolutions:[{key:"360x640",width:360,height:640,notes:"Low-density phone portrait baseline."},{key:"720x1280",width:720,height:1280,notes:"HD phone portrait."},{key:"1080x1920",width:1080,height:1920,notes:"Full HD phone portrait."}]}};function ne(a){return Le[a].displayAspect}function ie(a,e){let t=Le[a]?.resolutions||[];if(!e)return t[0];let n=e.toLowerCase().replace(/\s+/g,"").replace("\xD7","x");return t.find(i=>i.key.toLowerCase()===n)}function ae(a){if(!a)return null;let t=String(a).toLowerCase().trim().replace(/\s+/g,"").replace("\xD7","x").match(/^(\d+)x(\d+)$/);if(!t)return null;let n=parseInt(t[1],10),i=parseInt(t[2],10);return!Number.isFinite(n)||!Number.isFinite(i)?null:{width:n,height:i}}var oe=null,se=class{constructor(e,t,n,i,o,r,s,l,u,m,p,h,Z){this.id=e;this.globals=t;this.stages=n;this.debug=i;this.time=o;this.input=r;this.aspectRatio=s;this.internalResolution=l;this.fullscreen=u;this.bodyBackground=m;this.container=p;this.containerId=h;this.canvas=Z}};function at(a={}){return a.deviceProfile==="mobile"?!0:a.deviceProfile==="desktop"?!1:a.viewportSize?T({viewportSize:a.viewportSize,allowViewportOnly:!0}):T()}function ot(a,e){if(e)return e;if(a){let i=document.getElementById(a);if(i)return i}let t=a||"zylem-root",n=document.createElement("main");return n.setAttribute("id",t),n.style.position="relative",n.style.width="100%",n.style.height="100%",document.body.appendChild(n),n}function st(a){let e=a?.id??"zylem";return{id:e,globals:a?.globals??{},stages:a?.stages??[],debug:!!a?.debug,time:a?.time??0,input:a?.input,aspectRatio:I.SixteenByNine,fullscreen:!0,bodyBackground:"#000000",containerId:e}}var ke=360;function De(a,e){if(!a)return;if(typeof a=="string"){if(a==="native")return oe;let i=ae(a);if(i)return i;if(e){let o=ie(e,a);if(o)return{width:o.width,height:o.height}}return}let t=a.width,n=a.height;if(Number.isFinite(t)&&Number.isFinite(n))return{width:t,height:n}}function rt(a,e,t,n){if(typeof a=="number")return a;if(typeof a=="string")return I[a]??t;if(e)try{return ne(e)||t}catch{return t}return n?n.width/n.height:t}function lt(a){let e=Number.isFinite(a)&&a>0?a:I.SixteenByNine;if(e>=1){let i=ke;return{width:Math.round(i*e),height:i}}let t=ke,n=Math.round(t/e);return{width:t,height:n}}function P(a,e={}){let t=st({id:a?.id??"zylem",debug:!!a?.debug,time:a?.time??0,input:a?.input,stages:a?.stages??[],globals:a?.globals??{}}),n=a?.containerId??t.containerId,i=ot(n,a?.container??null),o=a?.mobile,r=at(e),s=r?o?.preset??a?.preset:a?.preset,l=De(a?.resolution,a?.preset),u=De(o?.resolution,o?.preset??a?.preset),m=(r?Ae(u):void 0)??Ae(l),p=r?o?.aspectRatio??a?.aspectRatio:a?.aspectRatio,h=rt(p,s,t.aspectRatio,m),Z=ut(r,u,l,h),Oe=a?.fullscreen??t.fullscreen,Ue=a?.bodyBackground??t.bodyBackground,Ne=a?.canvas??void 0,_e=pt(a?.input??t.input,o?.controls);return new se(a?.id??t.id,a?.globals??t.globals,a?.stages??t.stages,!!(a?.debug??t.debug),a?.time??t.time,_e,h,Z,Oe,Ue,i,n,Ne)}function Ae(a){if(a)return a}function ut(a,e,t,n){if(a)return e===oe?void 0:e??lt(n);if(t!==oe)return t}function pt(a,e){if(!e)return a;let n=be("p1",{enabled:"auto",...e===!0?{}:e});return v(n,a??{})}function dt(a){return{...a}}var O=class{id;container;canvas;bodyBackground;fullscreen;aspectRatio;ratioDelegate=null;overlayContainer=null;constructor(e){this.id=e.id,this.container=this.ensureContainer(e.containerId??e.id,e.container),this.canvas=e.canvas??document.createElement("canvas"),this.bodyBackground=e.bodyBackground,this.fullscreen=!!e.fullscreen,this.aspectRatio=(typeof e.aspectRatio=="number",e.aspectRatio)}applyBodyBackground(){this.bodyBackground&&(document.body.style.background=this.bodyBackground)}mountCanvas(){this.mountChildren(this.canvas)}mountRenderer(e,t){this.mountChildren(e),this.canvas=e,this.attachAspectRatio(t)}getOverlayContainer(){return this.ensureOverlayContainer()}centerIfFullscreen(){if(!this.fullscreen)return;let e=this.container.style;e.display="flex",e.alignItems="center",e.justifyContent="center",e.position="relative",e.inset="0"}attachAspectRatio(e){this.ratioDelegate?(this.ratioDelegate.canvas=this.canvas,this.ratioDelegate.onResize=e,this.ratioDelegate.aspectRatio=this.aspectRatio,this.ratioDelegate.apply()):(this.ratioDelegate=new H({container:this.container,canvas:this.canvas,aspectRatio:this.aspectRatio,onResize:e}),this.ratioDelegate.attach())}setAspectRatio(e){this.aspectRatio=e,this.ratioDelegate&&(this.ratioDelegate.aspectRatio=e,this.ratioDelegate.apply())}reapplyLayout(){this.ratioDelegate?.apply()}destroy(){this.ratioDelegate?.detach(),this.ratioDelegate=null}mountChildren(e){for(;this.container.firstChild;)this.container.removeChild(this.container.firstChild);this.container.appendChild(e),this.container.appendChild(this.ensureOverlayContainer())}ensureOverlayContainer(){if(this.overlayContainer)return this.overlayContainer;let e=document.createElement("div");return e.dataset.zylemOverlayRoot="true",e.style.position="absolute",e.style.inset="0",e.style.pointerEvents="none",e.style.touchAction="none",e.style.zIndex="10",this.overlayContainer=e,e}ensureContainer(e,t){if(t)return t;if(e){let o=document.getElementById(e);if(o)return o}let n=e||this.id||"zylem-root",i=document.createElement("main");return i.setAttribute("id",n),i.style.position="relative",i.style.width="100%",i.style.height="100%",document.body.appendChild(i),i}};import ct from"stats.js";import{subscribe as mt}from"valtio/vanilla";var U=class{statsRef=null;unsubscribe=null;constructor(){this.updateDebugUI(),this.unsubscribe=mt(g,()=>{this.updateDebugUI()})}begin(){this.statsRef?.begin()}end(){this.statsRef?.end()}updateDebugUI(){g.enabled&&!this.statsRef?(this.statsRef=new ct,this.statsRef.showPanel(0),this.statsRef.dom.style.position="absolute",this.statsRef.dom.style.bottom="0",this.statsRef.dom.style.right="0",this.statsRef.dom.style.top="auto",this.statsRef.dom.style.left="auto",document.body.appendChild(this.statsRef.dom)):!g.enabled&&this.statsRef&&(this.statsRef.dom.parentNode&&this.statsRef.dom.parentNode.removeChild(this.statsRef.dom),this.statsRef=null)}dispose(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.statsRef?.dom?.parentNode&&this.statsRef.dom.parentNode.removeChild(this.statsRef.dom),this.statsRef=null}};var N=class{loadingHandlers=[];stageLoadingUnsubscribes=[];onLoading(e){return this.loadingHandlers.push(e),()=>{this.loadingHandlers=this.loadingHandlers.filter(t=>t!==e)}}emit(e){for(let n of this.loadingHandlers)try{n(e)}catch(i){console.error("Game loading handler failed",i)}let t=`loading:${e.type}`;b.emit(t,e)}wireStageLoading(e,t){let n=e.onLoading(i=>{this.emit({type:i.type,message:i.message??"",progress:i.progress??0,current:i.current,total:i.total,stageName:e.uuid??`Stage ${t}`,stageIndex:t})});typeof n=="function"&&this.stageLoadingUnsubscribes.push(n)}unwireAllStages(){for(let e of this.stageLoadingUnsubscribes)try{e()}catch{}this.stageLoadingUnsubscribes=[]}dispose(){this.unwireAllStages(),this.loadingHandlers=[]}};import{getZylemBridge as ht}from"@zylem/bridge";var _=class{container=null;camera=null;rendererManager=null;gameCanvas=null;config=null;stage=null;mounted=!1;setGameCanvas(e){this.gameCanvas=e,this.tryMount()}setConfig(e){this.config=e,this.tryMount()}setContainer(e){this.container=e,this.tryMount()}setStage(e){this.stage=e,this.mounted&&this.gameCanvas?.reapplyLayout()}setCamera(e){this.camera=e,this.tryMount()}setRendererManager(e){this.rendererManager=e,this.tryMount()}tryMount(){this.mounted||!this.container||!this.gameCanvas||(this.rendererManager?this.mountWithRendererManager():this.camera&&this.mountWithCamera())}mountWithRendererManager(){if(!this.rendererManager||!this.gameCanvas)return;let e=this.rendererManager.getDomElement();this.gameCanvas.mountRenderer(e,(t,n)=>{if(!this.rendererManager)return;let i=this.config?.internalResolution;if(i)this.rendererManager.setPixelRatio(1),this.rendererManager.resize(i.width,i.height),this.stage?.resize(i.width,i.height);else{let o=window.devicePixelRatio||1;this.rendererManager.setPixelRatio(o),this.rendererManager.resize(t,n),this.stage?.resize(t,n)}}),this.mounted=!0}mountWithCamera(){if(!this.camera||!this.gameCanvas)return;let e=this.camera.getDomElement();this.gameCanvas.mountRenderer(e,(t,n)=>{if(!this.camera)return;let i=this.config?.internalResolution;if(i)this.camera.setPixelRatio(1),this.camera.resize(i.width,i.height);else{let o=window.devicePixelRatio||1;this.camera.setPixelRatio(o),this.camera.resize(t,n)}}),this.mounted=!0}reset(){this.camera=null,this.stage=null,this.mounted=!1}dispose(){this.container=null,this.camera=null,this.rendererManager=null,this.gameCanvas=null,this.config=null,this.stage=null,this.mounted=!1}};var F=class a{id;initialGlobals={};customSetup=null;customUpdate=null;customDestroy=null;stages=[];stageMap=new Map;currentStageId="";previousTimeStamp=0;totalTime=0;timer;inputManager;wrapperRef;globalInputConfig;defaultCamera=null;rendererManager=null;container=null;canvas=null;aspectRatioDelegate=null;resolvedConfig=null;gameCanvas=null;animationFrameId=null;isDisposed=!1;loadInFlight=!1;hasStarted=!1;debugDelegate=null;loadingDelegate=new N;rendererObserver=new _;eventBusUnsubscribes=[];thumbnailUnsubscribes=[];lastPublishedGameConfig=null;gameBridge=new we;catalogUnsubscribe=null;gameUpdateParams={};stageSetupParams={};stageUpdateParams={};frameCallback=e=>this.loop(e);sourceOptions;displayRuntime;static FRAME_LIMIT=120;static FRAME_DURATION=1e3/a.FRAME_LIMIT;static MAX_DELTA_SECONDS=1/30;constructor(e,t,n={}){this.wrapperRef=t,this.timer=new V,this.timer.connect(document),this.sourceOptions={...e},this.displayRuntime={...n};let i=P(e,this.displayRuntime);this.globalInputConfig=i.input,this.id=i.id,this.stages=i.stages||[],this.container=i.container,this.canvas=i.canvas??null,this.resolvedConfig=i,this.loadGameCanvas(i),this.container=this.gameCanvas?.container??this.container,this.inputManager=new z(i.input,{targetElement:this.gameCanvas?.getOverlayContainer(),mouseTargetElement:this.gameCanvas?.container}),this.loadDebugOptions(e),this.setGlobals(e),Re(),Te(),this.gameBridge.connect({resolveEntity:o=>this.currentStage()?.wrappedStage?.entityDelegate.childrenMap.get(o)??null,setStageVariable:(o,r)=>{let s=this.currentStage()?.wrappedStage?.state;s&&(s.variables[o]=r)},createEntity:(o,r,s)=>{this.createCatalogEntity(o,r,s)},applySceneOperation:(o,r)=>{this.currentStage()?.wrappedStage?.debugDelegate?.applySceneOperation(o,r)},pickEntity:o=>this.pickEntityAtNdc(o),applySwatches:o=>{let r=this.currentStage()?.wrappedStage?.debugDelegate;return r?r.applySwatches(o):{results:o.uuids.flatMap(s=>o.swatches.map(l=>({uuid:s,kind:l.kind,source:l.source,ok:!1,reason:"entity-not-found"}))),entries:[]}}}),this.publishEntityCatalog(),this.catalogUnsubscribe=Ge(()=>this.publishEntityCatalog())}pickEntityAtNdc(e){let t=this.currentStage()?.wrappedStage,n=t?.debugDelegate?.pickAtNdc(e.x,e.y);if(!t||!n)return null;let i=t.entityDelegate.childrenMap.get(n.uuid);return i?this.buildEntitySummary(i)??{uuid:n.uuid,name:n.name||"Unnamed",type:j(i),position:W(i).position,rotation:W(i).rotation,scale:$(i)}:null}publishEntityCatalog(){this.gameBridge.publishCatalog(xe())}createCatalogEntity(e,t,n){let i=this.currentStage()?.wrappedStage,o=Ce(e);if(!i||!o)return;let r=n?.position??{x:0,y:0,z:0},s=o.create({position:r,props:{...o.defaultProps??{},...t??{}}});s&&Promise.resolve(s).then(l=>l&&i.entityDelegate.spawnEntity(l)).catch(l=>{console.error("entity:create failed",l)})}setDisplayRuntime(e){this.displayRuntime={...e};let t=P(this.sourceOptions,this.displayRuntime);this.resolvedConfig=t,this.rendererObserver.setConfig(t),this.gameCanvas?.setAspectRatio(t.aspectRatio),this.publishGameConfig()}loadGameCanvas(e){this.gameCanvas=new O({id:e.id,container:e.container,containerId:e.containerId,canvas:this.canvas??void 0,bodyBackground:e.bodyBackground,fullscreen:e.fullscreen,aspectRatio:e.aspectRatio}),this.gameCanvas.applyBodyBackground(),this.gameCanvas.mountCanvas(),this.gameCanvas.centerIfFullscreen(),this.rendererObserver.setGameCanvas(this.gameCanvas),this.resolvedConfig&&this.rendererObserver.setConfig(this.resolvedConfig),this.container&&this.rendererObserver.setContainer(this.container),this.subscribeToEventBus()}loadDebugOptions(e){e.debug!==void 0&&(g.enabled=!!e.debug),this.debugDelegate=new U}isLoading(){return this.loadInFlight}async loadStage(e,t=0,n){if(this.loadInFlight){console.warn("loadStage ignored: a stage load is already in progress");return}this.loadInFlight=!0;try{await this.performLoadStage(e,t,n)}finally{this.loadInFlight=!1}}async performLoadStage(e,t=0,n){let i=n?Be(n):null,o=this.currentStage()??null,r=o?.wrappedStage??null,s=r?.scene?.scene??null,l=r?.cameraManagerRef?.primaryCamera?.camera??r?.cameraRef?.camera??null;i&&this.rendererManager?.initialized&&o&&s&&l&&this.rendererManager.beginSnapshotTransition(i,s,l),this.unloadCurrentStage();let m=e.options[0];if(this.loadingDelegate.wireStageLoading(e,t),this.rendererManager||(this.rendererManager=new ye,await this.rendererManager.initRenderer()),y.setRenderer(this.rendererManager.renderer),await e.load(this.id,m?.camera,this.rendererManager),this.stageMap.set(e.wrappedStage.uuid,e),this.currentStageId=e.wrappedStage.uuid,this.defaultCamera=e.wrappedStage.cameraRef,this.wireEntityThumbnails(e),this.rendererObserver.setStage(e.wrappedStage??null),this.rendererManager&&this.rendererObserver.setRendererManager(this.rendererManager),this.applyInputConfig(e),e.onInputConfigChanged=()=>this.applyInputConfig(e),this.hasStarted&&e.wrappedStage&&!e.wrappedStage.hasSetup){let p=this.params(),h={...this.stageSetupParams};h.inputs=p.inputs,h.globals=p.globals,h.camera=p.camera,h.stage=p.stage,h.game=p.game,h.me=e.wrappedStage,e.start(h)}this.publishGameConfig(),this.publishStageSnapshot()}applyInputConfig(e){let t=v(this.globalInputConfig??{},e.inputConfig??{});this.inputManager.configure(t)}setGlobalInputConfig(e){this.globalInputConfig=e;let t=this.currentStage();t&&this.applyInputConfig(t)}unloadCurrentStage(){if(!this.currentStageId)return;let e=this.getStage(this.currentStageId);if(e){if(this.clearEntityThumbnailWiring(),y.clear(),e.onInputConfigChanged=null,e?.wrappedStage){try{e.wrappedStage.nodeDestroy({me:e.wrappedStage,globals:C.globals})}catch(t){console.error("Failed to destroy previous stage",t)}e.wrappedStage=null}e.dispose(),this.stageMap.delete(this.currentStageId),this.currentStageId="",this.defaultCamera=null,this.rendererObserver.reset()}}setGlobals(e){this.initialGlobals={...e.globals};for(let t in this.initialGlobals){let n=this.initialGlobals[t];n===void 0&&console.error(`global ${t} is undefined`),de(t,n)}}params(){let e=this.currentStage(),t=this.timer.getDelta(),n=this.inputManager.getInputs(t),i=e?.wrappedStage?.cameraRef||this.defaultCamera,o=this.gameUpdateParams;return o.delta=t,o.inputs=n,o.globals=he(),o.me=this,o.camera=i,o.stage=e,o.game=this.wrapperRef,o}start(){let e=this.currentStage(),t=this.params(),n=this.stageSetupParams;n.inputs=t.inputs,n.globals=t.globals,n.camera=t.camera,n.stage=t.stage,n.game=t.game,n.me=e.wrappedStage,e.start(n),this.customSetup&&this.customSetup(t),this.hasStarted=!0,this.loop(0)}step(e){let t=this.currentStage();if(!t||!t.wrappedStage)return;let n=this.params(),i=e!==void 0?e:n.delta,o=Math.min(Math.max(i,0),a.MAX_DELTA_SECONDS);n.delta=o,this.customUpdate&&this.customUpdate(n);let r=this.currentStage();if(r!==t||!r?.wrappedStage){this.totalTime+=o,C.time=this.totalTime;return}let s=this.stageUpdateParams;s.delta=n.delta,s.inputs=n.inputs,s.globals=n.globals,s.camera=n.camera,s.stage=n.stage,s.game=n.game,s.me=t.wrappedStage,t.wrappedStage?.nodeUpdate(s),this.totalTime+=o,C.time=this.totalTime}loop(e){this.debugDelegate?.begin(),fe()||(this.timer.update(e),this.step(),this.previousTimeStamp=e),this.debugDelegate?.end(),this.outOfLoop(),this.isDisposed||(this.animationFrameId=requestAnimationFrame(this.frameCallback))}dispose(){this.isDisposed=!0,this.catalogUnsubscribe?.(),this.catalogUnsubscribe=null,this.gameBridge.disconnect(),this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.unloadCurrentStage(),this.debugDelegate&&(this.debugDelegate.dispose(),this.debugDelegate=null),this.eventBusUnsubscribes.forEach(e=>e()),this.eventBusUnsubscribes=[],this.rendererObserver.dispose(),this.inputManager.dispose(),this.rendererManager&&(y.setRenderer(null),this.rendererManager.dispose(),this.rendererManager=null),y.clear(),ht().channel.reset(),this.timer.dispose(),this.customDestroy&&this.customDestroy({me:this,globals:C.globals}),x()}outOfLoop(){let e=this.currentStage();e&&e.wrappedStage.outOfLoop()}getStage(e){return this.stageMap.get(e)}currentStage(){return this.getStage(this.currentStageId)}onLoading(e){return this.loadingDelegate.onLoading(e)}buildStageConfigPayload(){let e=this.currentStage();if(!e?.wrappedStage)return null;let t=e.wrappedStage.state,n=t.backgroundColor,i=typeof n=="string"?n:`#${n.getHexString()}`;return{id:e.wrappedStage.uuid,backgroundColor:i,backgroundImage:t.backgroundImage,gravity:{x:t.gravity.x,y:t.gravity.y,z:t.gravity.z},inputs:t.inputs,variables:t.variables}}buildEntitySummary(e){if(G(e.options))return null;let t=e.position??{x:0,y:0,z:0},n=e.rotation??{x:0,y:0,z:0},i=$(e),o=Se(e),r=y.get(e.uuid);return{uuid:e.uuid,name:e.name||"Unnamed",type:j(e),position:{x:t.x??0,y:t.y??0,z:t.z??0},rotation:{x:n.x??0,y:n.y??0,z:n.z??0},scale:i,quaternion:o,thumbnail:r?.dataUrl??null,bounds:r?.bounds}}buildEntitiesPayload(){let e=this.currentStage();if(!e?.wrappedStage)return[];let t=[];return e.wrappedStage.entityDelegate.childrenMap.forEach(n=>{let i=this.buildEntitySummary(n);i&&t.push(i)}),t}wireEntityThumbnails(e){if(this.clearEntityThumbnailWiring(),!e.wrappedStage)return;let t=r=>{if(!this.gameBridge.wantsThumbnails()||G(r.options))return;let s=r.group??r.mesh??null;s&&y.ensure(r.uuid,s).then(l=>{l&&!this.isDisposed&&this.gameBridge.queueThumbnails([{uuid:r.uuid,url:l.dataUrl,bounds:l.bounds}])})},n=e.wrappedStage.onEntityAdded(r=>{if(this.gameBridge.wantsEntityUpdates()){let s=this.buildEntitySummary(r);s&&this.gameBridge.queueEntityUpsert([s])}t(r)},{replayExisting:!0});this.thumbnailUnsubscribes.push(n);let i=r=>{if(!r.success)return;let s=e.wrappedStage?.entityDelegate.childrenMap.get(r.entityId);s&&(y.invalidate(r.entityId),t(s))};b.on("entity:model:loaded",i),this.thumbnailUnsubscribes.push(()=>{b.off("entity:model:loaded",i)});let o=r=>{y.invalidate(r.entityId),this.gameBridge.wantsEntityUpdates()&&this.gameBridge.queueEntityRemoved([r.entityId])};b.on("entity:destroyed",o),this.thumbnailUnsubscribes.push(()=>{b.off("entity:destroyed",o)}),this.wireEditorBackfill(e)}wireEditorBackfill(e){let t=this.gameBridge.onEditorAttached(()=>{if(!(this.isDisposed||this.currentStage()!==e)){this.lastPublishedGameConfig=null,this.publishGameConfig(),this.publishStageSnapshot();for(let n of e.wrappedStage?.entityDelegate.childrenMap.values()??[]){let i=n;if(G(i.options))continue;let o=i.group??i.mesh??null;o&&y.ensure(i.uuid,o).then(r=>{r&&!this.isDisposed&&this.gameBridge.queueThumbnails([{uuid:i.uuid,url:r.dataUrl,bounds:r.bounds}])})}}});this.thumbnailUnsubscribes.push(t)}clearEntityThumbnailWiring(){this.thumbnailUnsubscribes.forEach(e=>{try{e()}catch{}}),this.thumbnailUnsubscribes=[]}buildGameConfigPayload(){return this.resolvedConfig?{id:this.resolvedConfig.id,aspectRatio:this.resolvedConfig.aspectRatio,fullscreen:this.resolvedConfig.fullscreen,bodyBackground:this.resolvedConfig.bodyBackground,internalResolution:this.resolvedConfig.internalResolution,debug:this.resolvedConfig.debug}:null}publishGameConfig(){let e=this.buildGameConfigPayload();if(!e)return;let t=JSON.stringify(e);t!==this.lastPublishedGameConfig&&(this.lastPublishedGameConfig=t,this.gameBridge.publishConfig(e))}publishStageSnapshot(){this.gameBridge.publishStageSnapshot({stage:this.buildStageConfigPayload(),entities:this.buildEntitiesPayload()})}subscribeToEventBus(){this.eventBusUnsubscribes.push(pe.on("game:state:updated",e=>{this.gameBridge.publishVariable({path:e.path,value:e.value,previousValue:e.previousValue})}))}};async function ze(a){let{getGameDefaultConfig:e}=await import("./game-default-6YXFFZ2Q.js"),t={...e()},n=[],i=[],o=[];Object.values(a).forEach(s=>{if(s instanceof L)i.push(s);else if(s instanceof ee)o.push(s);else if(s instanceof Q)o.push(s);else if(s?.constructor?.name==="Object"&&typeof s=="object"){let l=Object.assign({...e()},{...s});n.push(l)}}),n.forEach(s=>{t=Object.assign(t,{...s})});let r=t;return r.input=n[0].input,i.forEach(s=>{s.addEntities(o)}),i.length?r.stages=i:r.stages[0].addEntities(o),r}function Ve(a){return!!a.find(t=>t instanceof L)}function re(a){for(let e of a)if(e&&typeof e=="object"&&!(e instanceof L)&&!(e instanceof Q)&&!(e instanceof ee)){let t=e;if(t.globals)return t.globals}}import{proxy as gt}from"valtio/vanilla";import{get as ft,set as yt}from"idb-keyval";import{pack as bt,unpack as vt}from"msgpackr";var c=gt({previous:null,current:null,next:null,isLoading:!1}),X={staticRegistry:new Map,registerStaticStage(a,e){this.staticRegistry.set(a,e)},async loadStageData(a){try{let e=await ft(a);if(e)return vt(e)}catch(e){console.warn(`Failed to load stage ${a} from storage`,e)}if(this.staticRegistry.has(a))return this.staticRegistry.get(a);throw new Error(`Stage ${a} not found in storage and static loading not fully implemented.`)},async transitionForward(a,e){if(!c.isLoading){c.isLoading=!0;try{c.current&&await yt(c.current.id,bt(c.current)),c.previous=c.current,c.current=c.next,c.current?.id!==a&&(e?c.current=await e(a):c.current=await this.loadStageData(a)),c.next=null}catch(t){console.error("Failed to transition stage:",t)}finally{c.isLoading=!1}}},async preloadNext(a,e){e?c.next=await e(a):c.next=await this.loadStageData(a)}};var le={async createFromBlueprint(a){let e=E({});if(a.entities)for(let t of a.entities)try{let n=await Ie.createFromBlueprint(t);e.add(n)}catch(n){console.error(`Failed to create entity ${t.id} for stage ${a.id}`,n)}return e}};var Y=class{wrappedGame=null;options;setupCallbacks=[];updateCallbacks=[];destroyCallbacks=[];pendingLoadingCallbacks=[];globalChangeCallbacks=[];globalChangesCallbacks=[];activeGlobalSubscriptions=[];eventDelegate=new ve;pendingInputConfig=null;displayRuntime={};refErrorMessage="lost reference to game";constructor(e){this.options=e,Ve(e)||this.options.push(E());let t=re(e);t&&J(t)}onSetup(...e){return this.setupCallbacks.push(...e),this}onUpdate(...e){return this.updateCallbacks.push(...e),this}onDestroy(...e){return this.destroyCallbacks.push(...e),this}setInputConfiguration(...e){let t=v(...e);return this.pendingInputConfig=t,this.wrappedGame&&this.wrappedGame.setGlobalInputConfig(t),this}async start(){x();let e=re(this.options);e&&J(e);let t=await this.load();return this.wrappedGame=t,this.setOverrides(),this.registerGlobalSubscriptions(),t.start(),this}setDisplayRuntime(e){return this.displayRuntime={...this.displayRuntime,...e},this.wrappedGame&&this.wrappedGame.setDisplayRuntime(this.displayRuntime),this}setDeviceProfile(e){return this.setDisplayRuntime({deviceProfile:e})}setViewportSize(e,t){return this.setDisplayRuntime({viewportSize:{width:e,height:t}})}async load(){let e=await ze(this.options),t=P(e,this.displayRuntime);this.pendingInputConfig&&(t.input=v(t.input??{},this.pendingInputConfig));let n=new F({...e,...t},this,this.displayRuntime);for(let i of this.pendingLoadingCallbacks)n.onLoading(i);return await n.loadStage(e.stages[0]),n}setOverrides(){if(!this.wrappedGame){console.error(this.refErrorMessage);return}this.wrappedGame.customSetup=e=>{this.setupCallbacks.forEach(t=>t(e))},this.wrappedGame.customUpdate=e=>{this.updateCallbacks.forEach(t=>t(e))},this.wrappedGame.customDestroy=e=>{this.destroyCallbacks.forEach(t=>t(e))}}onGlobalChange(e,t){return this.globalChangeCallbacks.push({path:e,callback:t}),this}onGlobalChanges(e,t){return this.globalChangesCallbacks.push({paths:e,callback:t}),this}registerGlobalSubscriptions(){for(let{path:e,callback:t}of this.globalChangeCallbacks){let n=ce(e,i=>{t(i,this.getCurrentStage())});this.activeGlobalSubscriptions.push(n)}for(let{paths:e,callback:t}of this.globalChangesCallbacks){let n=me(e,i=>{t(i,this.getCurrentStage())});this.activeGlobalSubscriptions.push(n)}}getCurrentStage(){return this.wrappedGame?.currentStage()??null}experimental={getRuntime:()=>this.getCurrentStage()?.wrappedStage?.world?.simulation??null};async pause(){K(!0)}async resume(){K(!1),this.wrappedGame&&(this.wrappedGame.previousTimeStamp=0,this.wrappedGame.timer.reset())}step(e=1/60){if(!this.wrappedGame){console.error(this.refErrorMessage);return}this.wrappedGame.step(e)}async reset(e){if(!this.wrappedGame){console.error(this.refErrorMessage);return}this.wrappedGame.isLoading()||await this.wrappedGame.loadStage(this.wrappedGame.stages[0],0,e?.transition)}previousStage(e){if(!this.wrappedGame){console.error(this.refErrorMessage);return}if(this.wrappedGame.isLoading())return;let t=this.wrappedGame.currentStageId,n=this.wrappedGame.stages.findIndex(o=>o.wrappedStage?.uuid===t),i=this.wrappedGame.stages[n-1];if(!i){console.error("previous stage called on first stage");return}this.wrappedGame.loadStage(i,n-1,e?.transition)}async loadStageFromId(e){if(!this.wrappedGame){console.error(this.refErrorMessage);return}try{let t=await X.loadStageData(e),n=await le.createFromBlueprint(t);await this.wrappedGame.loadStage(n),c.current=t}catch(t){console.error(`Failed to load stage ${e}`,t)}}nextStage(e){if(!this.wrappedGame){console.error(this.refErrorMessage);return}if(this.wrappedGame.isLoading())return;if(c.next){console.log("next stage called");let o=c.next.id;if(X.transitionForward(o),c.current){le.createFromBlueprint(c.current).then(r=>{this.wrappedGame?.loadStage(r,0,e?.transition)});return}}let t=this.wrappedGame.currentStageId,n=this.wrappedGame.stages.findIndex(o=>o.wrappedStage?.uuid===t),i=this.wrappedGame.stages[n+1];if(!i){console.error("next stage called on last stage");return}this.wrappedGame.loadStage(i,n+1,e?.transition)}async goToStage(){}async end(){}dispose(){this.eventDelegate.dispose();for(let e of this.activeGlobalSubscriptions)e();this.activeGlobalSubscriptions=[],this.wrappedGame&&(this.wrappedGame.dispose(),this.wrappedGame=null),ge(),x(),Ee.clearSharedMaterialCache()}dispatch(e,t){this.eventDelegate.dispatch(e,t),b.emit(e,t)}listen(e,t){return this.eventDelegate.listen(e,t)}onLoading(e){return this.wrappedGame?this.wrappedGame.onLoading(e):(this.pendingLoadingCallbacks.push(e),()=>{this.pendingLoadingCallbacks=this.pendingLoadingCallbacks.filter(t=>t!==e),this.wrappedGame})}};function St(...a){return new Y(a)}import{Euler as wt,Quaternion as Ct,Vector2 as xt}from"three";function Gt(a){return{spawn:async(e,t,n)=>{let i=await Promise.resolve(a(t,n));return e.add(i),i},spawnRelative:async(e,t,n=new xt(0,1))=>{if(!e.body){console.warn("body missing for entity during spawnRelative");return}let{x:i,y:o,z:r}=e.body.translation(),s=e._rotation2DAngle??0;try{let p=e.body.rotation(),h=new Ct(p.x,p.y,p.z,p.w);s=new wt().setFromQuaternion(h,"XYZ").z}catch{}let l=Math.sin(-s)*(n.x??0),u=Math.cos(-s)*(n.y??0),m=await Promise.resolve(a(i+l,o+u));return t.add(m),m}}}import{subscribe as Et}from"valtio/vanilla";var ue="STAGE_STATE_CHANGE";function Rt(){return Et(S,()=>{let a={entities:S.entities,variables:S.variables};window.dispatchEvent(new CustomEvent(ue,{detail:a}))})}function Tt(){let a={entities:S.entities,variables:S.variables};window.dispatchEvent(new CustomEvent(ue,{detail:a}))}import{MathUtils as Bt,Vector3 as Mt}from"three";var He={targetKey:"primary",offset:new Mt(0,0,0),lerpFactor:.1};function It(a){let e={...He,...a,offset:q(a?.offset,He.offset)},t=null;return{priority:0,enabled:!0,onAttach(){t=null},update(n,i){let o=n.targets[e.targetKey];if(!o)return i;let r=o.position.clone().add(e.offset),s=Me(i);if(!t)t=r.clone();else{let l=Bt.clamp(e.lerpFactor,0,1),u=1-Math.pow(1-l,n.dt*60);t.lerp(r,u)}return s.position.copy(t),s.lookAt=o.position.clone(),s},onDetach(){t=null}}}import{MeshBasicMaterial as Pt}from"three";function Lt(a,e,t){let n=e.cameraRef;if(!n.renderTarget){let r=t?.width??512,s=t?.height??512;n.createRenderTarget(r,s)}let i=n.getRenderTexture();if(!i){console.warn("setCameraFeed: Failed to obtain render texture from camera.");return}if(!a.mesh){console.warn("setCameraFeed: Entity has no mesh to apply the camera feed to.");return}let o=new Pt({map:i});a.mesh.material=o}export{I as a,ne as b,ie as c,ae as d,dt as e,c as f,X as g,Y as h,St as i,Gt as j,ue as k,Rt as l,Tt as m,It as n,Lt as o};