@energy8platform/shell 0.2.0 → 0.2.3
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/html.cjs.js +22 -8
- package/dist/html.cjs.js.map +1 -1
- package/dist/html.d.ts +2 -2
- package/dist/html.esm.js +22 -8
- package/dist/html.esm.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +1 -1
- package/dist/pixi.cjs.js +28 -11
- package/dist/pixi.cjs.js.map +1 -1
- package/dist/pixi.d.ts +2 -2
- package/dist/pixi.esm.js +28 -11
- package/dist/pixi.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/ui/html/HtmlRenderer.ts +1 -1
- package/src/ui/html/components/GameInfo.ts +1 -1
- package/src/ui/html/components/Modal.ts +8 -4
- package/src/ui/html/components/Settings.ts +1 -1
- package/src/ui/html/shell.css.ts +11 -0
- package/src/ui/pixi/PixiRenderer.ts +4 -1
- package/src/ui/pixi/components/BuyBonus.ts +21 -10
- package/src/ui/pixi/primitives/scroll.ts +3 -0
package/dist/pixi.d.ts
CHANGED
|
@@ -473,7 +473,7 @@ declare class ShellController extends EventEmitter<ShellEvents> implements Shell
|
|
|
473
473
|
tokens: ShellTokens;
|
|
474
474
|
layout: ShellLayoutMode;
|
|
475
475
|
soundOn: boolean;
|
|
476
|
-
readonly engineVersion = "0.2.
|
|
476
|
+
readonly engineVersion = "0.2.3";
|
|
477
477
|
readonly actions: ShellActions;
|
|
478
478
|
private renderer;
|
|
479
479
|
private i18n;
|
|
@@ -539,7 +539,7 @@ interface I18n {
|
|
|
539
539
|
declare function createI18n(opts: I18nOptions): I18n;
|
|
540
540
|
|
|
541
541
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
542
|
-
declare const PACKAGE_VERSION = "0.2.
|
|
542
|
+
declare const PACKAGE_VERSION = "0.2.3";
|
|
543
543
|
|
|
544
544
|
/** A shell: the renderer-agnostic controller plus the surface facade (safeArea/barHeight/setVisible)
|
|
545
545
|
* an embedding host reads. `createShell`, `createGameShell` and `createPixiShell` all return this. */
|
package/dist/pixi.esm.js
CHANGED
|
@@ -1352,7 +1352,7 @@ class KeyboardController {
|
|
|
1352
1352
|
|
|
1353
1353
|
// AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
|
|
1354
1354
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
1355
|
-
const PACKAGE_VERSION = '0.2.
|
|
1355
|
+
const PACKAGE_VERSION = '0.2.3';
|
|
1356
1356
|
|
|
1357
1357
|
/** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
|
|
1358
1358
|
function resolveConfig(config) {
|
|
@@ -3309,6 +3309,10 @@ class ScrollBox extends Container {
|
|
|
3309
3309
|
this.setScroll(this.scrollY + dy);
|
|
3310
3310
|
}
|
|
3311
3311
|
setScroll(y) {
|
|
3312
|
+
// Ignore late scrolls after teardown: a queued keydown (or resize) can route here once the modal
|
|
3313
|
+
// has been destroyed, and writing to a torn-down content Container throws (use-after-destroy).
|
|
3314
|
+
if (this.destroyed || !this.content || this.content.destroyed)
|
|
3315
|
+
return;
|
|
3312
3316
|
this.scrollY = Math.max(0, Math.min(this.maxScroll, y)) || 0; // || 0 converts -0 to 0
|
|
3313
3317
|
this.content.y = this.scrollY === 0 ? 0 : -this.scrollY;
|
|
3314
3318
|
}
|
|
@@ -4269,6 +4273,10 @@ function imageBox(url, w, h) {
|
|
|
4269
4273
|
return c;
|
|
4270
4274
|
}
|
|
4271
4275
|
|
|
4276
|
+
/** Below this frame height (px), a wide/landscape popout (e.g. Popout S 400×225) stacks its cards
|
|
4277
|
+
* vertically and scrolls — like mobile — so descriptions stay readable instead of shrinking to a
|
|
4278
|
+
* ~4px floor. Wide + taller frames (Popout L and up) keep the centred horizontal row. */
|
|
4279
|
+
const SHORT_STACK_H = 340;
|
|
4272
4280
|
/** Buy-bonus overlay — art-forward cards (one per option), a live bet footer, and a confirm modal.
|
|
4273
4281
|
* Returns null when there are no bonus options. */
|
|
4274
4282
|
function openBuyBonus(host) {
|
|
@@ -4298,6 +4306,8 @@ class BuyBonusOverlay extends Container {
|
|
|
4298
4306
|
cardEntries = [];
|
|
4299
4307
|
/** Keyboard focus index into the affordable subset of cardEntries. -1 = none. */
|
|
4300
4308
|
focusIndex = -1;
|
|
4309
|
+
/** true when cards are stacked vertically (mobile, or a short landscape popout). */
|
|
4310
|
+
stack = false;
|
|
4301
4311
|
// Drag-scroll state. The drag is handled on the (unmasked) overlay, not the masked strip — a mask
|
|
4302
4312
|
// prunes pointer events outside its band, stalling globalpointermove mid-drag so later cards never
|
|
4303
4313
|
// scroll into reach. The overlay sees the whole screen, so the scroll runs the full range.
|
|
@@ -4407,7 +4417,10 @@ class BuyBonusOverlay extends Container {
|
|
|
4407
4417
|
}
|
|
4408
4418
|
buildCards() {
|
|
4409
4419
|
this.strip.removeChildren().forEach((c) => c.destroy({ children: true }));
|
|
4410
|
-
|
|
4420
|
+
// Stack (readable vertical list + scroll) on mobile OR on a short landscape popout; a shrink-to-fit
|
|
4421
|
+
// horizontal row on wide + tall frames. See SHORT_STACK_H.
|
|
4422
|
+
const stack = this.host.layout === 'mobile' || this.h <= SHORT_STACK_H;
|
|
4423
|
+
this.stack = stack;
|
|
4411
4424
|
const top = this.headerH + 6;
|
|
4412
4425
|
const areaH = this.h - top - this.footerH - 6;
|
|
4413
4426
|
const gap = 14;
|
|
@@ -4418,12 +4431,12 @@ class BuyBonusOverlay extends Container {
|
|
|
4418
4431
|
// N cards (+ gaps + 24px side margins) fit the frame width. min() of the two = the binding fit.
|
|
4419
4432
|
// Floor 4 is a last-resort so a 400×225 popout still shows the CTA (then X-drag scrolls the slack).
|
|
4420
4433
|
const emH = 3.4 * (areaH / 100);
|
|
4421
|
-
const emW =
|
|
4434
|
+
const emW = stack
|
|
4422
4435
|
? (this.w - 48) / 18 // vertical stack: a single card spans the width
|
|
4423
4436
|
: (this.w - 48 - (n - 1) * gap) / (18 * n); // row: N cards + gaps fit the frame width
|
|
4424
|
-
const em =
|
|
4437
|
+
const em = stack ? Math.min(12, emW) : clamp(4, Math.min(emH, emW), 12);
|
|
4425
4438
|
const cardW = Math.min(18 * em, this.w - 48);
|
|
4426
|
-
const cards = this.bonuses.map((b) => this.buildCard(b, cardW, em,
|
|
4439
|
+
const cards = this.bonuses.map((b) => this.buildCard(b, cardW, em, stack, areaH));
|
|
4427
4440
|
const cardH = Math.max(...cards.map((c) => c.height));
|
|
4428
4441
|
for (const c of cards)
|
|
4429
4442
|
c.setHeight(cardH);
|
|
@@ -4446,7 +4459,7 @@ class BuyBonusOverlay extends Container {
|
|
|
4446
4459
|
this.focusIndex = -1;
|
|
4447
4460
|
}
|
|
4448
4461
|
this.stripMask.clear();
|
|
4449
|
-
if (
|
|
4462
|
+
if (stack) {
|
|
4450
4463
|
// vertical stack — scroll vertically if it overflows (simple drag)
|
|
4451
4464
|
let y = 0;
|
|
4452
4465
|
const colX = (this.w - cardW) / 2;
|
|
@@ -4473,7 +4486,7 @@ class BuyBonusOverlay extends Container {
|
|
|
4473
4486
|
}
|
|
4474
4487
|
}
|
|
4475
4488
|
// ── one card ──────────────────────────────────────────────────────────────
|
|
4476
|
-
buildCard(bonus, cardW, em,
|
|
4489
|
+
buildCard(bonus, cardW, em, stack, areaH) {
|
|
4477
4490
|
const accent = effectiveAccent(bonus);
|
|
4478
4491
|
const ink = contrastText(accent);
|
|
4479
4492
|
const price = bonus.priceMultiplier * this.host.state.bet;
|
|
@@ -4675,7 +4688,8 @@ class BuyBonusOverlay extends Container {
|
|
|
4675
4688
|
* Browse phase: arrows move focus; +/- step bet; Enter/Space opens confirm; Escape closes.
|
|
4676
4689
|
* Confirm phase: Enter/Space buys/activates; Escape returns to browse. */
|
|
4677
4690
|
onKey(e) {
|
|
4678
|
-
|
|
4691
|
+
// Vertical stack (mobile / short popout) → Up/Down navigate; horizontal row → Left/Right.
|
|
4692
|
+
const stack = this.stack;
|
|
4679
4693
|
if (this.confirm && this.confirmBonus) {
|
|
4680
4694
|
// ── Confirm phase ──
|
|
4681
4695
|
switch (e.code) {
|
|
@@ -4709,8 +4723,8 @@ class BuyBonusOverlay extends Container {
|
|
|
4709
4723
|
return true;
|
|
4710
4724
|
}
|
|
4711
4725
|
// Determine navigation direction from key code + layout
|
|
4712
|
-
const fwdKey = e.code === 'ArrowRight' || (
|
|
4713
|
-
const bwdKey = e.code === 'ArrowLeft' || (
|
|
4726
|
+
const fwdKey = e.code === 'ArrowRight' || (stack && e.code === 'ArrowDown');
|
|
4727
|
+
const bwdKey = e.code === 'ArrowLeft' || (stack && e.code === 'ArrowUp');
|
|
4714
4728
|
if (fwdKey) {
|
|
4715
4729
|
if (last < 0)
|
|
4716
4730
|
return true;
|
|
@@ -5692,7 +5706,10 @@ class PixiRenderer {
|
|
|
5692
5706
|
get screenH() { return self.app.screen.height; },
|
|
5693
5707
|
render: () => self.renderBar(),
|
|
5694
5708
|
pushLayer: (node) => self.pushLayer(node),
|
|
5695
|
-
|
|
5709
|
+
// Route component-initiated closes through the controller (not straight to self.closeLayer) so
|
|
5710
|
+
// it clears its OverlayHandle. Otherwise the handle goes stale: hasOpenLayer() stays true and
|
|
5711
|
+
// keydowns keep routing to onKey on a destroyed overlay → write to a torn-down ScrollBox.
|
|
5712
|
+
closeLayer: () => host.actions.closeOverlay(),
|
|
5696
5713
|
fitModals: () => self.fitModals(),
|
|
5697
5714
|
fmt: (n) => host.formatCurrency(n),
|
|
5698
5715
|
fmtWin: (n) => host.formatCurrency(n, true),
|