@energy8platform/shell 0.6.0 → 0.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energy8platform/shell",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Energy8 branded game shell — one logic core, pluggable html/pixi renderers behind a stable contract.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -314,10 +314,17 @@ export class ShellController extends EventEmitter<ShellEvents> implements ShellH
314
314
  this.prevBalance = n;
315
315
  this.money('balance', from, n);
316
316
  }
317
- setWin(n: number): void {
317
+ /** Set the WIN readout. Counts up/down from the previous value by default. Pass
318
+ * `{ animate: false }` to SNAP instantly (renderBar cancels any in-flight count-up) — used by the
319
+ * host to clear WIN to 0 at spin start, where an animated count-DOWN would look wrong. */
320
+ setWin(n: number, opts?: { animate?: boolean }): void {
318
321
  const from = this.prevWin;
319
322
  this.state.win = n;
320
323
  this.prevWin = n;
324
+ if (opts?.animate === false) {
325
+ this.renderer.renderBar(); // instant repaint from state; cancels running money anims
326
+ return;
327
+ }
321
328
  this.money('win', from, n);
322
329
  }
323
330
  setBet(n: number): void {
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
2
2
  /** The @energy8platform/shell package version, stamped into the game-info footer. */
3
- export const PACKAGE_VERSION = '0.6.0';
3
+ export const PACKAGE_VERSION = '0.6.2';
@@ -75,6 +75,12 @@ export class PixiRenderer implements ShellRenderer {
75
75
  this.app.stage.eventMode = 'static';
76
76
 
77
77
  this.app.renderer.on('resize', this.onResize);
78
+ // Seed the layout from the CURRENT screen size. The renderer was resized to the container during
79
+ // boot (ViewportManager.refresh) BEFORE this shell mounted and subscribed above, so that initial
80
+ // 'resize' event is already gone and won't fire again on a stationary device. Without this seed
81
+ // the controller's layout stays at its 'wide' DEFAULT — a portrait mobile would show the DESKTOP
82
+ // bar. (The HTML renderer gets this for free: its ResizeObserver fires immediately on observe.)
83
+ if (this.screenW > 0) this.host.notifyResize(this.screenW, this.screenH);
78
84
  whenFontReady(() => {
79
85
  if (!this.destroyed) this.renderBar();
80
86
  });
@@ -523,7 +523,7 @@ function sectionCustom(host: PixiComponentContext, s: Extract<GameInfoSection, {
523
523
  const sec = section(host, s.title != null ? host.t(s.title) : undefined);
524
524
  const inner = width - SECTION_PAD;
525
525
  if (s.node) {
526
- sec.add(s.node as Container); // game-supplied Pixi content owns its own layout
526
+ sec.add(persistentSlot(s.node as Container)); // game-supplied Pixi content owns its own layout
527
527
  } else if (s.html) {
528
528
  const text = s.html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
529
529
  if (text) sec.add(paragraph(host, text, inner, { size: 15 }));
@@ -579,6 +579,23 @@ function spacerBox(w: number, h: number): Graphics {
579
579
  return g;
580
580
  }
581
581
 
582
+ /** Wrap a GAME-supplied custom `node` so the shell BORROWS it instead of owning it. The overlay is
583
+ * torn down with `destroy({ children: true })` on every close; that would recursively destroy the
584
+ * game's node, so the section renders blank on reopen. This slot's `destroy` DETACHES the node
585
+ * (leaving it intact) and destroys only the empty wrapper — the SAME node instance is re-mounted,
586
+ * with all its drawing, the next time Game info opens. Mirrors the HTML shell, where the game's DOM
587
+ * node simply persists in config across open/close. The game owns the node's lifetime, not us. */
588
+ function persistentSlot(node: Container): Container {
589
+ const slot = new Container();
590
+ slot.addChild(node);
591
+ const destroySelf = Container.prototype.destroy.bind(slot);
592
+ slot.destroy = () => {
593
+ if (node.parent === slot) slot.removeChild(node); // keep the game node alive for the next open
594
+ destroySelf({ children: false });
595
+ };
596
+ return slot;
597
+ }
598
+
582
599
  /** A fixed box that loads an image into it (object-fit: contain) once the texture resolves. */
583
600
  function imageBox(url: string, w: number, h: number): Container {
584
601
  const c = new Container();