@zylem/game-lib 0.8.8 → 0.9.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 (95) hide show
  1. package/README.md +7 -1
  2. package/dist/actions.d.ts +2 -2
  3. package/dist/actions.js +1 -1
  4. package/dist/api/game-lib.api.json +35786 -18973
  5. package/dist/api/game-lib.api.md +1209 -13
  6. package/dist/api/game-lib.d.ts +1609 -7
  7. package/dist/api/game-lib.typedoc.json +220861 -97409
  8. package/dist/audio.d.ts +193 -1
  9. package/dist/audio.js +1 -1
  10. package/dist/behavior.js +1 -1
  11. package/dist/bridge.d.ts +46 -6
  12. package/dist/bridge.js +1 -1
  13. package/dist/catalog.d.ts +91 -3
  14. package/dist/catalog.js +1 -1
  15. package/dist/chunk-2HSR5XDQ.js +1 -0
  16. package/dist/chunk-2MHB4X6B.js +24 -0
  17. package/dist/chunk-2PFNNGTV.js +1 -0
  18. package/dist/chunk-2XMG3NJS.js +1 -0
  19. package/dist/chunk-4CZZZCFB.js +9 -0
  20. package/dist/{chunk-7NYP4YAG.js → chunk-6FGXC4T6.js} +1 -1
  21. package/dist/chunk-6XFXPIVB.js +1 -0
  22. package/dist/{chunk-CBUQBP2U.js → chunk-BQRMYLYD.js} +1 -1
  23. package/dist/chunk-FZNEWOC5.js +1 -0
  24. package/dist/chunk-GPCSX3M6.js +1 -0
  25. package/dist/chunk-HISTSRAL.js +1 -0
  26. package/dist/chunk-K3NNXZIJ.js +1 -0
  27. package/dist/chunk-KP6DLLJO.js +1 -0
  28. package/dist/{chunk-JNFFTNMH.js → chunk-KSEP7AUF.js} +1 -1
  29. package/dist/{chunk-YOVE25NW.js → chunk-LI43BZQN.js} +1 -1
  30. package/dist/chunk-LSFWI46T.js +1 -0
  31. package/dist/chunk-NVVLLWIM.js +1 -0
  32. package/dist/chunk-QGIYILYI.js +1 -0
  33. package/dist/chunk-STVEILJJ.js +1 -0
  34. package/dist/chunk-UUOPT2N4.js +1 -0
  35. package/dist/chunk-VMXSE3EC.js +0 -0
  36. package/dist/chunk-VSFULLND.js +1 -0
  37. package/dist/chunk-VUJXR5K5.js +1 -0
  38. package/dist/chunk-WOT6VMZA.js +1 -0
  39. package/dist/chunk-YNX3Q3CL.js +1 -0
  40. package/dist/chunk-YQS7CGXE.js +1 -0
  41. package/dist/chunk-ZZO4CKRU.js +1 -0
  42. package/dist/cinematics.d.ts +279 -0
  43. package/dist/cinematics.js +1 -0
  44. package/dist/core.d.ts +13 -10
  45. package/dist/core.js +1 -1
  46. package/dist/cutscene-definition-C479fkei.d.ts +509 -0
  47. package/dist/{debug-state-CpnNRUFh.d.ts → debug-state-Cg3f5FB6.d.ts} +1 -1
  48. package/dist/debug.d.ts +3 -2
  49. package/dist/debug.js +1 -1
  50. package/dist/{entity-XZNGBeca.d.ts → entity-XqvuWgPm.d.ts} +54 -0
  51. package/dist/{entity-type-map-CkkFMSrL.d.ts → entity-type-map-CrsrKT8c.d.ts} +13 -4
  52. package/dist/entity.d.ts +4 -3
  53. package/dist/entity.js +1 -1
  54. package/dist/events.js +1 -1
  55. package/dist/game-9PjI5z2p.d.ts +652 -0
  56. package/dist/game-default-WBKQCEDJ.js +1 -0
  57. package/dist/globals.js +1 -1
  58. package/dist/graphics.d.ts +1 -1
  59. package/dist/graphics.js +1 -1
  60. package/dist/input-ui.js +1 -1
  61. package/dist/input.js +1 -1
  62. package/dist/public.d.ts +14 -8
  63. package/dist/public.js +1 -1
  64. package/dist/runtime.js +1 -1
  65. package/dist/schema/cutscene.schema.json +782 -0
  66. package/dist/schema/entity.schema.json +24 -24
  67. package/dist/schema/game-config.schema.json +10 -10
  68. package/dist/schema/song.schema.json +430 -0
  69. package/dist/schema/stage.schema.json +29 -29
  70. package/dist/schema.d.ts +2 -0
  71. package/dist/schema.js +1 -1
  72. package/dist/selection-bounds-BKmSo9aG.d.ts +50 -0
  73. package/dist/song-definition-rEKksP0B.d.ts +263 -0
  74. package/dist/song-player-7QPLFLAS.js +1 -0
  75. package/dist/{game-BPOr7zTB.d.ts → stage-BuGkjZnr.d.ts} +90 -644
  76. package/dist/web-components.d.ts +7 -5
  77. package/dist/web-components.js +1 -1
  78. package/dist/{zylem-camera-DZTpPOiD.d.ts → zylem-camera-Baf5vH8Z.d.ts} +8 -0
  79. package/package.json +25 -16
  80. package/dist/chunk-34MYRTRP.js +0 -9
  81. package/dist/chunk-AE3CTVHY.js +0 -1
  82. package/dist/chunk-BMRFDDMR.js +0 -1
  83. package/dist/chunk-EVMLNMGU.js +0 -1
  84. package/dist/chunk-F5LROYZL.js +0 -24
  85. package/dist/chunk-GHJQ2HKI.js +0 -1
  86. package/dist/chunk-HNCTOJP7.js +0 -1
  87. package/dist/chunk-IBJLPJLE.js +0 -1
  88. package/dist/chunk-MXO4VGDB.js +0 -1
  89. package/dist/chunk-QDQ4QMAI.js +0 -1
  90. package/dist/chunk-SAQA4SXW.js +0 -1
  91. package/dist/chunk-XK63E4SX.js +0 -1
  92. package/dist/chunk-ZRT3ZQVH.js +0 -1
  93. package/dist/chunk-ZTYNZ2N2.js +0 -1
  94. package/dist/game-default-7HCJJF5S.js +0 -1
  95. /package/dist/{chunk-MSCVL5OK.js → chunk-ELQN62PQ.js} +0 -0
package/dist/audio.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export { Howl } from 'howler';
2
+ import { q as TimeSignature, g as SongDefinition, l as SongTrack, n as NoteClip, o as AudioClip, h as InstrumentDefinition, r as SongLoop } from './song-definition-rEKksP0B.js';
3
+ export { A as AudioClipSchema, k as EffectType, E as Envelope, I as InstrumentDefinitionSchema, i as InstrumentEffect, a as InstrumentEffectSchema, j as InstrumentPreset, b as InstrumentPresetSchema, N as NoteClipSchema, O as OscillatorType, m as SongClip, d as SongClipSchema, S as SongDefinitionSchema, f as SongLoopSchema, p as SongNote, e as SongNoteSchema, c as SongTrackSchema, T as TimeSignatureSchema } from './song-definition-rEKksP0B.js';
4
+ import * as ToneNs from 'tone';
5
+ import '@sinclair/typebox';
2
6
 
3
7
  /**
4
8
  * Plays a ricochet sound effect when boundary collision occurs
@@ -10,4 +14,192 @@ declare function ricochetSound(frequency?: number, duration?: number): void;
10
14
  */
11
15
  declare function pingPongBeep(frequency?: number, duration?: number): void;
12
16
 
13
- export { pingPongBeep, ricochetSound };
17
+ /**
18
+ * Pure timing and scheduling math for songs. Everything here runs without
19
+ * an AudioContext so the player, the offline renderer and the editor agree
20
+ * on when things happen.
21
+ */
22
+ /** Quarter-note beats per bar: 4/4 → 4, 6/8 → 3, 3/4 → 3. */
23
+ declare function beatsPerBar(signature: TimeSignature): number;
24
+ declare function songLengthBeats(song: Pick<SongDefinition, 'lengthBars' | 'timeSignature'>): number;
25
+ declare function beatsToSeconds(beats: number, bpm: number): number;
26
+ declare function secondsToBeats(seconds: number, bpm: number): number;
27
+ declare function songLengthSeconds(song: Pick<SongDefinition, 'lengthBars' | 'timeSignature' | 'bpm'>): number;
28
+ /** MIDI pitch to Hz with A4 = 440. */
29
+ declare function midiToFrequency(pitch: number): number;
30
+ /** `60` → `C4`, the spelling Tone.js accepts as a note name. */
31
+ declare function midiToNoteName(pitch: number): string;
32
+ declare function dbToGain(db: number): number;
33
+ declare function gainToDb(gain: number): number;
34
+ /**
35
+ * Tracks that actually make sound: when any track is soloed only the soloed,
36
+ * unmuted ones play; otherwise everything not muted.
37
+ */
38
+ declare function audibleTrackIds(tracks: readonly SongTrack[]): Set<string>;
39
+ interface ScheduledNote {
40
+ trackId: string;
41
+ clipId: string;
42
+ instrumentId: string;
43
+ /** Seconds from the song start. */
44
+ time: number;
45
+ /** Seconds. */
46
+ duration: number;
47
+ pitch: number;
48
+ velocity: number;
49
+ }
50
+ interface ScheduledAudio {
51
+ trackId: string;
52
+ clipId: string;
53
+ url: string;
54
+ /** Seconds from the song start. */
55
+ time: number;
56
+ /** Seconds into the file. */
57
+ offset: number;
58
+ /** Seconds. */
59
+ duration: number;
60
+ /** dB. */
61
+ gain: number;
62
+ }
63
+ interface SongSchedule {
64
+ notes: ScheduledNote[];
65
+ audio: ScheduledAudio[];
66
+ /** Seconds. */
67
+ length: number;
68
+ }
69
+ interface ScheduleOptions {
70
+ /** Only schedule these tracks (mute/solo are still honored). */
71
+ trackIds?: Iterable<string>;
72
+ /** Ignore mute/solo and schedule every listed track. */
73
+ ignoreMix?: boolean;
74
+ }
75
+ /**
76
+ * Flattens a song into absolute note and audio events in seconds. Notes are
77
+ * clipped to their clip's length and to the song end; audio clips are
78
+ * clipped to the song end.
79
+ */
80
+ declare function scheduleSong(song: SongDefinition, options?: ScheduleOptions): SongSchedule;
81
+ /** Clips whose window covers `beat` on a track. */
82
+ declare function clipsAt(song: SongDefinition, trackId: string, beat: number): Array<NoteClip | AudioClip>;
83
+
84
+ /**
85
+ * Tone.js is loaded on demand so games without music never download it, and
86
+ * so the AudioContext is only started after a user gesture (browsers refuse
87
+ * to start one otherwise).
88
+ */
89
+ type ToneModule = typeof ToneNs;
90
+ /** Loads Tone.js (once) without touching the AudioContext. */
91
+ declare function loadTone(): Promise<ToneModule>;
92
+ /**
93
+ * Loads Tone.js and resumes the AudioContext. Call from a click or key
94
+ * handler the first time; later calls are cheap.
95
+ */
96
+ declare function ensureAudio(): Promise<ToneModule>;
97
+ /** True once `ensureAudio()` has successfully started the context. */
98
+ declare function isAudioReady(): boolean;
99
+
100
+ /**
101
+ * A playable instrument: a Tone.js synth for the preset, its effects chain,
102
+ * and an output node the song player routes into a track channel.
103
+ */
104
+ interface Instrument {
105
+ readonly definition: InstrumentDefinition;
106
+ /** Connect this to a channel or destination. */
107
+ readonly output: ToneNs.ToneAudioNode;
108
+ /** Plays a note. `time` is in the Tone context clock (seconds); omit for now. */
109
+ trigger(pitch: number, duration: number, time?: number, velocity?: number): void;
110
+ /** Silences ringing notes. */
111
+ releaseAll(time?: number): void;
112
+ dispose(): void;
113
+ }
114
+ /**
115
+ * Builds the synth and effects chain for an instrument definition. The
116
+ * returned `output` is not connected anywhere; the caller routes it.
117
+ */
118
+ declare function createInstrument(Tone: ToneModule, def: InstrumentDefinition): Instrument;
119
+
120
+ type SongPlayerState = 'stopped' | 'playing' | 'paused';
121
+ interface SongPlayerEvents {
122
+ /** Fires at the start of every bar with the 0-based bar index. */
123
+ bar: (bar: number) => void;
124
+ /** Fires at the start of every beat with the 0-based beat index. */
125
+ beat: (beat: number) => void;
126
+ /** Fires when a non-looping song reaches its end. */
127
+ complete: () => void;
128
+ state: (state: SongPlayerState) => void;
129
+ }
130
+ interface SongPlayerOptions {
131
+ /** Resolve clip URLs (for example, relative asset paths) before loading. */
132
+ resolveUrl?: (url: string) => string;
133
+ /** Route the master output here instead of the speakers. */
134
+ destination?: ToneNs.InputNode;
135
+ }
136
+ interface SongPlayer {
137
+ readonly definition: SongDefinition;
138
+ readonly state: SongPlayerState;
139
+ /** Resolves once Tone.js and every audio clip are loaded. */
140
+ readonly ready: Promise<void>;
141
+ /** Starts (or resumes) playback; needs a prior user gesture the first time. */
142
+ play(fromBeat?: number): Promise<void>;
143
+ pause(): void;
144
+ /** Stops and rewinds to the start. */
145
+ stop(): void;
146
+ seek(beat: number): void;
147
+ /** Playhead in beats. */
148
+ position(): number;
149
+ /** Playhead in seconds at the current tempo. */
150
+ seconds(): number;
151
+ setBpm(bpm: number): void;
152
+ setLoop(loop: SongLoop | null): void;
153
+ setTrackMute(trackId: string, mute: boolean): void;
154
+ setTrackSolo(trackId: string, solo: boolean): void;
155
+ /** dB. */
156
+ setTrackVolume(trackId: string, volume: number): void;
157
+ setTrackPan(trackId: string, pan: number): void;
158
+ /** dB. */
159
+ setMasterVolume(volume: number): void;
160
+ /** Plays one note on a track's instrument right now (for auditioning). */
161
+ preview(trackId: string, pitch: number, duration?: number, velocity?: number): Promise<void>;
162
+ /** Swaps in a new definition, keeping the playhead and state. */
163
+ update(definition: SongDefinition): Promise<void>;
164
+ on<K extends keyof SongPlayerEvents>(event: K, handler: SongPlayerEvents[K]): () => void;
165
+ dispose(): void;
166
+ }
167
+ /**
168
+ * Plays a song on Tone.js's transport. The transport is shared, so creating
169
+ * a player disposes the previous one: one song plays at a time. Tone.js is
170
+ * loaded lazily; the first `play()` must follow a user gesture.
171
+ */
172
+ declare function createSongPlayer(definition: SongDefinition, options?: SongPlayerOptions): SongPlayer;
173
+ /** The most recently created, still-live song player, if any. */
174
+ declare function getActiveSongPlayer(): SongPlayer | null;
175
+
176
+ interface RenderSongOptions {
177
+ /** Render only these tracks (mute/solo are ignored so a muted track can still be bounced). */
178
+ trackIds?: Iterable<string>;
179
+ sampleRate?: number;
180
+ /** Extra seconds after the song end so releases and reverb tails finish. */
181
+ tail?: number;
182
+ resolveUrl?: (url: string) => string;
183
+ }
184
+ /**
185
+ * Renders a song (or a subset of its tracks) to an `AudioBuffer` offline,
186
+ * faster than real time. Pair with `encodeWav` to get a file. Works without
187
+ * a user gesture: offline contexts do not need to be resumed.
188
+ */
189
+ declare function renderSong(song: SongDefinition, options?: RenderSongOptions): Promise<AudioBuffer>;
190
+
191
+ /**
192
+ * Minimal WAV (RIFF, 16-bit PCM) encoder for rendered audio. Works on any
193
+ * `AudioBuffer`-shaped object so it can run without a Web Audio context.
194
+ */
195
+ interface PcmSource {
196
+ numberOfChannels: number;
197
+ sampleRate: number;
198
+ length: number;
199
+ getChannelData(channel: number): Float32Array;
200
+ }
201
+ declare function encodeWav(buffer: PcmSource): ArrayBuffer;
202
+ /** `encodeWav` as a `Blob` ready for upload or download. */
203
+ declare function encodeWavBlob(buffer: PcmSource): Blob;
204
+
205
+ export { AudioClip, type Instrument, InstrumentDefinition, NoteClip, type PcmSource, type RenderSongOptions, type ScheduleOptions, type ScheduledAudio, type ScheduledNote, SongDefinition, SongLoop, type SongPlayer, type SongPlayerEvents, type SongPlayerOptions, type SongPlayerState, type SongSchedule, SongTrack, TimeSignature, type ToneModule, audibleTrackIds, beatsPerBar, beatsToSeconds, clipsAt, createInstrument, createSongPlayer, dbToGain, encodeWav, encodeWavBlob, ensureAudio, gainToDb, getActiveSongPlayer, isAudioReady, loadTone, midiToFrequency, midiToNoteName, pingPongBeep, renderSong, ricochetSound, scheduleSong, secondsToBeats, songLengthBeats, songLengthSeconds };
package/dist/audio.js CHANGED
@@ -1 +1 @@
1
- import{a,b,c}from"./chunk-ZRT3ZQVH.js";export{c as Howl,b as pingPongBeep,a as ricochetSound};
1
+ import{a as s,b as t,c as F,d as G,e as H,f as I}from"./chunk-ZZO4CKRU.js";import{a as u,b as v,c as w,d as x,e as y,f as z,g as A,h as B,i as C,j as D,k as E}from"./chunk-NVVLLWIM.js";import{a as m,c as n,d as o,e as p,f as q,g as r}from"./chunk-2PFNNGTV.js";import{a,b,c,d,e,f,g,h,i,j,k,l}from"./chunk-QGIYILYI.js";import"./chunk-WOT6VMZA.js";export{A as AudioClipSchema,I as Howl,w as InstrumentDefinitionSchema,v as InstrumentEffectSchema,u as InstrumentPresetSchema,z as NoteClipSchema,B as SongClipSchema,E as SongDefinitionSchema,D as SongLoopSchema,x as SongNoteSchema,y as SongTrackSchema,C as TimeSignatureSchema,j as audibleTrackIds,a as beatsPerBar,c as beatsToSeconds,l as clipsAt,m as createInstrument,q as createSongPlayer,h as dbToGain,G as encodeWav,H as encodeWavBlob,o as ensureAudio,i as gainToDb,r as getActiveSongPlayer,p as isAudioReady,n as loadTone,f as midiToFrequency,g as midiToNoteName,t as pingPongBeep,F as renderSong,s as ricochetSound,k as scheduleSong,d as secondsToBeats,b as songLengthBeats,e as songLengthSeconds};
package/dist/behavior.js CHANGED
@@ -1 +1 @@
1
- import{$,$a,A,Aa,B,Ba,C,Ca,D,Da,E,Ea,F,Fa,G,Ga,H,Ha,I,Ia,J,Ja,K,Ka,L,La,M,Ma,N,Na,O,Oa,P,Pa,Q,Qa,R,Ra,S,Sa,T,Ta,U,Ua,V,Va,W,Wa,X,Xa,Y,Ya,Z,Za,_,_a,a,aa,ab,b,ba,bb,c,ca,cb,d,da,db,e,ea,eb,f,fa,fb,g,ga,gb,h,ha,hb,i,ia,ib,j,ja,k,ka,l,la,m,ma,n,na,o,oa,p,pa,q,qa,r,ra,s,sa,t,ta,u,ua,v,va,w,wa,x,xa,y,ya,z,za}from"./chunk-XK63E4SX.js";export{a as BoundaryRicochet3DCoordinator,b as BoundaryRicochetCoordinator,c as CooldownBehavior,d as Destructible3DBehavior,e as DestructibleMesh,f as FirstPersonBehavior,g as FirstPersonEvent,h as FirstPersonFSM,k as FirstPersonPresentation,i as FirstPersonShooterCoordinator,j as FirstPersonState,l as FractureOptions,m as Jumper2DBehavior,n as Jumper2DEvent,o as Jumper2DFSM,p as Jumper2DState,q as Jumper3DBehavior,r as Jumper3DEvent,s as Jumper3DFSM,t as Jumper3DState,u as MultidirectionalSpaceShooterCoordinator,v as ParticleEmitterBehavior,w as Platformer2DBehavior,x as Platformer2DEvent,y as Platformer2DFSM,z as Platformer2DState,A as Platformer3DBehavior,B as Platformer3DEvent,C as Platformer3DFSM,D as Platformer3DState,$a as RUNTIME_BOUNDARY_2D_BEHAVIOR_KEY,ab as RUNTIME_DYNAMIC_CIRCLE_BODY_2D_BEHAVIOR_KEY,bb as RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY,cb as RUNTIME_PLAYER_INPUT_2D_BEHAVIOR_KEY,db as RUNTIME_RICOCHET_2D_BEHAVIOR_KEY,eb as RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY,E as Ricochet2DBehavior,F as Ricochet2DEvent,G as Ricochet2DFSM,H as Ricochet2DState,I as Ricochet3DBehavior,J as Ricochet3DEvent,K as Ricochet3DFSM,L as Ricochet3DState,Va as RuntimeBoundary2DBehavior,Wa as RuntimeDynamicCircleBody2DBehavior,Xa as RuntimeGoalZone2DBehavior,Ya as RuntimePlayerInput2DBehavior,Za as RuntimeRicochet2DBehavior,_a as RuntimeTriggerRegion2DBehavior,M as ScreenVisibilityBehavior,N as ScreenVisibilityFSM,O as ScreenWrapBehavior,P as ScreenWrapEvent,Q as ScreenWrapFSM,R as ScreenWrapState,S as Shooter2DBehavior,T as ThrusterBehavior,U as ThrusterEvent,V as ThrusterFSM,W as ThrusterState,X as TopDownMovementBehavior,Y as TopDownShooterCoordinator,Z as WorldBoundary2DBehavior,_ as WorldBoundary2DEvent,$ as WorldBoundary2DFSM,aa as WorldBoundary2DState,ba as WorldBoundary3DBehavior,ca as WorldBoundary3DEvent,da as WorldBoundary3DFSM,ea as WorldBoundary3DState,fb as bindRuntimeDynamicCircleBody2DHandle,fa as computeWorldBoundary2DHits,ga as computeWorldBoundary3DHits,ha as createFirstPersonInputComponent,ia as createFirstPersonMovementComponent,ja as createFirstPersonStateComponent,ka as createJumpConfig2D,la as createJumpConfig3D,ma as createJumpInput2D,na as createJumpInput3D,oa as createJumpState2D,pa as createJumpState3D,qa as createPhysicsBodyComponent,ra as createPlatformer2DInputComponent,sa as createPlatformer2DMovementComponent,ta as createPlatformer2DStateComponent,ua as createPlatformer3DInputComponent,va as createPlatformer3DMovementComponent,wa as createPlatformer3DStateComponent,xa as createShooter2DStateComponent,ya as createThrusterInputComponent,za as createThrusterMovementComponent,Aa as createThrusterStateComponent,Ba as createTopDownMovementComponent,Ca as createTopDownMovementInputComponent,Da as createTopDownMovementStateComponent,Ea as createTransformComponent,Fa as defineBehavior,gb as emitRuntimeGoal,hb as emitRuntimeRicochet,ib as emitRuntimeTriggerRegionEnter,Ga as fireCooldown,Ha as fireShooter2DIfRequested,Ia as getCooldown,Ja as getCooldownStore,Ka as getEntityFacingAngle2D,La as hasAnyWorldBoundary2DHit,Ma as hasAnyWorldBoundary3DHit,Na as particleEffect,Oa as particlePresets,Pa as registerCooldown,Qa as resetCooldown,Ra as resolveAim2D,Sa as tickCooldowns,Ta as updateBoundaryRicochet,Ua as useBehavior};
1
+ import{a as Va,b as Wa,c as Xa,d as Ya,e as Za,f as _a,g as $a,h as ab,i as bb,j as cb,k as db,l as eb,m as fb,n as gb,o as hb,p as ib}from"./chunk-6XFXPIVB.js";import{$ as _,A as z,Aa as za,B as A,Ba as Aa,C as B,Ca as Ba,D as C,Da as Ca,E as D,Ea as Da,F as E,Fa as Ea,G as F,Ga as Fa,H as G,Ha as Ga,I as H,Ia as Ha,J as I,Ja as Ia,K as J,Ka as Ja,L as K,La as Ka,M as L,Ma as La,N as M,Na as Ma,O as N,Oa as Na,P as O,Pa as Oa,Q as P,Qa as Pa,R as Q,Ra as Qa,S as R,Sa as Ra,T as S,Ta as Sa,U as T,Ua as Ta,V as U,Va as Ua,W as V,X as W,Y as X,Z as Y,_ as Z,aa as $,b as a,ba as aa,c as b,ca as ba,d as c,da as ca,e as d,ea as da,f as e,fa as ea,g as f,ga as fa,h as g,ha as ga,i as h,ia as ha,j as i,ja as ia,k as j,ka as ja,l as k,la as ka,m as l,ma as la,n as m,na as ma,o as n,oa as na,p as o,pa as oa,q as p,qa as pa,r as q,ra as qa,s as r,sa as ra,t as s,ta as sa,u as t,ua as ta,v as u,va as ua,w as v,wa as va,x as w,xa as wa,y as x,ya as xa,z as y,za as ya}from"./chunk-VUJXR5K5.js";import"./chunk-WOT6VMZA.js";export{a as BoundaryRicochet3DCoordinator,b as BoundaryRicochetCoordinator,c as CooldownBehavior,d as Destructible3DBehavior,e as DestructibleMesh,f as FirstPersonBehavior,g as FirstPersonEvent,h as FirstPersonFSM,k as FirstPersonPresentation,i as FirstPersonShooterCoordinator,j as FirstPersonState,l as FractureOptions,m as Jumper2DBehavior,n as Jumper2DEvent,o as Jumper2DFSM,p as Jumper2DState,q as Jumper3DBehavior,r as Jumper3DEvent,s as Jumper3DFSM,t as Jumper3DState,u as MultidirectionalSpaceShooterCoordinator,v as ParticleEmitterBehavior,w as Platformer2DBehavior,x as Platformer2DEvent,y as Platformer2DFSM,z as Platformer2DState,A as Platformer3DBehavior,B as Platformer3DEvent,C as Platformer3DFSM,D as Platformer3DState,$a as RUNTIME_BOUNDARY_2D_BEHAVIOR_KEY,ab as RUNTIME_DYNAMIC_CIRCLE_BODY_2D_BEHAVIOR_KEY,bb as RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY,cb as RUNTIME_PLAYER_INPUT_2D_BEHAVIOR_KEY,db as RUNTIME_RICOCHET_2D_BEHAVIOR_KEY,eb as RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY,E as Ricochet2DBehavior,F as Ricochet2DEvent,G as Ricochet2DFSM,H as Ricochet2DState,I as Ricochet3DBehavior,J as Ricochet3DEvent,K as Ricochet3DFSM,L as Ricochet3DState,Va as RuntimeBoundary2DBehavior,Wa as RuntimeDynamicCircleBody2DBehavior,Xa as RuntimeGoalZone2DBehavior,Ya as RuntimePlayerInput2DBehavior,Za as RuntimeRicochet2DBehavior,_a as RuntimeTriggerRegion2DBehavior,M as ScreenVisibilityBehavior,N as ScreenVisibilityFSM,O as ScreenWrapBehavior,P as ScreenWrapEvent,Q as ScreenWrapFSM,R as ScreenWrapState,S as Shooter2DBehavior,T as ThrusterBehavior,U as ThrusterEvent,V as ThrusterFSM,W as ThrusterState,X as TopDownMovementBehavior,Y as TopDownShooterCoordinator,Z as WorldBoundary2DBehavior,_ as WorldBoundary2DEvent,$ as WorldBoundary2DFSM,aa as WorldBoundary2DState,ba as WorldBoundary3DBehavior,ca as WorldBoundary3DEvent,da as WorldBoundary3DFSM,ea as WorldBoundary3DState,fb as bindRuntimeDynamicCircleBody2DHandle,fa as computeWorldBoundary2DHits,ga as computeWorldBoundary3DHits,ha as createFirstPersonInputComponent,ia as createFirstPersonMovementComponent,ja as createFirstPersonStateComponent,ka as createJumpConfig2D,la as createJumpConfig3D,ma as createJumpInput2D,na as createJumpInput3D,oa as createJumpState2D,pa as createJumpState3D,qa as createPhysicsBodyComponent,ra as createPlatformer2DInputComponent,sa as createPlatformer2DMovementComponent,ta as createPlatformer2DStateComponent,ua as createPlatformer3DInputComponent,va as createPlatformer3DMovementComponent,wa as createPlatformer3DStateComponent,xa as createShooter2DStateComponent,ya as createThrusterInputComponent,za as createThrusterMovementComponent,Aa as createThrusterStateComponent,Ba as createTopDownMovementComponent,Ca as createTopDownMovementInputComponent,Da as createTopDownMovementStateComponent,Ea as createTransformComponent,Fa as defineBehavior,gb as emitRuntimeGoal,hb as emitRuntimeRicochet,ib as emitRuntimeTriggerRegionEnter,Ga as fireCooldown,Ha as fireShooter2DIfRequested,Ia as getCooldown,Ja as getCooldownStore,Ka as getEntityFacingAngle2D,La as hasAnyWorldBoundary2DHit,Ma as hasAnyWorldBoundary3DHit,Na as particleEffect,Oa as particlePresets,Pa as registerCooldown,Qa as resetCooldown,Ra as resolveAim2D,Sa as tickCooldowns,Ta as updateBoundaryRicochet,Ua as useBehavior};
package/dist/bridge.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { BridgePose, SceneOperationPayload, EntityApplySwatchPayload, GameConfigPayload, GameLoadingPayload, GameVariablePayload, GameNoticePayload, StageSnapshotPayload, EntitySummaryPayload, EntityThumbnailPayload, EntityTypeDescriptor } from '@zylem/bridge';
2
- export { BRIDGE_READY_EVENT, BridgeChannel, BridgeDebugTool, BridgeHandler, GameLoadingPayload as BridgeLoadingPayload, BridgeMessageType, BridgeMessages, BridgeVec3, EditorToGameMessages, EntityApplySwatchPayload, EntitySummaryPayload, EntityThumbnailPayload, GameConfigPayload, GameToEditorMessages, GameVariablePayload, StageConfigPayload, StageSnapshotPayload, ZylemBridge, announceBridgeReady, getZylemBridge } from '@zylem/bridge';
3
- import { G as GameEntity } from './entity-XZNGBeca.js';
1
+ import { BridgePose, SceneOperationPayload, BridgeNdc, EntitySummaryPayload, EntityApplySwatchPayload, SwatchApplyResult, SceneOperationEntry, CutsceneLoadPayload, CameraPosePayload, CutsceneStatusPayload, CutsceneViewPayload, GameConfigPayload, GameLoadingPayload, GameVariablePayload, GameNoticePayload, StageSnapshotPayload, EntityThumbnailPayload, EntityTypeDescriptor } from '@zylem/bridge';
2
+ export { BRIDGE_READY_EVENT, BridgeChannel, BridgeDebugTool, BridgeHandler, GameLoadingPayload as BridgeLoadingPayload, BridgeMessageType, BridgeMessages, BridgeNdc, BridgeVec3, CameraPosePayload, CutsceneLoadPayload, CutscenePlaybackState, CutsceneStatusPayload, CutsceneViewPayload, EditorToGameMessages, EntityApplySwatchPayload, EntityPickPayload, EntityPickResultPayload, EntitySummaryPayload, EntitySwatchAppliedPayload, EntityThumbnailPayload, GameConfigPayload, GameToEditorMessages, GameVariablePayload, StageConfigPayload, StageSnapshotPayload, SwatchApplyFailureReason, SwatchApplyResult, SwatchKind, SwatchSpec, ZylemBridge, announceBridgeReady, applySwatchesToSelection, getZylemBridge } from '@zylem/bridge';
3
+ import { G as GameEntity } from './entity-XqvuWgPm.js';
4
4
  import 'three';
5
5
  import '@zylem/behaviors/core';
6
6
  import './simulation-body-zQw-emOr.js';
@@ -38,8 +38,35 @@ interface GameBridgeHost {
38
38
  createEntity?(typeId: string, props: Record<string, unknown> | undefined, pose: BridgePose | undefined): void;
39
39
  /** Undo or redo a committed scene operation (`scene:operation:apply`). */
40
40
  applySceneOperation?(op: SceneOperationPayload, direction: 'undo' | 'redo'): void;
41
- /** Attach a catalog shader or behavior to a live entity (`entity:apply-swatch`). */
42
- applySwatch?(payload: EntityApplySwatchPayload): void;
41
+ /**
42
+ * Raycast at normalized device coordinates and describe the entity hit
43
+ * (`entity:pick`). Hover should follow the pick only while pick mode is on.
44
+ */
45
+ pickEntity?(ndc: BridgeNdc): EntitySummaryPayload | null;
46
+ /**
47
+ * Apply every swatch to every uuid (`entity:apply-swatch`). Must report one
48
+ * result per uuid × swatch pair and return a `scene:operation` entry for
49
+ * each success so the batch is undoable as a single step.
50
+ */
51
+ applySwatches?(payload: EntityApplySwatchPayload & {
52
+ opId: string;
53
+ }): SwatchApplyOutcome;
54
+ /** Cutscene preview hooks (`cutscene:*`); publish progress via `publishCutsceneStatus`. */
55
+ cutscene?: {
56
+ load(payload: CutsceneLoadPayload): void;
57
+ play(from?: number): void;
58
+ pause(): void;
59
+ stop(): void;
60
+ seek(time: number): void;
61
+ unload(): void;
62
+ };
63
+ /** Describe the live camera (`camera:pose:get`), for capturing framing into a cutscene. */
64
+ cameraPose?(): Omit<CameraPosePayload, 'requestId'> | null;
65
+ }
66
+ /** What a host reports back from a swatch batch. */
67
+ interface SwatchApplyOutcome {
68
+ results: SwatchApplyResult[];
69
+ entries: SceneOperationEntry[];
43
70
  }
44
71
  declare class GameBridge {
45
72
  private channel;
@@ -63,7 +90,20 @@ declare class GameBridge {
63
90
  * @param announceTarget DOM node the `zylem:bridge:ready` event bubbles from
64
91
  */
65
92
  connect(host: GameBridgeHost, announceTarget?: EventTarget): void;
93
+ /** Cutscene playback progress for Director mode's transport. */
94
+ publishCutsceneStatus(status: CutsceneStatusPayload): void;
95
+ /** The previewing camera's projection, for Director mode's viewport overlays. */
96
+ publishCutsceneView(view: CutsceneViewPayload): void;
66
97
  disconnect(): void;
98
+ /**
99
+ * Run a swatch batch and report back.
100
+ *
101
+ * Order matters for the consumer: selection changes first (so a following
102
+ * `entity:selection` describes the new targets), then the undo record, then
103
+ * the ack — a consumer that persists on `ok` sees the operation already on
104
+ * the stack.
105
+ */
106
+ private handleApplySwatch;
67
107
  /**
68
108
  * Publish only the parts of `debugState` the editor does not already know.
69
109
  * Values that arrived as editor commands are recorded on `editorKnown`
@@ -132,4 +172,4 @@ declare class GameBridge {
132
172
  wantsSceneOperations(): boolean;
133
173
  }
134
174
 
135
- export { GameBridge, type GameBridgeHost };
175
+ export { GameBridge, type GameBridgeHost, type SwatchApplyOutcome };
package/dist/bridge.js CHANGED
@@ -1 +1 @@
1
- import{a as b,b as c,c as d}from"./chunk-HNCTOJP7.js";import{f as a}from"./chunk-ZTYNZ2N2.js";import"./chunk-CBUQBP2U.js";import"./chunk-EVMLNMGU.js";export{d as BRIDGE_READY_EVENT,a as GameBridge,c as announceBridgeReady,b as getZylemBridge};
1
+ import{a as b,b as c,c as d,d as e}from"./chunk-FZNEWOC5.js";import{g as a}from"./chunk-HISTSRAL.js";import"./chunk-BQRMYLYD.js";import"./chunk-GPCSX3M6.js";import"./chunk-WOT6VMZA.js";export{e as BRIDGE_READY_EVENT,a as GameBridge,c as announceBridgeReady,d as applySwatchesToSelection,b as getZylemBridge};
package/dist/catalog.d.ts CHANGED
@@ -1,10 +1,13 @@
1
- import { EntityTypeDescriptor } from '@zylem/bridge';
2
- export { EntityTypeDescriptor } from '@zylem/bridge';
1
+ import { EntityTypeDescriptor, SwatchKind } from '@zylem/bridge';
2
+ export { EntityTypeDescriptor, SwatchKind, SwatchSpec } from '@zylem/bridge';
3
3
  import { B as BaseNode } from './base-node-idopiSw5.js';
4
4
  import { c as Vec3 } from './vector-D3eDzvcA.js';
5
+ import { BehaviorDescriptor } from '@zylem/behaviors/core';
6
+ import { d as ZylemShader } from './material-CxxAyJYp.js';
5
7
  import './base-node-life-cycle-BK9xebT9.js';
6
8
  import 'three';
7
9
  import './stage-transition-CmGpV4tc.js';
10
+ import 'three/webgpu';
8
11
 
9
12
  /**
10
13
  * Runtime registry of placeable entity types, backing the editor's Add palette.
@@ -74,4 +77,89 @@ declare const BUILT_IN_ENTITY_TYPES: EntityTypeRegistration[];
74
77
  */
75
78
  declare function registerBuiltInEntityTypes(): () => void;
76
79
 
77
- export { BUILT_IN_ENTITY_TYPES, type EntityPlacementContext, type EntityTypeFactory, type EntityTypeRegistration, buildCatalogDescriptors, clearEntityRegistry, getEntityType, listEntityTypes, onEntityRegistryChanged, registerBuiltInEntityTypes, registerEntityType, registerEntityTypes };
80
+ /**
81
+ * Runtime registry of swatch sources: the shader factories and behavior
82
+ * descriptors that `entity:apply-swatch` messages can name.
83
+ *
84
+ * A swatch crosses the bridge as `{ kind, source, props }` where `source` is an
85
+ * export name such as `createLava` or `ThrusterBehavior`. game-lib does not
86
+ * depend on `@zylem/shaders`, and behaviors are keyed by symbol rather than
87
+ * string, so this map is how a bare name resolves back to something callable.
88
+ * Hosts fill it at boot (typically by walking the module namespaces they
89
+ * already import, see {@link registerSwatchSourcesFromModule}); game-lib
90
+ * pre-registers its own re-exported behaviors via
91
+ * {@link registerBuiltInBehaviorSwatchSources}.
92
+ *
93
+ * Mirrors `entity-registry.ts`: the factory stays on this side of the bridge
94
+ * and only serializable identifiers cross it.
95
+ */
96
+
97
+ /** A shader factory: turns catalog props into a `ZylemShader`. */
98
+ type SwatchShaderFactory = (props: Record<string, unknown>) => ZylemShader;
99
+ interface ShaderSwatchSource {
100
+ kind: 'shader';
101
+ /** Export name, e.g. `createLava`. */
102
+ id: string;
103
+ create: SwatchShaderFactory;
104
+ }
105
+ interface BehaviorSwatchSource {
106
+ kind: 'behavior';
107
+ /** Export name, e.g. `ThrusterBehavior`. */
108
+ id: string;
109
+ descriptor: BehaviorDescriptor<any, any>;
110
+ }
111
+ type SwatchSource = ShaderSwatchSource | BehaviorSwatchSource;
112
+ /**
113
+ * Register one swatch source, replacing any existing source of the same kind
114
+ * and id so a host can override a built-in.
115
+ *
116
+ * @returns An unregister function.
117
+ */
118
+ declare function registerSwatchSource(source: SwatchSource): () => void;
119
+ /** Register several sources at once, notifying listeners only after all of them. */
120
+ declare function registerSwatchSources(sources: SwatchSource[]): () => void;
121
+ declare function getSwatchSource(kind: 'shader', id: string): ShaderSwatchSource | null;
122
+ declare function getSwatchSource(kind: 'behavior', id: string): BehaviorSwatchSource | null;
123
+ declare function getSwatchSource(kind: SwatchKind, id: string): SwatchSource | null;
124
+ /** Every registered source, shaders first, in registration order. */
125
+ declare function listSwatchSources(kind?: SwatchKind): SwatchSource[];
126
+ /**
127
+ * Observe registry changes.
128
+ *
129
+ * @returns An unsubscribe function.
130
+ */
131
+ declare function onSwatchRegistryChanged(listener: () => void): () => void;
132
+ /** Test hook: drop every registration. */
133
+ declare function clearSwatchRegistry(): void;
134
+ /** Structural check for a `defineBehavior` descriptor. */
135
+ declare function isBehaviorDescriptor(value: unknown): value is BehaviorDescriptor<any, any>;
136
+ /**
137
+ * Register every plausible source found on a module namespace object.
138
+ *
139
+ * - `kind: 'behavior'`: every export that is a behavior descriptor.
140
+ * - `kind: 'shader'`: every function export; with `filter` a host can narrow
141
+ * this to, say, names starting with `create`.
142
+ *
143
+ * Export names become source ids, which is what makes the live path agree with
144
+ * generated code that imports the same names.
145
+ *
146
+ * @returns An unregister function for everything this call registered.
147
+ */
148
+ declare function registerSwatchSourcesFromModule(kind: SwatchKind, module: Record<string, unknown>, filter?: (exportName: string, value: unknown) => boolean): () => void;
149
+
150
+ /**
151
+ * Built-in swatch sources: every behavior descriptor game-lib re-exports from
152
+ * `@zylem/game-lib/behavior`, registered under its export name.
153
+ *
154
+ * Kept apart from `swatch-registry.ts` so the registry module does not pull the
155
+ * whole behavior barrel into every bundle; only games that call this (the
156
+ * `ZylemGame` constructor does) pay for it. Shaders are not built in — game-lib
157
+ * does not depend on `@zylem/shaders` — so hosts register those themselves.
158
+ */
159
+ /**
160
+ * Register the built-in behavior descriptors as swatch sources. Idempotent, so
161
+ * a second game on the page does not re-register them.
162
+ */
163
+ declare function registerBuiltInBehaviorSwatchSources(): () => void;
164
+
165
+ export { BUILT_IN_ENTITY_TYPES, type BehaviorSwatchSource, type EntityPlacementContext, type EntityTypeFactory, type EntityTypeRegistration, type ShaderSwatchSource, type SwatchShaderFactory, type SwatchSource, buildCatalogDescriptors, clearEntityRegistry, clearSwatchRegistry, getEntityType, getSwatchSource, isBehaviorDescriptor, listEntityTypes, listSwatchSources, onEntityRegistryChanged, onSwatchRegistryChanged, registerBuiltInBehaviorSwatchSources, registerBuiltInEntityTypes, registerEntityType, registerEntityTypes, registerSwatchSource, registerSwatchSources, registerSwatchSourcesFromModule };
package/dist/catalog.js CHANGED
@@ -1 +1 @@
1
- import{a as o,b as s}from"./chunk-QDQ4QMAI.js";import{a as t,b as e,c as y,d as i,e as r,f as n,g as p}from"./chunk-AE3CTVHY.js";import"./chunk-BMRFDDMR.js";import"./chunk-SAQA4SXW.js";import"./chunk-7NYP4YAG.js";import"./chunk-AIQ6IVT5.js";import"./chunk-QXVH6POE.js";import"./chunk-EVYHPR3J.js";import"./chunk-4QLJUQSJ.js";import"./chunk-7WRQ2UAN.js";import"./chunk-XRP4JJXL.js";export{o as BUILT_IN_ENTITY_TYPES,r as buildCatalogDescriptors,p as clearEntityRegistry,y as getEntityType,i as listEntityTypes,n as onEntityRegistryChanged,s as registerBuiltInEntityTypes,t as registerEntityType,e as registerEntityTypes};
1
+ import{a,b as S,c as T}from"./chunk-VSFULLND.js";import{a as t,b as e,c as r,d as i,e as o,f as y,g as c,h as s,i as p,j as h,k as n,l as g,m as w,n as u,o as E}from"./chunk-2HSR5XDQ.js";import"./chunk-STVEILJJ.js";import"./chunk-KP6DLLJO.js";import"./chunk-6FGXC4T6.js";import"./chunk-AIQ6IVT5.js";import"./chunk-QXVH6POE.js";import"./chunk-UUOPT2N4.js";import"./chunk-EVYHPR3J.js";import"./chunk-VUJXR5K5.js";import"./chunk-4QLJUQSJ.js";import"./chunk-7WRQ2UAN.js";import"./chunk-XRP4JJXL.js";import"./chunk-WOT6VMZA.js";export{a as BUILT_IN_ENTITY_TYPES,o as buildCatalogDescriptors,c as clearEntityRegistry,w as clearSwatchRegistry,r as getEntityType,h as getSwatchSource,u as isBehaviorDescriptor,i as listEntityTypes,n as listSwatchSources,y as onEntityRegistryChanged,g as onSwatchRegistryChanged,T as registerBuiltInBehaviorSwatchSources,S as registerBuiltInEntityTypes,t as registerEntityType,e as registerEntityTypes,s as registerSwatchSource,p as registerSwatchSources,E as registerSwatchSourcesFromModule};
@@ -0,0 +1 @@
1
+ var o=new Map,d=new Set;function n(){for(let e of d)try{e()}catch(t){console.error("[zylem] entity registry listener failed",t)}}function S(e){return o.set(e.id,e),n(),()=>{o.get(e.id)===e&&(o.delete(e.id),n())}}function l(e){for(let t of e)o.set(t.id,t);return n(),()=>{for(let t of e)o.get(t.id)===t&&o.delete(t.id);n()}}function g(e){return o.get(e)??null}function y(){return[...o.values()]}function w(){return y().map(({create:e,...t})=>t)}function v(e){return d.add(e),()=>d.delete(e)}function x(){o.clear(),n()}var r={shader:new Map,behavior:new Map},p=new Set;function c(){for(let e of p)try{e()}catch(t){console.error("[zylem] swatch registry listener failed",t)}}function E(e){return r[e.kind].set(e.id,e),c(),()=>{r[e.kind].get(e.id)===e&&(r[e.kind].delete(e.id),c())}}function h(e){for(let t of e)r[t.kind].set(t.id,t);return c(),()=>{for(let t of e)r[t.kind].get(t.id)===t&&r[t.kind].delete(t.id);c()}}function b(e,t){return r[e].get(t)??null}function T(e){return e?[...r[e].values()]:[...r.shader.values(),...r.behavior.values()]}function k(e){return p.add(e),()=>p.delete(e)}function R(){r.shader.clear(),r.behavior.clear(),c()}function f(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.key=="symbol"&&typeof t.systemFactory=="function"&&typeof t.defaultOptions=="object"&&t.defaultOptions!==null}function B(e,t,u){let a=[];for(let[s,i]of Object.entries(t))u&&!u(s,i)||(e==="behavior"?f(i)&&a.push({kind:e,id:s,descriptor:i}):typeof i=="function"&&a.push({kind:e,id:s,create:i}));return h(a)}export{S as a,l as b,g as c,y as d,w as e,v as f,x as g,E as h,h as i,b as j,T as k,k as l,R as m,f as n,B as o};
@@ -0,0 +1,24 @@
1
+ import{b as ye,d as G,j as Ie,u as L,v as E}from"./chunk-LSFWI46T.js";import{g as be}from"./chunk-PCFF4LLO.js";import{b as y}from"./chunk-Q2YDBMVY.js";import{b as Re,c as Te}from"./chunk-VSFULLND.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-HISTSRAL.js";import{d as g,g as fe,h as K}from"./chunk-GPCSX3M6.js";import{k as Pe}from"./chunk-LI43BZQN.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{t as Me}from"./chunk-2XMG3NJS.js";import{b as Be}from"./chunk-7GYFZKK7.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{l as v}from"./chunk-UG22Z42P.js";function Xe(){return{pressed:!1,released:!1,held:0}}function Ye(){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?Xe():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?Ye():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 Ze}from"valtio/vanilla";var Je=.002;function A(a,e,t){return Math.max(e,Math.min(t,a))}function Ke(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=Ke(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??Je,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=Ze(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 $e=["A","B","X","Y","Start","Select","L","R","LTrigger","RTrigger","Up","Down","Left","Right"],We=new Set(["flex","flexGrow","flexShrink","fontWeight","lineHeight","opacity","order","zIndex","zoom"]),je={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"}},qe={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 $e){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},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=qe[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??et(t.label),n.appendChild(i),n.addEventListener("pointerdown",r=>{if(!Le(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??tt(),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??nt(),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(!Le(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"&&!We.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 et(a){let e=it(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 tt(){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 nt(){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 it(a){return a.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}function Le(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=at.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 at(){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 ke={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 ke[a].displayAspect}function ie(a,e){let t=ke[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 ot(a={}){return a.deviceProfile==="mobile"?!0:a.deviceProfile==="desktop"?!1:a.viewportSize?T({viewportSize:a.viewportSize,allowViewportOnly:!0}):T()}function st(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 rt(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 De=360;function Ae(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 lt(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 ut(a){let e=Number.isFinite(a)&&a>0?a:I.SixteenByNine;if(e>=1){let i=De;return{width:Math.round(i*e),height:i}}let t=De,n=Math.round(t/e);return{width:t,height:n}}function P(a,e={}){let t=rt({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=st(n,a?.container??null),o=a?.mobile,r=ot(e),s=r?o?.preset??a?.preset:a?.preset,l=Ae(a?.resolution,a?.preset),u=Ae(o?.resolution,o?.preset??a?.preset),m=(r?ze(u):void 0)??ze(l),p=r?o?.aspectRatio??a?.aspectRatio:a?.aspectRatio,h=lt(p,s,t.aspectRatio,m),Z=pt(r,u,l,h),Ue=a?.fullscreen??t.fullscreen,Ne=a?.bodyBackground??t.bodyBackground,_e=a?.canvas??void 0,Fe=dt(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,Fe,h,Z,Ue,Ne,i,n,_e)}function ze(a){if(a)return a}function pt(a,e,t,n){if(a)return e===oe?void 0:e??ut(n);if(t!==oe)return t}function dt(a,e){if(!e)return a;let n=be("p1",{enabled:"auto",...e===!0?{}:e});return v(n,a??{})}function ct(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 mt from"stats.js";import{subscribe as ht}from"valtio/vanilla";var U=class{statsRef=null;unsubscribe=null;constructor(){this.updateDebugUI(),this.unsubscribe=ht(g,()=>{this.updateDebugUI()})}begin(){this.statsRef?.begin()}end(){this.statsRef?.end()}updateDebugUI(){g.enabled&&!this.statsRef?(this.statsRef=new mt,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 gt}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;cutscenePreview=new Me(()=>this.currentStage()?.wrappedStage??null,e=>this.gameBridge.publishCutsceneStatus(e),{},e=>this.gameBridge.publishCutsceneView(e));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),cutscene:this.cutscenePreview,cameraPose:()=>this.cutscenePreview.cameraPose(),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;this.cutscenePreview.releaseStage();let 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(),this.cutscenePreview.stageReady()}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.cutscenePreview.frame(),this.isDisposed||(this.animationFrameId=requestAnimationFrame(this.frameCallback))}dispose(){this.isDisposed=!0,this.cutscenePreview.unload(),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(),gt().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 Ve(a){let{getGameDefaultConfig:e}=await import("./game-default-WBKQCEDJ.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 He(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 ft}from"valtio/vanilla";import{get as yt,set as bt}from"idb-keyval";import{pack as vt,unpack as St}from"msgpackr";var c=ft({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 yt(a);if(e)return St(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 bt(c.current.id,vt(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 Pe.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,He(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 Ve(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 wt(...a){return new Y(a)}import{Euler as Ct,Quaternion as xt,Vector2 as Gt}from"three";function Et(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 Gt(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 xt(p.x,p.y,p.z,p.w);s=new Ct().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 Rt}from"valtio/vanilla";var ue="STAGE_STATE_CHANGE";function Tt(){return Rt(S,()=>{let a={entities:S.entities,variables:S.variables};window.dispatchEvent(new CustomEvent(ue,{detail:a}))})}function Bt(){let a={entities:S.entities,variables:S.variables};window.dispatchEvent(new CustomEvent(ue,{detail:a}))}import{MathUtils as Mt,Vector3 as It}from"three";var Oe={targetKey:"primary",offset:new It(0,0,0),lerpFactor:.1};function Pt(a){let e={...Oe,...a,offset:q(a?.offset,Oe.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=Ie(i);if(!t)t=r.clone();else{let l=Mt.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 Lt}from"three";function kt(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 Lt({map:i});a.mesh.material=o}export{I as a,ne as b,ie as c,ae as d,ct as e,c as f,X as g,Y as h,wt as i,Et as j,ue as k,Tt as l,Bt as m,Pt as n,kt as o};
@@ -0,0 +1 @@
1
+ import{b as A,c as P,g as V,k as L}from"./chunk-QGIYILYI.js";var O={attack:.01,decay:.2,sustain:.5,release:.4};function Q(r,a){let n=a.envelope??O,l={type:a.oscillator??"triangle"},u=a.volume??-6;switch(a.preset){case"polySynth":return{synth:new r.PolySynth(r.Synth,{oscillator:l,envelope:n,volume:u}),pitched:!0};case"fmSynth":return{synth:new r.FMSynth({oscillator:l,envelope:n,volume:u}),pitched:!0};case"amSynth":return{synth:new r.AMSynth({oscillator:l,envelope:n,volume:u}),pitched:!0};case"membraneSynth":return{synth:new r.MembraneSynth({envelope:n,volume:u,octaves:6,pitchDecay:.05}),pitched:!0};case"metalSynth":return{synth:new r.MetalSynth({envelope:{attack:n.attack,decay:n.decay,release:n.release},volume:u}),pitched:!0};case"noiseSynth":return{synth:new r.NoiseSynth({envelope:{attack:n.attack,decay:n.decay,sustain:n.sustain,release:n.release},volume:u}),pitched:!1};case"pluckSynth":return{synth:new r.PluckSynth({volume:u,release:n.release}),pitched:!0};default:return{synth:new r.Synth({oscillator:l,envelope:n,volume:u}),pitched:!0}}}function C(r,a){let n=a.options??{},l=a.wet??1;switch(a.type){case"reverb":return new r.Reverb({decay:S(n.decay,2),preDelay:S(n.preDelay,.01),wet:l});case"delay":return new r.FeedbackDelay({delayTime:S(n.delayTime,.25),feedback:S(n.feedback,.35),wet:l});case"distortion":return new r.Distortion({distortion:S(n.distortion,.4),wet:l});case"filter":return new r.Filter({frequency:S(n.frequency,1200),type:typeof n.type=="string"?n.type:"lowpass",Q:S(n.Q,1)});default:return new r.Gain(1)}}function S(r,a){return typeof r=="number"&&Number.isFinite(r)?r:a}function R(r,a){let{synth:n,pitched:l}=Q(r,a),u=(a.effects??[]).map(c=>C(r,c)),t=new r.Gain(1);return u.length>0?n.chain(...u,t):n.connect(t),{definition:a,output:t,trigger(c,p,m,o=.8){let d=Math.max(.01,p);l?n.triggerAttackRelease(V(c),d,m,o):n.triggerAttackRelease(d,m,o)},releaseAll(c){n.releaseAll?n.releaseAll(c):n.triggerRelease?.(c)},dispose(){n.dispose();for(let c of u)c.dispose();t.dispose()}}}function K(r,a,n){let l=new Map,u=new Map,t=[],c=[],p=new Map(a.instruments.map(o=>[o.id,o]));for(let o of a.tracks){let d=new r.Channel({volume:o.volume??0,pan:o.pan??0,mute:o.mute??!1,solo:o.solo??!1});if(d.connect(n.master),l.set(o.id,d),o.kind==="instrument"&&o.instrumentId){let f=p.get(o.instrumentId);if(f){let y=R(r,f);y.output.connect(d),u.set(o.id,y)}}}let m=new Map;for(let o of n.schedule.notes){let d=m.get(o.trackId)??[];d.push({time:o.time,pitch:o.pitch,duration:o.duration,velocity:o.velocity}),m.set(o.trackId,d)}for(let[o,d]of m){let f=u.get(o);if(!f)continue;let y=new r.Part((g,v)=>{f.trigger(v.pitch,v.duration,g,v.velocity)},d);y.start(0),t.push(y)}for(let o of n.schedule.audio){let d=l.get(o.trackId);if(!d)continue;let f=n.resolveUrl?n.resolveUrl(o.url):o.url,y=n.buffers?.get(o.url)??n.buffers?.get(f),g=y?new r.Player(y):new r.Player(f);g.volume.value=o.gain,g.connect(d),g.sync().start(o.time,o.offset,o.duration),c.push(g)}return{channels:l,instruments:u,parts:t,players:c,dispose(){for(let o of t)o.dispose();for(let o of c)o.unsync(),o.dispose();for(let o of u.values())o.dispose();for(let o of l.values())o.dispose()}}}var N=null,I=!1;function D(){return N||(N=import("tone").then(r=>{let a=r;return typeof a.start=="function"?a:a.default??a})),N}async function x(){let r=await D();if(!I||r.getContext().state!=="running")try{await r.start(),I=!0}catch{}return r}function $(){return I}var w=null;function Y(r,a={}){w?.dispose();let n=r,l="stopped",u=null,t=null,c=null,p=null,m=!1,o=[],d={bar:new Set,beat:new Set,complete:new Set,state:new Set},f=new Map,y=(e,...i)=>{for(let s of d[e])s(...i)},g=e=>{l!==e&&(l=e,y("state",e))},v=()=>n.timeSignature.numerator*4/n.timeSignature.denominator,E=()=>{if(t){for(let e of o)t.clear(e);o.length=0}},B=async e=>{let i=new Set(n.clips.flatMap(s=>s.kind==="audio"?[s.url]:[]));await Promise.all([...i].map(async s=>{if(f.has(s))return;let h=a.resolveUrl?a.resolveUrl(s):s;try{f.set(s,await e.ToneAudioBuffer.fromUrl(h))}catch(b){console.warn(`[zylem/audio] could not load "${h}"`,b)}}))},G=e=>{if(!t||!c)return;p?.dispose(),E(),t.bpm.value=n.bpm,t.timeSignature=[n.timeSignature.numerator,n.timeSignature.denominator],c.volume.value=n.masterVolume??0;let i=L(n);p=K(e,n,{master:c,schedule:i,buffers:f,resolveUrl:a.resolveUrl}),T(n.loop??null);let s=i.length;o.push(t.schedule(()=>{t?.loop||e.getDraw().schedule(()=>{U(),y("complete")},e.now())},s)),o.push(t.scheduleRepeat(h=>{let b=Math.round(t.getSecondsAtTime(h)/P(1,t.bpm.value));e.getDraw().schedule(()=>{y("beat",b),b%v()===0&&y("bar",Math.floor(b/v()))},h)},"4n",0))},T=e=>{t&&(e?.enabled&&e.end>e.start?(t.loopStart=P(e.start,t.bpm.value),t.loopEnd=P(e.end,t.bpm.value),t.loop=!0):t.loop=!1)},k=(async()=>{let e=await D();m||(u=e,t=e.getTransport(),t.stop(),t.cancel(),t.position=0,c=new e.Volume(n.masterVolume??0),c.connect(a.destination??e.getDestination()),await B(e),!m&&G(e))})(),F=e=>t?e/t.PPQ:0,U=()=>{if(t){t.stop(),t.position=0;for(let e of p?.instruments.values()??[])e.releaseAll();g("stopped")}},M={get definition(){return n},get state(){return l},ready:k,async play(e){m||(await x(),await k,!(m||!t)&&(e!==void 0&&(t.ticks=Math.max(0,e)*t.PPQ),t.start(),g("playing")))},pause(){if(!(!t||l!=="playing")){t.pause();for(let e of p?.instruments.values()??[])e.releaseAll();g("paused")}},stop:U,seek(e){if(!t)return;let i=Math.min(Math.max(0,e),A(n));t.ticks=i*t.PPQ;for(let s of p?.instruments.values()??[])s.releaseAll()},position(){return t?F(t.ticks):0},seconds(){return t?t.seconds:0},setBpm(e){n={...n,bpm:e},t&&(t.bpm.value=e,T(n.loop??null))},setLoop(e){n={...n,loop:e??void 0},T(e)},setTrackMute(e,i){let s=p?.channels.get(e);s&&(s.mute=i)},setTrackSolo(e,i){let s=p?.channels.get(e);s&&(s.solo=i)},setTrackVolume(e,i){let s=p?.channels.get(e);s&&(s.volume.value=i)},setTrackPan(e,i){let s=p?.channels.get(e);s&&(s.pan.value=i)},setMasterVolume(e){n={...n,masterVolume:e},c&&(c.volume.value=e)},async preview(e,i,s=.4,h=.8){await x(),await k,p?.instruments.get(e)?.trigger(i,s,void 0,h)},async update(e){if(n=e,await k,m||!u||!t)return;let i=l==="playing",s=t.ticks;i&&t.pause(),await B(u),!m&&(G(u),t.ticks=Math.min(s,A(n)*t.PPQ),i&&t.start())},on(e,i){return d[e].add(i),()=>{d[e].delete(i)}},dispose(){if(!m){m=!0,t&&(t.stop(),E(),t.loop=!1),p?.dispose(),p=null,c?.dispose(),c=null;for(let e of Object.keys(d))d[e].clear();w===M&&(w=null),l="stopped"}}};return w=M,M}function Z(){return w}export{R as a,K as b,D as c,x as d,$ as e,Y as f,Z as g};