@energy8platform/platform-core 0.20.0 → 0.21.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/README.md +194 -0
- package/dist/index.cjs.js +1940 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +302 -2
- package/dist/index.esm.js +1938 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/shell.cjs.js +1993 -0
- package/dist/shell.cjs.js.map +1 -0
- package/dist/shell.d.ts +320 -0
- package/dist/shell.esm.js +1989 -0
- package/dist/shell.esm.js.map +1 -0
- package/package.json +6 -1
- package/scripts/build-shell-font.mjs +64 -0
- package/src/index.ts +16 -0
- package/src/shell/GameShell.ts +294 -0
- package/src/shell/INTER-LICENSE.txt +93 -0
- package/src/shell/colors.ts +32 -0
- package/src/shell/components/BottomBar.ts +217 -0
- package/src/shell/components/BuyBonus.ts +163 -0
- package/src/shell/components/GameInfo.ts +253 -0
- package/src/shell/components/Modal.ts +36 -0
- package/src/shell/components/ReplayModal.ts +56 -0
- package/src/shell/components/Settings.ts +60 -0
- package/src/shell/components/icons.ts +40 -0
- package/src/shell/components/pickers.ts +76 -0
- package/src/shell/components/primitives.ts +84 -0
- package/src/shell/fonts.ts +13 -0
- package/src/shell/format.ts +36 -0
- package/src/shell/i18n.ts +67 -0
- package/src/shell/index.ts +20 -0
- package/src/shell/motion.ts +43 -0
- package/src/shell/shell.css.ts +371 -0
- package/src/shell/state.ts +30 -0
- package/src/shell/theme.ts +56 -0
- package/src/shell/types.ts +191 -0
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ If you want the full PixiJS engine on top of this, install [`@energy8platform/ga
|
|
|
21
21
|
- [Vite Plugins](#vite-plugins)
|
|
22
22
|
- [Asset Manifest type](#asset-manifest-type)
|
|
23
23
|
- [Pairing with another renderer](#pairing-with-another-renderer)
|
|
24
|
+
- [Branded Game Shell](#branded-game-shell)
|
|
24
25
|
- [Sub-path exports](#sub-path-exports)
|
|
25
26
|
- [License](#license)
|
|
26
27
|
|
|
@@ -607,6 +608,198 @@ Nothing in this code is Pixi-specific. The same pattern fits Three.js, Babylon,
|
|
|
607
608
|
|
|
608
609
|
---
|
|
609
610
|
|
|
611
|
+
## Branded Game Shell
|
|
612
|
+
|
|
613
|
+
`@energy8platform/platform-core/shell` is a **vanilla-DOM UI overlay** you layer over the game
|
|
614
|
+
canvas — no Pixi, no React, no framework. It owns the control bar (3 modes: base / freeSpins /
|
|
615
|
+
replay), the menu, settings, the game-info panel, and a buy-bonus selection overlay, plus generic
|
|
616
|
+
modals and a replay summary. Branded Energy8 chrome, fully renderer-agnostic — pair it with Pixi,
|
|
617
|
+
Phaser, Three.js, or a custom engine.
|
|
618
|
+
|
|
619
|
+
> Also re-exported from `@energy8platform/game-engine/shell` — same module, no extra install for
|
|
620
|
+
> Pixi consumers.
|
|
621
|
+
|
|
622
|
+
### Mental model
|
|
623
|
+
|
|
624
|
+
The shell is **fully driven by the game** (single source of truth). It does **not** subscribe to
|
|
625
|
+
the SDK/session and holds no game logic. You:
|
|
626
|
+
|
|
627
|
+
1. **Feed state in** — once via the config object, then over time via `set*` methods.
|
|
628
|
+
2. **React to player intent out** — subscribe to typed events (`spin`, `betChange`, …) and run
|
|
629
|
+
your game logic, then push the resulting state back via setters.
|
|
630
|
+
|
|
631
|
+
This keeps replay and mid-spin restore deterministic: the shell never decides anything, it only
|
|
632
|
+
renders what you tell it and reports what the player tapped.
|
|
633
|
+
|
|
634
|
+
### Quick start
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
import { createGameShell, removeGameShell } from '@energy8platform/platform-core/shell';
|
|
638
|
+
|
|
639
|
+
const shell = createGameShell({
|
|
640
|
+
mount: document.getElementById('game')!, // shell appends its DOM here (position it relative)
|
|
641
|
+
language: 'en',
|
|
642
|
+
currency: { symbol: '€', position: 'left' },
|
|
643
|
+
availableBets: [0.2, 0.5, 1, 2, 5],
|
|
644
|
+
defaultBet: 1,
|
|
645
|
+
currentBet: null, // null → start at defaultBet; or restore a saved bet
|
|
646
|
+
balance: 1000,
|
|
647
|
+
win: 0,
|
|
648
|
+
mode: 'base',
|
|
649
|
+
gameInfo: { sections: [{ type: 'controls' }] }, // see "Game info" below
|
|
650
|
+
features: {
|
|
651
|
+
turbo: 3, // 0 = no turbo button, 1–3 = number of turbo levels
|
|
652
|
+
autoplay: true,
|
|
653
|
+
buyBonus: [
|
|
654
|
+
{ id: 'fs', type: 'bonus', title: 'Buy Free Spins', description: '10 free spins',
|
|
655
|
+
priceMultiplier: 100, volatility: 5 },
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
// ── player intent (shell → game) ──
|
|
661
|
+
shell.on('spin', () => runSpin(shell.state.bet));
|
|
662
|
+
shell.on('betChange', (bet) => { myState.bet = bet; });
|
|
663
|
+
shell.on('buyBonusSelect', ({ id }) => buyFeature(id));
|
|
664
|
+
|
|
665
|
+
// ── game state (game → shell) ──
|
|
666
|
+
shell.setBusy(true); // disable controls during an active spin
|
|
667
|
+
shell.setBalance(980);
|
|
668
|
+
shell.setWin(20); // both readouts count up automatically
|
|
669
|
+
shell.setBusy(false);
|
|
670
|
+
|
|
671
|
+
// teardown (single shell per page; fades out, resolves when removed)
|
|
672
|
+
await removeGameShell();
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
`createGameShell` is a **singleton** — calling it twice returns the existing shell. Use
|
|
676
|
+
`removeGameShell()` to dispose before creating another.
|
|
677
|
+
|
|
678
|
+
### Config reference (`ShellConfig`)
|
|
679
|
+
|
|
680
|
+
| Field | Type | Notes |
|
|
681
|
+
| --- | --- | --- |
|
|
682
|
+
| `mount` | `HTMLElement` | Container the shell DOM is appended into. Give it `position: relative`. |
|
|
683
|
+
| `theme` | `ThemeConfig?` | `{ scheme?: 'dark' \| 'light', accent?, buyBonusColor? }`. Defaults to dark. |
|
|
684
|
+
| `language` | `string` | Currently `'en'` is the source language. |
|
|
685
|
+
| `isSocial` | `boolean?` | Swap built-in text to social-casino vocabulary (bet → play, win → …). Game-supplied strings are untouched. |
|
|
686
|
+
| `currency` | `CurrencyConfig` | `{ symbol, position: 'left'\|'right', decimals?, minDecimals?, separator? }`. |
|
|
687
|
+
| `availableBets` | `number[]` | Bet ladder shown in the bet picker. |
|
|
688
|
+
| `defaultBet` / `currentBet` | `number` / `number \| null` | `currentBet` restores a saved bet; `null` falls back to `defaultBet`. |
|
|
689
|
+
| `balance` / `win` | `number` | Initial readouts. |
|
|
690
|
+
| `mode` | `'base' \| 'freeSpins' \| 'replay'` | Drives which bottom-bar variant renders. |
|
|
691
|
+
| `gameInfo` | `GameInfoContent` | Sections for the game-info overlay (see below). |
|
|
692
|
+
| `features` | `ShellFeatures` | `{ turbo: 0–3, autoplay, buyBonus: BonusOption[] \| false }`. |
|
|
693
|
+
|
|
694
|
+
### Events (`shell.on(name, handler)`)
|
|
695
|
+
|
|
696
|
+
| Event | Payload | When |
|
|
697
|
+
| --- | --- | --- |
|
|
698
|
+
| `spin` | — | Spin disc tapped (or Spacebar in base mode). |
|
|
699
|
+
| `betChange` | `number` | Player confirmed a new bet. |
|
|
700
|
+
| `autoplayStart` / `autoplayStop` | `{ active, remaining }` / — | Autoplay picker confirmed / stopped. |
|
|
701
|
+
| `turboChange` | `number` | Turbo level cycled. |
|
|
702
|
+
| `buyBonusSelect` | `{ id }` | A `type: 'bonus'` card was bought. |
|
|
703
|
+
| `featureActivate` / `featureDeactivate` | `{ id }` | A `type: 'feature'` option (e.g. Ante) toggled. |
|
|
704
|
+
| `menuOpen` / `settingsOpen` / `infoOpen` | — | Overlay opened. |
|
|
705
|
+
| `settingChange` | `{ key, value }` | Settings control changed. Keys: `sound` (bool), `master` / `music` / `sfx` (0–100). |
|
|
706
|
+
|
|
707
|
+
### State setters (`game → shell`)
|
|
708
|
+
|
|
709
|
+
Each setter updates `shell.state` and re-renders. `setBalance` / `setWin` animate a count-up from
|
|
710
|
+
the previous value.
|
|
711
|
+
|
|
712
|
+
```typescript
|
|
713
|
+
shell.setBalance(n); shell.setWin(n); shell.setBet(n);
|
|
714
|
+
shell.setBusy(true); // disables controls mid-spin
|
|
715
|
+
shell.setMode('freeSpins');
|
|
716
|
+
shell.setFreeSpins({ current: 1, total: 10, totalWin: 0, lastWin: 0 }); // freeSpins bar readout
|
|
717
|
+
shell.setAutoplay({ active: true, remaining: 25 });
|
|
718
|
+
shell.setTurbo(2);
|
|
719
|
+
shell.setBuyBonusEnabled(false); // grey out BUY BONUS (e.g. insufficient balance)
|
|
720
|
+
shell.setTheme({ scheme: 'light' }); // recolour at runtime
|
|
721
|
+
shell.setSocial(true); // swap vocabulary at runtime (reopen overlays to refresh them)
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
Read current state any time via `shell.state` (`ShellState`: `mode`, `balance`, `win`, `bet`,
|
|
725
|
+
`busy`, `autoplay`, `turbo`, `freeSpins`, `activeFeature`, …).
|
|
726
|
+
|
|
727
|
+
### Buy bonus & features
|
|
728
|
+
|
|
729
|
+
`features.buyBonus` is an array of cards. `type: 'bonus'` buys into a round (emits
|
|
730
|
+
`buyBonusSelect`); `type: 'feature'` toggles a base-game modifier like Ante. For features, drive
|
|
731
|
+
the bar readout with:
|
|
732
|
+
|
|
733
|
+
```typescript
|
|
734
|
+
shell.activateFeature(option); // bar shows the effective bet, BUY BONUS → DISABLE
|
|
735
|
+
shell.deactivateFeature(); // revert
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
Each card price renders as `priceMultiplier × current bet` in the shell currency.
|
|
739
|
+
|
|
740
|
+
### Game info (`gameInfo.sections`)
|
|
741
|
+
|
|
742
|
+
The game-info overlay is composed from typed sections — declare what your game has and the shell
|
|
743
|
+
draws the rest:
|
|
744
|
+
|
|
745
|
+
- `{ type: 'modes', modes: GameMode[] }` — comparison table (title / price / rtp / maxWin).
|
|
746
|
+
- `{ type: 'controls' }` — auto-generated control legend.
|
|
747
|
+
- `{ type: 'paytable', rows: PaytableRow[] }` — symbol → win tiers (`"<count> x<multiplier>"`).
|
|
748
|
+
- `{ type: 'wins', kind, grid, … }` — auto-drawn win illustration. `kind` is `'classic'` (paylines),
|
|
749
|
+
`'cluster'`, `'anywhere'`, or `'ways'`.
|
|
750
|
+
- `{ type: 'custom', title, html | node }` — your own rules markup.
|
|
751
|
+
|
|
752
|
+
```typescript
|
|
753
|
+
gameInfo: {
|
|
754
|
+
sections: [
|
|
755
|
+
{ type: 'modes', modes: [{ title: 'Base game', price: '1× bet', rtp: 96.5, maxWin: '5,000×' }] },
|
|
756
|
+
{ type: 'controls' },
|
|
757
|
+
{ type: 'paytable', rows: [
|
|
758
|
+
{ symbol: { text: 'Wild' }, wins: [{ count: '5', multiplier: 250 }, { count: '3', multiplier: 50 }] },
|
|
759
|
+
] },
|
|
760
|
+
{ type: 'wins', kind: 'classic', grid: { cols: 5, rows: 3 },
|
|
761
|
+
lines: [[1,1,1,1,1], [0,0,0,0,0], [2,2,2,2,2]] },
|
|
762
|
+
{ type: 'custom', title: 'Rules', html: '<p>Match left to right on adjacent reels.</p>' },
|
|
763
|
+
],
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Opening overlays & modals programmatically
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
shell.openSettings(); shell.openInfo(); shell.openBuyBonus();
|
|
771
|
+
shell.openBetPicker(); shell.openAutoplayPicker();
|
|
772
|
+
|
|
773
|
+
// generic card modal
|
|
774
|
+
shell.openModal({
|
|
775
|
+
availableClose: true,
|
|
776
|
+
title: 'Connection lost',
|
|
777
|
+
body: 'Reconnecting…',
|
|
778
|
+
actions: [{ title: 'Retry', color: '#e11', on: () => reconnect() }],
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// non-dismissable replay summary (START REPLAY → onReplay → reopen)
|
|
782
|
+
shell.openReplay({ bonusId: 'fs', bet: shell.state.bet, payoutMultiplier: 87.5,
|
|
783
|
+
onReplay: () => playRecordedRound() });
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Layout & visual system
|
|
787
|
+
|
|
788
|
+
Transparent neutral chrome that doesn't compete with the game — brand colour appears only on the
|
|
789
|
+
BUY BONUS control and a duotone icon set. The bottom bar **adapts by viewport** automatically (a
|
|
790
|
+
`ResizeObserver` on the mount): landscape → one row scaled to fit, portrait → stacked mobile
|
|
791
|
+
layout; Settings / Game info / Buy bonus open as full-screen overlays. Motion is minimal (press
|
|
792
|
+
feedback, money count-up, overlay fades) and respects `prefers-reduced-motion`. Spacebar triggers
|
|
793
|
+
a spin in base mode (ignored while busy, in autoplay, or when a modal/input is focused).
|
|
794
|
+
|
|
795
|
+
### Live demo
|
|
796
|
+
|
|
797
|
+
[`examples/shell-demo`](../../examples/shell-demo) is a full reference integration: every config
|
|
798
|
+
section, all three bar modes, theme/social toggles, viewport presets, and event wiring. QA params:
|
|
799
|
+
`?screen=<id>&kiosk=1&open=settings|info|buybonus`.
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
610
803
|
## Sub-path exports
|
|
611
804
|
|
|
612
805
|
| Path | What's there |
|
|
@@ -617,6 +810,7 @@ Nothing in this code is Pixi-specific. The same pattern fits Three.js, Babylon,
|
|
|
617
810
|
| `@energy8platform/platform-core/dev-bridge` | `DevBridge`, `DevBridgeConfig`, `ReplayConfig`, `ReplayLaunch` |
|
|
618
811
|
| `@energy8platform/platform-core/vite` | `devBridgePlugin`, `luaPlugin` |
|
|
619
812
|
| `@energy8platform/platform-core/loading` | `createCSSPreloader`, `setCSSPreloaderProgress`, `waitCSSPreloaderTap`, `removeCSSPreloader`, `buildLogoSVG`, `LOADER_BAR_MAX_WIDTH` |
|
|
813
|
+
| `@energy8platform/platform-core/shell` | `createGameShell`, `removeGameShell` — branded renderer-agnostic DOM game shell (control bar, menu, settings, game info, buy bonus) |
|
|
620
814
|
|
|
621
815
|
The sub-paths exist for tree-shaking — pulling only `/lua` doesn't drag in DevBridge or vite types. The main entry is convenient for app-level code where size hardly matters.
|
|
622
816
|
|