@duyquangnvx/spindle 1.0.0-beta.1

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 ADDED
@@ -0,0 +1,211 @@
1
+ # Spindle
2
+
3
+ Headless TypeScript slot game framework. Zero runtime dependencies.
4
+
5
+ Spindle orchestrates the entire spin lifecycle of a slot game — reels, wilds, wins, cascades, features — without knowing anything about your rendering layer. You implement async delegate methods; Spindle calls them in the right order and waits for your animations to finish.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @jagaming/spindle
11
+ ```
12
+
13
+ Subpath exports:
14
+
15
+ ```ts
16
+ import { createSpindle } from "@jagaming/spindle"; // core engine
17
+ import { createSlotRenderer } from "@jagaming/spindle/renderer"; // abstract renderer
18
+ import { recording } from "@jagaming/spindle/testing"; // test utilities
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```ts
24
+ import { createSpindle, createSymbolId } from "@jagaming/spindle";
25
+ import type { SpindleDelegate } from "@jagaming/spindle";
26
+
27
+ // Config is minimal — just grid dimensions
28
+ const config = { reels: 5, rows: 3 };
29
+
30
+ // Implement only the delegate methods your game needs.
31
+ // Core + Data are required; everything else is optional.
32
+ // If a method is present, the feature is enabled.
33
+ const delegate: SpindleDelegate = {
34
+ // Core (always required)
35
+ async onSpinStart() { /* dim UI, disable buttons */ },
36
+ async presentReelStop({ reelIndex, symbols }) { /* animate reel stopping */ },
37
+ async onSpinEnd({ totalWin }) { /* show total, re-enable buttons */ },
38
+
39
+ // Data (always required)
40
+ async requestSpinResult(context) {
41
+ const res = await fetch("/api/spin", { method: "POST" });
42
+ return res.json(); // must match SpinResult shape
43
+ },
44
+
45
+ // Ways wins — present because your game uses ways evaluation
46
+ async presentWaysWin(win) { /* highlight winning positions */ },
47
+
48
+ // Expanding wilds — present because your game has expanding wilds
49
+ async presentExpandingWild({ position, expandedPositions }) { /* animate */ },
50
+
51
+ // Scatter — present because your game has scatter wins
52
+ async presentScatterWin(win) { /* scatter animation */ },
53
+
54
+ // Free spins — present because your game has free spins
55
+ async onFreeSpinsEnter({ totalSpins }) { /* transition to free spins mode */ },
56
+ async onFreeSpinStart({ currentSpin, totalSpins }) { /* update counter */ },
57
+ async onFreeSpinsRetrigger({ added, totalSpins }) { /* retrigger animation */ },
58
+ async onFreeSpinsExit({ totalWin }) { /* show summary, transition back */ },
59
+ };
60
+
61
+ const spindle = await createSpindle(config, delegate);
62
+ await spindle.spin();
63
+ ```
64
+
65
+ ## How It Works
66
+
67
+ Spindle is a **presentation orchestrator**. Your game server computes the spin result; Spindle drives the visual flow:
68
+
69
+ ```
70
+ spindle.spin()
71
+ |
72
+ +-- onSpinStart()
73
+ +-- requestSpinResult() <- you call your server here
74
+ +-- presentAnticipation() <- if data + delegate present
75
+ +-- presentReelStop() x N <- left to right
76
+ +-- presentSymbolTransform() <- if data + delegate present
77
+ +-- presentExpandingWild() <- wild animations (per type)
78
+ +-- presentWaysWin() x N <- each winning combo
79
+ +-- presentCascadeDestroy/Drop/Fill loop
80
+ +-- presentScatterWin() <- after cascade
81
+ +-- presentBigWin() <- if data + delegate present
82
+ +-- presentJackpotTrigger() <- if data + delegate present
83
+ +-- [feature runner] <- free spins / hold-and-spin / etc.
84
+ +-- onSpinEnd({ spinWin, featureWin, totalWin })
85
+ +-- [gamble loop] <- if delegate present and win > 0
86
+ ```
87
+
88
+ Every delegate method returns `Promise<void>`. Spindle `await`s each one, so you control animation timing completely.
89
+
90
+ ## Data-Driven Architecture
91
+
92
+ Spindle uses a **data-driven** approach: `SpinResult` is the single runtime source of truth, and **delegate method presence** drives behavior. There is no config-driven type inference — you simply implement the methods your game needs.
93
+
94
+ | Data in SpinResult | Delegate method needed | What happens |
95
+ |---|---|---|
96
+ | `wins` with `type: "ways"` | `presentWaysWin` | Ways win animation |
97
+ | `wildEvents` with `type: "expanding"` | `presentExpandingWild` | Expanding wild animation |
98
+ | `cascadeSteps` | `presentCascadeDestroy` | Cascade sequence |
99
+ | `scatterWin` | `presentScatterWin` | Scatter animation |
100
+ | `bigWinTier` | `presentBigWin` | Big win celebration |
101
+ | `jackpotWin` | `presentJackpotTrigger` | Jackpot celebration |
102
+ | `featureTrigger` with `type: "freeSpins"` | `onFreeSpinsEnter` | Free spins loop |
103
+ | `gambleAvailable !== false` | `onGambleStart` | Gamble loop |
104
+
105
+ If data is present but the delegate method is missing, the feature is **silently skipped**. This means:
106
+ - No config arrays to maintain in sync with your server
107
+ - Adding a feature = implement the delegate method + have your server send the data
108
+ - Removing a feature = remove the delegate method
109
+
110
+ ## Game Mechanics
111
+
112
+ ### Win Types
113
+
114
+ - **Ways** — 243/1024+ ways to win (symbol matching across adjacent reels)
115
+ - **Payline** — Classic fixed payline patterns
116
+ - **Cluster** — Groups of adjacent matching symbols
117
+
118
+ ### Wild Types
119
+
120
+ `regular` | `expanding` | `sticky` | `walking` | `stacked` | `multiplier` | `random`
121
+
122
+ ### Capabilities
123
+
124
+ | Capability | Description |
125
+ |---|---|
126
+ | Cascade | Tumbling reels — destroy wins, drop new symbols, re-evaluate |
127
+ | Scatter | Scatter symbol wins (independent of paylines/ways) |
128
+ | Big Win | Celebration tiers (big, mega, super mega, etc.) |
129
+ | Anticipation | Suspense animation before specific reel stops |
130
+ | Symbol Transform | Mystery symbols that reveal after landing |
131
+ | Jackpot | Progressive jackpot trigger and award |
132
+
133
+ ### Features
134
+
135
+ | Feature | Description |
136
+ |---|---|
137
+ | Free Spins | Bonus spin loop with retrigger support |
138
+ | Hold and Spin | Lock symbols, respin remaining positions |
139
+ | Pick Bonus | Interactive pick-and-reveal mini-game |
140
+ | Wheel Bonus | Spinning wheel with nested inner wheels |
141
+
142
+ ### Modifiers
143
+
144
+ | Modifier | Description |
145
+ |---|---|
146
+ | Gamble | Post-spin double-or-nothing loop |
147
+ | Buy Feature | Purchase direct entry into any feature |
148
+
149
+ ## API
150
+
151
+ ### `createSpindle(config, delegate): Promise<Spindle>`
152
+
153
+ Factory function. Config only requires `{ reels, rows }`. Validates at construction time (fail-fast).
154
+
155
+ ### `spindle.spin(): Promise<SpinFlowResult>`
156
+
157
+ Runs a full spin cycle. Returns `{ totalWin: number }`.
158
+
159
+ ### `spindle.buyFeature(featureType): Promise<SpinFlowResult>`
160
+
161
+ Buys direct entry into a feature. Requires `requestBuyFeatureResult` delegate method.
162
+
163
+ ### `spindle.isSpinning: boolean`
164
+
165
+ Concurrent spin protection. `spin()` and `buyFeature()` share the same mutex.
166
+
167
+ ## Delegate Conventions
168
+
169
+ | Prefix | Direction | Purpose |
170
+ |---|---|---|
171
+ | `request` | Spindle <- Consumer | Pull data (server calls, player choices) |
172
+ | `on` | Spindle -> Consumer | Lifecycle notification (update UI state) |
173
+ | `present` | Spindle -> Consumer | Animate/display something |
174
+
175
+ ## SpinResult
176
+
177
+ The `SpinResult` type is the server contract — everything Spindle needs to drive the presentation:
178
+
179
+ ```ts
180
+ interface SpinResult {
181
+ grid: SymbolGrid; // reel x row symbol array
182
+ wins: WinResult[]; // line/ways/cluster wins
183
+ spinWin: number; // total win for this spin
184
+ scatterWin?: ScatterWin;
185
+ featureTrigger?: FeatureTrigger;
186
+ wildEvents?: WildEvent[];
187
+ symbolTransforms?: SymbolTransform[];
188
+ cascadeSteps?: CascadeStep[];
189
+ bigWinTier?: string;
190
+ anticipationReels?: number[];
191
+ jackpotWin?: JackpotWin;
192
+ newLockedSymbols?: LockedSymbol[];
193
+ gambleAvailable?: boolean; // opt out of gamble for this spin
194
+ metadata?: unknown; // consumer-defined passthrough data
195
+ }
196
+ ```
197
+
198
+ Spindle does **not** call your server. You call it in `requestSpinResult()` and return data in this shape.
199
+
200
+ ## Development
201
+
202
+ ```sh
203
+ npm test # Run all 203 tests
204
+ npm run lint # Biome lint + format check
205
+ npm run build # ESM + CJS dual output via tsdown
206
+ npm run typecheck # tsc --noEmit
207
+ ```
208
+
209
+ ## License
210
+
211
+ UNLICENSED
@@ -0,0 +1,463 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * Core type contracts for Spindle.
4
+ *
5
+ * These are the PUBLIC types consumers interact with.
6
+ */
7
+ /** Opaque string identifier for a symbol on the reels. */
8
+ type SymbolId = string & {
9
+ readonly __brand: unique symbol;
10
+ };
11
+ /** Create a SymbolId from a raw string. */
12
+ declare function createSymbolId(value: string): SymbolId;
13
+ /** A specific cell on the reel grid. */
14
+ interface GridPosition {
15
+ readonly reel: number;
16
+ readonly row: number;
17
+ }
18
+ /**
19
+ * Complete grid state — symbols per reel.
20
+ * Jagged array to support variable row counts (e.g., Megaways).
21
+ * Outer = reel index, inner = row symbols.
22
+ */
23
+ type SymbolGrid = SymbolId[][];
24
+ /** Discriminator for win evaluation method. */
25
+ type WinType = "ways" | "payline" | "cluster";
26
+ type WildType = "regular" | "expanding" | "sticky" | "walking" | "stacked" | "multiplier" | "random";
27
+ type CapabilityType = "cascade" | "scatter" | "bigWin" | "anticipation" | "symbolTransform" | "jackpot";
28
+ type FeatureType = "freeSpins" | "holdAndSpin" | "pickBonus" | "wheelBonus";
29
+ interface GameConfig {
30
+ readonly reels: number;
31
+ readonly rows: number;
32
+ }
33
+ type SpinRequestContext = {
34
+ readonly mode: "base";
35
+ } | {
36
+ readonly mode: "freeSpin";
37
+ readonly currentSpin: number;
38
+ readonly totalSpins: number;
39
+ } | {
40
+ readonly mode: "holdAndSpin";
41
+ readonly round: number;
42
+ readonly lockedSymbols: LockedSymbol[];
43
+ };
44
+ /** Current game mode during a spin. */
45
+ type SpinMode = "base" | "freeSpin" | "holdAndSpin";
46
+ /** Context injected into all spin-pipeline presentation delegates. */
47
+ interface PresentationContext {
48
+ readonly mode: SpinMode;
49
+ readonly metadata?: unknown;
50
+ }
51
+ /** Base fields shared by all winning combinations. */
52
+ interface WinBase {
53
+ readonly symbol: SymbolId;
54
+ readonly positions: GridPosition[];
55
+ readonly amount: number;
56
+ readonly multiplier?: number;
57
+ }
58
+ interface WaysWin extends WinBase {
59
+ readonly type: "ways";
60
+ readonly count: number;
61
+ }
62
+ interface PaylineWin extends WinBase {
63
+ readonly type: "payline";
64
+ readonly paylineIndex: number;
65
+ readonly matchCount: number;
66
+ }
67
+ interface ClusterWin extends WinBase {
68
+ readonly type: "cluster";
69
+ readonly size: number;
70
+ }
71
+ type WinResult = WaysWin | PaylineWin | ClusterWin;
72
+ interface ScatterWin {
73
+ readonly symbol: SymbolId;
74
+ readonly count: number;
75
+ readonly amount: number;
76
+ readonly positions: GridPosition[];
77
+ }
78
+ interface FreeSpinsParams {
79
+ readonly totalSpins: number;
80
+ }
81
+ interface HoldAndSpinParams {
82
+ readonly totalRounds: number;
83
+ readonly lockedSymbols: LockedSymbol[];
84
+ }
85
+ interface LockedSymbol {
86
+ readonly position: GridPosition;
87
+ readonly symbol: SymbolId;
88
+ readonly value?: number;
89
+ }
90
+ interface PickBonusParams {
91
+ readonly itemCount: number;
92
+ }
93
+ interface PickChoice {
94
+ readonly choiceIndex: number;
95
+ }
96
+ interface PickReveal {
97
+ readonly choiceIndex: number;
98
+ readonly prize: number;
99
+ readonly done: boolean;
100
+ }
101
+ interface WheelSegment {
102
+ readonly prize: number;
103
+ readonly innerWheel?: WheelBonusParams;
104
+ }
105
+ interface WheelBonusParams {
106
+ readonly segments: readonly WheelSegment[];
107
+ }
108
+ interface WheelSpinResult {
109
+ readonly segmentIndex: number;
110
+ readonly prize: number;
111
+ readonly innerWheel?: WheelBonusParams;
112
+ }
113
+ type FeatureTrigger = {
114
+ readonly type: "freeSpins";
115
+ readonly params: FreeSpinsParams;
116
+ } | {
117
+ readonly type: "holdAndSpin";
118
+ readonly params: HoldAndSpinParams;
119
+ } | {
120
+ readonly type: "pickBonus";
121
+ readonly params: PickBonusParams;
122
+ } | {
123
+ readonly type: "wheelBonus";
124
+ readonly params: WheelBonusParams;
125
+ };
126
+ interface RegularWildEvent {
127
+ readonly type: "regular";
128
+ readonly position: GridPosition;
129
+ }
130
+ interface ExpandingWildEvent {
131
+ readonly type: "expanding";
132
+ readonly position: GridPosition;
133
+ readonly expandedPositions: GridPosition[];
134
+ }
135
+ interface StickyWildEvent {
136
+ readonly type: "sticky";
137
+ readonly position: GridPosition;
138
+ }
139
+ interface WalkingWildEvent {
140
+ readonly type: "walking";
141
+ readonly from: GridPosition;
142
+ readonly to: GridPosition;
143
+ }
144
+ interface StackedWildEvent {
145
+ readonly type: "stacked";
146
+ readonly positions: GridPosition[];
147
+ }
148
+ interface MultiplierWildEvent {
149
+ readonly type: "multiplier";
150
+ readonly position: GridPosition;
151
+ readonly multiplier: number;
152
+ }
153
+ interface RandomWildEvent {
154
+ readonly type: "random";
155
+ readonly positions: GridPosition[];
156
+ }
157
+ type WildEvent = RegularWildEvent | ExpandingWildEvent | StickyWildEvent | WalkingWildEvent | StackedWildEvent | MultiplierWildEvent | RandomWildEvent;
158
+ interface HoldAndSpinRoundResult {
159
+ readonly grid: SymbolGrid;
160
+ readonly newLockedSymbols: LockedSymbol[];
161
+ readonly roundWin: number;
162
+ }
163
+ /** Player's decision during a gamble round. */
164
+ interface GambleChoice {
165
+ readonly action: "gamble" | "collect";
166
+ }
167
+ /** Server-provided outcome of a gamble round. */
168
+ interface GambleResult {
169
+ readonly won: boolean;
170
+ readonly amount: number;
171
+ }
172
+ /** Jackpot win outcome determined by server. */
173
+ interface JackpotWin {
174
+ readonly tier: string;
175
+ readonly amount: number;
176
+ }
177
+ /** A single symbol transformation on the grid, provided by the server. */
178
+ interface SymbolTransform {
179
+ readonly position: GridPosition;
180
+ readonly from: SymbolId;
181
+ readonly to: SymbolId;
182
+ }
183
+ /** Server response for a spin — canonical SDK type. */
184
+ interface SpinResult {
185
+ readonly grid: SymbolGrid;
186
+ readonly wins: WinResult[];
187
+ /**
188
+ * Win amount from this spin's evaluations only.
189
+ * Includes: line/ways/cluster wins, scatter win, cascade step wins.
190
+ * Excludes: jackpot wins (reported separately via {@link jackpotWin}).
191
+ * For feature spins, this is the win for THIS spin only, not cumulative.
192
+ */
193
+ readonly spinWin: number;
194
+ readonly scatterWin?: ScatterWin;
195
+ readonly featureTrigger?: FeatureTrigger;
196
+ readonly wildEvents?: WildEvent[];
197
+ /** Symbols that locked this round — present in holdAndSpin mode responses. */
198
+ readonly newLockedSymbols?: LockedSymbol[];
199
+ /** Server-provided big win tier string (e.g., "big", "mega", "super_mega"). */
200
+ readonly bigWinTier?: string;
201
+ /** Reel indices (0-based) that should receive anticipation before stopping. */
202
+ readonly anticipationReels?: number[];
203
+ /** Symbol transforms to present after reel stops, before wild events. */
204
+ readonly symbolTransforms?: SymbolTransform[];
205
+ /** Cascade sequence — present when capabilities includes "cascade". */
206
+ readonly cascadeSteps?: CascadeStep[];
207
+ /** Jackpot win — present when a jackpot triggers on this spin. */
208
+ readonly jackpotWin?: JackpotWin;
209
+ /** Whether gamble is available for this spin (default: true when gamble delegate is present). */
210
+ readonly gambleAvailable?: boolean;
211
+ /** Consumer-defined opaque data. Passed through to all presentation delegates unchanged. */
212
+ readonly metadata?: unknown;
213
+ }
214
+ /** A single step in a cascade sequence, provided by the server. */
215
+ interface CascadeStep {
216
+ /** Positions of symbols to destroy (winning symbols from previous evaluation). */
217
+ readonly destroyPositions: GridPosition[];
218
+ /** Grid state after symbols drop and new symbols fill. */
219
+ readonly grid: SymbolGrid;
220
+ /** Wins evaluated on the new grid (empty array if no wins -> cascade ends). */
221
+ readonly wins: WinResult[];
222
+ /** Optional multiplier for this cascade step (progressive multiplier from server). */
223
+ readonly multiplier?: number;
224
+ }
225
+ /**
226
+ * Summary returned from spindle.spin() after full flow completes.
227
+ *
228
+ * {@link totalWin} reflects spin-related wins only (base + features),
229
+ * optionally modified by gamble. Jackpot wins are excluded — consumers
230
+ * track those via {@link JackpotDelegate.onJackpotAwarded} callbacks.
231
+ */
232
+ interface SpinFlowResult {
233
+ readonly totalWin: number;
234
+ }
235
+ //#endregion
236
+ //#region src/delegates.d.ts
237
+ /**
238
+ * Single delegate interface for Spindle.
239
+ * Core + Data methods are required; all others are optional.
240
+ * Method presence drives behavior — if a method exists, the feature is enabled.
241
+ */
242
+ type SpindleDelegate = CoreDelegate & DataDelegate & Partial<WaysWinDelegate & PaylineWinDelegate & ClusterWinDelegate & ScatterWinDelegate & CascadeDelegate & BigWinDelegate & AnticipationDelegate & SymbolTransformDelegate & JackpotDelegate & GambleDelegate & BuyFeatureDelegate & PickBonusDelegate & WheelBonusDelegate & FreeSpinsDelegate & HoldAndSpinDelegate & ExpandingWildDelegate & StickyWildDelegate & WalkingWildDelegate & StackedWildDelegate & MultiplierWildDelegate & RandomWildDelegate>;
243
+ /** Consumer implements this to provide spin results to Spindle. */
244
+ interface DataDelegate {
245
+ requestSpinResult(context: SpinRequestContext): Promise<SpinResult>;
246
+ }
247
+ /** Every game MUST implement these lifecycle and presentation callbacks. */
248
+ interface CoreDelegate {
249
+ onSpinStart(): Promise<void>;
250
+ presentReelStop(data: {
251
+ reelIndex: number;
252
+ symbols: SymbolId[];
253
+ } & PresentationContext): Promise<void>;
254
+ onSpinEnd(data: {
255
+ spinWin: number;
256
+ featureWin: number;
257
+ totalWin: number;
258
+ }): Promise<void>;
259
+ }
260
+ /** Present when game uses ways win evaluation. */
261
+ interface WaysWinDelegate {
262
+ presentWaysWin(data: WaysWin & PresentationContext): Promise<void>;
263
+ }
264
+ /** Present when game uses payline win evaluation. */
265
+ interface PaylineWinDelegate {
266
+ presentPaylineWin(data: PaylineWin & PresentationContext): Promise<void>;
267
+ }
268
+ /** Present when game uses cluster win evaluation. */
269
+ interface ClusterWinDelegate {
270
+ presentClusterWin(data: ClusterWin & PresentationContext): Promise<void>;
271
+ }
272
+ /** Present when game has scatter wins. */
273
+ interface ScatterWinDelegate {
274
+ presentScatterWin(data: ScatterWin & PresentationContext): Promise<void>;
275
+ }
276
+ /** Present when game has cascade/tumble mechanics. */
277
+ interface CascadeDelegate {
278
+ presentCascadeDestroy(data: {
279
+ step: number;
280
+ positions: GridPosition[];
281
+ } & PresentationContext): Promise<void>;
282
+ presentCascadeDrop(data: {
283
+ step: number;
284
+ } & PresentationContext): Promise<void>;
285
+ presentCascadeFill(data: {
286
+ step: number;
287
+ grid: SymbolGrid;
288
+ multiplier?: number;
289
+ } & PresentationContext): Promise<void>;
290
+ }
291
+ /** Present when game has free spins feature. */
292
+ interface FreeSpinsDelegate {
293
+ onFreeSpinsEnter(data: {
294
+ totalSpins: number;
295
+ }): Promise<void>;
296
+ onFreeSpinStart(data: {
297
+ currentSpin: number;
298
+ totalSpins: number;
299
+ remaining: number;
300
+ accumulated: number;
301
+ }): Promise<void>;
302
+ onFreeSpinsRetrigger(data: {
303
+ added: number;
304
+ totalSpins: number;
305
+ }): Promise<void>;
306
+ onFreeSpinsExit(data: {
307
+ totalSpins: number;
308
+ totalWin: number;
309
+ }): Promise<void>;
310
+ }
311
+ /** Present when game has hold-and-spin feature. */
312
+ interface HoldAndSpinDelegate {
313
+ onHoldAndSpinEnter(data: {
314
+ totalRounds: number;
315
+ lockedSymbols: LockedSymbol[];
316
+ }): Promise<void>;
317
+ onHoldAndSpinRound(data: {
318
+ round: number;
319
+ remaining: number;
320
+ grid: SymbolGrid;
321
+ newLocked: LockedSymbol[];
322
+ allLocked: LockedSymbol[];
323
+ }): Promise<void>;
324
+ onHoldAndSpinExit(data: {
325
+ totalRounds: number;
326
+ totalWin: number;
327
+ fullGrid: boolean;
328
+ }): Promise<void>;
329
+ }
330
+ /** Present when game has big win celebrations. */
331
+ interface BigWinDelegate {
332
+ presentBigWin(data: {
333
+ tier: string;
334
+ amount: number;
335
+ } & PresentationContext): Promise<void>;
336
+ }
337
+ /** Present when game has reel anticipation. */
338
+ interface AnticipationDelegate {
339
+ presentAnticipation(data: {
340
+ reelIndex: number;
341
+ } & PresentationContext): Promise<void>;
342
+ }
343
+ /** Present when game has symbol transforms. */
344
+ interface SymbolTransformDelegate {
345
+ presentSymbolTransform(data: {
346
+ transforms: SymbolTransform[];
347
+ } & PresentationContext): Promise<void>;
348
+ }
349
+ /** Present when game has jackpot feature. */
350
+ interface JackpotDelegate {
351
+ presentJackpotTrigger(data: {
352
+ tier: string;
353
+ amount: number;
354
+ } & PresentationContext): Promise<void>;
355
+ onJackpotAwarded(data: {
356
+ tier: string;
357
+ amount: number;
358
+ } & PresentationContext): Promise<void>;
359
+ }
360
+ /** Present when game has pick bonus feature. */
361
+ interface PickBonusDelegate {
362
+ onPickBonusEnter(data: {
363
+ itemCount: number;
364
+ }): Promise<void>;
365
+ requestPickChoice(data: {
366
+ round: number;
367
+ accumulated: number;
368
+ }): Promise<PickChoice>;
369
+ requestPickReveal(data: {
370
+ choiceIndex: number;
371
+ }): Promise<PickReveal>;
372
+ presentPickReveal(data: {
373
+ choiceIndex: number;
374
+ prize: number;
375
+ done: boolean;
376
+ }): Promise<void>;
377
+ onPickBonusExit(data: {
378
+ totalWin: number;
379
+ }): Promise<void>;
380
+ }
381
+ /** Present when game has wheel bonus feature. */
382
+ interface WheelBonusDelegate {
383
+ onWheelBonusEnter(data: {
384
+ segments: readonly WheelSegment[];
385
+ }): Promise<void>;
386
+ requestWheelSpinResult(data: {
387
+ segments: readonly WheelSegment[];
388
+ }): Promise<WheelSpinResult>;
389
+ presentWheelResult(data: {
390
+ segmentIndex: number;
391
+ prize: number;
392
+ }): Promise<void>;
393
+ onWheelBonusExit(data: {
394
+ totalWin: number;
395
+ }): Promise<void>;
396
+ }
397
+ /** Present when game has gamble (double-up) feature. */
398
+ interface GambleDelegate {
399
+ onGambleStart(data: {
400
+ currentWin: number;
401
+ }): Promise<void>;
402
+ requestGambleChoice(data: {
403
+ currentWin: number;
404
+ }): Promise<GambleChoice>;
405
+ requestGambleResult(data: {
406
+ currentWin: number;
407
+ }): Promise<GambleResult>;
408
+ presentGambleResult(data: {
409
+ won: boolean;
410
+ amount: number;
411
+ }): Promise<void>;
412
+ onGambleEnd(data: {
413
+ finalWin: number;
414
+ }): Promise<void>;
415
+ }
416
+ /** Present when game has buy feature functionality. */
417
+ interface BuyFeatureDelegate {
418
+ requestBuyFeatureResult(data: {
419
+ featureType: FeatureType;
420
+ }): Promise<FeatureTrigger>;
421
+ onBuyFeatureStart(data: {
422
+ featureType: FeatureType;
423
+ }): Promise<void>;
424
+ onBuyFeatureEnd(data: {
425
+ totalWin: number;
426
+ }): Promise<void>;
427
+ }
428
+ interface ExpandingWildDelegate {
429
+ presentExpandingWild(data: {
430
+ position: GridPosition;
431
+ expandedPositions: GridPosition[];
432
+ } & PresentationContext): Promise<void>;
433
+ }
434
+ interface StickyWildDelegate {
435
+ presentStickyWild(data: {
436
+ position: GridPosition;
437
+ } & PresentationContext): Promise<void>;
438
+ }
439
+ interface WalkingWildDelegate {
440
+ presentWalkingWild(data: {
441
+ from: GridPosition;
442
+ to: GridPosition;
443
+ } & PresentationContext): Promise<void>;
444
+ }
445
+ interface StackedWildDelegate {
446
+ presentStackedWild(data: {
447
+ positions: GridPosition[];
448
+ } & PresentationContext): Promise<void>;
449
+ }
450
+ interface MultiplierWildDelegate {
451
+ presentMultiplierWild(data: {
452
+ position: GridPosition;
453
+ multiplier: number;
454
+ } & PresentationContext): Promise<void>;
455
+ }
456
+ interface RandomWildDelegate {
457
+ presentRandomWild(data: {
458
+ positions: GridPosition[];
459
+ } & PresentationContext): Promise<void>;
460
+ }
461
+ //#endregion
462
+ export { StackedWildEvent as $, FeatureType as A, MultiplierWildEvent as B, WaysWinDelegate as C, ClusterWin as D, CascadeStep as E, GridPosition as F, PresentationContext as G, PickBonusParams as H, HoldAndSpinParams as I, ScatterWin as J, RandomWildEvent as K, HoldAndSpinRoundResult as L, GambleChoice as M, GambleResult as N, ExpandingWildEvent as O, GameConfig as P, SpinResult as Q, JackpotWin as R, WalkingWildDelegate as S, CapabilityType as T, PickChoice as U, PaylineWin as V, PickReveal as W, SpinMode as X, SpinFlowResult as Y, SpinRequestContext as Z, ScatterWinDelegate as _, ClusterWinDelegate as a, WaysWin as at, StickyWildDelegate as b, ExpandingWildDelegate as c, WheelSpinResult as ct, HoldAndSpinDelegate as d, WinResult as dt, StickyWildEvent as et, JackpotDelegate as f, WinType as ft, RandomWildDelegate as g, PickBonusDelegate as h, CascadeDelegate as i, WalkingWildEvent as it, FreeSpinsParams as j, FeatureTrigger as k, FreeSpinsDelegate as l, WildEvent as lt, PaylineWinDelegate as m, BigWinDelegate as n, SymbolId as nt, CoreDelegate as o, WheelBonusParams as ot, MultiplierWildDelegate as p, createSymbolId as pt, RegularWildEvent as q, BuyFeatureDelegate as r, SymbolTransform as rt, DataDelegate as s, WheelSegment as st, AnticipationDelegate as t, SymbolGrid as tt, GambleDelegate as u, WildType as ut, SpindleDelegate as v, WheelBonusDelegate as w, SymbolTransformDelegate as x, StackedWildDelegate as y, LockedSymbol as z };
463
+ //# sourceMappingURL=delegates-DOwv3sAL.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegates-DOwv3sAL.d.cts","names":[],"sources":["../src/types.ts","../src/delegates.ts"],"mappings":"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"}