@energy8platform/shell 0.5.0 → 0.6.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/html.cjs.js +39 -5
- package/dist/html.cjs.js.map +1 -1
- package/dist/html.d.ts +28 -4
- package/dist/html.esm.js +39 -5
- package/dist/html.esm.js.map +1 -1
- package/dist/index.cjs.js +29 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +28 -4
- package/dist/index.esm.js +29 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/pixi.cjs.js +54 -9
- package/dist/pixi.cjs.js.map +1 -1
- package/dist/pixi.d.ts +28 -4
- package/dist/pixi.esm.js +54 -9
- package/dist/pixi.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ShellController.ts +21 -0
- package/src/core/renderer.ts +8 -1
- package/src/core/state.ts +10 -0
- package/src/core/types.ts +12 -1
- package/src/core/version.ts +1 -1
- package/src/ui/html/components/Settings.ts +14 -5
- package/src/ui/pixi/PixiRenderer.ts +3 -0
- package/src/ui/pixi/components/Settings.ts +23 -8
- package/src/ui/pixi/primitives/controls.ts +7 -0
package/dist/pixi.d.ts
CHANGED
|
@@ -23,6 +23,9 @@ declare class EventEmitter<TEvents extends {}> {
|
|
|
23
23
|
* `bonus` pairs with `setBonus()` to show a game-supplied label + value (adventure, hold-and-spin,
|
|
24
24
|
* respins — anything that isn't a plain free-spins counter). */
|
|
25
25
|
type ShellMode = 'base' | 'bonus' | 'freeSpins' | 'replay';
|
|
26
|
+
/** The three independent volume sliders shown in the Settings overlay. */
|
|
27
|
+
type VolumeKey = 'master' | 'music' | 'sfx';
|
|
28
|
+
type VolumeLevels = Record<VolumeKey, number>;
|
|
26
29
|
interface CurrencyConfig {
|
|
27
30
|
symbol: string;
|
|
28
31
|
position: 'left' | 'right';
|
|
@@ -284,9 +287,13 @@ interface ShellConfig {
|
|
|
284
287
|
* opening the built-in buy-bonus overlay (e.g. the game shows its own bonus UI). The button
|
|
285
288
|
* is shown whenever this OR `features.buyBonus` is set. */
|
|
286
289
|
onBonusBuy?: () => void;
|
|
290
|
+
/** Initial Settings-overlay volume slider positions (each 0..1, defaults to 1 = 100%). The shell
|
|
291
|
+
* keeps them stateful across opens; read/update at runtime via `shell.getVolume()` /
|
|
292
|
+
* `shell.setVolume()`, and listen to `settingChange` ({ key: 'master'|'music'|'sfx' }) to apply. */
|
|
293
|
+
volumes?: Partial<VolumeLevels>;
|
|
287
294
|
}
|
|
288
295
|
/** ShellConfig after the controller applies defaults (version, isSocial, replay, theme). No mount. */
|
|
289
|
-
type ResolvedShellConfig = Required<Pick<ShellConfig, 'language' | 'currency' | 'availableBets' | 'defaultBet' | 'balance' | 'win' | 'mode' | 'features' | 'gameInfo' | 'version' | 'isSocial' | 'replay'>> & Pick<ShellConfig, 'currentBet' | 'theme' | 'onBonusBuy'>;
|
|
296
|
+
type ResolvedShellConfig = Required<Pick<ShellConfig, 'language' | 'currency' | 'availableBets' | 'defaultBet' | 'balance' | 'win' | 'mode' | 'features' | 'gameInfo' | 'version' | 'isSocial' | 'replay'>> & Pick<ShellConfig, 'currentBet' | 'theme' | 'onBonusBuy' | 'volumes'>;
|
|
290
297
|
interface ShellState {
|
|
291
298
|
mode: ShellMode;
|
|
292
299
|
/** Sticky replay marker — true for a historical-round replay, regardless of the current
|
|
@@ -311,6 +318,9 @@ interface ShellState {
|
|
|
311
318
|
/** The currently activated `feature` option (e.g. Ante), or null. Drives the
|
|
312
319
|
* effective-bet readout tint and the BUY BONUS → DISABLE toggle on the bar. */
|
|
313
320
|
activeFeature: BonusOption$1 | null;
|
|
321
|
+
/** Volume slider positions (0..1) surfaced in the Settings overlay. Stateful across opens so a
|
|
322
|
+
* reopened overlay reflects the last-set positions instead of resetting to 100%. */
|
|
323
|
+
volumes: VolumeLevels;
|
|
314
324
|
}
|
|
315
325
|
interface ShellEvents {
|
|
316
326
|
spin: void;
|
|
@@ -433,6 +443,13 @@ interface ShellHost {
|
|
|
433
443
|
setSound(on: boolean): void;
|
|
434
444
|
/** An open Settings overlay registers an icon updater here (null clears it on close). */
|
|
435
445
|
setSoundRefresh(fn: ((on: boolean) => void) | null): void;
|
|
446
|
+
/** Current volume slider position (0..1) for master/music/sfx. */
|
|
447
|
+
getVolume(key: VolumeKey): number;
|
|
448
|
+
/** Set a volume slider (0..1): clamps, stores, emits `settingChange`, and live-updates an open
|
|
449
|
+
* Settings overlay. Called by the slider control on drag AND by game code as the public API. */
|
|
450
|
+
setVolume(key: VolumeKey, value: number): void;
|
|
451
|
+
/** An open Settings overlay registers a slider updater here (null clears it on close). */
|
|
452
|
+
setVolumeRefresh(fn: ((key: VolumeKey, value: number) => void) | null): void;
|
|
436
453
|
/** Logic-bearing actions invoked by renderer controls. */
|
|
437
454
|
readonly actions: ShellActions;
|
|
438
455
|
}
|
|
@@ -496,13 +513,14 @@ declare class ShellController extends EventEmitter<ShellEvents> implements Shell
|
|
|
496
513
|
tokens: ShellTokens;
|
|
497
514
|
layout: ShellLayoutMode;
|
|
498
515
|
soundOn: boolean;
|
|
499
|
-
readonly engineVersion = "0.
|
|
516
|
+
readonly engineVersion = "0.6.0";
|
|
500
517
|
readonly actions: ShellActions;
|
|
501
518
|
private renderer;
|
|
502
519
|
private i18n;
|
|
503
520
|
private kbd?;
|
|
504
521
|
private overlay;
|
|
505
522
|
private soundRefresh;
|
|
523
|
+
private volumeRefresh;
|
|
506
524
|
private prevBalance;
|
|
507
525
|
private prevWin;
|
|
508
526
|
private destroyed;
|
|
@@ -527,6 +545,12 @@ declare class ShellController extends EventEmitter<ShellEvents> implements Shell
|
|
|
527
545
|
closeModal(): void;
|
|
528
546
|
setSound(on: boolean): void;
|
|
529
547
|
setSoundRefresh(fn: ((on: boolean) => void) | null): void;
|
|
548
|
+
getVolume(key: VolumeKey): number;
|
|
549
|
+
/** Set a volume slider (0..1). Shared by the slider control (drag) and game code (public API):
|
|
550
|
+
* clamps, stores so a reopened Settings overlay reflects it, emits `settingChange`, and
|
|
551
|
+
* live-updates the slider if the overlay is currently open. */
|
|
552
|
+
setVolume(key: VolumeKey, value: number): void;
|
|
553
|
+
setVolumeRefresh(fn: ((key: VolumeKey, value: number) => void) | null): void;
|
|
530
554
|
activateFeature(bonus: BonusOption$1): void;
|
|
531
555
|
deactivateFeature(): void;
|
|
532
556
|
private money;
|
|
@@ -566,7 +590,7 @@ interface I18n {
|
|
|
566
590
|
declare function createI18n(opts: I18nOptions): I18n;
|
|
567
591
|
|
|
568
592
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
569
|
-
declare const PACKAGE_VERSION = "0.
|
|
593
|
+
declare const PACKAGE_VERSION = "0.6.0";
|
|
570
594
|
|
|
571
595
|
/** A shell: the renderer-agnostic controller plus the surface facade (safeArea/barHeight/setVisible)
|
|
572
596
|
* an embedding host reads. `createShell`, `createGameShell` and `createPixiShell` all return this. */
|
|
@@ -706,4 +730,4 @@ declare function createPixiShell(config: PixiShellConfig): PixiGameShell;
|
|
|
706
730
|
declare function removePixiShell(): Promise<void>;
|
|
707
731
|
|
|
708
732
|
export { DEFAULT_ACCENT, PACKAGE_VERSION, PixiRenderer, SCHEMES, ShellController, createI18n, createPixiShell, createShell, normalizeLang, removePixiShell, resolveConfig, resolveTheme, socialize };
|
|
709
|
-
export type { AutoplayConfig, AutoplayOptions, BonusCardContext, BonusOption, BonusReadout, CellRef, CreateShellOptions, CurrencyConfig, FreeSpinsState, GameInfoContent, GameInfoSection, GameMode, I18n, I18nOptions, Lang, ModalAction, ModalOptions, OverlayHandle, OverlayRequest, PaylineDef, PaytableRow, PixiGameShell, PixiShellConfig, PixiShellSurface, ReplayModalOptions, ResolvedShellConfig, SafeArea, ShapeDef, Shell, ShellActions, ShellConfig, ShellEvents, ShellFeatures, ShellHost, ShellLayoutMode, ShellMode, ShellRenderer, ShellState, ShellSurface, ShellTokens, ThemeConfig, WinSection };
|
|
733
|
+
export type { AutoplayConfig, AutoplayOptions, BonusCardContext, BonusOption, BonusReadout, CellRef, CreateShellOptions, CurrencyConfig, FreeSpinsState, GameInfoContent, GameInfoSection, GameMode, I18n, I18nOptions, Lang, ModalAction, ModalOptions, OverlayHandle, OverlayRequest, PaylineDef, PaytableRow, PixiGameShell, PixiShellConfig, PixiShellSurface, ReplayModalOptions, ResolvedShellConfig, SafeArea, ShapeDef, Shell, ShellActions, ShellConfig, ShellEvents, ShellFeatures, ShellHost, ShellLayoutMode, ShellMode, ShellRenderer, ShellState, ShellSurface, ShellTokens, ThemeConfig, VolumeKey, VolumeLevels, WinSection };
|
package/dist/pixi.esm.js
CHANGED
|
@@ -66,8 +66,17 @@ function createInitialState(config) {
|
|
|
66
66
|
freeSpins: { current: 0, total: 0, totalWin: 0 },
|
|
67
67
|
bonus: null,
|
|
68
68
|
activeFeature: null,
|
|
69
|
+
volumes: {
|
|
70
|
+
master: clampVolume(config.volumes?.master),
|
|
71
|
+
music: clampVolume(config.volumes?.music),
|
|
72
|
+
sfx: clampVolume(config.volumes?.sfx),
|
|
73
|
+
},
|
|
69
74
|
};
|
|
70
75
|
}
|
|
76
|
+
/** Clamp a configured volume to 0..1, defaulting to full (1) when unset/invalid. */
|
|
77
|
+
function clampVolume(v) {
|
|
78
|
+
return typeof v === 'number' && Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 1;
|
|
79
|
+
}
|
|
71
80
|
/** Step bet up/down within availableBets, clamped at the ends. */
|
|
72
81
|
function stepBet(state, direction) {
|
|
73
82
|
const idx = state.availableBets.indexOf(state.bet);
|
|
@@ -1438,7 +1447,7 @@ class KeyboardController {
|
|
|
1438
1447
|
|
|
1439
1448
|
// AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
|
|
1440
1449
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
1441
|
-
const PACKAGE_VERSION = '0.
|
|
1450
|
+
const PACKAGE_VERSION = '0.6.0';
|
|
1442
1451
|
|
|
1443
1452
|
/** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
|
|
1444
1453
|
function resolveConfig(config) {
|
|
@@ -1455,6 +1464,7 @@ function resolveConfig(config) {
|
|
|
1455
1464
|
features: config.features,
|
|
1456
1465
|
theme: config.theme,
|
|
1457
1466
|
onBonusBuy: config.onBonusBuy,
|
|
1467
|
+
volumes: config.volumes,
|
|
1458
1468
|
version: config.version ?? '1.0.0',
|
|
1459
1469
|
isSocial: config.isSocial ?? false,
|
|
1460
1470
|
replay: config.replay ?? config.mode === 'replay',
|
|
@@ -1476,6 +1486,7 @@ class ShellController extends EventEmitter {
|
|
|
1476
1486
|
kbd;
|
|
1477
1487
|
overlay = null;
|
|
1478
1488
|
soundRefresh = null;
|
|
1489
|
+
volumeRefresh = null;
|
|
1479
1490
|
prevBalance;
|
|
1480
1491
|
prevWin;
|
|
1481
1492
|
destroyed = false;
|
|
@@ -1659,6 +1670,7 @@ class ShellController extends EventEmitter {
|
|
|
1659
1670
|
return;
|
|
1660
1671
|
this.overlay = null;
|
|
1661
1672
|
this.soundRefresh = null;
|
|
1673
|
+
this.volumeRefresh = null;
|
|
1662
1674
|
this.renderer.closeOverlay();
|
|
1663
1675
|
}
|
|
1664
1676
|
// ── sound ──────────────────────────────────────────────────────────────────
|
|
@@ -1671,6 +1683,22 @@ class ShellController extends EventEmitter {
|
|
|
1671
1683
|
setSoundRefresh(fn) {
|
|
1672
1684
|
this.soundRefresh = fn;
|
|
1673
1685
|
}
|
|
1686
|
+
// ── volume ─────────────────────────────────────────────────────────────────
|
|
1687
|
+
getVolume(key) {
|
|
1688
|
+
return this.state.volumes[key];
|
|
1689
|
+
}
|
|
1690
|
+
/** Set a volume slider (0..1). Shared by the slider control (drag) and game code (public API):
|
|
1691
|
+
* clamps, stores so a reopened Settings overlay reflects it, emits `settingChange`, and
|
|
1692
|
+
* live-updates the slider if the overlay is currently open. */
|
|
1693
|
+
setVolume(key, value) {
|
|
1694
|
+
const v = Math.max(0, Math.min(1, value));
|
|
1695
|
+
this.state.volumes[key] = v;
|
|
1696
|
+
this.emit('settingChange', { key, value: v });
|
|
1697
|
+
this.volumeRefresh?.(key, v);
|
|
1698
|
+
}
|
|
1699
|
+
setVolumeRefresh(fn) {
|
|
1700
|
+
this.volumeRefresh = fn;
|
|
1701
|
+
}
|
|
1674
1702
|
// ── features ─────────────────────────────────────────────────────────────────
|
|
1675
1703
|
activateFeature(bonus) {
|
|
1676
1704
|
this.state.activeFeature = bonus;
|
|
@@ -3947,6 +3975,12 @@ class Slider extends Container {
|
|
|
3947
3975
|
this.thumb.circle(cx, cy, r).fill('#ffffff');
|
|
3948
3976
|
this.hitArea = new Rectangle(0, 0, this.w, h);
|
|
3949
3977
|
}
|
|
3978
|
+
/** Programmatically move the thumb (0..1) without firing onInput — for live updates driven by
|
|
3979
|
+
* `host.setVolume()` while the overlay is open. */
|
|
3980
|
+
setValue(v) {
|
|
3981
|
+
this._value = Math.max(0, Math.min(1, v));
|
|
3982
|
+
this.draw();
|
|
3983
|
+
}
|
|
3950
3984
|
setLayoutSize(w) {
|
|
3951
3985
|
if (w != null)
|
|
3952
3986
|
this.w = w;
|
|
@@ -4035,10 +4069,13 @@ function buildBody$1(host, width) {
|
|
|
4035
4069
|
speaker.active = on;
|
|
4036
4070
|
});
|
|
4037
4071
|
col.add(glassRow(host, [textNode(host, host.t('Sound')), new Spacer(), speaker]));
|
|
4038
|
-
// Volume sliders
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
col.add(sliderRow(host, width, '
|
|
4072
|
+
// Volume sliders — positions read from the shell's stored volumes (stateful across opens); the
|
|
4073
|
+
// registered refreshers let `host.setVolume()` from game code move the thumbs live.
|
|
4074
|
+
const updaters = {};
|
|
4075
|
+
col.add(sliderRow(host, width, 'master', host.t('Master volume'), updaters));
|
|
4076
|
+
col.add(sliderRow(host, width, 'music', host.t('Music'), updaters));
|
|
4077
|
+
col.add(sliderRow(host, width, 'sfx', host.t('SFX'), updaters));
|
|
4078
|
+
host.setVolumeRefresh?.((key, v) => updaters[key]?.(v));
|
|
4042
4079
|
// Game info link
|
|
4043
4080
|
const infoIcon = makeIcon('info', 22, '#ffffff');
|
|
4044
4081
|
const infoLabel = textNode(host, host.t('Game info'));
|
|
@@ -4082,7 +4119,7 @@ function glassRow(host, children, opts = {}) {
|
|
|
4082
4119
|
return row;
|
|
4083
4120
|
}
|
|
4084
4121
|
/** A column row: head (label + live % value) over a draggable slider. */
|
|
4085
|
-
function sliderRow(host, bodyWidth, key, label) {
|
|
4122
|
+
function sliderRow(host, bodyWidth, key, label, updaters) {
|
|
4086
4123
|
const row = new FlexBox({
|
|
4087
4124
|
direction: 'column',
|
|
4088
4125
|
align: 'stretch',
|
|
@@ -4091,14 +4128,19 @@ function sliderRow(host, bodyWidth, key, label) {
|
|
|
4091
4128
|
background: { fill: host.tokens.plaqueGlass, radius: 16 },
|
|
4092
4129
|
});
|
|
4093
4130
|
const head = new FlexBox({ direction: 'row', align: 'center', justify: 'space-between' });
|
|
4094
|
-
const
|
|
4131
|
+
const initial = host.getVolume(key);
|
|
4132
|
+
const valueText = makeText(`${Math.round(initial * 100)}%`, { size: 13, weight: '700', color: host.tokens.plaqueLabel });
|
|
4095
4133
|
head.add(makeText(label, { size: 14, weight: '600', color: '#ffffff' }));
|
|
4096
4134
|
head.add(new Spacer(), { grow: 1 });
|
|
4097
4135
|
head.add(valueText);
|
|
4098
|
-
const slider = new Slider(host,
|
|
4136
|
+
const slider = new Slider(host, initial, (v) => {
|
|
4099
4137
|
valueText.text = `${Math.round(v * 100)}%`;
|
|
4100
|
-
host.
|
|
4138
|
+
host.setVolume(key, v);
|
|
4101
4139
|
});
|
|
4140
|
+
updaters[key] = (v) => {
|
|
4141
|
+
valueText.text = `${Math.round(v * 100)}%`;
|
|
4142
|
+
slider.setValue(v);
|
|
4143
|
+
};
|
|
4102
4144
|
row.add(head);
|
|
4103
4145
|
row.add(slider);
|
|
4104
4146
|
return row;
|
|
@@ -6128,6 +6170,9 @@ class PixiRenderer {
|
|
|
6128
6170
|
notifyResize: (w, h) => host.notifyResize(w, h),
|
|
6129
6171
|
setSound: (on) => host.setSound(on),
|
|
6130
6172
|
setSoundRefresh: (fn) => host.setSoundRefresh(fn),
|
|
6173
|
+
getVolume: (key) => host.getVolume(key),
|
|
6174
|
+
setVolume: (key, v) => host.setVolume(key, v),
|
|
6175
|
+
setVolumeRefresh: (fn) => host.setVolumeRefresh(fn),
|
|
6131
6176
|
// — Pixi-specific surface —
|
|
6132
6177
|
get ticker() { return self.app.ticker; },
|
|
6133
6178
|
get canvas() { return self.app.canvas; },
|