@open-slot-ui/pixi 0.6.0 → 0.7.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/index.cjs +76 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +76 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -610,6 +610,19 @@ declare class DialogView extends ControlView {
|
|
|
610
610
|
dispose(): void;
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
/** The round facts shown at the start of a replay (Stake "Replay Support"). */
|
|
614
|
+
interface ReplayInfo {
|
|
615
|
+
/** The base bet (before the mode's cost multiplier). */
|
|
616
|
+
baseBet: number;
|
|
617
|
+
/** The mode's cost multiplier (×), e.g. a 185× bonus buy. */
|
|
618
|
+
costMultiplier: number;
|
|
619
|
+
/** The round's payout multiplier (× the base bet). */
|
|
620
|
+
payoutMultiplier: number;
|
|
621
|
+
/** The final amount the round paid. */
|
|
622
|
+
amount: number;
|
|
623
|
+
/** Currency for the money values (defaults to the balance currency). */
|
|
624
|
+
currency?: CurrencySpec;
|
|
625
|
+
}
|
|
613
626
|
interface HudOptions extends OpenUIPixiOptions {
|
|
614
627
|
hooks?: HostHooks;
|
|
615
628
|
}
|
|
@@ -655,6 +668,14 @@ interface BootedHud {
|
|
|
655
668
|
setFreeSpins(n: number): void;
|
|
656
669
|
/** Enter/leave replay mode (Stake `replay=true`) — locks the HUD + shows a REPLAY badge. */
|
|
657
670
|
setReplay(on: boolean): void;
|
|
671
|
+
/** Replay support (Stake "Replay Support"): at the START of a replay show the round's
|
|
672
|
+
* Base Bet, its Cost + Payout multipliers and the final amount in an open-ui panel;
|
|
673
|
+
* `onPlay` begins the playback. Labels are social-aware (Base Bet → Base Play, etc.);
|
|
674
|
+
* amounts format with `info.currency` (defaults to the balance currency). Also flips
|
|
675
|
+
* the HUD into replay mode (badge + lock). */
|
|
676
|
+
replayStart(info: ReplayInfo, onPlay?: () => void): void;
|
|
677
|
+
/** At the END of a replay, show a "Replay" button (open-ui styled) that re-runs it. */
|
|
678
|
+
replayEnd(onReplay: () => void): void;
|
|
658
679
|
/** Show a buy-feature confirm modal (Cancel / Confirm). Texts are literal-or-key. */
|
|
659
680
|
confirmBuy(opts: {
|
|
660
681
|
title?: string;
|
|
@@ -700,6 +721,20 @@ interface BootedHud {
|
|
|
700
721
|
*/
|
|
701
722
|
declare function mountHud(app: Application, spec?: UISpec, opts?: HudOptions): BootedHud;
|
|
702
723
|
|
|
724
|
+
interface BootErrorOptions {
|
|
725
|
+
title?: string;
|
|
726
|
+
message?: string;
|
|
727
|
+
/** Small technical detail for support (e.g. the RGS status line). */
|
|
728
|
+
detail?: string;
|
|
729
|
+
reloadLabel?: string;
|
|
730
|
+
/** Reload handler (default: `window.location.reload()`). Pass `null` for no button. */
|
|
731
|
+
onReload?: (() => void) | null;
|
|
732
|
+
}
|
|
733
|
+
/** Show the open-ui-themed blocking boot error. Idempotent (replaces its content). */
|
|
734
|
+
declare function showBootError(opts?: BootErrorOptions): void;
|
|
735
|
+
/** Remove the boot error screen (e.g. after a successful retry). */
|
|
736
|
+
declare function hideBootError(): void;
|
|
737
|
+
|
|
703
738
|
interface TextCellRendererOptions {
|
|
704
739
|
style: TextStyleOptions;
|
|
705
740
|
digitWidth: number;
|
|
@@ -768,4 +803,4 @@ declare class Tweener {
|
|
|
768
803
|
/** Treat touch devices as non-desktop so we don't fire phantom hover states. */
|
|
769
804
|
declare function isDesktop(): boolean;
|
|
770
805
|
|
|
771
|
-
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, isDesktop, mountHud, svgSpinSkin };
|
|
806
|
+
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountHud, showBootError, svgSpinSkin };
|
package/dist/index.d.ts
CHANGED
|
@@ -610,6 +610,19 @@ declare class DialogView extends ControlView {
|
|
|
610
610
|
dispose(): void;
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
/** The round facts shown at the start of a replay (Stake "Replay Support"). */
|
|
614
|
+
interface ReplayInfo {
|
|
615
|
+
/** The base bet (before the mode's cost multiplier). */
|
|
616
|
+
baseBet: number;
|
|
617
|
+
/** The mode's cost multiplier (×), e.g. a 185× bonus buy. */
|
|
618
|
+
costMultiplier: number;
|
|
619
|
+
/** The round's payout multiplier (× the base bet). */
|
|
620
|
+
payoutMultiplier: number;
|
|
621
|
+
/** The final amount the round paid. */
|
|
622
|
+
amount: number;
|
|
623
|
+
/** Currency for the money values (defaults to the balance currency). */
|
|
624
|
+
currency?: CurrencySpec;
|
|
625
|
+
}
|
|
613
626
|
interface HudOptions extends OpenUIPixiOptions {
|
|
614
627
|
hooks?: HostHooks;
|
|
615
628
|
}
|
|
@@ -655,6 +668,14 @@ interface BootedHud {
|
|
|
655
668
|
setFreeSpins(n: number): void;
|
|
656
669
|
/** Enter/leave replay mode (Stake `replay=true`) — locks the HUD + shows a REPLAY badge. */
|
|
657
670
|
setReplay(on: boolean): void;
|
|
671
|
+
/** Replay support (Stake "Replay Support"): at the START of a replay show the round's
|
|
672
|
+
* Base Bet, its Cost + Payout multipliers and the final amount in an open-ui panel;
|
|
673
|
+
* `onPlay` begins the playback. Labels are social-aware (Base Bet → Base Play, etc.);
|
|
674
|
+
* amounts format with `info.currency` (defaults to the balance currency). Also flips
|
|
675
|
+
* the HUD into replay mode (badge + lock). */
|
|
676
|
+
replayStart(info: ReplayInfo, onPlay?: () => void): void;
|
|
677
|
+
/** At the END of a replay, show a "Replay" button (open-ui styled) that re-runs it. */
|
|
678
|
+
replayEnd(onReplay: () => void): void;
|
|
658
679
|
/** Show a buy-feature confirm modal (Cancel / Confirm). Texts are literal-or-key. */
|
|
659
680
|
confirmBuy(opts: {
|
|
660
681
|
title?: string;
|
|
@@ -700,6 +721,20 @@ interface BootedHud {
|
|
|
700
721
|
*/
|
|
701
722
|
declare function mountHud(app: Application, spec?: UISpec, opts?: HudOptions): BootedHud;
|
|
702
723
|
|
|
724
|
+
interface BootErrorOptions {
|
|
725
|
+
title?: string;
|
|
726
|
+
message?: string;
|
|
727
|
+
/** Small technical detail for support (e.g. the RGS status line). */
|
|
728
|
+
detail?: string;
|
|
729
|
+
reloadLabel?: string;
|
|
730
|
+
/** Reload handler (default: `window.location.reload()`). Pass `null` for no button. */
|
|
731
|
+
onReload?: (() => void) | null;
|
|
732
|
+
}
|
|
733
|
+
/** Show the open-ui-themed blocking boot error. Idempotent (replaces its content). */
|
|
734
|
+
declare function showBootError(opts?: BootErrorOptions): void;
|
|
735
|
+
/** Remove the boot error screen (e.g. after a successful retry). */
|
|
736
|
+
declare function hideBootError(): void;
|
|
737
|
+
|
|
703
738
|
interface TextCellRendererOptions {
|
|
704
739
|
style: TextStyleOptions;
|
|
705
740
|
digitWidth: number;
|
|
@@ -768,4 +803,4 @@ declare class Tweener {
|
|
|
768
803
|
/** Treat touch devices as non-desktop so we don't fire phantom hover states. */
|
|
769
804
|
declare function isDesktop(): boolean;
|
|
770
805
|
|
|
771
|
-
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, isDesktop, mountHud, svgSpinSkin };
|
|
806
|
+
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountHud, showBootError, svgSpinSkin };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ControlView, ButtonView, SliderView, buildBlockColumn, OpenUIPixi } from './chunk-PYXZIGXG.js';
|
|
2
2
|
export { AutoplayDrawerView, AutoplayView, ButtonView, ControlView, DialogView, MenuView, OpenUIPixi, ReadoutView, SelectView, SliderView, SpinView, StepperView, TextCellRenderer, ToggleView, TurboView, Tweener, ValueDisplayView, buildBlockColumn, defaultSpinSkin, drawSpin, isDesktop, svgSpinSkin } from './chunk-PYXZIGXG.js';
|
|
3
3
|
import { Text, Graphics, Container, Rectangle } from 'pixi.js';
|
|
4
|
-
import { createUI, composeMenu, buildPanel } from '@open-slot-ui/core';
|
|
4
|
+
import { createUI, composeMenu, buildPanel, formatAmount } from '@open-slot-ui/core';
|
|
5
5
|
|
|
6
6
|
var RISE = 26;
|
|
7
7
|
var STAGGER = 38;
|
|
@@ -341,6 +341,33 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
341
341
|
setSocial: (on2, coin) => ui.setSocial(on2, coin),
|
|
342
342
|
setFreeSpins: (n) => ui.spin.setFreeSpins(n),
|
|
343
343
|
setReplay: (on2) => ui.setReplay(on2),
|
|
344
|
+
replayStart: (info, onPlay) => {
|
|
345
|
+
ui.setReplay(true);
|
|
346
|
+
const cur = info.currency ?? ui.balance.currency.get();
|
|
347
|
+
const money = (n) => formatAmount(n, cur);
|
|
348
|
+
ui.showNotice(
|
|
349
|
+
[
|
|
350
|
+
{ kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
|
|
351
|
+
{
|
|
352
|
+
kind: "stat-grid",
|
|
353
|
+
id: "openui-replay-g",
|
|
354
|
+
items: [
|
|
355
|
+
{ label: "openui.replay.baseBet", value: money(info.baseBet) },
|
|
356
|
+
{ label: "openui.replay.costMultiplier", value: `${info.costMultiplier}\xD7` },
|
|
357
|
+
{ label: "openui.replay.payoutMultiplier", value: `${info.payoutMultiplier}\xD7` },
|
|
358
|
+
{ label: "openui.replay.amount", value: money(info.amount) }
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
[{ label: "openui.replay.play", variant: "primary", onSelect: onPlay }]
|
|
363
|
+
);
|
|
364
|
+
},
|
|
365
|
+
replayEnd: (onReplay) => {
|
|
366
|
+
ui.showNotice(
|
|
367
|
+
[{ kind: "heading", id: "openui-replay-end", text: "openui.replay.title" }],
|
|
368
|
+
[{ label: "openui.replay.again", variant: "primary", onSelect: onReplay }]
|
|
369
|
+
);
|
|
370
|
+
},
|
|
344
371
|
confirmBuy: (o) => {
|
|
345
372
|
if (ui.isDisabled("buyFeature")) return;
|
|
346
373
|
ui.showNotice(
|
|
@@ -386,6 +413,53 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
386
413
|
};
|
|
387
414
|
}
|
|
388
415
|
|
|
389
|
-
|
|
416
|
+
// src/bootError.ts
|
|
417
|
+
var host = null;
|
|
418
|
+
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
419
|
+
function showBootError(opts = {}) {
|
|
420
|
+
const title = opts.title ?? "Connection lost";
|
|
421
|
+
const message = opts.message ?? "The game could not reach the game server. Please reload to reconnect and continue.";
|
|
422
|
+
const showReload = opts.onReload !== null;
|
|
423
|
+
host ??= document.createElement("div");
|
|
424
|
+
host.className = "openui-boot-error";
|
|
425
|
+
host.setAttribute("role", "alertdialog");
|
|
426
|
+
host.setAttribute("aria-modal", "true");
|
|
427
|
+
host.innerHTML = `
|
|
428
|
+
<div class="openui-be-card">
|
|
429
|
+
<div class="openui-be-icon" aria-hidden="true">
|
|
430
|
+
<svg viewBox="0 0 48 48" width="48" height="48"><path d="M24 4 3 42h42L24 4Z" fill="none" stroke="#ffc935" stroke-width="3" stroke-linejoin="round"/><rect x="22" y="18" width="4" height="12" rx="2" fill="#ffc935"/><circle cx="24" cy="35" r="2.4" fill="#ffc935"/></svg>
|
|
431
|
+
</div>
|
|
432
|
+
<h1 class="openui-be-title">${esc(title)}</h1>
|
|
433
|
+
<p class="openui-be-msg">${esc(message)}</p>
|
|
434
|
+
${opts.detail ? `<p class="openui-be-detail">${esc(opts.detail)}</p>` : ""}
|
|
435
|
+
${showReload ? `<button class="openui-be-reload" type="button">${esc(opts.reloadLabel ?? "Reload")}</button>` : ""}
|
|
436
|
+
</div>
|
|
437
|
+
<style>
|
|
438
|
+
.openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;
|
|
439
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: #e9edf2;
|
|
440
|
+
background: rgba(6,8,11,.92); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
|
|
441
|
+
.openui-be-card { width: min(90%, 440px); text-align: center; padding: 38px 32px 34px;
|
|
442
|
+
background: #161b22; border: 1.5px solid #ffc935; border-radius: 16px; box-shadow: 0 30px 80px rgba(0,0,0,.6); }
|
|
443
|
+
.openui-be-icon { margin-bottom: 14px; line-height: 0; }
|
|
444
|
+
.openui-be-title { margin: 0 0 12px; font-size: 24px; font-weight: 800; color: #ffc935; letter-spacing: .3px; }
|
|
445
|
+
.openui-be-msg { margin: 0 0 20px; font-size: 15px; line-height: 1.55; color: #c4ccd6; }
|
|
446
|
+
.openui-be-detail { margin: 0 0 20px; font-size: 12px; line-height: 1.4; color: #78828f; word-break: break-word; }
|
|
447
|
+
.openui-be-reload { appearance: none; border: 0; cursor: pointer; padding: 13px 42px; border-radius: 999px;
|
|
448
|
+
background: #ffc935; color: #161b22; font-weight: 800; font-size: 15px; letter-spacing: .3px;
|
|
449
|
+
box-shadow: 0 8px 22px rgba(255,201,53,.32); transition: transform .12s, filter .12s; }
|
|
450
|
+
.openui-be-reload:hover { filter: brightness(1.06); }
|
|
451
|
+
.openui-be-reload:active { transform: scale(.96); }
|
|
452
|
+
</style>`;
|
|
453
|
+
if (showReload) {
|
|
454
|
+
host.querySelector(".openui-be-reload")?.addEventListener("click", () => (opts.onReload ?? (() => window.location.reload()))());
|
|
455
|
+
}
|
|
456
|
+
if (!host.isConnected) document.body.appendChild(host);
|
|
457
|
+
}
|
|
458
|
+
function hideBootError() {
|
|
459
|
+
host?.remove();
|
|
460
|
+
host = null;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export { PanelBodyView, PanelView, PopoverView, hideBootError, mountHud, showBootError };
|
|
390
464
|
//# sourceMappingURL=index.js.map
|
|
391
465
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/views/PopoverView.ts","../src/views/PanelView.ts","../src/views/PanelBodyView.ts","../src/mountHud.ts"],"names":["Graphics","Container","opts","on"],"mappings":"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","file":"index.js","sourcesContent":["import { type Ticker, type Texture } from 'pixi.js';\nimport { type PanelControl, type SliderControl, type ButtonControl, type OpenUI } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { SliderView } from './SliderView';\nimport { ButtonView } from './ButtonView';\n\nexport interface PopoverParts {\n music: SliderControl;\n sfx: SliderControl;\n rules: ButtonControl;\n}\n\nexport interface PopoverArt {\n rulesTexture?: Texture;\n musicTrack?: Texture;\n soundTrack?: Texture;\n}\n\ninterface FanItem {\n view: ControlView;\n tx: number;\n ty: number;\n prog: number;\n}\n\nconst GAP = 80; // vertical spacing between fanned items (ref px)\nconst RISE = 26; // how far each item rises into place\nconst STAGGER = 38; // ms between pops — snappy \"pop-pop-pop\"\n// slider track is 290x60 @ ~0.9 → its visual centre, used as the scale pivot\nconst SLIDER_PIVOT_X = 130;\nconst SLIDER_PIVOT_Y = 27;\n\n/**\n * The settings flyout as a VERTICAL FAN: on open, the options swoosh up and pop\n * in one-by-one (bottom→top); on close they retract together. Items are\n * right-aligned and rise above the (right-side) menu button. No static panel.\n */\nexport class PopoverView extends ControlView {\n private readonly music: SliderView;\n private readonly sfx: SliderView;\n private readonly rules: ButtonView;\n private readonly items: FanItem[];\n private phase = 0;\n private running = false;\n private readonly tick: (t: Ticker) => void;\n\n constructor(private readonly panel: PanelControl, parts: PopoverParts, ui: OpenUI, private readonly ticker: Ticker, art: PopoverArt = {}) {\n super(panel, ui);\n\n this.rules = new ButtonView(parts.rules, ui, ticker, { shape: 'pill', height: 50, iconTexture: art.rulesTexture, iconTarget: 50 });\n this.music = new SliderView(parts.music, ui, art.musicTrack);\n this.sfx = new SliderView(parts.sfx, ui, art.soundTrack);\n // pivot sliders at their centre so they scale from the middle, not the left edge\n this.music.pivot.set(SLIDER_PIVOT_X, SLIDER_PIVOT_Y);\n this.sfx.pivot.set(SLIDER_PIVOT_X, SLIDER_PIVOT_Y);\n\n // Right-aligned column rising above the button; pop order = bottom → top.\n // tx/ty are the item CENTRES (rules ButtonView is already centre-origin).\n this.items = [\n { view: this.sfx, tx: -130, ty: -GAP, prog: 0 },\n { view: this.music, tx: -130, ty: -GAP * 2, prog: 0 },\n { view: this.rules, tx: -132, ty: -GAP * 3, prog: 0 },\n ];\n for (const it of this.items) {\n it.view.position.set(it.tx, it.ty);\n it.view.scale.set(0);\n it.view.alpha = 0;\n it.view.visible = false;\n this.addChild(it.view);\n }\n\n this.tick = (t) => this.update(t.deltaMS);\n this.applyState();\n this.disposers.push(this.panel.state.subscribe(() => this.applyState()));\n }\n\n private applyState(): void {\n this.phase = 0;\n const open = this.panel.isOpen;\n this.eventMode = open ? 'auto' : 'none';\n if (open) for (const it of this.items) it.view.visible = true;\n if (!this.running) {\n this.running = true;\n this.ticker.add(this.tick);\n }\n }\n\n private update(dt: number): void {\n this.phase += Math.min(dt, 40); // cap stalls so the stagger never gets skipped\n const open = this.panel.isOpen;\n const finalTarget = open ? 1 : 0;\n let settled = true;\n for (let i = 0; i < this.items.length; i++) {\n const it = this.items[i]!;\n const target = open && this.phase > i * STAGGER ? 1 : 0; // staggered easing target\n it.prog += (target - it.prog) * Math.min(1, dt / (open ? 50 : 80));\n const s = it.prog;\n it.view.scale.set(s);\n it.view.alpha = Math.min(1, s * 1.5);\n it.view.position.set(it.tx, it.ty + (1 - s) * RISE);\n it.view.visible = s > 0.01;\n // settle against the FINAL target so the loop keeps running until every item arrives\n if (Math.abs(it.prog - finalTarget) > 0.01) settled = false;\n }\n if (settled) {\n this.running = false;\n this.ticker.remove(this.tick);\n }\n }\n\n override dispose(): void {\n if (this.running) {\n this.ticker.remove(this.tick);\n this.running = false;\n }\n this.music.dispose();\n this.sfx.dispose();\n this.rules.dispose();\n super.dispose();\n }\n}\n","import { Container, Graphics, Text, Rectangle, type Texture, type FederatedPointerEvent, type Ticker } from 'pixi.js';\nimport { type PanelControl, type ButtonControl, type OpenUI, type ScreenState, type Theme } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { ButtonView } from './ButtonView';\n\nexport type InfoContentBuilder = (theme: Theme, width: number) => Container;\n\nexport interface PanelViewOptions {\n closeTexture?: Texture;\n content?: InfoContentBuilder;\n}\n\n// The modal is an intentionally LIGHT surface (per the design), distinct from the dark HUD theme.\nconst INK = 0x15171c;\nconst CARD = 0xffffff;\nconst HEADER_BG = 0x20242b;\nconst PAD = 16;\nconst HEADER_H = 56;\nconst MAX_W = 600;\n\n/**\n * Full-screen modal: dim backdrop + dark header (title + ✕ close) + a white,\n * scrollable content card. Content is built dynamically (so it scrolls and is\n * data-driven). Faithful to the provided Mobile Rules design.\n */\nexport class PanelView extends ControlView {\n private readonly backdrop = new Graphics();\n private readonly card = new Graphics();\n private readonly headerBg = new Graphics();\n private readonly title: Text;\n private readonly viewport = new Container();\n private readonly maskG = new Graphics();\n private readonly catcher = new Graphics();\n private readonly close: ButtonView;\n private content: Container | undefined;\n private builtWidth = -1;\n private scrollY = 0;\n private contentH = 0;\n private viewportH = 0;\n private dragging = false;\n private lastY = 0;\n private wheelHandler: ((e: WheelEvent) => void) | undefined;\n\n constructor(\n private readonly panel: PanelControl,\n closeBtn: ButtonControl,\n ui: OpenUI,\n ticker: Ticker,\n private readonly opts: PanelViewOptions = {},\n ) {\n super(panel, ui);\n this.zIndex = 100;\n\n this.backdrop.eventMode = 'static';\n this.backdrop.on('pointertap', () => this.panel.closePanel());\n\n this.title = new Text({\n text: panel.title ?? '',\n style: { fontFamily: ui.theme.type.family, fontSize: 22, fill: 0xffffff, fontWeight: '800', letterSpacing: 1 },\n });\n this.title.anchor.set(0.5);\n\n this.viewport.mask = this.maskG;\n this.catcher.eventMode = 'static';\n this.catcher.on('pointerdown', this.onDown);\n this.catcher.on('globalpointermove', this.onMove);\n this.catcher.on('pointerup', this.onUp);\n this.catcher.on('pointerupoutside', this.onUp);\n\n this.close = new ButtonView(closeBtn, ui, ticker, { iconTexture: opts.closeTexture, iconTarget: 44, glyph: 'close', radius: 24 });\n\n this.addChild(this.backdrop, this.card, this.viewport, this.maskG, this.catcher, this.headerBg, this.title, this.close);\n\n this.applyOpen(this.panel.isOpen);\n this.disposers.push(this.panel.state.subscribe(() => this.applyOpen(this.panel.isOpen)));\n }\n\n override applyLayout(screen: ScreenState): void {\n const W = screen.width;\n const H = screen.height;\n this.position.set(0, 0);\n this.scale.set(1);\n\n this.backdrop.clear().rect(0, 0, W, H).fill({ color: 0x000000, alpha: 0.6 });\n this.backdrop.hitArea = new Rectangle(0, 0, W, H);\n\n const cardW = Math.min(W - PAD * 2, MAX_W);\n const cx = (W - cardW) / 2;\n const hy = PAD;\n this.headerBg.clear().roundRect(cx, hy, cardW, HEADER_H, HEADER_H / 2).fill({ color: HEADER_BG });\n this.title.position.set(W / 2, hy + HEADER_H / 2);\n this.close.position.set(cx + cardW - HEADER_H / 2, hy + HEADER_H / 2);\n\n const cardY = hy + HEADER_H + 12;\n const cardH = H - cardY - PAD;\n this.card.clear().roundRect(cx, cardY, cardW, cardH, 22).fill({ color: CARD });\n\n const inset = 20;\n const vpX = cx + inset;\n const vpY = cardY + inset;\n const vpW = cardW - inset * 2;\n const vpH = cardH - inset * 2;\n this.viewport.position.set(vpX, vpY);\n this.viewportH = vpH;\n this.maskG.clear().rect(vpX, vpY, vpW, vpH).fill({ color: 0xffffff });\n this.catcher.clear().rect(vpX, vpY, vpW, vpH).fill({ color: 0xffffff, alpha: 0.0001 });\n\n // (re)build content to the current viewport width\n if (Math.abs(vpW - this.builtWidth) > 1) {\n this.content?.destroy({ children: true });\n this.content = this.opts.content?.(this.ui.theme, vpW) ?? this.fallback(vpW);\n this.viewport.addChild(this.content);\n this.builtWidth = vpW;\n }\n if (this.content) this.content.x = 0;\n this.contentH = this.content?.height ?? 0;\n this.clampScroll();\n }\n\n private fallback(width: number): Container {\n const c = new Container();\n const t = new Text({ text: 'No content provided.', style: { fontFamily: this.ui.theme.type.family, fontSize: 18, fill: INK, wordWrap: true, wordWrapWidth: width } });\n c.addChild(t);\n return c;\n }\n\n private readonly onDown = (e: FederatedPointerEvent): void => {\n this.dragging = true;\n this.lastY = e.global.y;\n };\n private readonly onMove = (e: FederatedPointerEvent): void => {\n if (!this.dragging) return;\n this.scrollY += e.global.y - this.lastY;\n this.lastY = e.global.y;\n this.clampScroll();\n };\n private readonly onUp = (): void => {\n this.dragging = false;\n };\n\n private clampScroll(): void {\n const min = Math.min(0, this.viewportH - this.contentH);\n this.scrollY = Math.max(min, Math.min(0, this.scrollY));\n if (this.content) this.content.y = this.scrollY;\n }\n\n private applyOpen(open: boolean): void {\n this.visible = open;\n this.eventMode = open ? 'static' : 'none';\n this.alpha = open ? 1 : 0;\n if (open) {\n this.scrollY = 0;\n this.clampScroll();\n if (!this.wheelHandler) {\n this.wheelHandler = (e: WheelEvent) => {\n this.scrollY -= e.deltaY;\n this.clampScroll();\n };\n window.addEventListener('wheel', this.wheelHandler, { passive: true });\n }\n } else if (this.wheelHandler) {\n window.removeEventListener('wheel', this.wheelHandler);\n this.wheelHandler = undefined;\n }\n }\n\n override dispose(): void {\n if (this.wheelHandler) window.removeEventListener('wheel', this.wheelHandler);\n this.close.dispose();\n super.dispose();\n }\n}\n","import { Container, Graphics, type Ticker } from 'pixi.js';\nimport { type OpenUI, type PanelControl, type Control, type BlockSpec } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { buildBlockColumn, type ControlViewFactory } from './blockColumn';\n\nexport interface PanelBodyOptions {\n width?: number;\n controlSkins?: Partial<Record<string, ControlViewFactory>>;\n}\n\n/**\n * A small, CENTERED panel body (the settings popover / declarative panels): walks\n * a `BlockSpec[]` via the shared {@link buildBlockColumn} renderer, draws a branded\n * card behind it, and follows the PanelControl's open/closed state. A `modal`\n * variant also gets a dismissable backdrop. Text re-renders on `ui.locale` change.\n * (The big scrollable menu uses {@link MenuView}, which shares the same renderer.)\n */\nexport class PanelBodyView extends ControlView {\n private readonly backdrop = new Graphics();\n private readonly card = new Graphics();\n private readonly content = new Container();\n private childViews: ControlView[] = [];\n private readonly bodyW: number;\n\n constructor(\n private readonly panelControl: PanelControl,\n private readonly controls: Control[],\n private readonly blocks: BlockSpec[],\n ui: OpenUI,\n private readonly ticker: Ticker,\n private readonly opts: PanelBodyOptions = {},\n ) {\n super(panelControl, ui);\n this.bodyW = opts.width ?? 360;\n\n this.addChild(this.backdrop, this.card, this.content);\n this.rebuild();\n this.applyVisibility();\n\n this.disposers.push(\n this.panelControl.state.subscribe(() => this.applyVisibility()),\n this.ui.locale.subscribe(() => {\n if (!this.destroyed) this.rebuild();\n }),\n );\n\n if (this.panelControl.variant === 'modal') {\n this.backdrop.eventMode = 'static';\n this.backdrop.on('pointertap', () => this.panelControl.closePanel());\n }\n }\n\n private rebuild(): void {\n for (const v of this.childViews) v.dispose();\n this.childViews.length = 0;\n // Destroy direct children (wraps/static nodes) WITHOUT children:true so the\n // already-disposed control views aren't re-destroyed (matches the prior code).\n for (const child of this.content.removeChildren()) child.destroy();\n\n const col = buildBlockColumn(this.blocks, this.controls, this.ui, this.ticker, this.bodyW, { controlSkins: this.opts.controlSkins });\n this.childViews = col.views;\n this.content.addChild(...col.content.removeChildren());\n this.content.position.set(0, -col.height / 2);\n this.drawChrome(this.bodyW, col.height);\n }\n\n private drawChrome(width: number, height: number): void {\n const t = this.ui.theme;\n this.card.clear()\n .roundRect(-width / 2, -height / 2, width, height, t.radius.card)\n .fill({ color: t.color.surface })\n .stroke({ width: 3, color: t.color.accent });\n\n this.backdrop.clear();\n if (this.panelControl.variant === 'modal') {\n this.backdrop.rect(-3000, -3000, 6000, 6000).fill({ color: 0x000000, alpha: 0.6 });\n }\n }\n\n private applyVisibility(): void {\n const open = this.panelControl.isOpen;\n this.visible = open;\n this.eventMode = open ? 'auto' : 'none';\n }\n\n override dispose(): void {\n for (const v of this.childViews) v.dispose();\n this.childViews.length = 0;\n super.dispose();\n }\n}\n","import { type Application } from 'pixi.js';\nimport {\n createUI,\n buildPanel,\n composeMenu,\n type OpenUI,\n type UISpec,\n type HostHooks,\n type CurrencySpec,\n type EventLog,\n type ControlSnapshot,\n type Signal,\n type OpenUIEvents,\n type Dispose,\n type JurisdictionConfig,\n type BlockSpec,\n type NoticeAction,\n type NoticeOptions,\n type RgsErrorOptions,\n} from '@open-slot-ui/core';\nimport { OpenUIPixi, type OpenUIPixiOptions } from './OpenUIPixi';\nimport { PanelBodyView } from './views/PanelBodyView';\n\nexport interface HudOptions extends OpenUIPixiOptions {\n hooks?: HostHooks;\n}\n\n/**\n * The complete-HUD handle returned by `mountHud`. Wraps the headless OpenUI + the\n * Pixi controller with the day-to-day game verbs, so the host rarely touches the\n * lower layers. `dispose()` is the single, leak-free teardown (Charter P12).\n */\nexport interface BootedHud {\n readonly ui: OpenUI;\n readonly pixi: OpenUIPixi;\n on<K extends keyof OpenUIEvents>(type: K, fn: (p: OpenUIEvents[K]) => void): Dispose;\n setBalance(major: number): void;\n setBet(major: number): void;\n /** Set the bonus total-win amount (major units). Shown in the buy-feature slot while\n * the spin button is in free-spins mode (`setFreeSpins(n > 0)`). */\n setTotalWin(major: number): void;\n setCurrency(spec: CurrencySpec): void;\n /** Apply a Stake Engine jurisdiction config (the compliance switchboard) at runtime. */\n applyJurisdiction(jur: JurisdictionConfig): void;\n /** Report a settled round (major units): updates net position + enforces autoplay limits. */\n reportRound(win: number, bet: number): void;\n /** Set the RTP percentage shown by the RTP readout (when `displayRTP`). */\n setRtp(percent: number): void;\n /** Master mute / unmute (music + sfx). */\n setMuted(muted: boolean): void;\n /** Show a menu-style notice modal: declarative blocks + optional action buttons. */\n showNotice(blocks: BlockSpec[], actions?: NoticeAction[]): void;\n /** Show a menu-style error modal — `message`/`opts.title` are literal text OR i18n\n * keys, and `opts.actions` adds custom buttons (e.g. a \"Reload\"). */\n showError(message: string, opts?: NoticeOptions): void;\n /** Show the default (localizable, per-call overridable) message for an RGS status\n * code (e.g. `'ERR_IPB'`, `'ERR_IS'`, `'ERR_MAINTENANCE'`). */\n showRgsError(code: string, opts?: RgsErrorOptions): void;\n /** Show a FATAL error: a blocking modal that LOCKS the HUD and is dismissable only\n * in code (`hideNotice`) — for unrecoverable RGS states. */\n showFatal(message: string, opts?: NoticeOptions): void;\n /** Dismiss the notice / error modal. */\n hideNotice(): void;\n /** Social / sweepstakes mode: one switch swaps gambling wording (+ a coin → GC/SC). */\n setSocial(on: boolean, coin?: string): void;\n /** Switch the spin button to / from its free-spins face: `n > 0` shows \"N FS\". */\n setFreeSpins(n: number): void;\n /** Enter/leave replay mode (Stake `replay=true`) — locks the HUD + shows a REPLAY badge. */\n setReplay(on: boolean): void;\n /** Show a buy-feature confirm modal (Cancel / Confirm). Texts are literal-or-key. */\n confirmBuy(opts: { title?: string; message?: string; onConfirm: () => void; confirmLabel?: string; cancelLabel?: string }): void;\n /** Confirm-GATE a buy / bet-mode activation: when its `cost` (× base bet) exceeds\n * the configured `confirmBuyAboveCost` threshold, show a confirm popup naming the\n * feature + `price` and run `onConfirm` only on confirm; otherwise run `onConfirm`\n * straight away. This is how a game honors Stake's \"no one-click activation above\n * 2×\" rule — the library owns the threshold + popup, the game just calls this. */\n requestBuyFeature(opts: {\n cost: number;\n name?: string;\n price?: string;\n onConfirm: () => void;\n title?: string;\n message?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n }): void;\n /** Read-back: would a play of this `cost` (× base bet) require confirmation? */\n shouldConfirmBuy(cost: number): boolean;\n /** Slide the whole interactive HUD in / out — bottom controls go down, top ones up\n * (behind the status-bar plaque). Non-interactive while moving. */\n showControls(): void;\n hideControls(): void;\n setControlsVisible(visible: boolean): void;\n snapshot(): ControlSnapshot[];\n readonly events: EventLog | undefined;\n readonly inputLocked: Signal<boolean>;\n lockInput(): void;\n unlockInput(): void;\n unmount(): void;\n dispose(): void;\n}\n\n/**\n * The one-call, out-of-the-box entry: `mountHud(app)` boots the full reference\n * HUD; `mountHud(app, spec, opts)` configures it from one JSON UISpec + renderer\n * art/skins. Pure assembly over `createUI` + `OpenUIPixi` (Charter B9).\n */\nexport function mountHud(app: Application, spec: UISpec = {}, opts: HudOptions = {}): BootedHud {\n const { hooks, ...pixiOpts } = opts;\n const ui = createUI(spec, hooks);\n // Compose the unified menu (Settings → Paytable → Rules). A Language switch is\n // added automatically when 2+ locales are configured; `spec.rules` is folded in\n // for back-compat. The built-in Music/Sound reuse the real volume controls.\n const locales = spec.locale ? Array.from(new Set([spec.locale.locale, ...Object.keys(spec.locale.messages)])) : [];\n // `menu: false` (e.g. when the host supplies its own HTML menu) skips the Pixi menu.\n const menu = pixiOpts.menu === false ? false : composeMenu(spec.menu, { locales, localeSelectId: spec.localeSelectId, rulesFallback: spec.rules });\n // Game name + version footer (support / certification) — appended to the menu.\n if (menu && spec.game && (spec.game.name || spec.game.version)) {\n menu.push({ kind: 'legal', id: 'openui-game-info', text: [spec.game.name, spec.game.version ? `v${spec.game.version}` : ''].filter(Boolean).join(' · ') });\n }\n const pixi = new OpenUIPixi(ui, { ...pixiOpts, menu });\n pixi.mount(app);\n\n // The reality-check reminder (RTS 13) is now wired in `createUI` (core), so it runs\n // on a wall-clock timer regardless of renderer — nothing to schedule here.\n\n // Extra declarative panels (beyond the settings menu) render as their own layers.\n const extra: PanelBodyView[] = [];\n if (spec.panels?.length) {\n for (const ps of spec.panels) {\n const built = buildPanel(ps, ui.bus);\n ui.register(built.panel);\n for (const c of built.controls) ui.register(c);\n const view = new PanelBodyView(built.panel, built.controls, built.blocks, ui, app.ticker, {\n controlSkins: pixiOpts.controlSkins,\n });\n pixi.root.addChild(view);\n view.applyLayout(ui.screen.get());\n extra.push(view);\n }\n }\n const offRelayout = ui.screen.subscribe(() => {\n const s = ui.screen.get();\n for (const v of extra) v.applyLayout(s);\n });\n\n const teardown = (): void => {\n offRelayout();\n for (const v of extra) v.dispose();\n extra.length = 0;\n pixi.unmount();\n ui.dispose(); // tear down the headless subscriptions too (Charter P12)\n };\n\n function on<K extends keyof OpenUIEvents>(type: K, fn: (p: OpenUIEvents[K]) => void): Dispose {\n return ui.on(type, fn);\n }\n\n return {\n ui,\n pixi,\n on,\n setBalance: (n) => ui.balance.set(n),\n setBet: (n) => ui.bet.set(n),\n setTotalWin: (n) => ui.totalWin.set(n),\n setCurrency: (c) => {\n ui.balance.setCurrency(c);\n ui.bet.setCurrency(c);\n ui.totalWin.setCurrency(c);\n ui.netPosition.setCurrency(c);\n },\n applyJurisdiction: (j) => ui.applyJurisdiction(j),\n reportRound: (win, bet) => ui.reportRound(win, bet),\n setRtp: (p) => ui.rtp.set(p),\n setMuted: (m) => ui.setMuted(m),\n showNotice: (blocks, actions) => ui.showNotice(blocks, actions),\n showError: (message, opts) => ui.showError(message, opts),\n showRgsError: (code, opts) => ui.showRgsError(code, opts),\n showFatal: (message, opts) => ui.showFatal(message, opts),\n hideNotice: () => ui.hideNotice(),\n setSocial: (on, coin) => ui.setSocial(on, coin),\n setFreeSpins: (n) => ui.spin.setFreeSpins(n),\n setReplay: (on) => ui.setReplay(on),\n confirmBuy: (o) => {\n // Real guard: a jurisdiction that disabled buy-feature makes this a no-op.\n if (ui.isDisabled('buyFeature')) return;\n ui.showNotice(\n [\n { kind: 'heading', id: 'buy-title', text: o.title ?? 'openui.buyFeature.title' },\n { kind: 'text', id: 'buy-body', text: o.message ?? 'openui.buyFeature.message' },\n ],\n [\n { label: o.cancelLabel ?? 'openui.cancel', variant: 'secondary' },\n { label: o.confirmLabel ?? 'openui.confirm', variant: 'primary', onSelect: o.onConfirm },\n ],\n );\n },\n shouldConfirmBuy: (cost) => ui.shouldConfirmBuy(cost),\n requestBuyFeature: (o) => {\n if (ui.isDisabled('buyFeature')) return; // jurisdiction fully disabled the feature\n if (!ui.shouldConfirmBuy(o.cost)) {\n o.onConfirm(); // cost at/under the threshold → one click is allowed\n return;\n }\n // Pre-resolve the message (block text can't interpolate); social/locale at open time.\n const message =\n o.message ??\n (o.name\n ? ui.t('openui.buyFeature.confirm', { name: ui.t(o.name), price: o.price ?? '' })\n : 'openui.buyFeature.message');\n ui.showNotice(\n [\n { kind: 'heading', id: 'buy-title', text: o.title ?? 'openui.buyFeature.title' },\n { kind: 'text', id: 'buy-body', text: message },\n ],\n [\n { label: o.cancelLabel ?? 'openui.cancel', variant: 'secondary' },\n { label: o.confirmLabel ?? 'openui.confirm', variant: 'primary', onSelect: o.onConfirm },\n ],\n );\n },\n showControls: () => pixi.setControlsVisible(true),\n hideControls: () => pixi.setControlsVisible(false),\n setControlsVisible: (v) => pixi.setControlsVisible(v),\n snapshot: () => ui.snapshot(),\n events: pixi.eventLog,\n inputLocked: ui.locked,\n lockInput: () => ui.lock(),\n unlockInput: () => ui.unlock(),\n unmount: teardown,\n dispose: teardown,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/views/PopoverView.ts","../src/views/PanelView.ts","../src/views/PanelBodyView.ts","../src/mountHud.ts","../src/bootError.ts"],"names":["Graphics","Container","opts","on"],"mappings":"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","file":"index.js","sourcesContent":["import { type Ticker, type Texture } from 'pixi.js';\nimport { type PanelControl, type SliderControl, type ButtonControl, type OpenUI } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { SliderView } from './SliderView';\nimport { ButtonView } from './ButtonView';\n\nexport interface PopoverParts {\n music: SliderControl;\n sfx: SliderControl;\n rules: ButtonControl;\n}\n\nexport interface PopoverArt {\n rulesTexture?: Texture;\n musicTrack?: Texture;\n soundTrack?: Texture;\n}\n\ninterface FanItem {\n view: ControlView;\n tx: number;\n ty: number;\n prog: number;\n}\n\nconst GAP = 80; // vertical spacing between fanned items (ref px)\nconst RISE = 26; // how far each item rises into place\nconst STAGGER = 38; // ms between pops — snappy \"pop-pop-pop\"\n// slider track is 290x60 @ ~0.9 → its visual centre, used as the scale pivot\nconst SLIDER_PIVOT_X = 130;\nconst SLIDER_PIVOT_Y = 27;\n\n/**\n * The settings flyout as a VERTICAL FAN: on open, the options swoosh up and pop\n * in one-by-one (bottom→top); on close they retract together. Items are\n * right-aligned and rise above the (right-side) menu button. No static panel.\n */\nexport class PopoverView extends ControlView {\n private readonly music: SliderView;\n private readonly sfx: SliderView;\n private readonly rules: ButtonView;\n private readonly items: FanItem[];\n private phase = 0;\n private running = false;\n private readonly tick: (t: Ticker) => void;\n\n constructor(private readonly panel: PanelControl, parts: PopoverParts, ui: OpenUI, private readonly ticker: Ticker, art: PopoverArt = {}) {\n super(panel, ui);\n\n this.rules = new ButtonView(parts.rules, ui, ticker, { shape: 'pill', height: 50, iconTexture: art.rulesTexture, iconTarget: 50 });\n this.music = new SliderView(parts.music, ui, art.musicTrack);\n this.sfx = new SliderView(parts.sfx, ui, art.soundTrack);\n // pivot sliders at their centre so they scale from the middle, not the left edge\n this.music.pivot.set(SLIDER_PIVOT_X, SLIDER_PIVOT_Y);\n this.sfx.pivot.set(SLIDER_PIVOT_X, SLIDER_PIVOT_Y);\n\n // Right-aligned column rising above the button; pop order = bottom → top.\n // tx/ty are the item CENTRES (rules ButtonView is already centre-origin).\n this.items = [\n { view: this.sfx, tx: -130, ty: -GAP, prog: 0 },\n { view: this.music, tx: -130, ty: -GAP * 2, prog: 0 },\n { view: this.rules, tx: -132, ty: -GAP * 3, prog: 0 },\n ];\n for (const it of this.items) {\n it.view.position.set(it.tx, it.ty);\n it.view.scale.set(0);\n it.view.alpha = 0;\n it.view.visible = false;\n this.addChild(it.view);\n }\n\n this.tick = (t) => this.update(t.deltaMS);\n this.applyState();\n this.disposers.push(this.panel.state.subscribe(() => this.applyState()));\n }\n\n private applyState(): void {\n this.phase = 0;\n const open = this.panel.isOpen;\n this.eventMode = open ? 'auto' : 'none';\n if (open) for (const it of this.items) it.view.visible = true;\n if (!this.running) {\n this.running = true;\n this.ticker.add(this.tick);\n }\n }\n\n private update(dt: number): void {\n this.phase += Math.min(dt, 40); // cap stalls so the stagger never gets skipped\n const open = this.panel.isOpen;\n const finalTarget = open ? 1 : 0;\n let settled = true;\n for (let i = 0; i < this.items.length; i++) {\n const it = this.items[i]!;\n const target = open && this.phase > i * STAGGER ? 1 : 0; // staggered easing target\n it.prog += (target - it.prog) * Math.min(1, dt / (open ? 50 : 80));\n const s = it.prog;\n it.view.scale.set(s);\n it.view.alpha = Math.min(1, s * 1.5);\n it.view.position.set(it.tx, it.ty + (1 - s) * RISE);\n it.view.visible = s > 0.01;\n // settle against the FINAL target so the loop keeps running until every item arrives\n if (Math.abs(it.prog - finalTarget) > 0.01) settled = false;\n }\n if (settled) {\n this.running = false;\n this.ticker.remove(this.tick);\n }\n }\n\n override dispose(): void {\n if (this.running) {\n this.ticker.remove(this.tick);\n this.running = false;\n }\n this.music.dispose();\n this.sfx.dispose();\n this.rules.dispose();\n super.dispose();\n }\n}\n","import { Container, Graphics, Text, Rectangle, type Texture, type FederatedPointerEvent, type Ticker } from 'pixi.js';\nimport { type PanelControl, type ButtonControl, type OpenUI, type ScreenState, type Theme } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { ButtonView } from './ButtonView';\n\nexport type InfoContentBuilder = (theme: Theme, width: number) => Container;\n\nexport interface PanelViewOptions {\n closeTexture?: Texture;\n content?: InfoContentBuilder;\n}\n\n// The modal is an intentionally LIGHT surface (per the design), distinct from the dark HUD theme.\nconst INK = 0x15171c;\nconst CARD = 0xffffff;\nconst HEADER_BG = 0x20242b;\nconst PAD = 16;\nconst HEADER_H = 56;\nconst MAX_W = 600;\n\n/**\n * Full-screen modal: dim backdrop + dark header (title + ✕ close) + a white,\n * scrollable content card. Content is built dynamically (so it scrolls and is\n * data-driven). Faithful to the provided Mobile Rules design.\n */\nexport class PanelView extends ControlView {\n private readonly backdrop = new Graphics();\n private readonly card = new Graphics();\n private readonly headerBg = new Graphics();\n private readonly title: Text;\n private readonly viewport = new Container();\n private readonly maskG = new Graphics();\n private readonly catcher = new Graphics();\n private readonly close: ButtonView;\n private content: Container | undefined;\n private builtWidth = -1;\n private scrollY = 0;\n private contentH = 0;\n private viewportH = 0;\n private dragging = false;\n private lastY = 0;\n private wheelHandler: ((e: WheelEvent) => void) | undefined;\n\n constructor(\n private readonly panel: PanelControl,\n closeBtn: ButtonControl,\n ui: OpenUI,\n ticker: Ticker,\n private readonly opts: PanelViewOptions = {},\n ) {\n super(panel, ui);\n this.zIndex = 100;\n\n this.backdrop.eventMode = 'static';\n this.backdrop.on('pointertap', () => this.panel.closePanel());\n\n this.title = new Text({\n text: panel.title ?? '',\n style: { fontFamily: ui.theme.type.family, fontSize: 22, fill: 0xffffff, fontWeight: '800', letterSpacing: 1 },\n });\n this.title.anchor.set(0.5);\n\n this.viewport.mask = this.maskG;\n this.catcher.eventMode = 'static';\n this.catcher.on('pointerdown', this.onDown);\n this.catcher.on('globalpointermove', this.onMove);\n this.catcher.on('pointerup', this.onUp);\n this.catcher.on('pointerupoutside', this.onUp);\n\n this.close = new ButtonView(closeBtn, ui, ticker, { iconTexture: opts.closeTexture, iconTarget: 44, glyph: 'close', radius: 24 });\n\n this.addChild(this.backdrop, this.card, this.viewport, this.maskG, this.catcher, this.headerBg, this.title, this.close);\n\n this.applyOpen(this.panel.isOpen);\n this.disposers.push(this.panel.state.subscribe(() => this.applyOpen(this.panel.isOpen)));\n }\n\n override applyLayout(screen: ScreenState): void {\n const W = screen.width;\n const H = screen.height;\n this.position.set(0, 0);\n this.scale.set(1);\n\n this.backdrop.clear().rect(0, 0, W, H).fill({ color: 0x000000, alpha: 0.6 });\n this.backdrop.hitArea = new Rectangle(0, 0, W, H);\n\n const cardW = Math.min(W - PAD * 2, MAX_W);\n const cx = (W - cardW) / 2;\n const hy = PAD;\n this.headerBg.clear().roundRect(cx, hy, cardW, HEADER_H, HEADER_H / 2).fill({ color: HEADER_BG });\n this.title.position.set(W / 2, hy + HEADER_H / 2);\n this.close.position.set(cx + cardW - HEADER_H / 2, hy + HEADER_H / 2);\n\n const cardY = hy + HEADER_H + 12;\n const cardH = H - cardY - PAD;\n this.card.clear().roundRect(cx, cardY, cardW, cardH, 22).fill({ color: CARD });\n\n const inset = 20;\n const vpX = cx + inset;\n const vpY = cardY + inset;\n const vpW = cardW - inset * 2;\n const vpH = cardH - inset * 2;\n this.viewport.position.set(vpX, vpY);\n this.viewportH = vpH;\n this.maskG.clear().rect(vpX, vpY, vpW, vpH).fill({ color: 0xffffff });\n this.catcher.clear().rect(vpX, vpY, vpW, vpH).fill({ color: 0xffffff, alpha: 0.0001 });\n\n // (re)build content to the current viewport width\n if (Math.abs(vpW - this.builtWidth) > 1) {\n this.content?.destroy({ children: true });\n this.content = this.opts.content?.(this.ui.theme, vpW) ?? this.fallback(vpW);\n this.viewport.addChild(this.content);\n this.builtWidth = vpW;\n }\n if (this.content) this.content.x = 0;\n this.contentH = this.content?.height ?? 0;\n this.clampScroll();\n }\n\n private fallback(width: number): Container {\n const c = new Container();\n const t = new Text({ text: 'No content provided.', style: { fontFamily: this.ui.theme.type.family, fontSize: 18, fill: INK, wordWrap: true, wordWrapWidth: width } });\n c.addChild(t);\n return c;\n }\n\n private readonly onDown = (e: FederatedPointerEvent): void => {\n this.dragging = true;\n this.lastY = e.global.y;\n };\n private readonly onMove = (e: FederatedPointerEvent): void => {\n if (!this.dragging) return;\n this.scrollY += e.global.y - this.lastY;\n this.lastY = e.global.y;\n this.clampScroll();\n };\n private readonly onUp = (): void => {\n this.dragging = false;\n };\n\n private clampScroll(): void {\n const min = Math.min(0, this.viewportH - this.contentH);\n this.scrollY = Math.max(min, Math.min(0, this.scrollY));\n if (this.content) this.content.y = this.scrollY;\n }\n\n private applyOpen(open: boolean): void {\n this.visible = open;\n this.eventMode = open ? 'static' : 'none';\n this.alpha = open ? 1 : 0;\n if (open) {\n this.scrollY = 0;\n this.clampScroll();\n if (!this.wheelHandler) {\n this.wheelHandler = (e: WheelEvent) => {\n this.scrollY -= e.deltaY;\n this.clampScroll();\n };\n window.addEventListener('wheel', this.wheelHandler, { passive: true });\n }\n } else if (this.wheelHandler) {\n window.removeEventListener('wheel', this.wheelHandler);\n this.wheelHandler = undefined;\n }\n }\n\n override dispose(): void {\n if (this.wheelHandler) window.removeEventListener('wheel', this.wheelHandler);\n this.close.dispose();\n super.dispose();\n }\n}\n","import { Container, Graphics, type Ticker } from 'pixi.js';\nimport { type OpenUI, type PanelControl, type Control, type BlockSpec } from '@open-slot-ui/core';\nimport { ControlView } from './ControlView';\nimport { buildBlockColumn, type ControlViewFactory } from './blockColumn';\n\nexport interface PanelBodyOptions {\n width?: number;\n controlSkins?: Partial<Record<string, ControlViewFactory>>;\n}\n\n/**\n * A small, CENTERED panel body (the settings popover / declarative panels): walks\n * a `BlockSpec[]` via the shared {@link buildBlockColumn} renderer, draws a branded\n * card behind it, and follows the PanelControl's open/closed state. A `modal`\n * variant also gets a dismissable backdrop. Text re-renders on `ui.locale` change.\n * (The big scrollable menu uses {@link MenuView}, which shares the same renderer.)\n */\nexport class PanelBodyView extends ControlView {\n private readonly backdrop = new Graphics();\n private readonly card = new Graphics();\n private readonly content = new Container();\n private childViews: ControlView[] = [];\n private readonly bodyW: number;\n\n constructor(\n private readonly panelControl: PanelControl,\n private readonly controls: Control[],\n private readonly blocks: BlockSpec[],\n ui: OpenUI,\n private readonly ticker: Ticker,\n private readonly opts: PanelBodyOptions = {},\n ) {\n super(panelControl, ui);\n this.bodyW = opts.width ?? 360;\n\n this.addChild(this.backdrop, this.card, this.content);\n this.rebuild();\n this.applyVisibility();\n\n this.disposers.push(\n this.panelControl.state.subscribe(() => this.applyVisibility()),\n this.ui.locale.subscribe(() => {\n if (!this.destroyed) this.rebuild();\n }),\n );\n\n if (this.panelControl.variant === 'modal') {\n this.backdrop.eventMode = 'static';\n this.backdrop.on('pointertap', () => this.panelControl.closePanel());\n }\n }\n\n private rebuild(): void {\n for (const v of this.childViews) v.dispose();\n this.childViews.length = 0;\n // Destroy direct children (wraps/static nodes) WITHOUT children:true so the\n // already-disposed control views aren't re-destroyed (matches the prior code).\n for (const child of this.content.removeChildren()) child.destroy();\n\n const col = buildBlockColumn(this.blocks, this.controls, this.ui, this.ticker, this.bodyW, { controlSkins: this.opts.controlSkins });\n this.childViews = col.views;\n this.content.addChild(...col.content.removeChildren());\n this.content.position.set(0, -col.height / 2);\n this.drawChrome(this.bodyW, col.height);\n }\n\n private drawChrome(width: number, height: number): void {\n const t = this.ui.theme;\n this.card.clear()\n .roundRect(-width / 2, -height / 2, width, height, t.radius.card)\n .fill({ color: t.color.surface })\n .stroke({ width: 3, color: t.color.accent });\n\n this.backdrop.clear();\n if (this.panelControl.variant === 'modal') {\n this.backdrop.rect(-3000, -3000, 6000, 6000).fill({ color: 0x000000, alpha: 0.6 });\n }\n }\n\n private applyVisibility(): void {\n const open = this.panelControl.isOpen;\n this.visible = open;\n this.eventMode = open ? 'auto' : 'none';\n }\n\n override dispose(): void {\n for (const v of this.childViews) v.dispose();\n this.childViews.length = 0;\n super.dispose();\n }\n}\n","import { type Application } from 'pixi.js';\nimport {\n createUI,\n buildPanel,\n composeMenu,\n formatAmount,\n type OpenUI,\n type UISpec,\n type HostHooks,\n type CurrencySpec,\n type EventLog,\n type ControlSnapshot,\n type Signal,\n type OpenUIEvents,\n type Dispose,\n type JurisdictionConfig,\n type BlockSpec,\n type NoticeAction,\n type NoticeOptions,\n type RgsErrorOptions,\n} from '@open-slot-ui/core';\nimport { OpenUIPixi, type OpenUIPixiOptions } from './OpenUIPixi';\nimport { PanelBodyView } from './views/PanelBodyView';\n\n/** The round facts shown at the start of a replay (Stake \"Replay Support\"). */\nexport interface ReplayInfo {\n /** The base bet (before the mode's cost multiplier). */\n baseBet: number;\n /** The mode's cost multiplier (×), e.g. a 185× bonus buy. */\n costMultiplier: number;\n /** The round's payout multiplier (× the base bet). */\n payoutMultiplier: number;\n /** The final amount the round paid. */\n amount: number;\n /** Currency for the money values (defaults to the balance currency). */\n currency?: CurrencySpec;\n}\n\nexport interface HudOptions extends OpenUIPixiOptions {\n hooks?: HostHooks;\n}\n\n/**\n * The complete-HUD handle returned by `mountHud`. Wraps the headless OpenUI + the\n * Pixi controller with the day-to-day game verbs, so the host rarely touches the\n * lower layers. `dispose()` is the single, leak-free teardown (Charter P12).\n */\nexport interface BootedHud {\n readonly ui: OpenUI;\n readonly pixi: OpenUIPixi;\n on<K extends keyof OpenUIEvents>(type: K, fn: (p: OpenUIEvents[K]) => void): Dispose;\n setBalance(major: number): void;\n setBet(major: number): void;\n /** Set the bonus total-win amount (major units). Shown in the buy-feature slot while\n * the spin button is in free-spins mode (`setFreeSpins(n > 0)`). */\n setTotalWin(major: number): void;\n setCurrency(spec: CurrencySpec): void;\n /** Apply a Stake Engine jurisdiction config (the compliance switchboard) at runtime. */\n applyJurisdiction(jur: JurisdictionConfig): void;\n /** Report a settled round (major units): updates net position + enforces autoplay limits. */\n reportRound(win: number, bet: number): void;\n /** Set the RTP percentage shown by the RTP readout (when `displayRTP`). */\n setRtp(percent: number): void;\n /** Master mute / unmute (music + sfx). */\n setMuted(muted: boolean): void;\n /** Show a menu-style notice modal: declarative blocks + optional action buttons. */\n showNotice(blocks: BlockSpec[], actions?: NoticeAction[]): void;\n /** Show a menu-style error modal — `message`/`opts.title` are literal text OR i18n\n * keys, and `opts.actions` adds custom buttons (e.g. a \"Reload\"). */\n showError(message: string, opts?: NoticeOptions): void;\n /** Show the default (localizable, per-call overridable) message for an RGS status\n * code (e.g. `'ERR_IPB'`, `'ERR_IS'`, `'ERR_MAINTENANCE'`). */\n showRgsError(code: string, opts?: RgsErrorOptions): void;\n /** Show a FATAL error: a blocking modal that LOCKS the HUD and is dismissable only\n * in code (`hideNotice`) — for unrecoverable RGS states. */\n showFatal(message: string, opts?: NoticeOptions): void;\n /** Dismiss the notice / error modal. */\n hideNotice(): void;\n /** Social / sweepstakes mode: one switch swaps gambling wording (+ a coin → GC/SC). */\n setSocial(on: boolean, coin?: string): void;\n /** Switch the spin button to / from its free-spins face: `n > 0` shows \"N FS\". */\n setFreeSpins(n: number): void;\n /** Enter/leave replay mode (Stake `replay=true`) — locks the HUD + shows a REPLAY badge. */\n setReplay(on: boolean): void;\n /** Replay support (Stake \"Replay Support\"): at the START of a replay show the round's\n * Base Bet, its Cost + Payout multipliers and the final amount in an open-ui panel;\n * `onPlay` begins the playback. Labels are social-aware (Base Bet → Base Play, etc.);\n * amounts format with `info.currency` (defaults to the balance currency). Also flips\n * the HUD into replay mode (badge + lock). */\n replayStart(info: ReplayInfo, onPlay?: () => void): void;\n /** At the END of a replay, show a \"Replay\" button (open-ui styled) that re-runs it. */\n replayEnd(onReplay: () => void): void;\n /** Show a buy-feature confirm modal (Cancel / Confirm). Texts are literal-or-key. */\n confirmBuy(opts: { title?: string; message?: string; onConfirm: () => void; confirmLabel?: string; cancelLabel?: string }): void;\n /** Confirm-GATE a buy / bet-mode activation: when its `cost` (× base bet) exceeds\n * the configured `confirmBuyAboveCost` threshold, show a confirm popup naming the\n * feature + `price` and run `onConfirm` only on confirm; otherwise run `onConfirm`\n * straight away. This is how a game honors Stake's \"no one-click activation above\n * 2×\" rule — the library owns the threshold + popup, the game just calls this. */\n requestBuyFeature(opts: {\n cost: number;\n name?: string;\n price?: string;\n onConfirm: () => void;\n title?: string;\n message?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n }): void;\n /** Read-back: would a play of this `cost` (× base bet) require confirmation? */\n shouldConfirmBuy(cost: number): boolean;\n /** Slide the whole interactive HUD in / out — bottom controls go down, top ones up\n * (behind the status-bar plaque). Non-interactive while moving. */\n showControls(): void;\n hideControls(): void;\n setControlsVisible(visible: boolean): void;\n snapshot(): ControlSnapshot[];\n readonly events: EventLog | undefined;\n readonly inputLocked: Signal<boolean>;\n lockInput(): void;\n unlockInput(): void;\n unmount(): void;\n dispose(): void;\n}\n\n/**\n * The one-call, out-of-the-box entry: `mountHud(app)` boots the full reference\n * HUD; `mountHud(app, spec, opts)` configures it from one JSON UISpec + renderer\n * art/skins. Pure assembly over `createUI` + `OpenUIPixi` (Charter B9).\n */\nexport function mountHud(app: Application, spec: UISpec = {}, opts: HudOptions = {}): BootedHud {\n const { hooks, ...pixiOpts } = opts;\n const ui = createUI(spec, hooks);\n // Compose the unified menu (Settings → Paytable → Rules). A Language switch is\n // added automatically when 2+ locales are configured; `spec.rules` is folded in\n // for back-compat. The built-in Music/Sound reuse the real volume controls.\n const locales = spec.locale ? Array.from(new Set([spec.locale.locale, ...Object.keys(spec.locale.messages)])) : [];\n // `menu: false` (e.g. when the host supplies its own HTML menu) skips the Pixi menu.\n const menu = pixiOpts.menu === false ? false : composeMenu(spec.menu, { locales, localeSelectId: spec.localeSelectId, rulesFallback: spec.rules });\n // Game name + version footer (support / certification) — appended to the menu.\n if (menu && spec.game && (spec.game.name || spec.game.version)) {\n menu.push({ kind: 'legal', id: 'openui-game-info', text: [spec.game.name, spec.game.version ? `v${spec.game.version}` : ''].filter(Boolean).join(' · ') });\n }\n const pixi = new OpenUIPixi(ui, { ...pixiOpts, menu });\n pixi.mount(app);\n\n // The reality-check reminder (RTS 13) is now wired in `createUI` (core), so it runs\n // on a wall-clock timer regardless of renderer — nothing to schedule here.\n\n // Extra declarative panels (beyond the settings menu) render as their own layers.\n const extra: PanelBodyView[] = [];\n if (spec.panels?.length) {\n for (const ps of spec.panels) {\n const built = buildPanel(ps, ui.bus);\n ui.register(built.panel);\n for (const c of built.controls) ui.register(c);\n const view = new PanelBodyView(built.panel, built.controls, built.blocks, ui, app.ticker, {\n controlSkins: pixiOpts.controlSkins,\n });\n pixi.root.addChild(view);\n view.applyLayout(ui.screen.get());\n extra.push(view);\n }\n }\n const offRelayout = ui.screen.subscribe(() => {\n const s = ui.screen.get();\n for (const v of extra) v.applyLayout(s);\n });\n\n const teardown = (): void => {\n offRelayout();\n for (const v of extra) v.dispose();\n extra.length = 0;\n pixi.unmount();\n ui.dispose(); // tear down the headless subscriptions too (Charter P12)\n };\n\n function on<K extends keyof OpenUIEvents>(type: K, fn: (p: OpenUIEvents[K]) => void): Dispose {\n return ui.on(type, fn);\n }\n\n return {\n ui,\n pixi,\n on,\n setBalance: (n) => ui.balance.set(n),\n setBet: (n) => ui.bet.set(n),\n setTotalWin: (n) => ui.totalWin.set(n),\n setCurrency: (c) => {\n ui.balance.setCurrency(c);\n ui.bet.setCurrency(c);\n ui.totalWin.setCurrency(c);\n ui.netPosition.setCurrency(c);\n },\n applyJurisdiction: (j) => ui.applyJurisdiction(j),\n reportRound: (win, bet) => ui.reportRound(win, bet),\n setRtp: (p) => ui.rtp.set(p),\n setMuted: (m) => ui.setMuted(m),\n showNotice: (blocks, actions) => ui.showNotice(blocks, actions),\n showError: (message, opts) => ui.showError(message, opts),\n showRgsError: (code, opts) => ui.showRgsError(code, opts),\n showFatal: (message, opts) => ui.showFatal(message, opts),\n hideNotice: () => ui.hideNotice(),\n setSocial: (on, coin) => ui.setSocial(on, coin),\n setFreeSpins: (n) => ui.spin.setFreeSpins(n),\n setReplay: (on) => ui.setReplay(on),\n replayStart: (info, onPlay) => {\n ui.setReplay(true); // REPLAY badge + locked HUD\n const cur = info.currency ?? ui.balance.currency.get();\n const money = (n: number): string => formatAmount(n, cur);\n ui.showNotice(\n [\n { kind: 'heading', id: 'openui-replay-h', text: 'openui.replay.title' },\n {\n kind: 'stat-grid',\n id: 'openui-replay-g',\n items: [\n { label: 'openui.replay.baseBet', value: money(info.baseBet) },\n { label: 'openui.replay.costMultiplier', value: `${info.costMultiplier}×` },\n { label: 'openui.replay.payoutMultiplier', value: `${info.payoutMultiplier}×` },\n { label: 'openui.replay.amount', value: money(info.amount) },\n ],\n },\n ],\n [{ label: 'openui.replay.play', variant: 'primary', onSelect: onPlay }],\n );\n },\n replayEnd: (onReplay) => {\n ui.showNotice(\n [{ kind: 'heading', id: 'openui-replay-end', text: 'openui.replay.title' }],\n [{ label: 'openui.replay.again', variant: 'primary', onSelect: onReplay }],\n );\n },\n confirmBuy: (o) => {\n // Real guard: a jurisdiction that disabled buy-feature makes this a no-op.\n if (ui.isDisabled('buyFeature')) return;\n ui.showNotice(\n [\n { kind: 'heading', id: 'buy-title', text: o.title ?? 'openui.buyFeature.title' },\n { kind: 'text', id: 'buy-body', text: o.message ?? 'openui.buyFeature.message' },\n ],\n [\n { label: o.cancelLabel ?? 'openui.cancel', variant: 'secondary' },\n { label: o.confirmLabel ?? 'openui.confirm', variant: 'primary', onSelect: o.onConfirm },\n ],\n );\n },\n shouldConfirmBuy: (cost) => ui.shouldConfirmBuy(cost),\n requestBuyFeature: (o) => {\n if (ui.isDisabled('buyFeature')) return; // jurisdiction fully disabled the feature\n if (!ui.shouldConfirmBuy(o.cost)) {\n o.onConfirm(); // cost at/under the threshold → one click is allowed\n return;\n }\n // Pre-resolve the message (block text can't interpolate); social/locale at open time.\n const message =\n o.message ??\n (o.name\n ? ui.t('openui.buyFeature.confirm', { name: ui.t(o.name), price: o.price ?? '' })\n : 'openui.buyFeature.message');\n ui.showNotice(\n [\n { kind: 'heading', id: 'buy-title', text: o.title ?? 'openui.buyFeature.title' },\n { kind: 'text', id: 'buy-body', text: message },\n ],\n [\n { label: o.cancelLabel ?? 'openui.cancel', variant: 'secondary' },\n { label: o.confirmLabel ?? 'openui.confirm', variant: 'primary', onSelect: o.onConfirm },\n ],\n );\n },\n showControls: () => pixi.setControlsVisible(true),\n hideControls: () => pixi.setControlsVisible(false),\n setControlsVisible: (v) => pixi.setControlsVisible(v),\n snapshot: () => ui.snapshot(),\n events: pixi.eventLog,\n inputLocked: ui.locked,\n lockInput: () => ui.lock(),\n unlockInput: () => ui.unlock(),\n unmount: teardown,\n dispose: teardown,\n };\n}\n","// Standalone boot / fatal ERROR screen — a full-screen block shown when the game\n// cannot reach or authenticate with the RGS BEFORE the HUD mounts (so the HUD's own\n// `showFatal` isn't available yet). It uses the open-ui dark + yellow palette so it\n// looks like the HUD's own modals, and it PREVENTS PLAY (non-dismissible; the only way\n// out is Reload, which re-runs the whole handshake) — Stake requires that a failed\n// connection/auth never silently continues. Pure DOM, no pixi needed.\n\nexport interface BootErrorOptions {\n title?: string;\n message?: string;\n /** Small technical detail for support (e.g. the RGS status line). */\n detail?: string;\n reloadLabel?: string;\n /** Reload handler (default: `window.location.reload()`). Pass `null` for no button. */\n onReload?: (() => void) | null;\n}\n\nlet host: HTMLElement | null = null;\n\nconst esc = (s: string): string => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\n/** Show the open-ui-themed blocking boot error. Idempotent (replaces its content). */\nexport function showBootError(opts: BootErrorOptions = {}): void {\n const title = opts.title ?? 'Connection lost';\n const message = opts.message ?? 'The game could not reach the game server. Please reload to reconnect and continue.';\n const showReload = opts.onReload !== null;\n host ??= document.createElement('div');\n host.className = 'openui-boot-error';\n host.setAttribute('role', 'alertdialog');\n host.setAttribute('aria-modal', 'true');\n host.innerHTML = `\n <div class=\"openui-be-card\">\n <div class=\"openui-be-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 48 48\" width=\"48\" height=\"48\"><path d=\"M24 4 3 42h42L24 4Z\" fill=\"none\" stroke=\"#ffc935\" stroke-width=\"3\" stroke-linejoin=\"round\"/><rect x=\"22\" y=\"18\" width=\"4\" height=\"12\" rx=\"2\" fill=\"#ffc935\"/><circle cx=\"24\" cy=\"35\" r=\"2.4\" fill=\"#ffc935\"/></svg>\n </div>\n <h1 class=\"openui-be-title\">${esc(title)}</h1>\n <p class=\"openui-be-msg\">${esc(message)}</p>\n ${opts.detail ? `<p class=\"openui-be-detail\">${esc(opts.detail)}</p>` : ''}\n ${showReload ? `<button class=\"openui-be-reload\" type=\"button\">${esc(opts.reloadLabel ?? 'Reload')}</button>` : ''}\n </div>\n <style>\n .openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif; color: #e9edf2;\n background: rgba(6,8,11,.92); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }\n .openui-be-card { width: min(90%, 440px); text-align: center; padding: 38px 32px 34px;\n background: #161b22; border: 1.5px solid #ffc935; border-radius: 16px; box-shadow: 0 30px 80px rgba(0,0,0,.6); }\n .openui-be-icon { margin-bottom: 14px; line-height: 0; }\n .openui-be-title { margin: 0 0 12px; font-size: 24px; font-weight: 800; color: #ffc935; letter-spacing: .3px; }\n .openui-be-msg { margin: 0 0 20px; font-size: 15px; line-height: 1.55; color: #c4ccd6; }\n .openui-be-detail { margin: 0 0 20px; font-size: 12px; line-height: 1.4; color: #78828f; word-break: break-word; }\n .openui-be-reload { appearance: none; border: 0; cursor: pointer; padding: 13px 42px; border-radius: 999px;\n background: #ffc935; color: #161b22; font-weight: 800; font-size: 15px; letter-spacing: .3px;\n box-shadow: 0 8px 22px rgba(255,201,53,.32); transition: transform .12s, filter .12s; }\n .openui-be-reload:hover { filter: brightness(1.06); }\n .openui-be-reload:active { transform: scale(.96); }\n </style>`;\n if (showReload) {\n host.querySelector('.openui-be-reload')?.addEventListener('click', () => (opts.onReload ?? (() => window.location.reload()))());\n }\n if (!host.isConnected) document.body.appendChild(host);\n}\n\n/** Remove the boot error screen (e.g. after a successful retry). */\nexport function hideBootError(): void {\n host?.remove();\n host = null;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-slot-ui/pixi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "PixiJS v8 view + controller binding for open-ui — mount a themeable, responsive, fully-tested slot-game HUD onto your Pixi scene in one call.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pixijs",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"access": "public"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@open-slot-ui/core": "0.
|
|
62
|
+
"@open-slot-ui/core": "0.7.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"pixi.js": "^8"
|