@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 +211 -0
- package/dist/delegates-DOwv3sAL.d.cts +463 -0
- package/dist/delegates-DOwv3sAL.d.cts.map +1 -0
- package/dist/delegates-Jm8q1-L0.d.mts +463 -0
- package/dist/delegates-Jm8q1-L0.d.mts.map +1 -0
- package/dist/index.cjs +436 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +434 -0
- package/dist/index.mjs.map +1 -0
- package/dist/renderer/index.cjs +548 -0
- package/dist/renderer/index.cjs.map +1 -0
- package/dist/renderer/index.d.cts +279 -0
- package/dist/renderer/index.d.cts.map +1 -0
- package/dist/renderer/index.d.mts +279 -0
- package/dist/renderer/index.d.mts.map +1 -0
- package/dist/renderer/index.mjs +534 -0
- package/dist/renderer/index.mjs.map +1 -0
- package/dist/testing/index.cjs +729 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +76 -0
- package/dist/testing/index.d.cts.map +1 -0
- package/dist/testing/index.d.mts +76 -0
- package/dist/testing/index.d.mts.map +1 -0
- package/dist/testing/index.mjs +721 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/types-B1TeoRrL.mjs +9 -0
- package/dist/types-B1TeoRrL.mjs.map +1 -0
- package/dist/types-NL78Eg3j.cjs +15 -0
- package/dist/types-NL78Eg3j.cjs.map +1 -0
- package/package.json +61 -0
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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"}
|