@energy8platform/game-engine 0.34.2 → 0.35.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 (45) hide show
  1. package/dist/audio.cjs.js +114 -59
  2. package/dist/audio.cjs.js.map +1 -1
  3. package/dist/audio.d.ts +25 -0
  4. package/dist/audio.esm.js +114 -59
  5. package/dist/audio.esm.js.map +1 -1
  6. package/dist/core.cjs.js +222 -66
  7. package/dist/core.cjs.js.map +1 -1
  8. package/dist/core.d.ts +25 -0
  9. package/dist/core.esm.js +223 -67
  10. package/dist/core.esm.js.map +1 -1
  11. package/dist/flow.cjs.js +246 -0
  12. package/dist/flow.cjs.js.map +1 -1
  13. package/dist/flow.d.ts +192 -33
  14. package/dist/flow.esm.js +238 -1
  15. package/dist/flow.esm.js.map +1 -1
  16. package/dist/host.cjs.js +343 -82
  17. package/dist/host.cjs.js.map +1 -1
  18. package/dist/host.d.ts +82 -2
  19. package/dist/host.esm.js +344 -83
  20. package/dist/host.esm.js.map +1 -1
  21. package/dist/index.cjs.js +222 -66
  22. package/dist/index.cjs.js.map +1 -1
  23. package/dist/index.d.ts +72 -0
  24. package/dist/index.esm.js +223 -67
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/scene-devtools.cjs.js +529 -115
  27. package/dist/scene-devtools.cjs.js.map +1 -1
  28. package/dist/scene-devtools.d.ts +187 -34
  29. package/dist/scene-devtools.esm.js +529 -115
  30. package/dist/scene-devtools.esm.js.map +1 -1
  31. package/dist/scene.cjs.js +704 -46
  32. package/dist/scene.cjs.js.map +1 -1
  33. package/dist/scene.d.ts +228 -41
  34. package/dist/scene.esm.js +698 -47
  35. package/dist/scene.esm.js.map +1 -1
  36. package/package.json +2 -2
  37. package/src/audio/AudioManager.ts +111 -53
  38. package/src/core/GameApplication.ts +47 -5
  39. package/src/host/buildConfig.ts +17 -4
  40. package/src/host/createSlotGame.ts +114 -12
  41. package/src/host/index.ts +3 -0
  42. package/src/host/types.ts +58 -0
  43. package/src/loading/LoadingScene.ts +76 -2
  44. package/src/loading/index.ts +6 -0
  45. package/src/types.ts +2 -0
package/dist/host.d.ts CHANGED
@@ -337,6 +337,12 @@ declare class AudioManager {
337
337
  private _categories;
338
338
  private _masterGain;
339
339
  private _currentMusic;
340
+ /** Duck factor (0..1) from duckMusic/unduckMusic. A presentation state, not a player setting. */
341
+ private _musicDuck;
342
+ /** Crossfade ramp (0..1) for the track that is fading IN. 1 whenever no fade is running. */
343
+ private _musicFade;
344
+ /** Generation counter so a superseded crossfade ramp stops writing over the new track's. */
345
+ private _musicFadeToken;
340
346
  private _unlocked;
341
347
  private _unlockHandler;
342
348
  constructor(config?: AudioConfig);
@@ -430,6 +436,25 @@ declare class AudioManager {
430
436
  * Smoothly fade a sound's volume from `fromVol` to `toVol` over `durationMs`.
431
437
  */
432
438
  private fadeVolume;
439
+ /**
440
+ * The SOUND-layer gain for the running music track.
441
+ *
442
+ * @pixi/sound resolves a playing instance as `instance × sound × global` (WebAudioInstance.
443
+ * refresh). Each of those three has exactly ONE owner here, which is what keeps the mixer honest:
444
+ * global — the master gain (`applyVolumes`)
445
+ * sound — music: this function. sfx: untouched, left at 1.
446
+ * instance — sfx: the per-call volume × the sfx category. music: always 1.
447
+ * Everything that can move music volume — the player's slider, the category mute, a big-win duck,
448
+ * a crossfade — is a term below, so they compose instead of overwriting each other.
449
+ */
450
+ private musicGain;
451
+ /** Push `musicGain()` at the current track. Safe before it starts playing and with none playing. */
452
+ private applyMusicGain;
453
+ /** Current SOUND-layer volume of `alias`, or 0 when it cannot be read. */
454
+ private soundVolumeOf;
455
+ /** Ramp the crossfade term 0 → 1 over `durationMs`, recomposing the gain each frame so a slider
456
+ * drag or a duck landing mid-fade is honoured rather than overwritten when the fade ends. */
457
+ private rampMusicFade;
433
458
  private applyVolumes;
434
459
  private setupMobileUnlock;
435
460
  private removeMobileUnlock;
@@ -871,6 +896,55 @@ interface StakeIntegration {
871
896
  /** The game's BookAdapter (or its module). modeMap + gameId come from the model. */
872
897
  adapter: BookAdapter | AdapterModule;
873
898
  }
899
+ /** The live Artube bridge, structurally. Kept minimal so game-engine never has to import
900
+ * `@energy8platform/artube-bridge` — see `ArtubeIntegration.load`. */
901
+ interface ArtubeBridgeLike {
902
+ /** Resolves once the backend has sent its init. */
903
+ ready(): Promise<void>;
904
+ destroy(): void;
905
+ }
906
+ /** What `ArtubeIntegration.load()` must resolve to. `@energy8platform/artube-bridge`'s own entry
907
+ * satisfies this structurally, so `load: () => import('@energy8platform/artube-bridge')` typechecks
908
+ * with no adapter. The launch CLASSIFIER comes from the same module as the bridge: one import, and
909
+ * no chicken-and-egg where the host would have to load something to decide whether to load. */
910
+ interface ArtubeModule {
911
+ classifyArtubeLaunch: (url: string) => 'artube' | 'blocked' | 'offline';
912
+ ArtubeBridge: new (options: {
913
+ devMode?: boolean;
914
+ gameId?: string;
915
+ url?: string;
916
+ apiBase?: string;
917
+ demoBalance?: number;
918
+ }) => ArtubeBridgeLike;
919
+ }
920
+ /** Artube host integration. There is no per-game artifact to pass: the game's own BACKEND
921
+ * (`@energy8platform/artube-server`) owns the round shape, so the bridge is a pure protocol
922
+ * translator — `load` is the only required field. `gameId` comes from the model, the launch params
923
+ * from the URL. */
924
+ interface ArtubeIntegration {
925
+ /** REQUIRED. How the host reaches the bridge:
926
+ * `load: () => import('@energy8platform/artube-bridge')`.
927
+ *
928
+ * Why the GAME supplies this instead of the host importing the package itself: a bare
929
+ * `import('@energy8platform/artube-bridge')` inside this always-shipped `/host` entry is resolved
930
+ * STATICALLY by every bundler, so it would have to resolve in games that never opted into Artube
931
+ * and therefore never installed the package — esbuild/webpack fail the build outright, and Vite
932
+ * silently substitutes an empty module (it stubs uninstalled optional peers), which is worse:
933
+ * the game builds and then dies at runtime. With the loader, the specifier only ever appears in
934
+ * the bundle of a game that took the dependency.
935
+ *
936
+ * The loaded chunk is fetched on every launch of such a game (the classifier lives in it), which
937
+ * is the point of the split: only Artube-targeted builds pay for it. */
938
+ load: () => Promise<ArtubeModule>;
939
+ /** Starting virtual balance for a DEMO session (the platform doesn't keep one — the bridge does,
940
+ * client-side). Default: the backend's own configured demo balance. Ignored for real sessions. */
941
+ demoBalance?: number;
942
+ /** Origin of the game's backend. Default (and the only supported PRODUCTION value) is the launch
943
+ * URL's own origin: Artube serves frontend and backend on one domain, split by path (`/api/**`).
944
+ * Override only for local dev against a backend on another port — prefer proxying `/api` from the
945
+ * dev server (what the `BUILD_TARGET=artube` target does) so dev matches production. */
946
+ apiBase?: string;
947
+ }
874
948
  /** One scene registered with the host: a key + its constructor. The list order matters — the
875
949
  * first scene that is eligible for the current launch mode is the start scene (unless an explicit
876
950
  * `startScene` overrides it). */
@@ -915,6 +989,10 @@ interface CreateSlotGameOptions<T extends SlotSpinResultBase = SlotSpinResultBas
915
989
  textureDefaults?: boolean;
916
990
  dev?: boolean;
917
991
  stake?: StakeIntegration;
992
+ /** Run on Artube when the launch URL says so (`?sessionId=…`):
993
+ * `artube: { load: () => import('@energy8platform/artube-bridge') }`. See `ArtubeIntegration`
994
+ * for why the game supplies the loader. Build with `BUILD_TARGET=artube`. */
995
+ artube?: ArtubeIntegration;
918
996
  shell?: SlotShellOptions;
919
997
  /** Customise the bonus bar readout for games whose bonus isn't plain free spins (adventure,
920
998
  * hold-and-spin, respins). Omit for the free-spins default. See `BonusReadoutConfig`. */
@@ -937,11 +1015,13 @@ type ShellFactory = (config: PixiShellConfig) => Shell;
937
1015
  interface SlotGameHandle {
938
1016
  game: GameApplication;
939
1017
  stakeBridge: StakeBridge | null;
1018
+ /** The live Artube bridge — non-null only on a real Artube launch (`opts.artube` + `?sessionId=…`). */
1019
+ artubeBridge: ArtubeBridgeLike | null;
940
1020
  shell: Shell | null;
941
1021
  }
942
1022
 
943
1023
  /**
944
- * One-call slot bootstrap: preboot → (optional Stake bridge) → GameApplication
1024
+ * One-call slot bootstrap: preboot → (optional Stake / Artube bridge) → GameApplication
945
1025
  * → register scene → start. Collapses the per-game main.ts boilerplate.
946
1026
  *
947
1027
  * Not unit-tested: GameApplication.init() drives Pixi, which hangs in headless
@@ -1136,4 +1216,4 @@ interface SlotSceneController<T extends SlotSpinResultBase = SlotSpinResultBase>
1136
1216
  }
1137
1217
 
1138
1218
  export { buildShellConfig, createSlotGame, createWinReporter, resolveReplayBonusId, resolveStartScene, stakeForAction };
1139
- export type { AutoplaySceneState, CreateSlotGameOptions, OverlayShowOptions, RenderContext, SceneApi, SceneAudio, SceneNavData, SceneOverlay, SceneRegistration, SceneShell, ShellFactory, SlotGameHandle, SlotSceneController, SlotShellOptions, StakeIntegration, WinReportOptions, WinReporter };
1219
+ export type { ArtubeBridgeLike, ArtubeIntegration, ArtubeModule, AutoplaySceneState, CreateSlotGameOptions, OverlayShowOptions, RenderContext, SceneApi, SceneAudio, SceneNavData, SceneOverlay, SceneRegistration, SceneShell, ShellFactory, SlotGameHandle, SlotSceneController, SlotShellOptions, StakeIntegration, WinReportOptions, WinReporter };