@energy8platform/game-engine 0.23.0 → 0.25.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 (68) hide show
  1. package/dist/core.cjs.js +2 -2
  2. package/dist/core.cjs.js.map +1 -1
  3. package/dist/core.d.ts +3 -3
  4. package/dist/core.esm.js +2 -2
  5. package/dist/core.esm.js.map +1 -1
  6. package/dist/devtools.cjs.js +577 -0
  7. package/dist/devtools.cjs.js.map +1 -0
  8. package/dist/devtools.d.ts +424 -0
  9. package/dist/devtools.esm.js +565 -0
  10. package/dist/devtools.esm.js.map +1 -0
  11. package/dist/harness.cjs.js +33 -0
  12. package/dist/harness.cjs.js.map +1 -0
  13. package/dist/harness.d.ts +25 -0
  14. package/dist/harness.esm.js +30 -0
  15. package/dist/harness.esm.js.map +1 -0
  16. package/dist/host.cjs.js +35 -10
  17. package/dist/host.cjs.js.map +1 -1
  18. package/dist/host.d.ts +22 -9
  19. package/dist/host.esm.js +24 -11
  20. package/dist/host.esm.js.map +1 -1
  21. package/dist/index.cjs.js +2 -2
  22. package/dist/index.cjs.js.map +1 -1
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.esm.js +2 -2
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/reel-panel-client.cjs.js +610 -0
  27. package/dist/reel-panel-client.cjs.js.map +1 -0
  28. package/dist/reel-panel-client.d.ts +5 -0
  29. package/dist/reel-panel-client.esm.js +608 -0
  30. package/dist/reel-panel-client.esm.js.map +1 -0
  31. package/dist/shell.cjs.js +4 -4
  32. package/dist/shell.d.ts +1 -1
  33. package/dist/shell.esm.js +1 -1
  34. package/dist/slot.cjs.js +226 -75
  35. package/dist/slot.cjs.js.map +1 -1
  36. package/dist/slot.d.ts +137 -19
  37. package/dist/slot.esm.js +224 -76
  38. package/dist/slot.esm.js.map +1 -1
  39. package/package.json +17 -2
  40. package/src/core/GameApplication.ts +3 -3
  41. package/src/harness/index.ts +35 -0
  42. package/src/host/createSlotGame.ts +6 -3
  43. package/src/host/index.ts +11 -1
  44. package/src/host/shellConfig.ts +22 -12
  45. package/src/host/types.ts +13 -2
  46. package/src/shell/index.ts +4 -3
  47. package/src/slot/cascade/TumbleController.ts +6 -3
  48. package/src/slot/config/ReelSystemConfig.ts +19 -0
  49. package/src/slot/devtools/configDiff.ts +41 -0
  50. package/src/slot/devtools/controlPanel.ts +151 -0
  51. package/src/slot/devtools/fieldSchema.ts +190 -0
  52. package/src/slot/devtools/index.ts +31 -0
  53. package/src/slot/devtools/panelClient.ts +113 -0
  54. package/src/slot/devtools/protocol.ts +29 -0
  55. package/src/slot/devtools/reelDevBridge.ts +80 -0
  56. package/src/slot/features/extra.ts +1 -2
  57. package/src/slot/features/symbols.ts +10 -10
  58. package/src/slot/features/types.ts +13 -5
  59. package/src/slot/features/wilds.ts +1 -1
  60. package/src/slot/grid/AnimatedSymbol.ts +20 -11
  61. package/src/slot/grid/ReelGrid.ts +80 -41
  62. package/src/slot/grid/SymbolCell.ts +14 -7
  63. package/src/slot/grid/SymbolView.ts +2 -2
  64. package/src/slot/grid/geometry.ts +155 -0
  65. package/src/slot/index.ts +3 -0
  66. package/src/slot/motion/SpinEngine.ts +1 -1
  67. package/src/slot/system/ReelSystem.ts +10 -0
  68. package/src/types.ts +1 -1
@@ -0,0 +1,25 @@
1
+ import { HarnessPlugin } from '@energy8platform/harness';
2
+
3
+ /**
4
+ * `@energy8platform/game-engine/harness` — node-only entry.
5
+ *
6
+ * Contributes the reel-config **panel** to `@energy8platform/harness`: a docked
7
+ * right sidebar that tunes a running game's ReelSystem live. Pair it with
8
+ * `mountReelDevBridge` (from `@energy8platform/game-engine/devtools`) in the game.
9
+ *
10
+ * Usage in a game's vite.config:
11
+ * import { createHarness } from '@energy8platform/harness';
12
+ * import { reelDevtoolsPlugin } from '@energy8platform/game-engine/harness';
13
+ * createHarness({ plugins: [ reelDevtoolsPlugin() ] });
14
+ *
15
+ * Node-only: resolves the built, self-contained panel-client ESM the harness serves.
16
+ */
17
+
18
+ interface ReelDevtoolsPluginOptions {
19
+ /** Sidebar header / tab label. Default 'Reels'. */
20
+ title?: string;
21
+ }
22
+ declare function reelDevtoolsPlugin(opts?: ReelDevtoolsPluginOptions): HarnessPlugin;
23
+
24
+ export { reelDevtoolsPlugin };
25
+ export type { ReelDevtoolsPluginOptions };
@@ -0,0 +1,30 @@
1
+ import { fileURLToPath } from 'node:url';
2
+
3
+ /**
4
+ * `@energy8platform/game-engine/harness` — node-only entry.
5
+ *
6
+ * Contributes the reel-config **panel** to `@energy8platform/harness`: a docked
7
+ * right sidebar that tunes a running game's ReelSystem live. Pair it with
8
+ * `mountReelDevBridge` (from `@energy8platform/game-engine/devtools`) in the game.
9
+ *
10
+ * Usage in a game's vite.config:
11
+ * import { createHarness } from '@energy8platform/harness';
12
+ * import { reelDevtoolsPlugin } from '@energy8platform/game-engine/harness';
13
+ * createHarness({ plugins: [ reelDevtoolsPlugin() ] });
14
+ *
15
+ * Node-only: resolves the built, self-contained panel-client ESM the harness serves.
16
+ */
17
+ function reelDevtoolsPlugin(opts = {}) {
18
+ // The self-contained panel client sits next to this module in dist/.
19
+ const clientEntry = fileURLToPath(new URL('./reel-panel-client.esm.js', import.meta.url));
20
+ const panel = {
21
+ id: 'reels',
22
+ title: opts.title ?? 'Reels',
23
+ placement: 'sidebar',
24
+ clientEntry,
25
+ };
26
+ return { panel };
27
+ }
28
+
29
+ export { reelDevtoolsPlugin };
30
+ //# sourceMappingURL=harness.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.esm.js","sources":["../src/harness/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;AAaG;AAWG,SAAU,kBAAkB,CAAC,IAAA,GAAkC,EAAE,EAAA;;AAErE,IAAA,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzF,IAAA,MAAM,KAAK,GAAiB;AAC1B,QAAA,EAAE,EAAE,OAAO;AACX,QAAA,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,OAAO;AAC5B,QAAA,SAAS,EAAE,SAAS;QACpB,WAAW;KACZ;IACD,OAAO,EAAE,KAAK,EAAE;AAClB;;;;"}
package/dist/host.cjs.js CHANGED
@@ -3,7 +3,8 @@
3
3
  var pixi_js = require('pixi.js');
4
4
  var platformCore = require('@energy8platform/platform-core');
5
5
  var loading = require('@energy8platform/platform-core/loading');
6
- var shell = require('@energy8platform/platform-core/shell');
6
+ var pixi = require('@energy8platform/shell/pixi');
7
+ var shell = require('@energy8platform/shell');
7
8
 
8
9
  // ─── Scale Modes ───────────────────────────────────────────
9
10
  var ScaleMode;
@@ -1887,7 +1888,7 @@ class GameApplication extends EventEmitter {
1887
1888
  await this.initSDK();
1888
1889
  // 4b. Mount the branded game shell after the SDK handshake (optional)
1889
1890
  if (this.config.shell) {
1890
- const { createGameShell } = await import('@energy8platform/platform-core/shell');
1891
+ const { createGameShell } = await import('@energy8platform/shell/html');
1891
1892
  this.shell = createGameShell(this.config.shell);
1892
1893
  }
1893
1894
  // 5. Merge design dimensions from SDK config
@@ -1922,7 +1923,7 @@ class GameApplication extends EventEmitter {
1922
1923
  this._destroyed = true;
1923
1924
  this._running = false;
1924
1925
  if (this.shell) {
1925
- const { removeGameShell } = await import('@energy8platform/platform-core/shell');
1926
+ const { removeGameShell } = await import('@energy8platform/shell/html');
1926
1927
  await removeGameShell();
1927
1928
  this.shell = undefined;
1928
1929
  }
@@ -2369,7 +2370,7 @@ async function createSlotGame(opts) {
2369
2370
  ack: (raw) => game.platformSession.playAck(raw),
2370
2371
  });
2371
2372
  if (opts.shell) {
2372
- const { createPixiShell } = await import('@energy8platform/pixi-shell');
2373
+ const { createPixiShell } = await import('@energy8platform/shell/pixi');
2373
2374
  const { buildShellConfig } = await Promise.resolve().then(function () { return shellConfig; });
2374
2375
  const { resolveReplayBonusId } = await Promise.resolve().then(function () { return replay; });
2375
2376
  const ps = game.platformSession;
@@ -2419,7 +2420,10 @@ async function createSlotGame(opts) {
2419
2420
  // pixi-shell mounts its root onto the engine's unscaled, screen-space UI layer (above the
2420
2421
  // scaled world/scene root) so the control bar fills the real screen, not the letterboxed game.
2421
2422
  // The host adds the mount target (`app`) + parent; buildShellConfig produces everything else.
2422
- shell = createPixiShell({ ...buildShellConfig(opts.shell, opts.model, runtime), app: game.app, parent: game.uiLayer });
2423
+ const pixiShellCfg = { ...buildShellConfig(opts.shell, opts.model, runtime), app: game.app, parent: game.uiLayer };
2424
+ // The game may swap in its own shell (a custom renderer over the same core) via shellFactory;
2425
+ // default is the built-in Pixi shell. The host drives whichever it gets through the Shell contract.
2426
+ shell = (opts.shellFactory ?? createPixiShell)(pixiShellCfg);
2423
2427
  // Scope the bar to the slot scene: show only when a SlotSceneController scene is current
2424
2428
  // (hidden over the intro / non-slot scenes). Applies in BOTH base and replay modes.
2425
2429
  shell.setVisible(!!gameScene());
@@ -2771,8 +2775,9 @@ async function createSlotGame(opts) {
2771
2775
  }
2772
2776
 
2773
2777
  // packages/game-engine/src/host/shellConfig.ts
2774
- // `socialize` / `createI18n` are runtime helpers sourced from platform-core/shell;
2775
- // pixi-shell re-exports only types so we import directly from platform-core.
2778
+ // `socialize` / `createI18n` / `Lang` are renderer-agnostic helpers from the shell core
2779
+ // (@energy8platform/shell). Renderer-agnostic types (GameInfoSection/Content, PaytableRow,
2780
+ // GameMode) and the pixi-specific surface types come from the @energy8platform/shell/pixi entry.
2776
2781
  /**
2777
2782
  * Apply jurisdiction restrictions over the resolved shell features, in place. A restriction ALWAYS
2778
2783
  * wins over the author's intent (a forbidden control must stay off even if the game enabled it).
@@ -2972,13 +2977,19 @@ function sectionKey(s) {
2972
2977
  function mergeGameInfo(derived, override) {
2973
2978
  if (!override)
2974
2979
  return derived;
2980
+ // `GameInfoContent.sections` is typed with the core GameInfoSection (node?: unknown) because
2981
+ // shell/pixi re-exports GameInfoContent unchanged from core. Host-built sections never set `node`,
2982
+ // so they are structurally compatible with pixi's GameInfoSection (node?: Container). Cast once
2983
+ // here so the rest of the function works against the pixi-widened type.
2984
+ const derivedSections = (derived.sections ?? []);
2985
+ const overrideSections = (override.sections ?? []);
2975
2986
  const authorByKey = new Map();
2976
- for (const s of override.sections ?? [])
2987
+ for (const s of overrideSections)
2977
2988
  authorByKey.set(sectionKey(s), s);
2978
2989
  const out = [];
2979
2990
  const used = new Set();
2980
2991
  // Keep derived order; swap in the author's version where identities collide.
2981
- for (const s of derived.sections ?? []) {
2992
+ for (const s of derivedSections) {
2982
2993
  const k = sectionKey(s);
2983
2994
  const replacement = authorByKey.get(k);
2984
2995
  if (replacement) {
@@ -2989,7 +3000,7 @@ function mergeGameInfo(derived, override) {
2989
3000
  out.push(s);
2990
3001
  }
2991
3002
  // Append author sections whose identity wasn't in the derived set, in author order.
2992
- for (const s of override.sections ?? []) {
3003
+ for (const s of overrideSections) {
2993
3004
  const k = sectionKey(s);
2994
3005
  if (!used.has(k)) {
2995
3006
  out.push(s);
@@ -3054,6 +3065,8 @@ function buildShellConfig(opts, model, runtime) {
3054
3065
  const authored = typeof opts.gameInfo === 'function' ? opts.gameInfo(t) : opts.gameInfo;
3055
3066
  // Pass t() through to spec-derived sections so symbol names, mode titles, and descriptions are
3056
3067
  // pre-translated before they reach the shell renderer.
3068
+ // Cast to { sections?: GameInfoSection[] } (pixi-widened) so downstream map/filter calls work
3069
+ // against the pixi section union. Host-derived sections never set `node`, so the widening is safe.
3057
3070
  let gameInfo = mergeGameInfo(defaultGameInfo(model, runtime, t), authored);
3058
3071
  // The DISCLAIMER is required legal copy and must be shown VERBATIM — never socialized (its
3059
3072
  // wording is mandated, and word-swaps like "bet → play" would corrupt the legal text).
@@ -3499,6 +3512,18 @@ var autoplay = /*#__PURE__*/Object.freeze({
3499
3512
  createAutoplayLoop: createAutoplayLoop
3500
3513
  });
3501
3514
 
3515
+ Object.defineProperty(exports, "PixiRenderer", {
3516
+ enumerable: true,
3517
+ get: function () { return pixi.PixiRenderer; }
3518
+ });
3519
+ Object.defineProperty(exports, "createPixiShell", {
3520
+ enumerable: true,
3521
+ get: function () { return pixi.createPixiShell; }
3522
+ });
3523
+ Object.defineProperty(exports, "createShell", {
3524
+ enumerable: true,
3525
+ get: function () { return pixi.createShell; }
3526
+ });
3502
3527
  Object.defineProperty(exports, "socialize", {
3503
3528
  enumerable: true,
3504
3529
  get: function () { return shell.socialize; }