@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
@@ -1,5 +1,6 @@
1
1
  import { abs } from 'three/tsl';
2
2
  import { announceBridgeReady } from '@zylem/bridge';
3
+ import { applySwatchesToSelection } from '@zylem/bridge';
3
4
  import { asin } from 'three/tsl';
4
5
  import { atan } from 'three/tsl';
5
6
  import { BehaviorDescriptor } from '@zylem/behaviors';
@@ -21,6 +22,7 @@ import { BoundaryRicochet3DEntity } from '@zylem/behaviors';
21
22
  import { BoundaryRicochetCoordinator } from '@zylem/behaviors';
22
23
  import { BoundaryRicochetEntity } from '@zylem/behaviors';
23
24
  import { BoundaryRicochetUpdate } from '@zylem/behaviors';
25
+ import { Box3 } from 'three';
24
26
  import { BRIDGE_READY_EVENT } from '@zylem/bridge';
25
27
  import { BridgeChannel } from '@zylem/bridge';
26
28
  import { BridgeDebugTool } from '@zylem/bridge';
@@ -28,11 +30,13 @@ import { BridgeHandler } from '@zylem/bridge';
28
30
  import { GameLoadingPayload as BridgeLoadingPayload } from '@zylem/bridge';
29
31
  import { BridgeMessages } from '@zylem/bridge';
30
32
  import { BridgeMessageType } from '@zylem/bridge';
33
+ import { BridgeNdc } from '@zylem/bridge';
31
34
  import { BridgePose } from '@zylem/bridge';
32
35
  import { BridgeVec3 } from '@zylem/bridge';
33
36
  import { BufferGeometry } from 'three';
34
37
  import { BurstParticlePresetOptions } from '@zylem/behaviors';
35
38
  import { Camera } from 'three';
39
+ import { CameraPosePayload } from '@zylem/bridge';
36
40
  import { clamp } from 'three/tsl';
37
41
  import { Color } from 'three';
38
42
  import { ColorRepresentation } from 'three';
@@ -70,6 +74,10 @@ import { createTopDownMovementInputComponent } from '@zylem/behaviors';
70
74
  import { createTopDownMovementStateComponent } from '@zylem/behaviors';
71
75
  import { createTransformComponent } from '@zylem/behaviors';
72
76
  import { createTransformStore } from '@zylem/behaviors/core';
77
+ import { CutsceneLoadPayload } from '@zylem/bridge';
78
+ import { CutscenePlaybackState } from '@zylem/bridge';
79
+ import { CutsceneStatusPayload } from '@zylem/bridge';
80
+ import { CutsceneViewPayload } from '@zylem/bridge';
73
81
  import { defineBehavior } from '@zylem/behaviors';
74
82
  import { DefineBehaviorConfig } from '@zylem/behaviors';
75
83
  import { Destructible3DBehavior } from '@zylem/behaviors';
@@ -88,7 +96,10 @@ import { emitRuntimeTriggerRegionEnter } from '@zylem/behaviors/runtime-2d';
88
96
  import { EntityApplySwatchPayload } from '@zylem/bridge';
89
97
  import { EntityDefinition } from '@zylem/behaviors/core';
90
98
  import { EntityHandle } from '@zylem/behaviors/core';
99
+ import { EntityPickPayload } from '@zylem/bridge';
100
+ import { EntityPickResultPayload } from '@zylem/bridge';
91
101
  import { EntitySummaryPayload } from '@zylem/bridge';
102
+ import { EntitySwatchAppliedPayload } from '@zylem/bridge';
92
103
  import { EntityThumbnailPayload } from '@zylem/bridge';
93
104
  import { EntityTypeDescriptor } from '@zylem/bridge';
94
105
  import { exp } from 'three/tsl';
@@ -276,6 +287,7 @@ import { RuntimeTriggerRegion2DEvent } from '@zylem/behaviors/runtime-2d';
276
287
  import { RuntimeTriggerRegion2DHandle } from '@zylem/behaviors/runtime-2d';
277
288
  import { RuntimeTriggerRegion2DOptions } from '@zylem/behaviors/runtime-2d';
278
289
  import { Scene } from 'three';
290
+ import { SceneOperationEntry } from '@zylem/bridge';
279
291
  import { SceneOperationPayload } from '@zylem/bridge';
280
292
  import { ScreenVisibilityBehavior } from '@zylem/behaviors';
281
293
  import { ScreenVisibilityChangeContext } from '@zylem/behaviors';
@@ -336,6 +348,10 @@ import { StageSnapshotPayload } from '@zylem/bridge';
336
348
  import { StageTopDownPlane } from '@zylem/behaviors/core';
337
349
  import { Static } from '@sinclair/typebox';
338
350
  import { step } from 'three/tsl';
351
+ import { SwatchApplyFailureReason } from '@zylem/bridge';
352
+ import { SwatchApplyResult } from '@zylem/bridge';
353
+ import { SwatchKind } from '@zylem/bridge';
354
+ import { SwatchSpec } from '@zylem/bridge';
339
355
  import { Texture } from 'three';
340
356
  import * as three from 'three';
341
357
  import { ThrusterBehavior } from '@zylem/behaviors';
@@ -350,6 +366,7 @@ import { ThrusterState } from '@zylem/behaviors';
350
366
  import { ThrusterStateComponent } from '@zylem/behaviors';
351
367
  import { tickCooldowns } from '@zylem/behaviors';
352
368
  import { time } from 'three/tsl';
369
+ import * as ToneNs from 'tone';
353
370
  import { TopDownMovementBehavior } from '@zylem/behaviors';
354
371
  import { TopDownMovementBehaviorOptions } from '@zylem/behaviors';
355
372
  import { TopDownMovementComponent } from '@zylem/behaviors';
@@ -421,6 +438,12 @@ export declare interface Action {
421
438
  reset(): void;
422
439
  }
423
440
 
441
+ /**
442
+ * The active shot across every camera track. Tracks are prioritised in
443
+ * order, so a shot on the first camera track overrides one on the second.
444
+ */
445
+ export declare function activeShot(definition: CutsceneDefinition, time: number): CameraShot | undefined;
446
+
424
447
  export declare const ACTOR_TYPE: unique symbol;
425
448
 
426
449
  declare type ActorOptions = BaseNode | ZylemActorOptions;
@@ -471,6 +494,8 @@ export { announceBridgeReady }
471
494
 
472
495
  declare type AnyNode = NodeLike | Promise<NodeLike>;
473
496
 
497
+ export { applySwatchesToSelection }
498
+
474
499
  /**
475
500
  * Apply accumulated transformations from the store to the physics body.
476
501
  *
@@ -533,6 +558,62 @@ export declare type AspectRatioValue = (typeof AspectRatio)[keyof typeof AspectR
533
558
 
534
559
  export { atan }
535
560
 
561
+ /**
562
+ * Tracks that actually make sound: when any track is soloed only the soloed,
563
+ * unmuted ones play; otherwise everything not muted.
564
+ */
565
+ export declare function audibleTrackIds(tracks: readonly SongTrack[]): Set<string>;
566
+
567
+ export declare type AudioClip = Static<typeof AudioClipSchema>;
568
+
569
+ export declare const AudioClipSchema: _sinclair_typebox.TObject<{
570
+ kind: _sinclair_typebox.TLiteral<"audio">;
571
+ id: _sinclair_typebox.TString;
572
+ trackId: _sinclair_typebox.TString;
573
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
574
+ /** URL of the audio file. */
575
+ url: _sinclair_typebox.TString;
576
+ /** Beats from the song start. */
577
+ start: _sinclair_typebox.TNumber;
578
+ /** Seconds trimmed from the start of the file. */
579
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
580
+ /** Beats. */
581
+ length: _sinclair_typebox.TNumber;
582
+ /** Clip gain in dB. */
583
+ gain: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
584
+ }>;
585
+
586
+ export declare type AudioItem = Static<typeof AudioItemSchema>;
587
+
588
+ export declare const AudioItemSchema: _sinclair_typebox.TObject<{
589
+ id: _sinclair_typebox.TString;
590
+ time: _sinclair_typebox.TNumber;
591
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"song">, _sinclair_typebox.TLiteral<"sfx">]>;
592
+ /** Song slug for `song`, asset URL for `sfx`. */
593
+ ref: _sinclair_typebox.TString;
594
+ loop: _sinclair_typebox.TBoolean;
595
+ /** Gain in dB. */
596
+ volume: _sinclair_typebox.TNumber;
597
+ }>;
598
+
599
+ export declare type AudioTrack = Static<typeof AudioTrackSchema>;
600
+
601
+ declare const AudioTrackSchema: _sinclair_typebox.TObject<{
602
+ kind: _sinclair_typebox.TLiteral<"audio">;
603
+ id: _sinclair_typebox.TString;
604
+ name: _sinclair_typebox.TString;
605
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
606
+ id: _sinclair_typebox.TString;
607
+ time: _sinclair_typebox.TNumber;
608
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"song">, _sinclair_typebox.TLiteral<"sfx">]>;
609
+ /** Song slug for `song`, asset URL for `sfx`. */
610
+ ref: _sinclair_typebox.TString;
611
+ loop: _sinclair_typebox.TBoolean;
612
+ /** Gain in dB. */
613
+ volume: _sinclair_typebox.TNumber;
614
+ }>>;
615
+ }>;
616
+
536
617
  declare interface BaseCollisionOptions {
537
618
  /** Whether the body is static (fixed) or dynamic */
538
619
  static?: boolean;
@@ -662,6 +743,16 @@ declare type BaseNodeOptions<T = any> = BaseNode | Partial<T>;
662
743
 
663
744
  declare type BasicTypes = number | string | boolean;
664
745
 
746
+ /**
747
+ * Pure timing and scheduling math for songs. Everything here runs without
748
+ * an AudioContext so the player, the offline renderer and the editor agree
749
+ * on when things happen.
750
+ */
751
+ /** Quarter-note beats per bar: 4/4 → 4, 6/8 → 3, 3/4 → 3. */
752
+ export declare function beatsPerBar(signature: TimeSignature): number;
753
+
754
+ export declare function beatsToSeconds(beats: number, bpm: number): number;
755
+
665
756
  export { BehaviorDescriptor }
666
757
 
667
758
  export { BehaviorHandle }
@@ -724,6 +815,8 @@ export { BridgeMessages }
724
815
 
725
816
  export { BridgeMessageType }
726
817
 
818
+ export { BridgeNdc }
819
+
727
820
  export { BridgeVec3 }
728
821
 
729
822
  /** Cuboid collider sized as `size.xyz` (full extents — half-extents are computed). */
@@ -836,6 +929,27 @@ export declare interface CameraFeedOptions {
836
929
  height?: number;
837
930
  }
838
931
 
932
+ export declare type CameraKeyframe = Static<typeof CameraKeyframeSchema>;
933
+
934
+ export declare const CameraKeyframeSchema: _sinclair_typebox.TObject<{
935
+ id: _sinclair_typebox.TString;
936
+ /** Seconds from the cutscene start. */
937
+ time: _sinclair_typebox.TNumber;
938
+ position: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
939
+ x: _sinclair_typebox.TNumber;
940
+ y: _sinclair_typebox.TNumber;
941
+ z: _sinclair_typebox.TNumber;
942
+ }>>;
943
+ lookAt: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
944
+ x: _sinclair_typebox.TNumber;
945
+ y: _sinclair_typebox.TNumber;
946
+ z: _sinclair_typebox.TNumber;
947
+ }>>;
948
+ fov: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
949
+ /** Easing used to arrive at this keyframe from the previous one. */
950
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
951
+ }>;
952
+
839
953
  /**
840
954
  * CameraManager orchestrates multiple cameras per stage.
841
955
  *
@@ -1122,6 +1236,59 @@ export declare interface CameraPose {
1122
1236
  lookAt?: Vector3;
1123
1237
  }
1124
1238
 
1239
+ export declare type CameraPoseDef = Static<typeof CameraPoseDefSchema>;
1240
+
1241
+ declare const CameraPoseDefSchema: _sinclair_typebox.TObject<{
1242
+ position: _sinclair_typebox.TObject<{
1243
+ x: _sinclair_typebox.TNumber;
1244
+ y: _sinclair_typebox.TNumber;
1245
+ z: _sinclair_typebox.TNumber;
1246
+ }>;
1247
+ lookAt: _sinclair_typebox.TObject<{
1248
+ x: _sinclair_typebox.TNumber;
1249
+ y: _sinclair_typebox.TNumber;
1250
+ z: _sinclair_typebox.TNumber;
1251
+ }>;
1252
+ }>;
1253
+
1254
+ export { CameraPosePayload }
1255
+
1256
+ export declare type CameraShot = Static<typeof CameraShotSchema>;
1257
+
1258
+ export declare const CameraShotSchema: _sinclair_typebox.TObject<{
1259
+ id: _sinclair_typebox.TString;
1260
+ cameraId: _sinclair_typebox.TString;
1261
+ start: _sinclair_typebox.TNumber;
1262
+ end: _sinclair_typebox.TNumber;
1263
+ blend: _sinclair_typebox.TObject<{
1264
+ /** Seconds spent blending from the previous shot's camera; 0 is a hard cut. */
1265
+ duration: _sinclair_typebox.TNumber;
1266
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
1267
+ }>;
1268
+ }>;
1269
+
1270
+ export declare type CameraTrack = Static<typeof CameraTrackSchema>;
1271
+
1272
+ /** Camera tracks in priority order. */
1273
+ export declare function cameraTracks(definition: CutsceneDefinition): CameraTrack[];
1274
+
1275
+ declare const CameraTrackSchema: _sinclair_typebox.TObject<{
1276
+ kind: _sinclair_typebox.TLiteral<"camera">;
1277
+ id: _sinclair_typebox.TString;
1278
+ name: _sinclair_typebox.TString;
1279
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
1280
+ id: _sinclair_typebox.TString;
1281
+ cameraId: _sinclair_typebox.TString;
1282
+ start: _sinclair_typebox.TNumber;
1283
+ end: _sinclair_typebox.TNumber;
1284
+ blend: _sinclair_typebox.TObject<{
1285
+ /** Seconds spent blending from the previous shot's camera; 0 is a hard cut. */
1286
+ duration: _sinclair_typebox.TNumber;
1287
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
1288
+ }>;
1289
+ }>>;
1290
+ }>;
1291
+
1125
1292
  /**
1126
1293
  * CameraWrapper is the user-facing camera handle returned by createCamera().
1127
1294
  * It provides convenience methods for target management, orbital controls,
@@ -1225,6 +1392,9 @@ declare interface CleanupFunction<T, TGlobals extends GlobalRecord = any> {
1225
1392
  */
1226
1393
  export declare function clearGlobalSubscriptions(): void;
1227
1394
 
1395
+ /** Clips whose window covers `beat` on a track. */
1396
+ export declare function clipsAt(song: SongDefinition, trackId: string, beat: number): Array<NoteClip | AudioClip>;
1397
+
1228
1398
  /**
1229
1399
  * Closest point along an infinite line to a ray, as a distance along the line.
1230
1400
  *
@@ -1481,6 +1651,19 @@ export declare function createCone(...args: Array<ConeOptions>): ZylemCone;
1481
1651
  */
1482
1652
  export declare function createCooldownIcon(...args: Array<CooldownIconOptions>): ZylemCooldownIcon;
1483
1653
 
1654
+ /**
1655
+ * Plays a cutscene against a live stage: drives the camera through a
1656
+ * pipeline behavior, fires event/audio items as the playhead crosses them,
1657
+ * and runs scene transitions through the renderer.
1658
+ *
1659
+ * ```ts
1660
+ * const player = createCutscenePlayer(INTRO_CUTSCENE, { host: createStageCutsceneHost(stage) });
1661
+ * player.on('complete', () => player.dispose());
1662
+ * player.play();
1663
+ * ```
1664
+ */
1665
+ export declare function createCutscenePlayer(initial: CutsceneDefinition, options: CutscenePlayerOptions): CutscenePlayer;
1666
+
1484
1667
  /**
1485
1668
  * Create a cylinder entity.
1486
1669
  * @param args Options or child nodes
@@ -1585,6 +1768,12 @@ declare interface CreateGameEntityOptions<T extends GameEntity<any>, CreateOptio
1585
1768
  */
1586
1769
  export declare function createGlobal<T>(path: string, defaultValue: T): T;
1587
1770
 
1771
+ /**
1772
+ * Builds the synth and effects chain for an instrument definition. The
1773
+ * returned `output` is not connected anywhere; the caller routes it.
1774
+ */
1775
+ export declare function createInstrument(Tone: ToneModule, def: InstrumentDefinition): Instrument;
1776
+
1588
1777
  export { createJumpConfig2D }
1589
1778
 
1590
1779
  export { createJumpConfig3D }
@@ -1667,6 +1856,13 @@ export { createShooter2DStateComponent }
1667
1856
 
1668
1857
  export { createSimulation }
1669
1858
 
1859
+ /**
1860
+ * Plays a song on Tone.js's transport. The transport is shared, so creating
1861
+ * a player disposes the previous one: one song plays at a time. Tone.js is
1862
+ * loaded lazily; the first `play()` must follow a user gesture.
1863
+ */
1864
+ export declare function createSongPlayer(definition: SongDefinition, options?: SongPlayerOptions): SongPlayer;
1865
+
1670
1866
  export declare function createSphere(...args: Array<SphereOptions>): ZylemSphere;
1671
1867
 
1672
1868
  export declare function createSprite(...args: Array<SpriteOptions>): ZylemSprite;
@@ -1676,6 +1872,8 @@ export declare function createSprite(...args: Array<SpriteOptions>): ZylemSprite
1676
1872
  */
1677
1873
  export declare function createStage(...options: StageOptions): Stage;
1678
1874
 
1875
+ export declare function createStageCutsceneHost(stageLike: CutsceneStageLike, options?: StageCutsceneHostOptions): CutsceneHost;
1876
+
1679
1877
  export declare function createText(...args: Array<TextOptions>): ZylemText;
1680
1878
 
1681
1879
  export { createThrusterInputComponent }
@@ -1707,6 +1905,509 @@ export declare function createZone(...args: Array<ZoneOptions>): ZylemZone;
1707
1905
  /** Default blend: plain crossfade between the two frames. */
1708
1906
  export declare const crossfadeTransitionShader: ZylemTransitionShader;
1709
1907
 
1908
+ /** Pipeline key the cutscene player registers its behavior under. */
1909
+ export declare const CUTSCENE_BEHAVIOR_KEY = "cutscene";
1910
+
1911
+ export declare type CutsceneCamera = Static<typeof CutsceneCameraSchema>;
1912
+
1913
+ /**
1914
+ * Camera behavior that hands the pipeline a fixed pose each frame while a
1915
+ * cutscene is playing. It runs after the game's own behaviors (high
1916
+ * priority) so shots override follow/look-at logic, and it disables itself
1917
+ * when the player has no pose (no active shot) so gameplay framing resumes.
1918
+ *
1919
+ * `damping` applies optional per-frame smoothing for follow cameras; the
1920
+ * player passes 0 for authored moves so keyframes land exactly.
1921
+ */
1922
+ export declare class CutsceneCameraBehavior implements CameraBehavior {
1923
+ priority: number;
1924
+ enabled: boolean;
1925
+ private target;
1926
+ private smoothed;
1927
+ private damping;
1928
+ /** Sets the pose to show; `null` releases the camera back to gameplay. */
1929
+ setPose(pose: EvaluatedPose | null, damping?: number): void;
1930
+ /** Snap smoothing state so the next frame lands exactly on the pose (seeks, cuts). */
1931
+ snap(): void;
1932
+ onDetach(): void;
1933
+ update(ctx: CameraContext, pose: CameraPose): CameraPose;
1934
+ }
1935
+
1936
+ export declare type CutsceneCameraKind = Static<typeof CutsceneCameraKindSchema>;
1937
+
1938
+ declare const CutsceneCameraKindSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"static">, _sinclair_typebox.TLiteral<"dolly">, _sinclair_typebox.TLiteral<"follow">]>;
1939
+
1940
+ export declare const CutsceneCameraSchema: _sinclair_typebox.TObject<{
1941
+ id: _sinclair_typebox.TString;
1942
+ name: _sinclair_typebox.TString;
1943
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"static">, _sinclair_typebox.TLiteral<"dolly">, _sinclair_typebox.TLiteral<"follow">]>;
1944
+ /** Vertical field of view in degrees. */
1945
+ fov: _sinclair_typebox.TNumber;
1946
+ /** Base pose; `static` cameras hold it, keyframes and dollies start from it. */
1947
+ pose: _sinclair_typebox.TObject<{
1948
+ position: _sinclair_typebox.TObject<{
1949
+ x: _sinclair_typebox.TNumber;
1950
+ y: _sinclair_typebox.TNumber;
1951
+ z: _sinclair_typebox.TNumber;
1952
+ }>;
1953
+ lookAt: _sinclair_typebox.TObject<{
1954
+ x: _sinclair_typebox.TNumber;
1955
+ y: _sinclair_typebox.TNumber;
1956
+ z: _sinclair_typebox.TNumber;
1957
+ }>;
1958
+ }>;
1959
+ /** `dolly` cameras ride this path over each shot. */
1960
+ dollyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1961
+ /** Progress curve along the dolly path (0 → 1 over the shot). */
1962
+ dollyEasing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
1963
+ /** Entity name a `follow` camera tracks, and what a dolly looks at when set. */
1964
+ target: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1965
+ /** Offset from the target for `follow` cameras. */
1966
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
1967
+ x: _sinclair_typebox.TNumber;
1968
+ y: _sinclair_typebox.TNumber;
1969
+ z: _sinclair_typebox.TNumber;
1970
+ }>>;
1971
+ /** Smoothing for `follow` cameras, 0 (instant) … 1 (very slow). */
1972
+ damping: _sinclair_typebox.TNumber;
1973
+ keyframes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
1974
+ id: _sinclair_typebox.TString;
1975
+ /** Seconds from the cutscene start. */
1976
+ time: _sinclair_typebox.TNumber;
1977
+ position: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
1978
+ x: _sinclair_typebox.TNumber;
1979
+ y: _sinclair_typebox.TNumber;
1980
+ z: _sinclair_typebox.TNumber;
1981
+ }>>;
1982
+ lookAt: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
1983
+ x: _sinclair_typebox.TNumber;
1984
+ y: _sinclair_typebox.TNumber;
1985
+ z: _sinclair_typebox.TNumber;
1986
+ }>>;
1987
+ fov: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1988
+ /** Easing used to arrive at this keyframe from the previous one. */
1989
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
1990
+ }>>;
1991
+ }>;
1992
+
1993
+ export declare type CutsceneDefinition = Static<typeof CutsceneDefinitionSchema>;
1994
+
1995
+ export declare const CutsceneDefinitionSchema: _sinclair_typebox.TObject<{
1996
+ id: _sinclair_typebox.TString;
1997
+ name: _sinclair_typebox.TString;
1998
+ /** Seconds. */
1999
+ duration: _sinclair_typebox.TNumber;
2000
+ /** Stage the cutscene was authored against; informational. */
2001
+ stage: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
2002
+ skippable: _sinclair_typebox.TBoolean;
2003
+ scenes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2004
+ id: _sinclair_typebox.TString;
2005
+ name: _sinclair_typebox.TString;
2006
+ /** Seconds from the cutscene start. */
2007
+ start: _sinclair_typebox.TNumber;
2008
+ end: _sinclair_typebox.TNumber;
2009
+ /** How the picture arrives at this scene's start. */
2010
+ transitionIn: _sinclair_typebox.TObject<{
2011
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"cut">, _sinclair_typebox.TLiteral<"fade">, _sinclair_typebox.TLiteral<"wipe">, _sinclair_typebox.TLiteral<"radial">, _sinclair_typebox.TLiteral<"noise">, _sinclair_typebox.TLiteral<"cells">]>;
2012
+ /** Seconds; ignored for `cut`. */
2013
+ duration: _sinclair_typebox.TNumber;
2014
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2015
+ }>;
2016
+ }>>;
2017
+ cameras: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2018
+ id: _sinclair_typebox.TString;
2019
+ name: _sinclair_typebox.TString;
2020
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"static">, _sinclair_typebox.TLiteral<"dolly">, _sinclair_typebox.TLiteral<"follow">]>;
2021
+ /** Vertical field of view in degrees. */
2022
+ fov: _sinclair_typebox.TNumber;
2023
+ /** Base pose; `static` cameras hold it, keyframes and dollies start from it. */
2024
+ pose: _sinclair_typebox.TObject<{
2025
+ position: _sinclair_typebox.TObject<{
2026
+ x: _sinclair_typebox.TNumber;
2027
+ y: _sinclair_typebox.TNumber;
2028
+ z: _sinclair_typebox.TNumber;
2029
+ }>;
2030
+ lookAt: _sinclair_typebox.TObject<{
2031
+ x: _sinclair_typebox.TNumber;
2032
+ y: _sinclair_typebox.TNumber;
2033
+ z: _sinclair_typebox.TNumber;
2034
+ }>;
2035
+ }>;
2036
+ /** `dolly` cameras ride this path over each shot. */
2037
+ dollyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2038
+ /** Progress curve along the dolly path (0 → 1 over the shot). */
2039
+ dollyEasing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2040
+ /** Entity name a `follow` camera tracks, and what a dolly looks at when set. */
2041
+ target: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2042
+ /** Offset from the target for `follow` cameras. */
2043
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
2044
+ x: _sinclair_typebox.TNumber;
2045
+ y: _sinclair_typebox.TNumber;
2046
+ z: _sinclair_typebox.TNumber;
2047
+ }>>;
2048
+ /** Smoothing for `follow` cameras, 0 (instant) … 1 (very slow). */
2049
+ damping: _sinclair_typebox.TNumber;
2050
+ keyframes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2051
+ id: _sinclair_typebox.TString;
2052
+ /** Seconds from the cutscene start. */
2053
+ time: _sinclair_typebox.TNumber;
2054
+ position: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
2055
+ x: _sinclair_typebox.TNumber;
2056
+ y: _sinclair_typebox.TNumber;
2057
+ z: _sinclair_typebox.TNumber;
2058
+ }>>;
2059
+ lookAt: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
2060
+ x: _sinclair_typebox.TNumber;
2061
+ y: _sinclair_typebox.TNumber;
2062
+ z: _sinclair_typebox.TNumber;
2063
+ }>>;
2064
+ fov: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
2065
+ /** Easing used to arrive at this keyframe from the previous one. */
2066
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2067
+ }>>;
2068
+ }>>;
2069
+ dollies: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2070
+ id: _sinclair_typebox.TString;
2071
+ name: _sinclair_typebox.TString;
2072
+ points: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2073
+ x: _sinclair_typebox.TNumber;
2074
+ y: _sinclair_typebox.TNumber;
2075
+ z: _sinclair_typebox.TNumber;
2076
+ }>>;
2077
+ closed: _sinclair_typebox.TBoolean;
2078
+ /** Catmull-Rom tension; 0.5 is centripetal. */
2079
+ tension: _sinclair_typebox.TNumber;
2080
+ }>>;
2081
+ tracks: _sinclair_typebox.TArray<_sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
2082
+ kind: _sinclair_typebox.TLiteral<"camera">;
2083
+ id: _sinclair_typebox.TString;
2084
+ name: _sinclair_typebox.TString;
2085
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2086
+ id: _sinclair_typebox.TString;
2087
+ cameraId: _sinclair_typebox.TString;
2088
+ start: _sinclair_typebox.TNumber;
2089
+ end: _sinclair_typebox.TNumber;
2090
+ blend: _sinclair_typebox.TObject<{
2091
+ /** Seconds spent blending from the previous shot's camera; 0 is a hard cut. */
2092
+ duration: _sinclair_typebox.TNumber;
2093
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2094
+ }>;
2095
+ }>>;
2096
+ }>, _sinclair_typebox.TObject<{
2097
+ kind: _sinclair_typebox.TLiteral<"event">;
2098
+ id: _sinclair_typebox.TString;
2099
+ name: _sinclair_typebox.TString;
2100
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2101
+ id: _sinclair_typebox.TString;
2102
+ time: _sinclair_typebox.TNumber;
2103
+ event: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
2104
+ type: _sinclair_typebox.TLiteral<"emit">;
2105
+ /** Stage event name. */
2106
+ name: _sinclair_typebox.TString;
2107
+ payload: _sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>>;
2108
+ }>, _sinclair_typebox.TObject<{
2109
+ type: _sinclair_typebox.TLiteral<"playAnimation">;
2110
+ /** Entity name. */
2111
+ entity: _sinclair_typebox.TString;
2112
+ /** Animation key as passed to `playAnimation({ key })`. */
2113
+ key: _sinclair_typebox.TString;
2114
+ }>, _sinclair_typebox.TObject<{
2115
+ type: _sinclair_typebox.TLiteral<"playSong">;
2116
+ /** Song slug or URL; resolved by the host. */
2117
+ song: _sinclair_typebox.TString;
2118
+ loop: _sinclair_typebox.TBoolean;
2119
+ }>, _sinclair_typebox.TObject<{
2120
+ type: _sinclair_typebox.TLiteral<"stopSong">;
2121
+ song: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2122
+ }>, _sinclair_typebox.TObject<{
2123
+ type: _sinclair_typebox.TLiteral<"setVariable">;
2124
+ name: _sinclair_typebox.TString;
2125
+ value: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>;
2126
+ }>]>;
2127
+ }>>;
2128
+ }>, _sinclair_typebox.TObject<{
2129
+ kind: _sinclair_typebox.TLiteral<"audio">;
2130
+ id: _sinclair_typebox.TString;
2131
+ name: _sinclair_typebox.TString;
2132
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2133
+ id: _sinclair_typebox.TString;
2134
+ time: _sinclair_typebox.TNumber;
2135
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"song">, _sinclair_typebox.TLiteral<"sfx">]>;
2136
+ /** Song slug for `song`, asset URL for `sfx`. */
2137
+ ref: _sinclair_typebox.TString;
2138
+ loop: _sinclair_typebox.TBoolean;
2139
+ /** Gain in dB. */
2140
+ volume: _sinclair_typebox.TNumber;
2141
+ }>>;
2142
+ }>]>>;
2143
+ }>;
2144
+
2145
+ export declare type CutsceneEasing = Static<typeof CutsceneEasingSchema>;
2146
+
2147
+ declare const CutsceneEasingSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2148
+
2149
+ export declare type CutsceneEvent = Static<typeof CutsceneEventSchema>;
2150
+
2151
+ export declare const CutsceneEventSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
2152
+ type: _sinclair_typebox.TLiteral<"emit">;
2153
+ /** Stage event name. */
2154
+ name: _sinclair_typebox.TString;
2155
+ payload: _sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>>;
2156
+ }>, _sinclair_typebox.TObject<{
2157
+ type: _sinclair_typebox.TLiteral<"playAnimation">;
2158
+ /** Entity name. */
2159
+ entity: _sinclair_typebox.TString;
2160
+ /** Animation key as passed to `playAnimation({ key })`. */
2161
+ key: _sinclair_typebox.TString;
2162
+ }>, _sinclair_typebox.TObject<{
2163
+ type: _sinclair_typebox.TLiteral<"playSong">;
2164
+ /** Song slug or URL; resolved by the host. */
2165
+ song: _sinclair_typebox.TString;
2166
+ loop: _sinclair_typebox.TBoolean;
2167
+ }>, _sinclair_typebox.TObject<{
2168
+ type: _sinclair_typebox.TLiteral<"stopSong">;
2169
+ song: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2170
+ }>, _sinclair_typebox.TObject<{
2171
+ type: _sinclair_typebox.TLiteral<"setVariable">;
2172
+ name: _sinclair_typebox.TString;
2173
+ value: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>;
2174
+ }>]>;
2175
+
2176
+ export declare interface CutsceneFrame {
2177
+ scene: CutsceneScene | undefined;
2178
+ shot: CameraShot | undefined;
2179
+ camera: CutsceneCamera | undefined;
2180
+ pose: EvaluatedPose | undefined;
2181
+ /** 0…1 while blending in from the previous shot, else 1. */
2182
+ blend: number;
2183
+ }
2184
+
2185
+ /**
2186
+ * What the player needs from the running game. `createStageCutsceneHost`
2187
+ * builds one from a live stage; tests and the editor can hand in stubs.
2188
+ */
2189
+ export declare interface CutsceneHost {
2190
+ /** The camera the cutscene drives; resolved each frame so stage swaps are safe. */
2191
+ camera: () => ZylemCamera | null;
2192
+ /** World position of a named entity, for follow cameras and dolly look-ats. */
2193
+ entityPosition?: (name: string) => Vec3Def | undefined;
2194
+ playAnimation?: (entity: string, key: string) => void;
2195
+ /** Stage event dispatch (`emit` events). */
2196
+ dispatch?: (name: string, payload: Record<string, unknown>) => void;
2197
+ setVariable?: (name: string, value: unknown) => void;
2198
+ playSong?: (ref: string, options: {
2199
+ loop: boolean;
2200
+ volume: number;
2201
+ }) => void;
2202
+ stopSong?: (ref?: string) => void;
2203
+ playSfx?: (url: string, options: {
2204
+ volume: number;
2205
+ loop: boolean;
2206
+ }) => void;
2207
+ /**
2208
+ * Runs a picture transition into the new scene: snapshot the current frame
2209
+ * and blend it into the frames that follow. Omit to hard-cut everywhere.
2210
+ */
2211
+ beginTransition?: (transition: SceneTransition, shader: ZylemTransitionShader | undefined) => void;
2212
+ }
2213
+
2214
+ /** Total length: the declared duration, or the furthest scene end if longer. */
2215
+ export declare function cutsceneLength(definition: Pick<CutsceneDefinition, 'duration' | 'scenes'>): number;
2216
+
2217
+ export { CutsceneLoadPayload }
2218
+
2219
+ export { CutscenePlaybackState }
2220
+
2221
+ export declare interface CutscenePlayer {
2222
+ readonly definition: CutsceneDefinition;
2223
+ readonly state: CutscenePlayerState;
2224
+ /** Seconds. */
2225
+ readonly time: number;
2226
+ readonly length: number;
2227
+ /** The pose the picture shows right now, if a shot is active. */
2228
+ readonly pose: EvaluatedPose | undefined;
2229
+ play(from?: number): void;
2230
+ pause(): void;
2231
+ /** Stops, rewinds, and returns the camera to gameplay. */
2232
+ stop(): void;
2233
+ seek(time: number): void;
2234
+ /** Jumps to the end (when `skippable`) and completes. */
2235
+ skip(): boolean;
2236
+ /** Advances by `dt` seconds; only needed with `tick: 'manual'`. */
2237
+ update(dt: number): void;
2238
+ /** Swaps the definition in place, keeping time and state (live editing). */
2239
+ setDefinition(definition: CutsceneDefinition): void;
2240
+ on<K extends keyof CutscenePlayerEvents>(event: K, handler: CutscenePlayerEvents[K]): () => void;
2241
+ dispose(): void;
2242
+ }
2243
+
2244
+ export declare interface CutscenePlayerEvents {
2245
+ time: (time: number) => void;
2246
+ state: (state: CutscenePlayerState) => void;
2247
+ scene: (scene: CutsceneScene | undefined) => void;
2248
+ shot: (shot: CameraShot | undefined) => void;
2249
+ event: (item: EventItem) => void;
2250
+ audio: (item: AudioItem) => void;
2251
+ complete: () => void;
2252
+ skip: () => void;
2253
+ }
2254
+
2255
+ export declare interface CutscenePlayerOptions {
2256
+ host: CutsceneHost;
2257
+ /**
2258
+ * `auto` (default) advances on `requestAnimationFrame`; `manual` leaves it
2259
+ * to the caller's `update(dt)` — e.g. a stage `update` hook, so the
2260
+ * cutscene pauses with the game.
2261
+ */
2262
+ tick?: 'auto' | 'manual';
2263
+ /** Maps a transition type to a blend shader (e.g. `createStageTransition({ pattern }).shader`). */
2264
+ transitionShader?: (type: SceneTransitionType) => ZylemTransitionShader | undefined;
2265
+ /** Fire events/audio crossed by a `seek`. Off by default: scrubbing should not trigger gameplay. */
2266
+ fireEventsOnSeek?: boolean;
2267
+ timeScale?: number;
2268
+ }
2269
+
2270
+ export declare type CutscenePlayerState = 'idle' | 'playing' | 'paused' | 'finished';
2271
+
2272
+ /**
2273
+ * Editor preview of a cutscene inside the running game: answers the bridge's
2274
+ * `cutscene:*` commands with a player bound to the current stage and reports
2275
+ * progress back. Owned by `ZylemGame`; Director mode drives it.
2276
+ */
2277
+ export declare class CutscenePreviewController {
2278
+ private readonly getStage;
2279
+ private readonly publish;
2280
+ private readonly hostOptions;
2281
+ private readonly publishView?;
2282
+ private player;
2283
+ private lastStatus;
2284
+ /** A load that arrived before the stage existed; replayed by `stageReady()`. */
2285
+ private pending;
2286
+ private readonly viewInverse;
2287
+ private readonly viewProjection;
2288
+ private lastView;
2289
+ constructor(getStage: () => ZylemStage | null, publish: (status: CutsceneStatusPayload) => void, hostOptions?: StageCutsceneHostOptions, publishView?: ((view: CutsceneViewPayload) => void) | undefined);
2290
+ get active(): boolean;
2291
+ /**
2292
+ * The game reports itself running before its first stage finishes loading,
2293
+ * so an editor that loads a cutscene straight away would find no stage.
2294
+ * The game calls this once a stage is up; a held load runs then.
2295
+ */
2296
+ stageReady(): void;
2297
+ load(payload: CutsceneLoadPayload): void;
2298
+ play(from?: number): void;
2299
+ pause(): void;
2300
+ stop(): void;
2301
+ seek(time: number): void;
2302
+ /** Drops the player because its stage is going away; a held load survives for the next stage. */
2303
+ releaseStage(): void;
2304
+ /**
2305
+ * Once per rendered frame while a cutscene is loaded: publishes the
2306
+ * camera's projection and the canvas box when either changed, so the
2307
+ * editor's overlays track the view without polling.
2308
+ */
2309
+ frame(): void;
2310
+ unload(): void;
2311
+ /** The live camera as position + look-at, for "capture from viewport". */
2312
+ cameraPose(): Omit<CameraPosePayload, 'requestId'> | null;
2313
+ private report;
2314
+ }
2315
+
2316
+ export declare type CutsceneScene = Static<typeof CutsceneSceneSchema>;
2317
+
2318
+ export declare const CutsceneSceneSchema: _sinclair_typebox.TObject<{
2319
+ id: _sinclair_typebox.TString;
2320
+ name: _sinclair_typebox.TString;
2321
+ /** Seconds from the cutscene start. */
2322
+ start: _sinclair_typebox.TNumber;
2323
+ end: _sinclair_typebox.TNumber;
2324
+ /** How the picture arrives at this scene's start. */
2325
+ transitionIn: _sinclair_typebox.TObject<{
2326
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"cut">, _sinclair_typebox.TLiteral<"fade">, _sinclair_typebox.TLiteral<"wipe">, _sinclair_typebox.TLiteral<"radial">, _sinclair_typebox.TLiteral<"noise">, _sinclair_typebox.TLiteral<"cells">]>;
2327
+ /** Seconds; ignored for `cut`. */
2328
+ duration: _sinclair_typebox.TNumber;
2329
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2330
+ }>;
2331
+ }>;
2332
+
2333
+ /**
2334
+ * A `CutsceneHost` bound to a live stage: drives the stage camera, resolves
2335
+ * entities by name, dispatches stage events, writes stage variables, plays
2336
+ * songs through `@zylem/game-lib/audio` (loaded on demand) and one-shots
2337
+ * through Howler, and runs scene transitions on the stage renderer.
2338
+ */
2339
+ /** What a stage-bound cutscene plays on: the public `Stage` wrapper or the internal stage. */
2340
+ export declare type CutsceneStageLike = ZylemStage | Stage;
2341
+
2342
+ export { CutsceneStatusPayload }
2343
+
2344
+ export declare type CutsceneTrack = Static<typeof CutsceneTrackSchema>;
2345
+
2346
+ export declare const CutsceneTrackSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
2347
+ kind: _sinclair_typebox.TLiteral<"camera">;
2348
+ id: _sinclair_typebox.TString;
2349
+ name: _sinclair_typebox.TString;
2350
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2351
+ id: _sinclair_typebox.TString;
2352
+ cameraId: _sinclair_typebox.TString;
2353
+ start: _sinclair_typebox.TNumber;
2354
+ end: _sinclair_typebox.TNumber;
2355
+ blend: _sinclair_typebox.TObject<{
2356
+ /** Seconds spent blending from the previous shot's camera; 0 is a hard cut. */
2357
+ duration: _sinclair_typebox.TNumber;
2358
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
2359
+ }>;
2360
+ }>>;
2361
+ }>, _sinclair_typebox.TObject<{
2362
+ kind: _sinclair_typebox.TLiteral<"event">;
2363
+ id: _sinclair_typebox.TString;
2364
+ name: _sinclair_typebox.TString;
2365
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2366
+ id: _sinclair_typebox.TString;
2367
+ time: _sinclair_typebox.TNumber;
2368
+ event: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
2369
+ type: _sinclair_typebox.TLiteral<"emit">;
2370
+ /** Stage event name. */
2371
+ name: _sinclair_typebox.TString;
2372
+ payload: _sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>>;
2373
+ }>, _sinclair_typebox.TObject<{
2374
+ type: _sinclair_typebox.TLiteral<"playAnimation">;
2375
+ /** Entity name. */
2376
+ entity: _sinclair_typebox.TString;
2377
+ /** Animation key as passed to `playAnimation({ key })`. */
2378
+ key: _sinclair_typebox.TString;
2379
+ }>, _sinclair_typebox.TObject<{
2380
+ type: _sinclair_typebox.TLiteral<"playSong">;
2381
+ /** Song slug or URL; resolved by the host. */
2382
+ song: _sinclair_typebox.TString;
2383
+ loop: _sinclair_typebox.TBoolean;
2384
+ }>, _sinclair_typebox.TObject<{
2385
+ type: _sinclair_typebox.TLiteral<"stopSong">;
2386
+ song: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2387
+ }>, _sinclair_typebox.TObject<{
2388
+ type: _sinclair_typebox.TLiteral<"setVariable">;
2389
+ name: _sinclair_typebox.TString;
2390
+ value: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>;
2391
+ }>]>;
2392
+ }>>;
2393
+ }>, _sinclair_typebox.TObject<{
2394
+ kind: _sinclair_typebox.TLiteral<"audio">;
2395
+ id: _sinclair_typebox.TString;
2396
+ name: _sinclair_typebox.TString;
2397
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2398
+ id: _sinclair_typebox.TString;
2399
+ time: _sinclair_typebox.TNumber;
2400
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"song">, _sinclair_typebox.TLiteral<"sfx">]>;
2401
+ /** Song slug for `song`, asset URL for `sfx`. */
2402
+ ref: _sinclair_typebox.TString;
2403
+ loop: _sinclair_typebox.TBoolean;
2404
+ /** Gain in dB. */
2405
+ volume: _sinclair_typebox.TNumber;
2406
+ }>>;
2407
+ }>]>;
2408
+
2409
+ export { CutsceneViewPayload }
2410
+
1710
2411
  export declare const CYLINDER_TYPE: unique symbol;
1711
2412
 
1712
2413
  /**
@@ -1741,6 +2442,8 @@ declare interface CylinderMeshOptions extends BaseMeshOptions {
1741
2442
 
1742
2443
  declare type CylinderOptions = BaseNode | Partial<ZylemCylinderOptions>;
1743
2444
 
2445
+ export declare function dbToGain(db: number): number;
2446
+
1744
2447
  /** Resolves a UUID to the live entity owned by the active stage. */
1745
2448
  export declare type DebugEntityResolver = (uuid: string) => GameEntity<any> | null;
1746
2449
 
@@ -1931,16 +2634,57 @@ declare type DiskOptions = BaseNode | Partial<ZylemDiskOptions>;
1931
2634
  */
1932
2635
  export declare function dispatchStageState(): void;
1933
2636
 
2637
+ export declare type DollyPath = Static<typeof DollyPathSchema>;
2638
+
2639
+ export declare const DollyPathSchema: _sinclair_typebox.TObject<{
2640
+ id: _sinclair_typebox.TString;
2641
+ name: _sinclair_typebox.TString;
2642
+ points: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
2643
+ x: _sinclair_typebox.TNumber;
2644
+ y: _sinclair_typebox.TNumber;
2645
+ z: _sinclair_typebox.TNumber;
2646
+ }>>;
2647
+ closed: _sinclair_typebox.TBoolean;
2648
+ /** Catmull-Rom tension; 0.5 is centripetal. */
2649
+ tension: _sinclair_typebox.TNumber;
2650
+ }>;
2651
+
2652
+ /** Point along a dolly path at `u` in 0…1 (arc-length parameterised). */
2653
+ export declare function dollyPointAt(path: DollyPath, u: number): Vec3Def;
2654
+
1934
2655
  export { dot }
1935
2656
 
2657
+ /**
2658
+ * Pure evaluation of a cutscene at a point in time: which scene and shot are
2659
+ * active, where each camera is, and the blended pose the picture should
2660
+ * show. Nothing here touches Three.js cameras or the stage, so the same code
2661
+ * drives the runtime player, the editor's scrubbing, and the unit specs.
2662
+ */
2663
+ export declare function easeValue(easing: CutsceneEasing, t: number): number;
2664
+
1936
2665
  export { EditorToGameMessages }
1937
2666
 
2667
+ export declare type EffectType = Static<typeof EffectTypeSchema>;
2668
+
2669
+ declare const EffectTypeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"reverb">, _sinclair_typebox.TLiteral<"delay">, _sinclair_typebox.TLiteral<"distortion">, _sinclair_typebox.TLiteral<"filter">]>;
2670
+
1938
2671
  export { emitRuntimeGoal }
1939
2672
 
1940
2673
  export { emitRuntimeRicochet }
1941
2674
 
1942
2675
  export { emitRuntimeTriggerRegionEnter }
1943
2676
 
2677
+ export declare function encodeWav(buffer: PcmSource): ArrayBuffer;
2678
+
2679
+ /** `encodeWav` as a `Blob` ready for upload or download. */
2680
+ export declare function encodeWavBlob(buffer: PcmSource): Blob;
2681
+
2682
+ /**
2683
+ * Loads Tone.js and resumes the AudioContext. Call from a click or key
2684
+ * handler the first time; later calls are cheap.
2685
+ */
2686
+ export declare function ensureAudio(): Promise<ToneModule>;
2687
+
1944
2688
  declare interface Entity<T = any> {
1945
2689
  setup: (entity: T) => void;
1946
2690
  destroy: () => void;
@@ -2104,6 +2848,10 @@ declare abstract class EntityMeshBuilder extends MeshBuilder {
2104
2848
  postBuild(): void;
2105
2849
  }
2106
2850
 
2851
+ export { EntityPickPayload }
2852
+
2853
+ export { EntityPickResultPayload }
2854
+
2107
2855
  /**
2108
2856
  * Runtime entity blueprint (open `data` for factory spreading).
2109
2857
  * Prefer {@link EntityJsonSchema} for editor / Monaco JSON Schema.
@@ -2134,6 +2882,8 @@ export declare function entitySpawner(factory: (x: number, y: number) => Promise
2134
2882
 
2135
2883
  export { EntitySummaryPayload }
2136
2884
 
2885
+ export { EntitySwatchAppliedPayload }
2886
+
2137
2887
  /**
2138
2888
  * Generates and caches entity thumbnail previews for the editor entity list.
2139
2889
  * Renders a cloned Object3D into an offscreen RenderTarget on the shared WebGPU renderer.
@@ -2218,9 +2968,38 @@ export declare interface EntityTypeMap {
2218
2968
  [LINE_TYPE]: ZylemLine;
2219
2969
  }
2220
2970
 
2971
+ export declare type Envelope = Static<typeof EnvelopeSchema>;
2972
+
2973
+ declare const EnvelopeSchema: _sinclair_typebox.TObject<{
2974
+ attack: _sinclair_typebox.TNumber;
2975
+ decay: _sinclair_typebox.TNumber;
2976
+ sustain: _sinclair_typebox.TNumber;
2977
+ release: _sinclair_typebox.TNumber;
2978
+ }>;
2979
+
2221
2980
  /** Convert Euler angles (radians, XYZ order) to a quaternion. */
2222
2981
  export declare function eulerToQuaternion(rotation: Vec3): Quat;
2223
2982
 
2983
+ /**
2984
+ * Where a camera is at `time` while `shot` is active: base pose, then dolly
2985
+ * progress or follow target, then keyframes on top.
2986
+ */
2987
+ export declare function evaluateCameraPose(camera: CutsceneCamera, definition: Pick<CutsceneDefinition, 'dollies'>, shot: Pick<CameraShot, 'start' | 'end'>, time: number, lookup?: TargetLookup): EvaluatedPose;
2988
+
2989
+ /**
2990
+ * Everything the picture needs at `time`: the active scene and shot, and the
2991
+ * camera pose after blending from the previous shot when the shot asks for
2992
+ * it. Without an active shot the pose is `undefined` and the gameplay camera
2993
+ * keeps control.
2994
+ */
2995
+ export declare function evaluateCutscene(definition: CutsceneDefinition, time: number, lookup?: TargetLookup): CutsceneFrame;
2996
+
2997
+ export declare interface EvaluatedPose {
2998
+ position: Vec3Def;
2999
+ lookAt: Vec3Def;
3000
+ fov: number;
3001
+ }
3002
+
2224
3003
  /**
2225
3004
  * Reusable delegate for event emission and subscription.
2226
3005
  * Use via composition in Game, Stage, and Entity classes.
@@ -2256,6 +3035,73 @@ export declare class EventEmitterDelegate<TEvents extends Record<string, unknown
2256
3035
  dispose(): void;
2257
3036
  }
2258
3037
 
3038
+ export declare type EventItem = Static<typeof EventItemSchema>;
3039
+
3040
+ export declare const EventItemSchema: _sinclair_typebox.TObject<{
3041
+ id: _sinclair_typebox.TString;
3042
+ time: _sinclair_typebox.TNumber;
3043
+ event: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
3044
+ type: _sinclair_typebox.TLiteral<"emit">;
3045
+ /** Stage event name. */
3046
+ name: _sinclair_typebox.TString;
3047
+ payload: _sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>>;
3048
+ }>, _sinclair_typebox.TObject<{
3049
+ type: _sinclair_typebox.TLiteral<"playAnimation">;
3050
+ /** Entity name. */
3051
+ entity: _sinclair_typebox.TString;
3052
+ /** Animation key as passed to `playAnimation({ key })`. */
3053
+ key: _sinclair_typebox.TString;
3054
+ }>, _sinclair_typebox.TObject<{
3055
+ type: _sinclair_typebox.TLiteral<"playSong">;
3056
+ /** Song slug or URL; resolved by the host. */
3057
+ song: _sinclair_typebox.TString;
3058
+ loop: _sinclair_typebox.TBoolean;
3059
+ }>, _sinclair_typebox.TObject<{
3060
+ type: _sinclair_typebox.TLiteral<"stopSong">;
3061
+ song: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
3062
+ }>, _sinclair_typebox.TObject<{
3063
+ type: _sinclair_typebox.TLiteral<"setVariable">;
3064
+ name: _sinclair_typebox.TString;
3065
+ value: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>;
3066
+ }>]>;
3067
+ }>;
3068
+
3069
+ export declare type EventTrack = Static<typeof EventTrackSchema>;
3070
+
3071
+ declare const EventTrackSchema: _sinclair_typebox.TObject<{
3072
+ kind: _sinclair_typebox.TLiteral<"event">;
3073
+ id: _sinclair_typebox.TString;
3074
+ name: _sinclair_typebox.TString;
3075
+ items: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
3076
+ id: _sinclair_typebox.TString;
3077
+ time: _sinclair_typebox.TNumber;
3078
+ event: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
3079
+ type: _sinclair_typebox.TLiteral<"emit">;
3080
+ /** Stage event name. */
3081
+ name: _sinclair_typebox.TString;
3082
+ payload: _sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>>;
3083
+ }>, _sinclair_typebox.TObject<{
3084
+ type: _sinclair_typebox.TLiteral<"playAnimation">;
3085
+ /** Entity name. */
3086
+ entity: _sinclair_typebox.TString;
3087
+ /** Animation key as passed to `playAnimation({ key })`. */
3088
+ key: _sinclair_typebox.TString;
3089
+ }>, _sinclair_typebox.TObject<{
3090
+ type: _sinclair_typebox.TLiteral<"playSong">;
3091
+ /** Song slug or URL; resolved by the host. */
3092
+ song: _sinclair_typebox.TString;
3093
+ loop: _sinclair_typebox.TBoolean;
3094
+ }>, _sinclair_typebox.TObject<{
3095
+ type: _sinclair_typebox.TLiteral<"stopSong">;
3096
+ song: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
3097
+ }>, _sinclair_typebox.TObject<{
3098
+ type: _sinclair_typebox.TLiteral<"setVariable">;
3099
+ name: _sinclair_typebox.TString;
3100
+ value: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNumber, _sinclair_typebox.TBoolean]>;
3101
+ }>]>;
3102
+ }>>;
3103
+ }>;
3104
+
2259
3105
  export { exp }
2260
3106
 
2261
3107
  export { FacingAngle2DEntity }
@@ -2474,6 +3320,8 @@ export { FractureOptions }
2474
3320
 
2475
3321
  export { FractureOptionsInput }
2476
3322
 
3323
+ export declare function gainToDb(gain: number): number;
3324
+
2477
3325
  export declare class Game<TGlobals extends BaseGlobals> implements IGame<TGlobals> {
2478
3326
  private wrappedGame;
2479
3327
  options: GameOptions<TGlobals>;
@@ -2615,7 +3463,20 @@ export declare class GameBridge {
2615
3463
  * @param announceTarget DOM node the `zylem:bridge:ready` event bubbles from
2616
3464
  */
2617
3465
  connect(host: GameBridgeHost, announceTarget?: EventTarget): void;
3466
+ /** Cutscene playback progress for Director mode's transport. */
3467
+ publishCutsceneStatus(status: CutsceneStatusPayload): void;
3468
+ /** The previewing camera's projection, for Director mode's viewport overlays. */
3469
+ publishCutsceneView(view: CutsceneViewPayload): void;
2618
3470
  disconnect(): void;
3471
+ /**
3472
+ * Run a swatch batch and report back.
3473
+ *
3474
+ * Order matters for the consumer: selection changes first (so a following
3475
+ * `entity:selection` describes the new targets), then the undo record, then
3476
+ * the ack — a consumer that persists on `ok` sees the operation already on
3477
+ * the stack.
3478
+ */
3479
+ private handleApplySwatch;
2619
3480
  /**
2620
3481
  * Publish only the parts of `debugState` the editor does not already know.
2621
3482
  * Values that arrived as editor commands are recorded on `editorKnown`
@@ -2708,8 +3569,30 @@ export declare interface GameBridgeHost {
2708
3569
  createEntity?(typeId: string, props: Record<string, unknown> | undefined, pose: BridgePose | undefined): void;
2709
3570
  /** Undo or redo a committed scene operation (`scene:operation:apply`). */
2710
3571
  applySceneOperation?(op: SceneOperationPayload, direction: 'undo' | 'redo'): void;
2711
- /** Attach a catalog shader or behavior to a live entity (`entity:apply-swatch`). */
2712
- applySwatch?(payload: EntityApplySwatchPayload): void;
3572
+ /**
3573
+ * Raycast at normalized device coordinates and describe the entity hit
3574
+ * (`entity:pick`). Hover should follow the pick only while pick mode is on.
3575
+ */
3576
+ pickEntity?(ndc: BridgeNdc): EntitySummaryPayload | null;
3577
+ /**
3578
+ * Apply every swatch to every uuid (`entity:apply-swatch`). Must report one
3579
+ * result per uuid × swatch pair and return a `scene:operation` entry for
3580
+ * each success so the batch is undoable as a single step.
3581
+ */
3582
+ applySwatches?(payload: EntityApplySwatchPayload & {
3583
+ opId: string;
3584
+ }): SwatchApplyOutcome;
3585
+ /** Cutscene preview hooks (`cutscene:*`); publish progress via `publishCutsceneStatus`. */
3586
+ cutscene?: {
3587
+ load(payload: CutsceneLoadPayload): void;
3588
+ play(from?: number): void;
3589
+ pause(): void;
3590
+ stop(): void;
3591
+ seek(time: number): void;
3592
+ unload(): void;
3593
+ };
3594
+ /** Describe the live camera (`camera:pose:get`), for capturing framing into a cutscene. */
3595
+ cameraPose?(): Omit<CameraPosePayload, 'requestId'> | null;
2713
3596
  }
2714
3597
 
2715
3598
  /**
@@ -3164,6 +4047,30 @@ export declare class GameEntity<O extends GameEntityOptions> extends BaseNode<O>
3164
4047
  * Used by the stage to auto-register required systems.
3165
4048
  */
3166
4049
  getBehaviorRefs(): BehaviorRef_2[];
4050
+ /**
4051
+ * Find the attached ref for a behavior, matched by descriptor key so a
4052
+ * re-imported copy of the same descriptor still resolves.
4053
+ */
4054
+ getBehaviorRef<O extends Record<string, any>>(descriptor: BehaviorDescriptor_2<O, any>): BehaviorRef_2<O> | null;
4055
+ hasBehavior(descriptor: BehaviorDescriptor_2<any, any>): boolean;
4056
+ /**
4057
+ * Detach a behavior from this entity.
4058
+ *
4059
+ * Removes the ref so future spawns skip it. If the entity is live in a
4060
+ * stage, the stage must also drop the system link (see
4061
+ * `StageEntityDelegate.detachBehaviorLink`); `StageDebugDelegate` does this
4062
+ * for editor-driven removals.
4063
+ *
4064
+ * @param target The descriptor (matched by key) or the exact ref to remove.
4065
+ * @returns The removed ref, or `null` when nothing matched.
4066
+ */
4067
+ removeBehavior(target: BehaviorDescriptor_2<any, any> | BehaviorRef_2<any>): BehaviorRef_2<any> | null;
4068
+ /**
4069
+ * Re-attach a previously removed ref as-is (options, FSM state and all).
4070
+ * Used by undo so a restored behavior is the same object, not a re-created
4071
+ * one.
4072
+ */
4073
+ restoreBehaviorRef(ref: BehaviorRef_2<any>): void;
3167
4074
  getCollisionCallbacks(): Array<(params: CollisionContext<this, O>) => void>;
3168
4075
  getCollisionRegistrations(): Array<CollisionRegistration<this, O>>;
3169
4076
  private copyBehaviorRefsTo;
@@ -3194,6 +4101,36 @@ export declare class GameEntity<O extends GameEntityOptions> extends BaseNode<O>
3194
4101
  */
3195
4102
  protected _cleanup(_params: CleanupContext<this>): void;
3196
4103
  _collision(other: GameEntity<O>, globals?: any, dispatch?: CollisionDispatchMetadata): void;
4104
+ /**
4105
+ * Whether this entity renders a mesh that a material can be assigned to.
4106
+ * Lights, zones, and other mesh-less entities return `false`.
4107
+ */
4108
+ hasMaterial(): boolean;
4109
+ /** The materials currently driving this entity's meshes. */
4110
+ getMaterials(): Material[];
4111
+ /**
4112
+ * Rebuild this entity's material from creation-style options and swap it in
4113
+ * on the live mesh, so a runtime change (an editor applying a shader swatch)
4114
+ * renders exactly like a restart with `material: options` would.
4115
+ *
4116
+ * @param options Same shape as `GameEntityOptions.material`.
4117
+ * @param settings `disposePrevious` (default `true`) frees the replaced
4118
+ * materials; pass `false` when keeping them for undo.
4119
+ * @returns The replaced materials, or `null` when the entity has no mesh.
4120
+ */
4121
+ setMaterial(options: Partial<MaterialOptions>, settings?: {
4122
+ disposePrevious?: boolean;
4123
+ }): Material[] | null;
4124
+ /**
4125
+ * Assign already-built materials to every mesh this entity renders. Meshes
4126
+ * that carried a material array keep the array shape, cycling through the
4127
+ * supplied list so multi-material geometry stays fully covered.
4128
+ *
4129
+ * @returns The replaced materials, or `null` when the entity has no mesh.
4130
+ */
4131
+ replaceMaterials(materials: Material[], settings?: {
4132
+ disposePrevious?: boolean;
4133
+ }): Material[] | null;
3197
4134
  protected updateMaterials(params: any): void;
3198
4135
  buildInfo(): Record<string, string>;
3199
4136
  /**
@@ -3496,6 +4433,9 @@ export { GameToEditorMessages }
3496
4433
 
3497
4434
  export { GameVariablePayload }
3498
4435
 
4436
+ /** The most recently created, still-live song player, if any. */
4437
+ export declare function getActiveSongPlayer(): SongPlayer | null;
4438
+
3499
4439
  export { getCooldown }
3500
4440
 
3501
4441
  export { getCooldownStore }
@@ -3796,6 +4736,70 @@ declare class InstanceManager {
3796
4736
  private growPack;
3797
4737
  }
3798
4738
 
4739
+ /**
4740
+ * A playable instrument: a Tone.js synth for the preset, its effects chain,
4741
+ * and an output node the song player routes into a track channel.
4742
+ */
4743
+ export declare interface Instrument {
4744
+ readonly definition: InstrumentDefinition;
4745
+ /** Connect this to a channel or destination. */
4746
+ readonly output: ToneNs.ToneAudioNode;
4747
+ /** Plays a note. `time` is in the Tone context clock (seconds); omit for now. */
4748
+ trigger(pitch: number, duration: number, time?: number, velocity?: number): void;
4749
+ /** Silences ringing notes. */
4750
+ releaseAll(time?: number): void;
4751
+ dispose(): void;
4752
+ }
4753
+
4754
+ export declare type InstrumentDefinition = Static<typeof InstrumentDefinitionSchema>;
4755
+
4756
+ export declare const InstrumentDefinitionSchema: _sinclair_typebox.TObject<{
4757
+ id: _sinclair_typebox.TString;
4758
+ name: _sinclair_typebox.TString;
4759
+ preset: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"synth">, _sinclair_typebox.TLiteral<"polySynth">, _sinclair_typebox.TLiteral<"fmSynth">, _sinclair_typebox.TLiteral<"amSynth">, _sinclair_typebox.TLiteral<"membraneSynth">, _sinclair_typebox.TLiteral<"metalSynth">, _sinclair_typebox.TLiteral<"noiseSynth">, _sinclair_typebox.TLiteral<"pluckSynth">]>;
4760
+ oscillator: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"sine">, _sinclair_typebox.TLiteral<"square">, _sinclair_typebox.TLiteral<"sawtooth">, _sinclair_typebox.TLiteral<"triangle">]>>;
4761
+ envelope: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
4762
+ attack: _sinclair_typebox.TNumber;
4763
+ decay: _sinclair_typebox.TNumber;
4764
+ sustain: _sinclair_typebox.TNumber;
4765
+ release: _sinclair_typebox.TNumber;
4766
+ }>>;
4767
+ /** Output trim in dB. */
4768
+ volume: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
4769
+ effects: _sinclair_typebox.TOptional<_sinclair_typebox.TArray<_sinclair_typebox.TObject<{
4770
+ id: _sinclair_typebox.TString;
4771
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"reverb">, _sinclair_typebox.TLiteral<"delay">, _sinclair_typebox.TLiteral<"distortion">, _sinclair_typebox.TLiteral<"filter">]>;
4772
+ /** Dry/wet mix, 0–1. */
4773
+ wet: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
4774
+ /** Effect-specific settings forwarded to the Tone.js constructor. */
4775
+ options: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TString, _sinclair_typebox.TBoolean]>>>;
4776
+ }>>>;
4777
+ }>;
4778
+
4779
+ export declare type InstrumentEffect = Static<typeof InstrumentEffectSchema>;
4780
+
4781
+ export declare const InstrumentEffectSchema: _sinclair_typebox.TObject<{
4782
+ id: _sinclair_typebox.TString;
4783
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"reverb">, _sinclair_typebox.TLiteral<"delay">, _sinclair_typebox.TLiteral<"distortion">, _sinclair_typebox.TLiteral<"filter">]>;
4784
+ /** Dry/wet mix, 0–1. */
4785
+ wet: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
4786
+ /** Effect-specific settings forwarded to the Tone.js constructor. */
4787
+ options: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TString, _sinclair_typebox.TBoolean]>>>;
4788
+ }>;
4789
+
4790
+ export declare type InstrumentPreset = Static<typeof InstrumentPresetSchema>;
4791
+
4792
+ /**
4793
+ * TypeBox schema for a song the audio module can play: instruments (Tone.js
4794
+ * presets with an effects chain), tracks (one instrument or audio lane each)
4795
+ * and clips placed on those tracks. All positions and lengths are in beats at
4796
+ * the song's tempo; audio clips reference a URL the runtime can fetch.
4797
+ *
4798
+ * Creator's Music mode authors `.song.json` documents that strip down to this
4799
+ * shape (`toRuntimeSong` in `@zylem-creator/shared`).
4800
+ */
4801
+ export declare const InstrumentPresetSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"synth">, _sinclair_typebox.TLiteral<"polySynth">, _sinclair_typebox.TLiteral<"fmSynth">, _sinclair_typebox.TLiteral<"amSynth">, _sinclair_typebox.TLiteral<"membraneSynth">, _sinclair_typebox.TLiteral<"metalSynth">, _sinclair_typebox.TLiteral<"noiseSynth">, _sinclair_typebox.TLiteral<"pluckSynth">]>;
4802
+
3799
4803
  /**
3800
4804
  * Intersect a ray with the plane through `origin` with the given normal.
3801
4805
  *
@@ -3804,6 +4808,9 @@ declare class InstanceManager {
3804
4808
  */
3805
4809
  export declare function intersectPlane(ray: GizmoRay, origin: Vector3, normal: Vector3, target: Vector3): Vector3 | null;
3806
4810
 
4811
+ /** True once `ensureAudio()` has successfully started the context. */
4812
+ export declare function isAudioReady(): boolean;
4813
+
3807
4814
  /**
3808
4815
  * Check if a shader is a GLSL shader
3809
4816
  */
@@ -3839,6 +4846,11 @@ export declare function isTSLShader(shader: ZylemShader): shader is ZylemTSLShad
3839
4846
  */
3840
4847
  export declare function isWebGPUSupported(): Promise<boolean>;
3841
4848
 
4849
+ /** Items on every event/audio track with `time` in `(from, to]`, in time order. */
4850
+ export declare function itemsBetween<T extends {
4851
+ time: number;
4852
+ }>(items: readonly T[], from: number, to: number): T[];
4853
+
3842
4854
  /**
3843
4855
  * Stylized joystick base SVG: outer ring, subtle inner ring, and four
3844
4856
  * directional tabs. Designed to scale to any size; consumes only theme
@@ -3900,6 +4912,10 @@ export declare const KeyboardMappingSchema: _sinclair_typebox.TRecord<_sinclair_
3900
4912
 
3901
4913
  export { length_2 as length }
3902
4914
 
4915
+ export declare function lerpPose(a: EvaluatedPose, b: EvaluatedPose, t: number): EvaluatedPose;
4916
+
4917
+ export declare function lerpVec3(a: Vec3Def, b: Vec3Def, t: number): Vec3Def;
4918
+
3903
4919
  /**
3904
4920
  * Provides BaseNode-like lifecycle without ECS/children. Consumers implement
3905
4921
  * the protected hooks and may assign public setup/update/destroy callbacks.
@@ -4008,6 +5024,9 @@ export declare type LoadingEvent = {
4008
5024
  current?: number;
4009
5025
  };
4010
5026
 
5027
+ /** Loads Tone.js (once) without touching the AudioContext. */
5028
+ export declare function loadTone(): Promise<ToneModule>;
5029
+
4011
5030
  /** Per-axis lock input: `true` locks all axes, or pass an [x, y, z] tuple. */
4012
5031
  declare type LockAxesInput = boolean | readonly [boolean, boolean, boolean];
4013
5032
 
@@ -4076,6 +5095,9 @@ declare interface MaterialOptions {
4076
5095
 
4077
5096
  export { max }
4078
5097
 
5098
+ /** The default selection view: the object's world AABB, padded. */
5099
+ export declare function measureObjectSelectionBounds(object: Object3D, target: Box3): Box3;
5100
+
4079
5101
  /**
4080
5102
  * Deep-merges multiple GameInputConfig objects into one.
4081
5103
  * At the player level, configs are merged (both apply).
@@ -4096,6 +5118,12 @@ declare class MeshBuilder {
4096
5118
  */
4097
5119
  declare type MeshBuilderOptions = Partial<Pick<GameEntityOptions, 'material'>>;
4098
5120
 
5121
+ /** MIDI pitch to Hz with A4 = 440. */
5122
+ export declare function midiToFrequency(pitch: number): number;
5123
+
5124
+ /** `60` → `C4`, the spelling Tone.js accepts as a note name. */
5125
+ export declare function midiToNoteName(pitch: number): string;
5126
+
4099
5127
  export { min }
4100
5128
 
4101
5129
  export { mix }
@@ -4250,6 +5278,30 @@ export declare function normalizeVec2(input?: Vec2Input | null, defaults?: Vec2I
4250
5278
 
4251
5279
  export declare function normalizeVec3(input?: Vec3Input | null, defaults?: Vec3Input | Partial<Vec3Components>): Vec3Components;
4252
5280
 
5281
+ export declare type NoteClip = Static<typeof NoteClipSchema>;
5282
+
5283
+ export declare const NoteClipSchema: _sinclair_typebox.TObject<{
5284
+ kind: _sinclair_typebox.TLiteral<"notes">;
5285
+ id: _sinclair_typebox.TString;
5286
+ trackId: _sinclair_typebox.TString;
5287
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
5288
+ /** Beats from the song start. */
5289
+ start: _sinclair_typebox.TNumber;
5290
+ /** Beats; notes past the end are not played. */
5291
+ length: _sinclair_typebox.TNumber;
5292
+ notes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
5293
+ id: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
5294
+ /** MIDI pitch, 0–127. */
5295
+ pitch: _sinclair_typebox.TInteger;
5296
+ /** Beats from the clip start. */
5297
+ start: _sinclair_typebox.TNumber;
5298
+ /** Beats. */
5299
+ duration: _sinclair_typebox.TNumber;
5300
+ /** 0–1; defaults to 0.8. */
5301
+ velocity: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
5302
+ }>>;
5303
+ }>;
5304
+
4253
5305
  declare interface ObjectBounds {
4254
5306
  width: number;
4255
5307
  height: number;
@@ -4371,6 +5423,11 @@ export declare type OpacityEntity = {
4371
5423
  mesh?: Object3D | null;
4372
5424
  };
4373
5425
 
5426
+ declare type OscillatorType_2 = Static<typeof OscillatorTypeSchema>;
5427
+ export { OscillatorType_2 as OscillatorType }
5428
+
5429
+ declare const OscillatorTypeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"sine">, _sinclair_typebox.TLiteral<"square">, _sinclair_typebox.TLiteral<"sawtooth">, _sinclair_typebox.TLiteral<"triangle">]>;
5430
+
4374
5431
  /**
4375
5432
  * Pack a collision type + filter into the runtime's interaction-groups u32
4376
5433
  * (high 16 bits = membership mask, low 16 bits = filter mask).
@@ -4386,6 +5443,14 @@ declare interface PackKeyConfig {
4386
5443
  colorHex?: number;
4387
5444
  }
4388
5445
 
5446
+ /**
5447
+ * Thicken any axis thinner than the minimum and add the uniform margin, in
5448
+ * place. The minimum is proportional to the entity's largest extent so a
5449
+ * 10-unit floor gets a visible slab while a coin-sized disk does not turn
5450
+ * into a cube. Empty or non-finite boxes are returned untouched.
5451
+ */
5452
+ export declare function padSelectionBounds(box: Box3): Box3;
5453
+
4389
5454
  /**
4390
5455
  * Run all actions simultaneously. Done when all children are done.
4391
5456
  *
@@ -4434,6 +5499,17 @@ export { ParticlePresetMaterialOptions }
4434
5499
 
4435
5500
  export { particlePresets }
4436
5501
 
5502
+ /**
5503
+ * Minimal WAV (RIFF, 16-bit PCM) encoder for rendered audio. Works on any
5504
+ * `AudioBuffer`-shaped object so it can run without a Web Audio context.
5505
+ */
5506
+ export declare interface PcmSource {
5507
+ numberOfChannels: number;
5508
+ sampleRate: number;
5509
+ length: number;
5510
+ getChannelData(channel: number): Float32Array;
5511
+ }
5512
+
4437
5513
  /**
4438
5514
  * Perspective-specific options union.
4439
5515
  * Extend as new perspective types are added.
@@ -4626,6 +5702,9 @@ export { PrebakeWorkerRequest }
4626
5702
 
4627
5703
  export { PrebakeWorkerResponse }
4628
5704
 
5705
+ /** The shot that ended most recently before `shot` began, on any camera track. */
5706
+ export declare function previousShot(definition: CutsceneDefinition, shot: CameraShot): CameraShot | undefined;
5707
+
4629
5708
  export declare const PYRAMID_TYPE: unique symbol;
4630
5709
 
4631
5710
  /**
@@ -4802,6 +5881,14 @@ declare class RendererManager {
4802
5881
  * its pipeline is set up. Call before tearing down the outgoing stage.
4803
5882
  */
4804
5883
  beginSnapshotTransition(resolved: ResolvedStageTransition, scene: Scene, camera: Camera): void;
5884
+ /**
5885
+ * Blend from the current picture into the frames that follow without
5886
+ * changing stage: snapshot the outgoing frame, then rebuild the pipeline
5887
+ * so the blend is composed immediately. Used by cutscene scene changes
5888
+ * and any in-stage "cut" the game wants to soften. Move the camera right
5889
+ * after calling this so the snapshot shows the outgoing shot.
5890
+ */
5891
+ beginInStageTransition(resolved: ResolvedStageTransition, scene: Scene, camera: Camera): void;
4805
5892
  /**
4806
5893
  * Complete the active transition immediately: rebuild the normal
4807
5894
  * pipeline, release transition resources, and fire `onComplete`.
@@ -4889,6 +5976,22 @@ declare class RendererManager {
4889
5976
  dispose(): void;
4890
5977
  }
4891
5978
 
5979
+ /**
5980
+ * Renders a song (or a subset of its tracks) to an `AudioBuffer` offline,
5981
+ * faster than real time. Pair with `encodeWav` to get a file. Works without
5982
+ * a user gesture: offline contexts do not need to be resumed.
5983
+ */
5984
+ export declare function renderSong(song: SongDefinition, options?: RenderSongOptions): Promise<AudioBuffer>;
5985
+
5986
+ export declare interface RenderSongOptions {
5987
+ /** Render only these tracks (mute/solo are ignored so a muted track can still be bounced). */
5988
+ trackIds?: Iterable<string>;
5989
+ sampleRate?: number;
5990
+ /** Extra seconds after the song end so releases and reverb tails finish. */
5991
+ tail?: number;
5992
+ resolveUrl?: (url: string) => string;
5993
+ }
5994
+
4892
5995
  /**
4893
5996
  * Routes entities to scene-direct (`none`), WebGPU bundles (`environment`), or
4894
5997
  * instanced meshes (`pack`) based on `options.category`.
@@ -4986,6 +6089,13 @@ export declare interface ResolveGameConfigRuntime {
4986
6089
  /** Resolve the render category for an entity. Defaults to `none`. */
4987
6090
  export declare function resolveRenderCategory(options?: RenderCategoryOptions | null): RenderCategory;
4988
6091
 
6092
+ /**
6093
+ * The selection bounds for an entity: its own {@link SelectionBoundsProvider}
6094
+ * answer when it has one, otherwise the padded AABB of `group ?? mesh`.
6095
+ * Returns `null` when there is nothing to select, so callers need one check.
6096
+ */
6097
+ export declare function resolveSelectionBounds(entity: unknown, target: Box3): Box3 | null;
6098
+
4989
6099
  /**
4990
6100
  * Normalize a theme input to a fully populated {@link TouchTheme}.
4991
6101
  *
@@ -5265,6 +6375,12 @@ export { RuntimeTriggerRegion2DHandle }
5265
6375
 
5266
6376
  export { RuntimeTriggerRegion2DOptions }
5267
6377
 
6378
+ /** Evenly spaced samples of a dolly path, for drawing it. */
6379
+ export declare function sampleDollyPath(path: DollyPath, segments?: number): Vec3Def[];
6380
+
6381
+ /** The scene containing `time` (last one wins on shared boundaries; the final scene past the end). */
6382
+ export declare function sceneAt(scenes: readonly CutsceneScene[], time: number): CutsceneScene | undefined;
6383
+
5268
6384
  declare interface SceneState {
5269
6385
  backgroundColor: Color | string;
5270
6386
  backgroundImage: string | null;
@@ -5278,6 +6394,59 @@ declare interface SceneState {
5278
6394
  defaultLighting?: boolean;
5279
6395
  }
5280
6396
 
6397
+ export declare type SceneTransition = Static<typeof SceneTransitionSchema>;
6398
+
6399
+ export declare const SceneTransitionSchema: _sinclair_typebox.TObject<{
6400
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"cut">, _sinclair_typebox.TLiteral<"fade">, _sinclair_typebox.TLiteral<"wipe">, _sinclair_typebox.TLiteral<"radial">, _sinclair_typebox.TLiteral<"noise">, _sinclair_typebox.TLiteral<"cells">]>;
6401
+ /** Seconds; ignored for `cut`. */
6402
+ duration: _sinclair_typebox.TNumber;
6403
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
6404
+ }>;
6405
+
6406
+ export declare type SceneTransitionType = Static<typeof SceneTransitionTypeSchema>;
6407
+
6408
+ declare const SceneTransitionTypeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"cut">, _sinclair_typebox.TLiteral<"fade">, _sinclair_typebox.TLiteral<"wipe">, _sinclair_typebox.TLiteral<"radial">, _sinclair_typebox.TLiteral<"noise">, _sinclair_typebox.TLiteral<"cells">]>;
6409
+
6410
+ export declare interface ScheduledAudio {
6411
+ trackId: string;
6412
+ clipId: string;
6413
+ url: string;
6414
+ /** Seconds from the song start. */
6415
+ time: number;
6416
+ /** Seconds into the file. */
6417
+ offset: number;
6418
+ /** Seconds. */
6419
+ duration: number;
6420
+ /** dB. */
6421
+ gain: number;
6422
+ }
6423
+
6424
+ export declare interface ScheduledNote {
6425
+ trackId: string;
6426
+ clipId: string;
6427
+ instrumentId: string;
6428
+ /** Seconds from the song start. */
6429
+ time: number;
6430
+ /** Seconds. */
6431
+ duration: number;
6432
+ pitch: number;
6433
+ velocity: number;
6434
+ }
6435
+
6436
+ export declare interface ScheduleOptions {
6437
+ /** Only schedule these tracks (mute/solo are still honored). */
6438
+ trackIds?: Iterable<string>;
6439
+ /** Ignore mute/solo and schedule every listed track. */
6440
+ ignoreMix?: boolean;
6441
+ }
6442
+
6443
+ /**
6444
+ * Flattens a song into absolute note and audio events in seconds. Notes are
6445
+ * clipped to their clip's length and to the song end; audio clips are
6446
+ * clipped to the song end.
6447
+ */
6448
+ export declare function scheduleSong(song: SongDefinition, options?: ScheduleOptions): SongSchedule;
6449
+
5281
6450
  /**
5282
6451
  * CooldownIcon -- a WoW-style cooldown icon UI entity.
5283
6452
  *
@@ -5353,6 +6522,28 @@ export { ScreenWrapOptions }
5353
6522
 
5354
6523
  export { ScreenWrapState }
5355
6524
 
6525
+ export declare function secondsToBeats(seconds: number, bpm: number): number;
6526
+
6527
+ /** Uniform margin around the box, as a fraction of its largest extent. */
6528
+ export declare const SELECTION_BOUNDS_MARGIN = 0.02;
6529
+
6530
+ /** A thin axis is padded up to this fraction of the largest extent... */
6531
+ export declare const SELECTION_THIN_AXIS_FRACTION = 0.05;
6532
+
6533
+ export declare const SELECTION_THIN_AXIS_MAX = 1;
6534
+
6535
+ /** ...clamped between these world-unit bounds. */
6536
+ export declare const SELECTION_THIN_AXIS_MIN = 0.1;
6537
+
6538
+ /**
6539
+ * Implemented by entities that define their own selection view. `target`
6540
+ * is a scratch box to write into; return it, or `null` when the entity
6541
+ * currently has no selectable volume. World space.
6542
+ */
6543
+ export declare interface SelectionBoundsProvider {
6544
+ getSelectionBounds(target: Box3): Box3 | null;
6545
+ }
6546
+
5356
6547
  export { SemanticParticlePresetOptions }
5357
6548
 
5358
6549
  /**
@@ -5401,6 +6592,19 @@ export declare function setAddType(typeId: string | null, props?: Record<string,
5401
6592
  */
5402
6593
  export declare function setCameraFeed(entity: StageEntity, camera: CameraWrapper, options?: CameraFeedOptions): void;
5403
6594
 
6595
+ /**
6596
+ * Registers the blend shaders every stage-bound cutscene uses for its scene
6597
+ * transitions, typically once at startup:
6598
+ *
6599
+ * ```ts
6600
+ * import { createStageTransition } from '@zylem/shaders';
6601
+ * setCutsceneTransitionShaders((type) => createStageTransition({ pattern: type }).shader);
6602
+ * ```
6603
+ *
6604
+ * Without this, every non-`cut` transition is a plain crossfade.
6605
+ */
6606
+ export declare function setCutsceneTransitionShaders(resolver: ((type: SceneTransitionType) => ZylemTransitionShader | undefined) | null): void;
6607
+
5404
6608
  export declare function setDebugTool(tool: DebugTools): void;
5405
6609
 
5406
6610
  /**
@@ -5550,6 +6754,17 @@ export declare function shortestAngleDelta(from: number, to: number): number;
5550
6754
 
5551
6755
  declare function shortHash(objString: string): string;
5552
6756
 
6757
+ /** The shot covering `time` on one track, if any (last one wins on overlaps). */
6758
+ export declare function shotAt(shots: readonly CameraShot[], time: number): CameraShot | undefined;
6759
+
6760
+ export declare type ShotBlend = Static<typeof ShotBlendSchema>;
6761
+
6762
+ declare const ShotBlendSchema: _sinclair_typebox.TObject<{
6763
+ /** Seconds spent blending from the previous shot's camera; 0 is a hard cut. */
6764
+ duration: _sinclair_typebox.TNumber;
6765
+ easing: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"linear">, _sinclair_typebox.TLiteral<"easeIn">, _sinclair_typebox.TLiteral<"easeOut">, _sinclair_typebox.TLiteral<"easeInOut">]>;
6766
+ }>;
6767
+
5553
6768
  export { Simulation }
5554
6769
 
5555
6770
  export declare class SimulationBody implements PhysicsRenderPoseProvider {
@@ -5700,6 +6915,238 @@ export declare function snapToIncrement(value: number, increment: number): numbe
5700
6915
  /** {@link snapToIncrement} across all three components. */
5701
6916
  export declare function snapVec3(value: Vec3, increment: number): Vec3;
5702
6917
 
6918
+ export declare type SongClip = Static<typeof SongClipSchema>;
6919
+
6920
+ export declare const SongClipSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
6921
+ kind: _sinclair_typebox.TLiteral<"notes">;
6922
+ id: _sinclair_typebox.TString;
6923
+ trackId: _sinclair_typebox.TString;
6924
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
6925
+ /** Beats from the song start. */
6926
+ start: _sinclair_typebox.TNumber;
6927
+ /** Beats; notes past the end are not played. */
6928
+ length: _sinclair_typebox.TNumber;
6929
+ notes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
6930
+ id: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
6931
+ /** MIDI pitch, 0–127. */
6932
+ pitch: _sinclair_typebox.TInteger;
6933
+ /** Beats from the clip start. */
6934
+ start: _sinclair_typebox.TNumber;
6935
+ /** Beats. */
6936
+ duration: _sinclair_typebox.TNumber;
6937
+ /** 0–1; defaults to 0.8. */
6938
+ velocity: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
6939
+ }>>;
6940
+ }>, _sinclair_typebox.TObject<{
6941
+ kind: _sinclair_typebox.TLiteral<"audio">;
6942
+ id: _sinclair_typebox.TString;
6943
+ trackId: _sinclair_typebox.TString;
6944
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
6945
+ /** URL of the audio file. */
6946
+ url: _sinclair_typebox.TString;
6947
+ /** Beats from the song start. */
6948
+ start: _sinclair_typebox.TNumber;
6949
+ /** Seconds trimmed from the start of the file. */
6950
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
6951
+ /** Beats. */
6952
+ length: _sinclair_typebox.TNumber;
6953
+ /** Clip gain in dB. */
6954
+ gain: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
6955
+ }>]>;
6956
+
6957
+ export declare type SongDefinition = Static<typeof SongDefinitionSchema>;
6958
+
6959
+ export declare const SongDefinitionSchema: _sinclair_typebox.TObject<{
6960
+ id: _sinclair_typebox.TString;
6961
+ name: _sinclair_typebox.TString;
6962
+ bpm: _sinclair_typebox.TNumber;
6963
+ timeSignature: _sinclair_typebox.TObject<{
6964
+ numerator: _sinclair_typebox.TInteger;
6965
+ denominator: _sinclair_typebox.TInteger;
6966
+ }>;
6967
+ lengthBars: _sinclair_typebox.TInteger;
6968
+ loop: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
6969
+ enabled: _sinclair_typebox.TBoolean;
6970
+ /** Beats. */
6971
+ start: _sinclair_typebox.TNumber;
6972
+ end: _sinclair_typebox.TNumber;
6973
+ }>>;
6974
+ instruments: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
6975
+ id: _sinclair_typebox.TString;
6976
+ name: _sinclair_typebox.TString;
6977
+ preset: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"synth">, _sinclair_typebox.TLiteral<"polySynth">, _sinclair_typebox.TLiteral<"fmSynth">, _sinclair_typebox.TLiteral<"amSynth">, _sinclair_typebox.TLiteral<"membraneSynth">, _sinclair_typebox.TLiteral<"metalSynth">, _sinclair_typebox.TLiteral<"noiseSynth">, _sinclair_typebox.TLiteral<"pluckSynth">]>;
6978
+ oscillator: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"sine">, _sinclair_typebox.TLiteral<"square">, _sinclair_typebox.TLiteral<"sawtooth">, _sinclair_typebox.TLiteral<"triangle">]>>;
6979
+ envelope: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
6980
+ attack: _sinclair_typebox.TNumber;
6981
+ decay: _sinclair_typebox.TNumber;
6982
+ sustain: _sinclair_typebox.TNumber;
6983
+ release: _sinclair_typebox.TNumber;
6984
+ }>>;
6985
+ /** Output trim in dB. */
6986
+ volume: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
6987
+ effects: _sinclair_typebox.TOptional<_sinclair_typebox.TArray<_sinclair_typebox.TObject<{
6988
+ id: _sinclair_typebox.TString;
6989
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"reverb">, _sinclair_typebox.TLiteral<"delay">, _sinclair_typebox.TLiteral<"distortion">, _sinclair_typebox.TLiteral<"filter">]>;
6990
+ /** Dry/wet mix, 0–1. */
6991
+ wet: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
6992
+ /** Effect-specific settings forwarded to the Tone.js constructor. */
6993
+ options: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TString, _sinclair_typebox.TBoolean]>>>;
6994
+ }>>>;
6995
+ }>>;
6996
+ tracks: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
6997
+ id: _sinclair_typebox.TString;
6998
+ name: _sinclair_typebox.TString;
6999
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"instrument">, _sinclair_typebox.TLiteral<"audio">]>;
7000
+ instrumentId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7001
+ color: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7002
+ /** Fader in dB. */
7003
+ volume: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7004
+ /** -1 (left) … 1 (right). */
7005
+ pan: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7006
+ mute: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
7007
+ solo: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
7008
+ }>>;
7009
+ clips: _sinclair_typebox.TArray<_sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
7010
+ kind: _sinclair_typebox.TLiteral<"notes">;
7011
+ id: _sinclair_typebox.TString;
7012
+ trackId: _sinclair_typebox.TString;
7013
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7014
+ /** Beats from the song start. */
7015
+ start: _sinclair_typebox.TNumber;
7016
+ /** Beats; notes past the end are not played. */
7017
+ length: _sinclair_typebox.TNumber;
7018
+ notes: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
7019
+ id: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7020
+ /** MIDI pitch, 0–127. */
7021
+ pitch: _sinclair_typebox.TInteger;
7022
+ /** Beats from the clip start. */
7023
+ start: _sinclair_typebox.TNumber;
7024
+ /** Beats. */
7025
+ duration: _sinclair_typebox.TNumber;
7026
+ /** 0–1; defaults to 0.8. */
7027
+ velocity: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7028
+ }>>;
7029
+ }>, _sinclair_typebox.TObject<{
7030
+ kind: _sinclair_typebox.TLiteral<"audio">;
7031
+ id: _sinclair_typebox.TString;
7032
+ trackId: _sinclair_typebox.TString;
7033
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7034
+ /** URL of the audio file. */
7035
+ url: _sinclair_typebox.TString;
7036
+ /** Beats from the song start. */
7037
+ start: _sinclair_typebox.TNumber;
7038
+ /** Seconds trimmed from the start of the file. */
7039
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7040
+ /** Beats. */
7041
+ length: _sinclair_typebox.TNumber;
7042
+ /** Clip gain in dB. */
7043
+ gain: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7044
+ }>]>>;
7045
+ /** Master fader in dB. */
7046
+ masterVolume: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7047
+ }>;
7048
+
7049
+ export declare function songLengthBeats(song: Pick<SongDefinition, 'lengthBars' | 'timeSignature'>): number;
7050
+
7051
+ export declare function songLengthSeconds(song: Pick<SongDefinition, 'lengthBars' | 'timeSignature' | 'bpm'>): number;
7052
+
7053
+ export declare type SongLoop = Static<typeof SongLoopSchema>;
7054
+
7055
+ export declare const SongLoopSchema: _sinclair_typebox.TObject<{
7056
+ enabled: _sinclair_typebox.TBoolean;
7057
+ /** Beats. */
7058
+ start: _sinclair_typebox.TNumber;
7059
+ end: _sinclair_typebox.TNumber;
7060
+ }>;
7061
+
7062
+ export declare type SongNote = Static<typeof SongNoteSchema>;
7063
+
7064
+ export declare const SongNoteSchema: _sinclair_typebox.TObject<{
7065
+ id: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7066
+ /** MIDI pitch, 0–127. */
7067
+ pitch: _sinclair_typebox.TInteger;
7068
+ /** Beats from the clip start. */
7069
+ start: _sinclair_typebox.TNumber;
7070
+ /** Beats. */
7071
+ duration: _sinclair_typebox.TNumber;
7072
+ /** 0–1; defaults to 0.8. */
7073
+ velocity: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7074
+ }>;
7075
+
7076
+ export declare interface SongPlayer {
7077
+ readonly definition: SongDefinition;
7078
+ readonly state: SongPlayerState;
7079
+ /** Resolves once Tone.js and every audio clip are loaded. */
7080
+ readonly ready: Promise<void>;
7081
+ /** Starts (or resumes) playback; needs a prior user gesture the first time. */
7082
+ play(fromBeat?: number): Promise<void>;
7083
+ pause(): void;
7084
+ /** Stops and rewinds to the start. */
7085
+ stop(): void;
7086
+ seek(beat: number): void;
7087
+ /** Playhead in beats. */
7088
+ position(): number;
7089
+ /** Playhead in seconds at the current tempo. */
7090
+ seconds(): number;
7091
+ setBpm(bpm: number): void;
7092
+ setLoop(loop: SongLoop | null): void;
7093
+ setTrackMute(trackId: string, mute: boolean): void;
7094
+ setTrackSolo(trackId: string, solo: boolean): void;
7095
+ /** dB. */
7096
+ setTrackVolume(trackId: string, volume: number): void;
7097
+ setTrackPan(trackId: string, pan: number): void;
7098
+ /** dB. */
7099
+ setMasterVolume(volume: number): void;
7100
+ /** Plays one note on a track's instrument right now (for auditioning). */
7101
+ preview(trackId: string, pitch: number, duration?: number, velocity?: number): Promise<void>;
7102
+ /** Swaps in a new definition, keeping the playhead and state. */
7103
+ update(definition: SongDefinition): Promise<void>;
7104
+ on<K extends keyof SongPlayerEvents>(event: K, handler: SongPlayerEvents[K]): () => void;
7105
+ dispose(): void;
7106
+ }
7107
+
7108
+ export declare interface SongPlayerEvents {
7109
+ /** Fires at the start of every bar with the 0-based bar index. */
7110
+ bar: (bar: number) => void;
7111
+ /** Fires at the start of every beat with the 0-based beat index. */
7112
+ beat: (beat: number) => void;
7113
+ /** Fires when a non-looping song reaches its end. */
7114
+ complete: () => void;
7115
+ state: (state: SongPlayerState) => void;
7116
+ }
7117
+
7118
+ export declare interface SongPlayerOptions {
7119
+ /** Resolve clip URLs (for example, relative asset paths) before loading. */
7120
+ resolveUrl?: (url: string) => string;
7121
+ /** Route the master output here instead of the speakers. */
7122
+ destination?: ToneNs.InputNode;
7123
+ }
7124
+
7125
+ export declare type SongPlayerState = 'stopped' | 'playing' | 'paused';
7126
+
7127
+ export declare interface SongSchedule {
7128
+ notes: ScheduledNote[];
7129
+ audio: ScheduledAudio[];
7130
+ /** Seconds. */
7131
+ length: number;
7132
+ }
7133
+
7134
+ export declare type SongTrack = Static<typeof SongTrackSchema>;
7135
+
7136
+ export declare const SongTrackSchema: _sinclair_typebox.TObject<{
7137
+ id: _sinclair_typebox.TString;
7138
+ name: _sinclair_typebox.TString;
7139
+ kind: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"instrument">, _sinclair_typebox.TLiteral<"audio">]>;
7140
+ instrumentId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7141
+ color: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
7142
+ /** Fader in dB. */
7143
+ volume: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7144
+ /** -1 (left) … 1 (right). */
7145
+ pan: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
7146
+ mute: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
7147
+ solo: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
7148
+ }>;
7149
+
5703
7150
  export declare const SPHERE_TYPE: unique symbol;
5704
7151
 
5705
7152
  /**
@@ -5950,6 +7397,19 @@ export declare type StageConfigLike = Partial<{
5950
7397
 
5951
7398
  export { StageConfigPayload }
5952
7399
 
7400
+ export declare interface StageCutsceneHostOptions {
7401
+ /**
7402
+ * Looks a song reference (slug or URL from a `playSong` event / audio
7403
+ * item) up to a definition the audio module can play. Without it song
7404
+ * items are ignored.
7405
+ */
7406
+ resolveSong?: (ref: string) => SongDefinition | Promise<SongDefinition | undefined> | undefined;
7407
+ /** Maps a transition type to a blend shader; defaults to a crossfade for every type. */
7408
+ transitionShader?: (type: SceneTransitionType) => ZylemTransitionShader | undefined;
7409
+ /** Called for `emit` events in addition to the stage dispatch. */
7410
+ onEvent?: (name: string, payload: Record<string, unknown>) => void;
7411
+ }
7412
+
5953
7413
  /**
5954
7414
  * Self-managing debug delegate that subscribes to `debugState` internally.
5955
7415
  *
@@ -5974,6 +7434,11 @@ declare class StageDebugDelegate {
5974
7434
  private lastDebugEnabled;
5975
7435
  private warnedMissingAddFactory;
5976
7436
  private transformTool;
7437
+ private swatchApplier;
7438
+ private marquee;
7439
+ private selectionHighlight;
7440
+ private selectionBoundsPool;
7441
+ private hoverBounds;
5977
7442
  private grid;
5978
7443
  private lastTool;
5979
7444
  /** Element the current gizmo drag captured, so pointerup is never missed. */
@@ -5987,6 +7452,13 @@ declare class StageDebugDelegate {
5987
7452
  /** Camera used for debug orbit / raycasts (active primary, usually `__debug__`). */
5988
7453
  private getDebugViewCamera;
5989
7454
  private resolveEntity;
7455
+ /**
7456
+ * Every entity a marquee may catch. `childrenMap` is the live stage;
7457
+ * `debugMap` is consulted too so anything only registered there (the same
7458
+ * set the single pick resolves through) is not skipped. Whether an entity
7459
+ * has a selectable volume is the marquee's call, via its selection bounds.
7460
+ */
7461
+ private forEachSelectableEntity;
5990
7462
  /** Copy all stage children into debugMap so raycast/select tools work after enabling debug mid-session. */
5991
7463
  private populateDebugMap;
5992
7464
  private ensureCameraDebugDelegate;
@@ -6019,6 +7491,12 @@ declare class StageDebugDelegate {
6019
7491
  * available when a tool is armed with debug off.
6020
7492
  */
6021
7493
  private ensureToolVisuals;
7494
+ /**
7495
+ * Outline every selected entity. Re-fitted each frame so the boxes follow
7496
+ * entities that move, and so a uuid whose entity has gone (deleted, or
7497
+ * undone) simply drops out instead of leaving a stale box behind.
7498
+ */
7499
+ private updateSelectionHighlight;
6022
7500
  /**
6023
7501
  * Hide the overlays whose tool has just gone away.
6024
7502
  *
@@ -6032,13 +7510,27 @@ declare class StageDebugDelegate {
6032
7510
  update(): void;
6033
7511
  /**
6034
7512
  * Raycast at NDC coordinates (from a host that cannot send DOM pointer
6035
- * events, e.g. an overlay sitting on a preview iframe). Updates hover so
6036
- * the next `update()` paints the highlight.
7513
+ * events, e.g. an overlay sitting on a preview iframe, or the bridge's
7514
+ * `entity:pick`).
7515
+ *
7516
+ * Hover follows the pick only while pick mode is armed (a drag in flight),
7517
+ * so a one-shot pick from an inspector does not disturb the user's hover.
7518
+ * While armed, the next `update()` paints the highlight.
6037
7519
  */
6038
- pickAtNdc(ndcX: number, ndcY: number): {
7520
+ pickAtNdc(ndcX: number, ndcY: number, options?: {
7521
+ updateHover?: boolean;
7522
+ }): {
6039
7523
  uuid: string;
6040
7524
  name: string;
6041
7525
  } | null;
7526
+ /**
7527
+ * Apply swatches to live entities (`entity:apply-swatch`). Every uuid ×
7528
+ * swatch pair is attempted and reported; successful pairs are recorded so
7529
+ * the operation can be undone exactly via {@link applySceneOperation}.
7530
+ */
7531
+ applySwatches(payload: EntityApplySwatchPayload & {
7532
+ opId: string;
7533
+ }): SwatchApplyOutcome_2;
6042
7534
  /** Collider wireframes, straight from the wasm simulation. */
6043
7535
  private updateColliderWireframes;
6044
7536
  /**
@@ -6286,11 +7778,35 @@ declare class StageEntityDelegate {
6286
7778
  */
6287
7779
  destroyAll(): void;
6288
7780
  private registerBehaviorLinks;
7781
+ /**
7782
+ * Index one ref, lazily create its system, and attach. Shared by spawn-time
7783
+ * registration and late per-ref attaches.
7784
+ */
7785
+ private linkBehaviorRef;
7786
+ private unlinkBehaviorLink;
6289
7787
  /**
6290
7788
  * Re-index an entity's behavior refs after a late `entity.use(...)`.
6291
7789
  * Spawn-time registration only sees refs that existed at attach.
7790
+ *
7791
+ * Detaches and re-attaches every behavior on the entity, which resets their
7792
+ * per-link state. Prefer {@link attachBehaviorLink} /
7793
+ * {@link detachBehaviorLink} when only one ref changed.
6292
7794
  */
6293
7795
  syncBehaviorLinks(entity: any): void;
7796
+ /**
7797
+ * Attach a single ref that was added to a live entity (`entity.use(...)`
7798
+ * after spawn) without disturbing the entity's other behaviors.
7799
+ *
7800
+ * @returns `false` when the stage is not loaded or the ref is already linked.
7801
+ */
7802
+ attachBehaviorLink(entity: any, ref: BehaviorRef_2): boolean;
7803
+ /**
7804
+ * Detach a single ref's system link from a live entity, leaving its other
7805
+ * behaviors attached.
7806
+ *
7807
+ * @returns `false` when no link for that ref exists.
7808
+ */
7809
+ detachBehaviorLink(entity: any, ref: BehaviorRef_2): boolean;
6294
7810
  private unregisterBehaviorLinks;
6295
7811
  }
6296
7812
 
@@ -6611,6 +8127,45 @@ export declare const standardShader: {
6611
8127
 
6612
8128
  export { step }
6613
8129
 
8130
+ export { SwatchApplyFailureReason }
8131
+
8132
+ /** What a host reports back from a swatch batch. */
8133
+ export declare interface SwatchApplyOutcome {
8134
+ results: SwatchApplyResult[];
8135
+ entries: SceneOperationEntry[];
8136
+ }
8137
+
8138
+ /**
8139
+ * Applies swatches (configured shaders / behaviors) to live entities and
8140
+ * inverts those applications for undo.
8141
+ *
8142
+ * One `entity:apply-swatch` message is a batch: every swatch is applied to
8143
+ * every uuid, in order, under a single operation id. Each pair reports its own
8144
+ * result so a multi-select apply can partially succeed (a light in the
8145
+ * selection has no material) while the rest still land.
8146
+ *
8147
+ * Undo follows the stage's "editor holds the history, game holds the
8148
+ * instances" rule. The original material and any displaced behavior refs are
8149
+ * kept here per operation, so undo puts back the exact objects rather than a
8150
+ * reconstruction — the pre-swatch material (texture, tint, standard shader) is
8151
+ * usually not describable as a swatch at all.
8152
+ */
8153
+
8154
+ declare interface SwatchApplyOutcome_2 {
8155
+ results: SwatchApplyResult[];
8156
+ /** One entry per successful pair, ready for a `scene:operation`. */
8157
+ entries: SceneOperationEntry[];
8158
+ }
8159
+
8160
+ export { SwatchApplyResult }
8161
+
8162
+ export { SwatchKind }
8163
+
8164
+ export { SwatchSpec }
8165
+
8166
+ /** Positions of named entities the cameras may reference, by name. */
8167
+ export declare type TargetLookup = (name: string) => Vec3Def | undefined;
8168
+
6614
8169
  /**
6615
8170
  * Factory interface for generating entity copies
6616
8171
  */
@@ -6884,6 +8439,20 @@ declare class Timer {
6884
8439
  update(timestamp?: number): Timer;
6885
8440
  }
6886
8441
 
8442
+ export declare type TimeSignature = Static<typeof TimeSignatureSchema>;
8443
+
8444
+ export declare const TimeSignatureSchema: _sinclair_typebox.TObject<{
8445
+ numerator: _sinclair_typebox.TInteger;
8446
+ denominator: _sinclair_typebox.TInteger;
8447
+ }>;
8448
+
8449
+ /**
8450
+ * Tone.js is loaded on demand so games without music never download it, and
8451
+ * so the AudioContext is only started after a user gesture (browsers refuse
8452
+ * to start one otherwise).
8453
+ */
8454
+ export declare type ToneModule = typeof ToneNs;
8455
+
6887
8456
  export { TopDownMovementBehavior }
6888
8457
 
6889
8458
  export { TopDownMovementBehaviorOptions }
@@ -7286,6 +8855,8 @@ export declare type Vec3Components = {
7286
8855
  /** Gravity as `[x, y, z]` components (JSON-serializable). */
7287
8856
  export declare const Vec3ComponentsSchema: _sinclair_typebox.TTuple<[_sinclair_typebox.TNumber, _sinclair_typebox.TNumber, _sinclair_typebox.TNumber]>;
7288
8857
 
8858
+ export declare type Vec3Def = Static<typeof Vec3Schema>;
8859
+
7289
8860
  export declare type Vec3Input = Vec3 | {
7290
8861
  x?: number;
7291
8862
  y?: number;
@@ -7294,6 +8865,21 @@ export declare type Vec3Input = Vec3 | {
7294
8865
 
7295
8866
  export { Vec3Like }
7296
8867
 
8868
+ /**
8869
+ * TypeBox schema for a cutscene the cinematics module can play: a timeline in
8870
+ * seconds split into scenes, cameras (static, dolly along a spline, or
8871
+ * following an entity) placed on camera tracks as shots, camera keyframes,
8872
+ * and event/audio tracks that fire gameplay hooks at points in time.
8873
+ *
8874
+ * Creator's Director mode authors `.cutscene.json` documents that strip down
8875
+ * to this shape (`toRuntimeCutscene` in `@zylem-creator/shared`).
8876
+ */
8877
+ declare const Vec3Schema: _sinclair_typebox.TObject<{
8878
+ x: _sinclair_typebox.TNumber;
8879
+ y: _sinclair_typebox.TNumber;
8880
+ z: _sinclair_typebox.TNumber;
8881
+ }>;
8882
+
7297
8883
  declare type Vec3Tuple = readonly [number?, number?, number?] & {
7298
8884
  x?: number;
7299
8885
  y?: number;
@@ -8264,6 +9850,8 @@ declare class ZylemGame<TGlobals extends BaseGlobals> {
8264
9850
  private lastPublishedGameConfig;
8265
9851
  /** Editor ↔ game bridge adapter (RAF-coalesced publishes, command intake). */
8266
9852
  private gameBridge;
9853
+ /** Director mode's in-game cutscene preview, driven over the bridge. */
9854
+ private cutscenePreview;
8267
9855
  /** Stops republishing the entity catalog on registry changes. */
8268
9856
  private catalogUnsubscribe;
8269
9857
  private readonly gameUpdateParams;
@@ -8276,6 +9864,12 @@ declare class ZylemGame<TGlobals extends BaseGlobals> {
8276
9864
  static FRAME_DURATION: number;
8277
9865
  static MAX_DELTA_SECONDS: number;
8278
9866
  constructor(options: ZylemGameOptions<TGlobals>, wrapperRef: Game<TGlobals>, displayRuntime?: ResolveGameConfigRuntime);
9867
+ /**
9868
+ * Raycast at normalized device coordinates (editor `entity:pick`) and
9869
+ * describe the hit the same way the entity list does, so a consumer can
9870
+ * show name, type, and pose for whatever is under the pointer.
9871
+ */
9872
+ private pickEntityAtNdc;
8279
9873
  /** Publish the placeable entity types the editor's Add palette lists. */
8280
9874
  private publishEntityCatalog;
8281
9875
  /** Spawn a catalog type programmatically (editor `entity:create`). */
@@ -8496,10 +10090,12 @@ export declare type ZylemLineOptions = GameEntityOptions & {
8496
10090
  pickThreshold?: number;
8497
10091
  };
8498
10092
 
8499
- export declare class ZylemParticleSystem extends GameEntity<ZylemParticleSystemOptions> {
10093
+ export declare class ZylemParticleSystem extends GameEntity<ZylemParticleSystemOptions> implements SelectionBoundsProvider {
8500
10094
  static type: symbol;
8501
10095
  __zylemParticleSystemEntity: true;
8502
10096
  private particleHandle;
10097
+ /** The emitter's `group` is empty, so measuring it yields nothing; see {@link PARTICLE_SYSTEM_SELECTION_EXTENT}. */
10098
+ getSelectionBounds(target: Box3): Box3 | null;
8503
10099
  constructor(options?: Partial<ZylemParticleSystemOptions>, initializeBehavior?: boolean);
8504
10100
  private bindStandaloneTransforms;
8505
10101
  private resolveParticleHandle;
@@ -9140,12 +10736,18 @@ declare class ZylemWorld implements Entity<ZylemWorld> {
9140
10736
  private clearEntityPhysicsState;
9141
10737
  }
9142
10738
 
9143
- export declare class ZylemZone extends GameEntity<ZylemZoneOptions> implements CollisionHandlerDelegate {
10739
+ export declare class ZylemZone extends GameEntity<ZylemZoneOptions> implements CollisionHandlerDelegate, SelectionBoundsProvider {
9144
10740
  static type: symbol;
9145
10741
  private _enteredZone;
9146
10742
  private _exitedZone;
9147
10743
  private _zoneEntities;
9148
10744
  constructor(options?: ZylemZoneOptions);
10745
+ /**
10746
+ * A zone has no render object, so the editor cannot measure it. Its
10747
+ * selection view is the sensor volume itself: `options.size` centred on
10748
+ * the live pose (or the configured position before spawn).
10749
+ */
10750
+ getSelectionBounds(target: Box3): Box3 | null;
9149
10751
  handlePostCollision({ delta }: {
9150
10752
  delta: number;
9151
10753
  }): boolean;