@energy8platform/game-engine 0.20.0 → 0.22.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.
Files changed (93) hide show
  1. package/README.md +121 -0
  2. package/dist/animation.cjs.js +18 -3
  3. package/dist/animation.cjs.js.map +1 -1
  4. package/dist/animation.esm.js +18 -3
  5. package/dist/animation.esm.js.map +1 -1
  6. package/dist/core.cjs.js +18 -3
  7. package/dist/core.cjs.js.map +1 -1
  8. package/dist/core.esm.js +18 -3
  9. package/dist/core.esm.js.map +1 -1
  10. package/dist/host.cjs.js +18 -3
  11. package/dist/host.cjs.js.map +1 -1
  12. package/dist/host.d.ts +3 -5
  13. package/dist/host.esm.js +18 -3
  14. package/dist/host.esm.js.map +1 -1
  15. package/dist/index.cjs.js +18 -2535
  16. package/dist/index.cjs.js.map +1 -1
  17. package/dist/index.d.ts +3 -1020
  18. package/dist/index.esm.js +20 -2525
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/slot.cjs.js +1872 -61
  21. package/dist/slot.cjs.js.map +1 -1
  22. package/dist/slot.d.ts +555 -28
  23. package/dist/slot.esm.js +1857 -62
  24. package/dist/slot.esm.js.map +1 -1
  25. package/dist/vite.cjs.js +0 -5
  26. package/dist/vite.cjs.js.map +1 -1
  27. package/dist/vite.esm.js +0 -5
  28. package/dist/vite.esm.js.map +1 -1
  29. package/package.json +2 -35
  30. package/src/animation/Tween.ts +14 -3
  31. package/src/host/index.ts +0 -1
  32. package/src/host/types.ts +0 -3
  33. package/src/index.ts +0 -28
  34. package/src/slot/anim/easing-map.ts +16 -2
  35. package/src/slot/cascade/TumbleController.ts +230 -0
  36. package/src/slot/config/ReelSystemConfig.ts +559 -0
  37. package/src/slot/config/presets.ts +222 -0
  38. package/src/slot/features/extra.ts +189 -0
  39. package/src/slot/features/index.ts +44 -0
  40. package/src/slot/features/symbols.ts +183 -0
  41. package/src/slot/features/types.ts +136 -0
  42. package/src/slot/features/wilds.ts +151 -0
  43. package/src/slot/grid/ReelGrid.ts +93 -24
  44. package/src/slot/grid/SymbolCell.ts +45 -11
  45. package/src/slot/index.ts +61 -2
  46. package/src/slot/motion/AnticipationController.ts +96 -0
  47. package/src/slot/motion/SpinEngine.ts +384 -0
  48. package/src/slot/system/ReelSystem.ts +295 -0
  49. package/src/vite/index.ts +0 -5
  50. package/dist/react-jsx.cjs.js +0 -3
  51. package/dist/react-jsx.cjs.js.map +0 -1
  52. package/dist/react-jsx.d.ts +0 -602
  53. package/dist/react-jsx.esm.js +0 -2
  54. package/dist/react-jsx.esm.js.map +0 -1
  55. package/dist/react.cjs.js +0 -3787
  56. package/dist/react.cjs.js.map +0 -1
  57. package/dist/react.d.ts +0 -1467
  58. package/dist/react.esm.js +0 -3771
  59. package/dist/react.esm.js.map +0 -1
  60. package/dist/ui.cjs.js +0 -2999
  61. package/dist/ui.cjs.js.map +0 -1
  62. package/dist/ui.d.ts +0 -1116
  63. package/dist/ui.esm.js +0 -2983
  64. package/dist/ui.esm.js.map +0 -1
  65. package/src/react/EngineContext.ts +0 -26
  66. package/src/react/ReactScene.ts +0 -88
  67. package/src/react/applyProps.ts +0 -271
  68. package/src/react/catalogue.ts +0 -17
  69. package/src/react/createPixiRoot.ts +0 -31
  70. package/src/react/extendAll.ts +0 -74
  71. package/src/react/hooks.ts +0 -46
  72. package/src/react/index.ts +0 -29
  73. package/src/react/jsx-runtime.ts +0 -346
  74. package/src/react/reconciler.ts +0 -338
  75. package/src/slot/freeSpins/FreeSpinsSession.ts +0 -40
  76. package/src/state/StateMachine.ts +0 -231
  77. package/src/state/index.ts +0 -1
  78. package/src/ui/BalanceDisplay.ts +0 -159
  79. package/src/ui/Button.ts +0 -304
  80. package/src/ui/FlexContainer.ts +0 -775
  81. package/src/ui/Label.ts +0 -124
  82. package/src/ui/LabelValue.ts +0 -122
  83. package/src/ui/Layout.ts +0 -291
  84. package/src/ui/Modal.ts +0 -170
  85. package/src/ui/Panel.ts +0 -204
  86. package/src/ui/ProgressBar.ts +0 -170
  87. package/src/ui/ScrollContainer.ts +0 -478
  88. package/src/ui/Slider.ts +0 -241
  89. package/src/ui/Toast.ts +0 -150
  90. package/src/ui/Toggle.ts +0 -201
  91. package/src/ui/WinDisplay.ts +0 -145
  92. package/src/ui/index.ts +0 -33
  93. package/src/ui/view.ts +0 -28
@@ -5,10 +5,24 @@ import type { EasingFunction } from '../../types';
5
5
  /** Resolve a descriptor's string easing name to the engine's easing function. */
6
6
  export const EASING_BY_NAME: Record<string, EasingFunction> = {
7
7
  linear: Easing.linear,
8
+ easeInQuad: Easing.easeInQuad,
8
9
  easeOutQuad: Easing.easeOutQuad,
10
+ easeInOutQuad: Easing.easeInOutQuad,
11
+ easeInCubic: Easing.easeInCubic,
9
12
  easeOutCubic: Easing.easeOutCubic,
13
+ easeInOutCubic: Easing.easeInOutCubic,
14
+ easeInBack: Easing.easeInBack,
10
15
  easeOutBack: Easing.easeOutBack,
16
+ easeInOutBack: Easing.easeInOutBack,
11
17
  easeOutBounce: Easing.easeOutBounce,
12
- easeInBack: Easing.easeInBack,
13
- easeInOutCubic: Easing.easeInOutCubic,
18
+ easeInBounce: Easing.easeInBounce,
19
+ easeOutElastic: Easing.easeOutElastic,
20
+ easeInSine: Easing.easeInSine,
21
+ easeOutSine: Easing.easeOutSine,
22
+ easeInOutSine: Easing.easeInOutSine,
14
23
  };
24
+
25
+ /** Resolve an easing name to a function, falling back to easeOutQuad. */
26
+ export function easingByName(name?: string): EasingFunction {
27
+ return (name && EASING_BY_NAME[name]) || Easing.easeOutQuad;
28
+ }
@@ -0,0 +1,230 @@
1
+ // packages/game-engine/src/slot/cascade/TumbleController.ts
2
+ //
3
+ // Richer cascade/tumble than the back-compat CascadeController: animates surviving symbols
4
+ // sliding into the gaps (gravity), supports per-step deceleration (tension build), dimming of
5
+ // non-winning symbols, and a running win multiplier (Pragmatic Tumble / NetEnt Avalanche style).
6
+ //
7
+ // Presentation only — the settled board is provided by the caller.
8
+
9
+ import { Tween } from '../../animation';
10
+ import { easingByName } from '../anim/easing-map';
11
+ import type { ReelGrid } from '../grid/ReelGrid';
12
+ import type { CellData } from '../grid/SymbolCell';
13
+ import {
14
+ DEFAULT_REEL_CONFIG,
15
+ type CascadeConfig,
16
+ type WinConfig,
17
+ } from '../config/ReelSystemConfig';
18
+
19
+ export interface TumbleStep {
20
+ winningCells: { col: number; row: number }[];
21
+ removedCells: { col: number; row: number }[];
22
+ /** Optional explicit survivor slides (col, fromRow→toRow). When omitted, gravity is derived. */
23
+ drops?: { col: number; fromRow: number; toRow: number }[];
24
+ newCells: { col: number; row: number; symbol: string }[];
25
+ settledGrid: CellData[][];
26
+ }
27
+
28
+ export class TumbleController {
29
+ private _grid: ReelGrid;
30
+ private _cfg: CascadeConfig;
31
+ private _win: WinConfig = DEFAULT_REEL_CONFIG.win;
32
+ private _killed = false;
33
+ private _mult: number;
34
+
35
+ constructor(grid: ReelGrid, cfg: CascadeConfig, win?: WinConfig) {
36
+ this._grid = grid;
37
+ this._cfg = cfg;
38
+ this._mult = cfg.multiplier.start;
39
+ if (win) this._win = win;
40
+ }
41
+
42
+ setConfig(cfg: CascadeConfig): void {
43
+ this._cfg = cfg;
44
+ }
45
+ setWin(win: WinConfig): void {
46
+ this._win = win;
47
+ }
48
+ /** Killed, or the grid was torn down underneath us (rebuild during a cascade). */
49
+ private get _dead(): boolean {
50
+ return this._killed || this._grid.destroyed;
51
+ }
52
+ get multiplier(): number {
53
+ return this._mult;
54
+ }
55
+ resetMultiplier(): void {
56
+ this._mult = this._cfg.multiplier.start;
57
+ }
58
+
59
+ private advanceMultiplier(): void {
60
+ const m = this._cfg.multiplier;
61
+ if (!m.enabled) return;
62
+ const next = m.mode === 'mul' ? this._mult * m.step : this._mult + m.step;
63
+ this._mult = m.cap != null ? Math.min(next, m.cap) : next;
64
+ }
65
+
66
+ /** Derive survivor slides for one column when explicit drops aren't supplied. */
67
+ private deriveDrops(step: TumbleStep): { col: number; fromRow: number; toRow: number }[] {
68
+ const removedByCol = new Map<number, Set<number>>();
69
+ for (const r of step.removedCells) {
70
+ if (!removedByCol.has(r.col)) removedByCol.set(r.col, new Set());
71
+ removedByCol.get(r.col)!.add(r.row);
72
+ }
73
+ const out: { col: number; fromRow: number; toRow: number }[] = [];
74
+ for (const [col, removed] of removedByCol) {
75
+ const rows = this._grid.rowsOf(col);
76
+ // survivors keep order and fall to the bottom; count holes below each survivor
77
+ const survivors: number[] = [];
78
+ for (let r = 0; r < rows; r++) if (!removed.has(r)) survivors.push(r);
79
+ const newCount = rows - survivors.length;
80
+ survivors.forEach((fromRow, i) => {
81
+ const toRow = newCount + i;
82
+ if (toRow !== fromRow) out.push({ col, fromRow, toRow });
83
+ });
84
+ }
85
+ return out;
86
+ }
87
+
88
+ /** Run a single cascade step. `stepIndex` drives per-step deceleration. */
89
+ async step(step: TumbleStep, stepIndex = 0, opts?: { turbo?: boolean }): Promise<void> {
90
+ if (this._grid.destroyed) return;
91
+ if (!this._cfg.enabled) {
92
+ this._grid.setGrid(step.settledGrid);
93
+ return;
94
+ }
95
+ this._killed = false;
96
+ const turbo = opts?.turbo ? 0.5 : 1;
97
+ const decel = Math.min(this._cfg.perStepDecelCap, 1 + stepIndex * this._cfg.perStepDecel);
98
+ const f = turbo * decel;
99
+ const t = this._cfg.timings;
100
+
101
+ // 1. highlight winners (+ dim others). win.highlightScale / win.glow drive the pop.
102
+ const winSet = new Set(step.winningCells.map((w) => `${w.col}:${w.row}`));
103
+ const dimmed = this._cfg.dimNonWinners && step.winningCells.length > 0;
104
+ if (dimmed) this._dim(winSet);
105
+ const hs = this._win.highlightScale;
106
+ await Promise.all(
107
+ step.winningCells.map((w) => {
108
+ const cell = this._grid.getCell(w.col, w.row);
109
+ if (this._win.glow) cell.setState({ winning: true });
110
+ return Tween.to(
111
+ cell,
112
+ { 'scale.x': hs, 'scale.y': hs },
113
+ t.highlight * f,
114
+ easingByName(this._cfg.easings.highlight),
115
+ );
116
+ }),
117
+ );
118
+ if (this._dead) {
119
+ if (dimmed) this._undim();
120
+ return;
121
+ }
122
+ await Tween.delay(t.wait * f);
123
+
124
+ // 2. remove the cleared cells (removedCells, falling back to winningCells)
125
+ const cleared = step.removedCells.length ? step.removedCells : step.winningCells;
126
+ await Promise.all(
127
+ cleared.map((w) => {
128
+ const cell = this._grid.getCell(w.col, w.row);
129
+ return Tween.to(
130
+ cell,
131
+ { 'scale.x': 0, 'scale.y': 0, alpha: 0 },
132
+ t.remove * f,
133
+ easingByName(this._cfg.easings.remove),
134
+ );
135
+ }),
136
+ );
137
+ if (this._dead) {
138
+ if (dimmed) this._undim();
139
+ return;
140
+ }
141
+ for (const w of cleared) {
142
+ const cell = this._grid.getCell(w.col, w.row);
143
+ cell.setData({ symbol: null });
144
+ cell.setState({});
145
+ cell.scale.set(1);
146
+ cell.alpha = 1;
147
+ }
148
+ this._undim();
149
+
150
+ // 3. gravity: survivors slide down, new cells drop from above
151
+ const rowStep = this._grid.cellPosition(0, 1).y - this._grid.cellPosition(0, 0).y;
152
+ const slides = this._cfg.gravity ? (step.drops ?? this.deriveDrops(step)) : [];
153
+ const anims: Promise<void>[] = [];
154
+
155
+ for (const d of slides) {
156
+ const cell = this._grid.getCell(d.col, d.toRow);
157
+ const home = this._grid.cellPosition(d.col, d.toRow);
158
+ cell.setData(step.settledGrid[d.col]?.[d.toRow] ?? { symbol: null });
159
+ cell.alpha = 1;
160
+ cell.scale.set(1);
161
+ cell.position.set(home.x, this._grid.cellPosition(d.col, d.fromRow).y);
162
+ anims.push(
163
+ Tween.to(cell, { 'position.y': home.y }, t.drop * f, easingByName(this._cfg.easings.drop)),
164
+ );
165
+ }
166
+
167
+ const perCol: Record<number, number> = {};
168
+ for (const n of step.newCells) {
169
+ const cell = this._grid.getCell(n.col, n.row);
170
+ const home = this._grid.cellPosition(n.col, n.row);
171
+ cell.setData({ symbol: n.symbol });
172
+ cell.setState({ fresh: true });
173
+ cell.alpha = 1;
174
+ cell.scale.set(1);
175
+ cell.position.set(home.x, home.y - rowStep * (this._grid.rowsOf(n.col) + 1));
176
+ const idx = (perCol[n.col] = (perCol[n.col] ?? 0) + 1);
177
+ anims.push(
178
+ (async () => {
179
+ await Tween.delay(idx * 28 * f);
180
+ if (this._dead) return;
181
+ await Tween.to(
182
+ cell,
183
+ { 'position.y': home.y },
184
+ t.refill * f,
185
+ easingByName(this._cfg.easings.drop),
186
+ );
187
+ cell.setState({});
188
+ })(),
189
+ );
190
+ }
191
+ await Promise.all(anims);
192
+ if (this._dead) return;
193
+
194
+ // 4. normalise + advance multiplier
195
+ this._grid.setGrid(step.settledGrid);
196
+ this._resetPositions();
197
+ if (step.winningCells.length) this.advanceMultiplier();
198
+ }
199
+
200
+ private _dim(winSet: Set<string>): void {
201
+ for (let c = 0; c < this._grid.cols; c++)
202
+ for (let r = 0; r < this._grid.rowsOf(c); r++)
203
+ if (!winSet.has(`${c}:${r}`)) this._grid.getCell(c, r).alpha = this._cfg.dimAlpha;
204
+ }
205
+ private _undim(): void {
206
+ for (let c = 0; c < this._grid.cols; c++)
207
+ for (let r = 0; r < this._grid.rowsOf(c); r++) {
208
+ const cell = this._grid.getCell(c, r);
209
+ if (cell.alpha !== 0) cell.alpha = 1;
210
+ }
211
+ }
212
+ private _resetPositions(): void {
213
+ if (this._grid.destroyed) return;
214
+ for (let c = 0; c < this._grid.cols; c++)
215
+ for (let r = 0; r < this._grid.rowsOf(c); r++) {
216
+ const cell = this._grid.getCell(c, r);
217
+ const { x, y } = this._grid.cellPosition(c, r);
218
+ cell.position.set(x, y);
219
+ cell.scale.set(1);
220
+ cell.alpha = 1;
221
+ }
222
+ }
223
+
224
+ skip(): void {
225
+ this._killed = true;
226
+ for (let c = 0; c < this._grid.cols; c++)
227
+ for (let r = 0; r < this._grid.rowsOf(c); r++) Tween.killTweensOf(this._grid.getCell(c, r));
228
+ this._resetPositions();
229
+ }
230
+ }