@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
@@ -1,159 +0,0 @@
1
- import { Container } from 'pixi.js';
2
- import { Label } from './Label';
3
- import { Tween } from '../animation/Tween';
4
- import { Easing } from '../animation/Easing';
5
-
6
- export interface BalanceDisplayConfig {
7
- /** Label prefix (e.g., "BALANCE") */
8
- prefix?: string;
9
- /** Text style overrides */
10
- style?: Record<string, unknown>;
11
- /** Currency code */
12
- currency?: string;
13
- /** Locale for number formatting */
14
- locale?: string;
15
- /** Max width */
16
- maxWidth?: number;
17
- /** Animate value changes */
18
- animated?: boolean;
19
- /** Animation duration in ms */
20
- animationDuration?: number;
21
- }
22
-
23
- /**
24
- * Reactive balance display component.
25
- *
26
- * Automatically formats currency and can animate value changes
27
- * with a smooth countup/countdown effect using engine Tween.
28
- *
29
- * @example
30
- * ```ts
31
- * const balance = new BalanceDisplay({ currency: 'USD', animated: true });
32
- * balance.setValue(1000);
33
- *
34
- * // Wire to SDK
35
- * sdk.on('balanceUpdate', ({ balance: val }) => balance.setValue(val));
36
- * ```
37
- */
38
- export class BalanceDisplay extends Container {
39
- readonly __uiComponent = true as const;
40
-
41
- private _prefixLabel: Label | null = null;
42
- private _valueLabel: Label;
43
- private _config: Required<Pick<BalanceDisplayConfig, 'currency' | 'locale' | 'animated' | 'animationDuration'>>;
44
- private _currentValue = 0;
45
- private _displayedValue = 0;
46
- /** Internal target for Tween animation */
47
- private _tweenTarget = { value: 0 };
48
-
49
- constructor(config: BalanceDisplayConfig = {}) {
50
- super();
51
-
52
- this._config = {
53
- currency: config.currency ?? 'USD',
54
- locale: config.locale ?? 'en-US',
55
- animated: config.animated ?? true,
56
- animationDuration: config.animationDuration ?? 500,
57
- };
58
-
59
- // Prefix label
60
- if (config.prefix) {
61
- this._prefixLabel = new Label({
62
- text: config.prefix,
63
- style: {
64
- fontSize: 16,
65
- fill: 0xaaaaaa,
66
- ...(config.style as any),
67
- },
68
- });
69
- this.addChild(this._prefixLabel);
70
- }
71
-
72
- // Value label
73
- this._valueLabel = new Label({
74
- text: '0.00',
75
- style: {
76
- fontSize: 28,
77
- fontWeight: 'bold',
78
- fill: 0xffffff,
79
- ...(config.style as any),
80
- },
81
- maxWidth: config.maxWidth,
82
- autoFit: !!config.maxWidth,
83
- });
84
- this.addChild(this._valueLabel);
85
-
86
- this.layoutLabels();
87
- }
88
-
89
- /** Current displayed value */
90
- get value(): number {
91
- return this._currentValue;
92
- }
93
-
94
- /**
95
- * Set the balance value. If animated, smoothly counts to the new value.
96
- */
97
- setValue(value: number): void {
98
- const oldValue = this._currentValue;
99
- this._currentValue = value;
100
-
101
- if (this._config.animated && oldValue !== value) {
102
- this.animateValue(oldValue, value);
103
- } else {
104
- this._displayedValue = value;
105
- this.updateDisplay();
106
- }
107
- }
108
-
109
- /**
110
- * Set the currency code.
111
- */
112
- setCurrency(currency: string): void {
113
- this._config.currency = currency;
114
- this.updateDisplay();
115
- }
116
-
117
- private animateValue(from: number, to: number): void {
118
- // Cancel any running animation
119
- Tween.killTweensOf(this._tweenTarget);
120
-
121
- this._tweenTarget.value = from;
122
- Tween.to(
123
- this._tweenTarget,
124
- { value: to },
125
- this._config.animationDuration,
126
- Easing.easeOutCubic,
127
- () => {
128
- this._displayedValue = this._tweenTarget.value;
129
- this.updateDisplay();
130
- },
131
- );
132
- }
133
-
134
- private updateDisplay(): void {
135
- this._valueLabel.setCurrency(
136
- this._displayedValue,
137
- this._config.currency,
138
- this._config.locale,
139
- );
140
- }
141
-
142
- private layoutLabels(): void {
143
- if (this._prefixLabel) {
144
- this._prefixLabel.y = -14;
145
- this._valueLabel.y = 14;
146
- }
147
- }
148
-
149
- /** React reconciler update hook */
150
- updateConfig(changed: Record<string, any>): void {
151
- if ('value' in changed) this.setValue(changed.value);
152
- if ('currency' in changed) this.setCurrency(changed.currency);
153
- }
154
-
155
- override destroy(options?: boolean | { children?: boolean; texture?: boolean; textureSource?: boolean }): void {
156
- Tween.killTweensOf(this._tweenTarget);
157
- super.destroy(options);
158
- }
159
- }
package/src/ui/Button.ts DELETED
@@ -1,304 +0,0 @@
1
- import { Container, Graphics, Text } from 'pixi.js';
2
- import { Tween } from '../animation/Tween';
3
- import { Easing } from '../animation/Easing';
4
- import { resolveView } from './view';
5
- import type { ViewInput } from './view';
6
-
7
- export type ButtonState = 'default' | 'hover' | 'pressed' | 'disabled';
8
-
9
- export interface ButtonConfig {
10
- /** Custom view for default state (string texture name, Texture, or Container) */
11
- defaultView?: ViewInput;
12
- /** Custom view for hover state */
13
- hoverView?: ViewInput;
14
- /** Custom view for pressed state */
15
- pressedView?: ViewInput;
16
- /** Custom view for disabled state */
17
- disabledView?: ViewInput;
18
-
19
- /** Width (for Graphics-based button, ignored when custom views provided) */
20
- width?: number;
21
- /** Height (for Graphics-based button) */
22
- height?: number;
23
- /** Corner radius (for Graphics-based button) */
24
- borderRadius?: number;
25
- /** Colors for each state (for Graphics-based button) */
26
- colors?: Partial<Record<ButtonState, number>>;
27
-
28
- /** Scale on press */
29
- pressScale?: number;
30
- /** Scale animation duration (ms) */
31
- animationDuration?: number;
32
- /** Start disabled */
33
- disabled?: boolean;
34
- /** Button text (rendered on top of the view) */
35
- text?: string;
36
- /** Button text style */
37
- textStyle?: Record<string, unknown>;
38
- /** Press callback */
39
- onPress?: () => void;
40
- }
41
-
42
- const DEFAULT_COLORS: Record<ButtonState, number> = {
43
- default: 0xffd700,
44
- hover: 0xffe44d,
45
- pressed: 0xccac00,
46
- disabled: 0x666666,
47
- };
48
-
49
- function makeGraphicsView(
50
- w: number, h: number, radius: number, color: number,
51
- ): Graphics {
52
- const g = new Graphics();
53
- g.roundRect(-w / 2, -h / 2, w, h, radius).fill(color);
54
- return g;
55
- }
56
-
57
- /**
58
- * Interactive button with per-state custom views and animations.
59
- *
60
- * Each visual state accepts a `ViewInput`: texture name, Texture, or any Container
61
- * (Sprite, NineSliceSprite, AnimatedSprite, custom artwork, etc).
62
- * Falls back to colored Graphics when no custom view is provided.
63
- *
64
- * @example
65
- * ```ts
66
- * // Graphics-based (quick prototyping)
67
- * const btn = new Button({
68
- * width: 200, height: 60, borderRadius: 12,
69
- * colors: { default: 0x22aa22, hover: 0x33cc33 },
70
- * text: 'SPIN',
71
- * onPress: () => spin(),
72
- * });
73
- *
74
- * // Asset-based (production art)
75
- * const btn = new Button({
76
- * defaultView: 'btn-idle',
77
- * hoverView: 'btn-hover',
78
- * pressedView: 'btn-pressed',
79
- * disabledView: 'btn-disabled',
80
- * text: 'SPIN',
81
- * onPress: () => spin(),
82
- * });
83
- *
84
- * // Custom Container view
85
- * const btn = new Button({
86
- * defaultView: myAnimatedSprite,
87
- * text: 'SPIN',
88
- * });
89
- * ```
90
- */
91
- export class Button extends Container {
92
- readonly __uiComponent = true as const;
93
-
94
- private _views: Map<ButtonState, Container> = new Map();
95
- private _state: ButtonState = 'default';
96
- private _enabled = true;
97
- private _config: Required<
98
- Pick<ButtonConfig, 'width' | 'height' | 'borderRadius' | 'pressScale' | 'animationDuration'>
99
- > & ButtonConfig;
100
- private _textObj: Text | null = null;
101
-
102
- /** Press callback */
103
- public onPress?: () => void;
104
-
105
- constructor(config: ButtonConfig = {}) {
106
- super();
107
-
108
- this._config = {
109
- width: config.width ?? 200,
110
- height: config.height ?? 60,
111
- borderRadius: config.borderRadius ?? 8,
112
- pressScale: config.pressScale ?? 0.95,
113
- animationDuration: config.animationDuration ?? 100,
114
- ...config,
115
- };
116
-
117
- this.onPress = config.onPress;
118
- this._buildViews(config);
119
-
120
- // Text
121
- if (config.text) {
122
- this._textObj = new Text({
123
- text: config.text,
124
- style: {
125
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
126
- fontSize: 20,
127
- fill: 0xffffff,
128
- fontWeight: 'bold',
129
- ...config.textStyle,
130
- },
131
- });
132
- this._textObj.anchor.set(0.5);
133
- this.addChild(this._textObj);
134
- }
135
-
136
- // Interaction
137
- this.eventMode = 'static';
138
- this.cursor = 'pointer';
139
-
140
- this.on('pointerover', this._onPointerOver, this);
141
- this.on('pointerout', this._onPointerOut, this);
142
- this.on('pointerdown', this._onPointerDown, this);
143
- this.on('pointerup', this._onPointerUp, this);
144
- this.on('pointerupoutside', this._onPointerUpOutside, this);
145
-
146
- if (config.disabled) {
147
- this.enabled = false;
148
- }
149
- }
150
-
151
- /** Current button state */
152
- get state(): ButtonState {
153
- return this._state;
154
- }
155
-
156
- /** Enable the button */
157
- enable(): void {
158
- this.enabled = true;
159
- }
160
-
161
- /** Disable the button */
162
- disable(): void {
163
- this.enabled = false;
164
- }
165
-
166
- /** Whether the button is enabled */
167
- get enabled(): boolean {
168
- return this._enabled;
169
- }
170
-
171
- set enabled(value: boolean) {
172
- this._enabled = value;
173
- this.cursor = value ? 'pointer' : 'default';
174
- this.eventMode = value ? 'static' : 'none';
175
- this._setState(value ? 'default' : 'disabled');
176
- }
177
-
178
- /** Whether the button is disabled */
179
- get disabled(): boolean {
180
- return !this._enabled;
181
- }
182
-
183
- /** Update button text */
184
- set text(value: string) {
185
- if (this._textObj) {
186
- this._textObj.text = value;
187
- }
188
- }
189
-
190
- // ─── View building ──────────────────────────────────
191
-
192
- private _buildViews(config: ButtonConfig): void {
193
- const colorMap = { ...DEFAULT_COLORS, ...config.colors };
194
- const { width, height, borderRadius } = this._config;
195
- const stateViews: Record<ButtonState, ViewInput | undefined> = {
196
- default: config.defaultView,
197
- hover: config.hoverView,
198
- pressed: config.pressedView,
199
- disabled: config.disabledView,
200
- };
201
-
202
- const states: ButtonState[] = ['default', 'hover', 'pressed', 'disabled'];
203
-
204
- for (const state of states) {
205
- const customView = resolveView(stateViews[state]);
206
- const view = customView ?? makeGraphicsView(width, height, borderRadius, colorMap[state]);
207
- view.visible = state === 'default';
208
- this._views.set(state, view);
209
- this.addChild(view);
210
- }
211
- }
212
-
213
- private _rebuildViews(): void {
214
- for (const [, view] of this._views) {
215
- this.removeChild(view);
216
- view.destroy();
217
- }
218
- this._views.clear();
219
-
220
- this._buildViews(this._config);
221
-
222
- // Re-insert views before text
223
- if (this._textObj && this._textObj.parent === this) {
224
- this.setChildIndex(this._textObj, this.children.length - 1);
225
- }
226
- }
227
-
228
- // ─── State management ───────────────────────────────
229
-
230
- private _setState(state: ButtonState): void {
231
- if (this._state === state) return;
232
- this._state = state;
233
-
234
- for (const [s, view] of this._views) {
235
- view.visible = s === state;
236
- }
237
- }
238
-
239
- private _onPointerOver(): void {
240
- if (!this._enabled) return;
241
- this._setState('hover');
242
- Tween.killTweensOf(this);
243
- Tween.to(this, { 'scale.x': 1.03, 'scale.y': 1.03 }, this._config.animationDuration, Easing.easeOutQuad);
244
- }
245
-
246
- private _onPointerOut(): void {
247
- if (!this._enabled) return;
248
- this._setState('default');
249
- Tween.killTweensOf(this);
250
- Tween.to(this, { 'scale.x': 1, 'scale.y': 1 }, this._config.animationDuration, Easing.easeOutQuad);
251
- }
252
-
253
- private _onPointerDown(): void {
254
- if (!this._enabled) return;
255
- this._setState('pressed');
256
- Tween.killTweensOf(this);
257
- const s = this._config.pressScale;
258
- Tween.to(this, { 'scale.x': s, 'scale.y': s }, this._config.animationDuration, Easing.easeOutQuad);
259
- }
260
-
261
- private _onPointerUp(): void {
262
- if (!this._enabled) return;
263
- this._setState('hover');
264
- Tween.killTweensOf(this);
265
- Tween.to(this, { 'scale.x': 1.03, 'scale.y': 1.03 }, this._config.animationDuration, Easing.easeOutQuad);
266
- this.onPress?.();
267
- }
268
-
269
- private _onPointerUpOutside(): void {
270
- if (!this._enabled) return;
271
- this._setState('default');
272
- Tween.killTweensOf(this);
273
- Tween.to(this, { 'scale.x': 1, 'scale.y': 1 }, this._config.animationDuration, Easing.easeOutQuad);
274
- }
275
-
276
- /** React reconciler update hook */
277
- updateConfig(changed: Record<string, any>): void {
278
- if ('text' in changed && this._textObj) this._textObj.text = changed.text;
279
- if ('disabled' in changed) this.enabled = !changed.disabled;
280
- if ('onPress' in changed) this.onPress = changed.onPress;
281
-
282
- const structural = [
283
- 'colors', 'width', 'height', 'borderRadius', 'textStyle',
284
- 'defaultView', 'hoverView', 'pressedView', 'disabledView',
285
- ];
286
- const needsRebuild = structural.some((k) => k in changed);
287
- if (needsRebuild) {
288
- Object.assign(this._config, changed);
289
- this._rebuildViews();
290
- }
291
- }
292
-
293
- override destroy(options?: boolean | { children?: boolean; texture?: boolean; textureSource?: boolean }): void {
294
- Tween.killTweensOf(this);
295
- this.off('pointerover', this._onPointerOver, this);
296
- this.off('pointerout', this._onPointerOut, this);
297
- this.off('pointerdown', this._onPointerDown, this);
298
- this.off('pointerup', this._onPointerUp, this);
299
- this.off('pointerupoutside', this._onPointerUpOutside, this);
300
- this._views.clear();
301
- this._textObj = null;
302
- super.destroy(options);
303
- }
304
- }