@energy8platform/game-engine 0.18.0 → 0.20.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.
package/dist/host.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Container, ApplicationOptions, Application, Texture } from 'pixi.js';
2
2
  import { GameModel } from '@energy8platform/platform-core/game-spec';
3
3
  import { LoadingScreenConfig, AssetManifest, PlatformSession } from '@energy8platform/platform-core';
4
+ import { CurrencyConfig, GameInfoContent, BonusOption, ShellFeatures, ShellMode, PixiShellConfig, PixiGameShell } from '@energy8platform/pixi-shell';
4
5
  import * as _energy8platform_platform_core_shell from '@energy8platform/platform-core/shell';
5
- import { CurrencyConfig, GameInfoContent, BonusOption, ShellFeatures, ShellMode, ShellConfig, GameShell } from '@energy8platform/platform-core/shell';
6
+ import { Lang } from '@energy8platform/platform-core/shell';
6
7
  export { socialize } from '@energy8platform/platform-core/shell';
7
8
  import { BookAdapter, AdapterModule, StakeBridge } from '@energy8platform/stake-bridge';
8
9
  import { CasinoGameSDK, InitData, GameConfigData, SessionData } from '@energy8platform/game-sdk';
@@ -333,6 +334,7 @@ declare class AudioManager {
333
334
  private _persist;
334
335
  private _storageKey;
335
336
  private _categories;
337
+ private _masterGain;
336
338
  private _currentMusic;
337
339
  private _unlocked;
338
340
  private _unlockHandler;
@@ -373,6 +375,10 @@ declare class AudioManager {
373
375
  * Stop all sounds.
374
376
  */
375
377
  stopAll(): void;
378
+ /** Global gain (0..1) folded into every category's effective volume. Driven by the shell's
379
+ * 'master' settingChange. Does not affect the persisted per-category volumes. */
380
+ setMasterVolume(volume: number): void;
381
+ getMasterVolume(): number;
376
382
  /**
377
383
  * Set volume for a category.
378
384
  */
@@ -575,6 +581,7 @@ declare class ViewportManager extends EventEmitter<ViewportEvents> {
575
581
  private _app;
576
582
  private _container;
577
583
  private _config;
584
+ private _target;
578
585
  private _resizeObserver;
579
586
  private _currentOrientation;
580
587
  private _currentWidth;
@@ -582,7 +589,7 @@ declare class ViewportManager extends EventEmitter<ViewportEvents> {
582
589
  private _currentScale;
583
590
  private _destroyed;
584
591
  private _resizeTimeout;
585
- constructor(app: Application, container: HTMLElement, config: ViewportConfig);
592
+ constructor(app: Application, container: HTMLElement, config: ViewportConfig, target?: Container);
586
593
  /** Current canvas width in game units */
587
594
  get width(): number;
588
595
  /** Current canvas height in game units */
@@ -683,6 +690,12 @@ declare class GameApplication extends EventEmitter<GameEngineEvents> {
683
690
  input: InputManager;
684
691
  /** Viewport manager */
685
692
  viewport: ViewportManager;
693
+ /** Scaled world root (holds scenes). Transformed by the ViewportManager to fit the design
694
+ * resolution; lives below the UI layer on app.stage. */
695
+ worldRoot: Container;
696
+ /** Unscaled, screen-space UI layer. Sits above {@link worldRoot} and is NOT touched by the
697
+ * viewport transform — children fill the real screen (e.g. the host's shell + overlay). */
698
+ uiLayer: Container;
686
699
  /** SDK instance (null in offline mode) */
687
700
  sdk: CasinoGameSDK | null;
688
701
  /** FPS overlay instance (only when debug: true) */
@@ -737,7 +750,6 @@ interface WinTier {
737
750
  }
738
751
 
739
752
  interface SlotShellOptions {
740
- mount?: HTMLElement;
741
753
  /** Override the derived currency (normally taken from initData). */
742
754
  currency?: CurrencyConfig;
743
755
  /** Author-supplied info sections, MERGED over the host-derived set by section identity (an author
@@ -754,6 +766,11 @@ interface SlotShellOptions {
754
766
  buyBonus?: BonusOption[];
755
767
  tiers?: WinTier[];
756
768
  features?: Partial<ShellFeatures>;
769
+ /** Per-game translation map. Keys are the English source strings (from the spec or copy);
770
+ * values are the translated strings for each language. Merged with the shell's built-in
771
+ * `LOCALES` catalog — game strings take precedence over the built-in entries for the same key.
772
+ * When not supplied, English source strings pass through verbatim (socialised in social mode). */
773
+ i18n?: Partial<Record<Lang, Record<string, string>>>;
757
774
  }
758
775
  /** Runtime context from the SDK handshake (initData) + the resolved mode. */
759
776
  interface ShellRuntime {
@@ -795,8 +812,9 @@ interface JurisdictionRestrictions {
795
812
  /** Total stake for an action = bet × the action's cost multiplier (1 for a base spin; e.g. 100 for
796
813
  * a buy bonus). The host uses this to block a play the balance can't cover. */
797
814
  declare function stakeForAction(model: GameModel, action: string, bet: number): number;
798
- /** Pure: assemble a ShellConfig from the model + runtime context (currency/balance/language/mode). */
799
- declare function buildShellConfig(opts: SlotShellOptions, model: GameModel, runtime: ShellRuntime): ShellConfig;
815
+ /** Pure: assemble the shell config (sans mount target) from the model + runtime context
816
+ * (currency/balance/language/mode). The host adds `app` at the call site. */
817
+ declare function buildShellConfig(opts: SlotShellOptions, model: GameModel, runtime: ShellRuntime): Omit<PixiShellConfig, 'app' | 'parent'>;
800
818
 
801
819
  interface StakeIntegration {
802
820
  /** The game's BookAdapter (or its module). modeMap + gameId come from the model. */
@@ -849,12 +867,15 @@ interface CreateSlotGameOptions<T extends SlotSpinResultBase = SlotSpinResultBas
849
867
  dev?: boolean;
850
868
  stake?: StakeIntegration;
851
869
  shell?: SlotShellOptions;
870
+ /** Double-tap on the play area to skip the current spin animation. Default `true`. Set `false`
871
+ * to disable the gesture (e.g. games where a tap means something else). */
872
+ skipGesture?: boolean;
852
873
  onFatalError?: (message: string) => void;
853
874
  }
854
875
  interface SlotGameHandle {
855
876
  game: GameApplication;
856
877
  stakeBridge: StakeBridge | null;
857
- shell: GameShell | null;
878
+ shell: PixiGameShell | null;
858
879
  }
859
880
 
860
881
  /**
@@ -882,34 +903,104 @@ declare function resolveReplayBonusId(model: GameModel, stakeMode: string): stri
882
903
  */
883
904
  declare function resolveStartScene(scenes: SceneRegistration[], isReplay: boolean, explicitStart?: string): string;
884
905
 
885
- /** Everything a scene needs to render one result. The host builds it once per round. */
906
+ /** Everything a scene needs to render one segment. The host builds it per segment. */
886
907
  interface RenderContext {
887
- /** Bet for this round (major units). Stable for the whole round (a bonus is one round). */
908
+ /** Bet for this round (major units). Stable for the whole round. */
888
909
  bet: number;
889
- /** Trigger action in the game's own vocabulary (gameSpec.actions keys): 'spin' | 'ante' |
890
- * 'buy_bonus' | … Stable for the whole round. */
910
+ /** Trigger action in the game's own vocabulary ('spin' | 'ante' | 'buy_bonus' | …). */
891
911
  action: string;
892
- /** Stake bet-mode of the round (model.spec.modeMap[action]): 'BASE' | 'ANTE' | 'BONUS' | …
893
- * Canonical per-round identifier of WHICH bonus/feature this is. Stable for the whole round. */
912
+ /** Stake bet-mode of the round ('BASE' | 'ANTE' | 'BONUS' | …). */
894
913
  mode: string;
895
- /** Currency-aware money formatter. win/totalWin get variable decimals (0.0041 stays 0.0041). */
914
+ /** Currency-aware money formatter. */
896
915
  formatAmount(value: number): string;
897
- /** LIVE turbo level (0 = off, 1..3 = escalating speed), matching the shell's state.turbo. Read at
898
- * the moment of access (getter) so a mid-round toggle is reflected. */
916
+ /** LIVE turbo level (0 = off, 1..3 = escalating speed). Read at access. */
899
917
  readonly turbo: number;
918
+ /** Aborted when the player skips this segment (double-tap). The scene's async pacing can race or
919
+ * cancel on it; on abort the scene must collapse to the segment's final visual state. */
920
+ signal: AbortSignal;
900
921
  }
901
- /** The contract a slot scene implements. The HOST owns the play→present→ack→drain loop and calls
902
- * these; the scene only renders. The game never sees play/ack/roundId. */
922
+ /** Playback-only audio handle. Volume/mute are shell settings host, never the scene. */
923
+ interface SceneAudio {
924
+ play(alias: string, opts?: {
925
+ volume?: number;
926
+ loop?: boolean;
927
+ speed?: number;
928
+ }): void;
929
+ playMusic(alias: string, fadeMs?: number): void;
930
+ stopMusic(): void;
931
+ duck(factor: number): void;
932
+ unduck(): void;
933
+ }
934
+ interface OverlayShowOptions {
935
+ /** Draw the overlay content into `container` (sized to the canvas). */
936
+ build(container: Container, size: {
937
+ width: number;
938
+ height: number;
939
+ }): void;
940
+ /** Auto-close after N ms (combine with closeOn — whichever fires first). */
941
+ autoCloseMs?: number;
942
+ /** Dismiss on a single tap. Default 'tap'. Set false to require an explicit close(). */
943
+ closeOn?: 'tap' | false;
944
+ /** Optional host-drawn backdrop alpha (0..1). Default: none (game draws its own). */
945
+ dim?: number;
946
+ }
947
+ /** Single host-owned layer above scene + shell. Eats pointer events so shell controls are
948
+ * unreachable while open. */
949
+ interface SceneOverlay {
950
+ /** Resolves when the overlay closes. Rejects if one is already open. */
951
+ show(opts: OverlayShowOptions): Promise<void>;
952
+ close(): void;
953
+ }
954
+ interface SceneShell {
955
+ /** Live insets (px). `bottom` = the shell bar height; read inside onResize. */
956
+ readonly safeArea: {
957
+ top: number;
958
+ right: number;
959
+ bottom: number;
960
+ left: number;
961
+ };
962
+ }
963
+ interface AutoplaySceneState {
964
+ running: boolean;
965
+ remaining: number;
966
+ }
967
+ /** Stable capabilities injected once via onCreate. */
968
+ interface SceneApi {
969
+ audio: SceneAudio;
970
+ overlay: SceneOverlay;
971
+ shell: SceneShell;
972
+ formatAmount(value: number): string;
973
+ readonly bet: number;
974
+ readonly mode: string;
975
+ readonly turbo: number;
976
+ }
977
+ /** The contract a slot scene implements. The HOST owns the play→present→ack→drain loop and the
978
+ * shell; the scene only renders + reacts. The core spin-lifecycle hooks are REQUIRED (implement
979
+ * them — empty bodies are fine where a game has nothing to do); the incidental reactions below
980
+ * stay optional. */
903
981
  interface SlotSceneController<T extends SlotSpinResultBase = SlotSpinResultBase> {
904
- /** Render ONE segment (a spin, or one free spin). All pacing/pauses/overlays live here
905
- * (await your own animations). The host calls this once per segment. */
906
- present(result: T, ctx: RenderContext): Promise<void>;
907
- /** Optional. Fires EXACTLY before the first free spin of a bonus (intro; spin counts in
908
- * trigger.freeSpins). */
909
- onBonusEnter?(trigger: T, ctx: RenderContext): Promise<void>;
910
- /** Optional. Fires after the last free spin of a bonus (summary; last.totalWin = bonus total). */
911
- onBonusExit?(last: T, ctx: RenderContext): Promise<void>;
982
+ /** Injected ONCE before the first round — capabilities, subscriptions, one-time setup. */
983
+ onCreate(api: SceneApi): void;
984
+ /** Fires once per round when the player presses spin (before the network result). */
985
+ onSpinStart(): void;
986
+ /** Render ONE segment (a spin or one free spin). Await your own pacing. */
987
+ onSpin(result: T, ctx: RenderContext): Promise<void>;
988
+ /** Fires when ctx.mode changes between segments (entering a non-BASE mode/bonus). */
989
+ onEnterMode(result: T, ctx: RenderContext): Promise<void>;
990
+ /** Fires when leaving a mode (back toward BASE). */
991
+ onExitMode(result: T, ctx: RenderContext): Promise<void>;
992
+ /** Fires once per round after the full drain (controls unlocked). */
993
+ onSpinEnd(result: T, ctx: RenderContext): void;
994
+ /** Shell events (may fire while idle) — optional. */
995
+ onBetChanged?(bet: number): void;
996
+ onTurboChanged?(level: number): void;
997
+ onAutoplayChanged?(state: AutoplaySceneState): void;
998
+ /** Double-tap skip during an active onSpin (gated by the skipGesture setting). */
999
+ onSkip?(): void;
1000
+ /** Tab focus lost / regained. */
1001
+ onPause?(): void;
1002
+ onResume?(): void;
912
1003
  }
913
1004
 
914
1005
  export { buildShellConfig, createSlotGame, resolveReplayBonusId, resolveStartScene, stakeForAction };
915
- export type { CreateSlotGameOptions, RenderContext, SceneEntry, SceneNavData, SceneRegistration, SlotGameHandle, SlotSceneController, SlotShellOptions, StakeIntegration };
1006
+ export type { AutoplaySceneState, CreateSlotGameOptions, OverlayShowOptions, RenderContext, SceneApi, SceneAudio, SceneEntry, SceneNavData, SceneOverlay, SceneRegistration, SceneShell, SlotGameHandle, SlotSceneController, SlotShellOptions, StakeIntegration };