cascading-reel 1.0.2 → 2.0.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 +169 -169
- package/dist/index.cjs +1512 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +168 -0
- package/dist/index.d.ts +168 -169
- package/dist/index.js +1510 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -27
- package/dist/index.cjs.js +0 -131
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js +0 -1069
- package/dist/index.es.js.map +0 -1
- package/dist/index.umd.js +0 -131
- package/dist/index.umd.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
# cascading-reel
|
|
2
|
-
|
|
3
|
-
A high-performance WebGL cascading reel animator for slot-style UIs on any `HTMLCanvasElement`.
|
|
4
|
-
|
|
5
|
-
- 3x3 reel grid with deterministic scripted outcomes.
|
|
6
|
-
- Queued spins with per-spin callbacks.
|
|
7
|
-
- Win highlight with electric border and particle burst.
|
|
8
|
-
- DPR-aware rendering for mobile and desktop.
|
|
9
|
-
|
|
10
|
-
## Install
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Usage (TypeScript)
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import { CascadingReel } from 'cascading-reel';
|
|
20
|
-
|
|
21
|
-
const container = document.getElementById('reelWrap');
|
|
22
|
-
const canvas = document.getElementById('canvas');
|
|
23
|
-
const button = document.getElementById('spinBtn');
|
|
24
|
-
|
|
25
|
-
if (!container || !canvas || !button) {
|
|
26
|
-
throw new Error('Demo DOM is not ready');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const reel = new CascadingReel({
|
|
30
|
-
container: container as HTMLDivElement,
|
|
31
|
-
canvas: canvas as HTMLCanvasElement,
|
|
32
|
-
button: button as HTMLButtonElement,
|
|
33
|
-
sprite: new URL('./assets/reel.webp', import.meta.url).href,
|
|
34
|
-
spriteCrossOrigin: 'anonymous',
|
|
35
|
-
spriteElementsCount: 6,
|
|
36
|
-
symbolScale: 0.85,
|
|
37
|
-
initialSegments: [
|
|
38
|
-
[0, 1, 2],
|
|
39
|
-
[3, 0, 5],
|
|
40
|
-
[0, 1, 0],
|
|
41
|
-
],
|
|
42
|
-
queuedSpinStates: [
|
|
43
|
-
{
|
|
44
|
-
stopRows: [
|
|
45
|
-
[0, 4, 5],
|
|
46
|
-
[2, 1, 4],
|
|
47
|
-
[1, 3, 0],
|
|
48
|
-
],
|
|
49
|
-
finaleSequenceRows: [
|
|
50
|
-
[
|
|
51
|
-
[1, 1, 0],
|
|
52
|
-
[0, 1, 2],
|
|
53
|
-
[4, 5, 1],
|
|
54
|
-
],
|
|
55
|
-
],
|
|
56
|
-
highlightWin: true,
|
|
57
|
-
callback: () => console.log('spin complete'),
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
await reel.init();
|
|
63
|
-
reel.spin();
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Usage (Vue 3)
|
|
67
|
-
|
|
68
|
-
```vue
|
|
69
|
-
<script setup lang="ts">
|
|
70
|
-
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
|
|
71
|
-
import { CascadingReel } from 'cascading-reel';
|
|
72
|
-
|
|
73
|
-
const containerRef = ref<HTMLDivElement | null>(null);
|
|
74
|
-
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
|
75
|
-
const buttonRef = ref<HTMLButtonElement | null>(null);
|
|
76
|
-
const reel = shallowRef<CascadingReel | null>(null);
|
|
77
|
-
|
|
78
|
-
onMounted(async () => {
|
|
79
|
-
if (!containerRef.value || !canvasRef.value) return;
|
|
80
|
-
reel.value = new CascadingReel({
|
|
81
|
-
container: containerRef.value,
|
|
82
|
-
canvas: canvasRef.value,
|
|
83
|
-
button: buttonRef.value ?? undefined,
|
|
84
|
-
sprite: new URL('./assets/reel.webp', import.meta.url).href,
|
|
85
|
-
spriteCrossOrigin: 'anonymous',
|
|
86
|
-
spriteElementsCount: 6,
|
|
87
|
-
symbolScale: 0.85,
|
|
88
|
-
particleColor: 'rainbow',
|
|
89
|
-
});
|
|
90
|
-
await reel.value.init();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
onBeforeUnmount(() => {
|
|
94
|
-
reel.value?.destroy();
|
|
95
|
-
reel.value = null;
|
|
96
|
-
});
|
|
97
|
-
</script>
|
|
98
|
-
|
|
99
|
-
<template>
|
|
100
|
-
<button ref="buttonRef">Spin</button>
|
|
101
|
-
<div ref="containerRef">
|
|
102
|
-
<canvas ref="canvasRef"></canvas>
|
|
103
|
-
</div>
|
|
104
|
-
</template>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## HTML Layout
|
|
108
|
-
|
|
109
|
-
```html
|
|
110
|
-
<button id="spinBtn">Spin</button>
|
|
111
|
-
<div id="reelWrap">
|
|
112
|
-
<canvas id="canvas"></canvas>
|
|
113
|
-
</div>
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Call `reel.spin()` to consume the next item from `queuedSpinStates`.
|
|
117
|
-
|
|
118
|
-
## SpinState
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
type SpinState = {
|
|
122
|
-
stopGrid?: number[][];
|
|
123
|
-
stopRows?: number[][];
|
|
124
|
-
finaleSequence?: number[][][];
|
|
125
|
-
finaleSequenceRows?: number[][][];
|
|
126
|
-
highlightWin?: boolean;
|
|
127
|
-
callback?: () => void;
|
|
128
|
-
};
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
- Use `stopRows` for row-major input (`[row][col]`).
|
|
132
|
-
- Use `stopGrid` for column-major input (`[col][row]`).
|
|
133
|
-
- `finaleSequenceRows` and `finaleSequence` follow the same row/column conventions.
|
|
134
|
-
|
|
135
|
-
## Options
|
|
136
|
-
|
|
137
|
-
| Option | Type | Default | Description |
|
|
138
|
-
|:-------------------------------|:-----------------------------------------|:-----------------:|:-------------------------------------------------------|
|
|
139
|
-
| `canvas` | `HTMLCanvasElement` | — | Canvas for rendering. |
|
|
140
|
-
| `container` | `HTMLElement` | — | Element used for responsive sizing. |
|
|
141
|
-
| `button` | `HTMLButtonElement` | — | Optional spin button. |
|
|
142
|
-
| `sprite` | `string \| HTMLImageElement` | — | Sprite sheet URL or preloaded image element. |
|
|
143
|
-
| `spriteCrossOrigin` | `'' \| 'anonymous' \| 'use-credentials'` | `'anonymous'` | `crossOrigin` mode used when `sprite` is a URL string. |
|
|
144
|
-
| `spriteElementsCount` | `number` | `6` | Number of symbols in the sprite sheet. |
|
|
145
|
-
| `symbolScale` | `number` | `0.9` | Symbol scale inside the cell. Clamped to `0.5..1.2`. |
|
|
146
|
-
| `initialSegments` | `number[][]` | randomized | Initial 3x3 state in rows format. |
|
|
147
|
-
| `highlightInitialWinningCells` | `boolean` | `true` | Show initial highlight before first spin. |
|
|
148
|
-
| `queuedSpinStates` | `SpinState[]` | `[]` | Predefined queue consumed by `spin()`. |
|
|
149
|
-
| `particleColor` | `'rainbow' \| [number, number, number]` | `[255, 235, 110]` | Win particle color mode or solid RGB color. |
|
|
150
|
-
|
|
151
|
-
## Methods
|
|
152
|
-
|
|
153
|
-
```ts
|
|
154
|
-
await reel.init();
|
|
155
|
-
reel.spin();
|
|
156
|
-
reel.destroy();
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Sprite Format
|
|
160
|
-
|
|
161
|
-
- Single vertical sprite sheet.
|
|
162
|
-
- Every symbol frame is square.
|
|
163
|
-
- Total texture height equals `spriteElementsCount * frameWidth` (square-frame assumption).
|
|
164
|
-
- `PNG` and `WebP` with transparency are supported.
|
|
165
|
-
- When using a cross-origin sprite URL (CDN/sandbox), keep `spriteCrossOrigin: 'anonymous'` and ensure the host returns CORS headers.
|
|
166
|
-
|
|
167
|
-
## License
|
|
168
|
-
|
|
169
|
-
MIT
|
|
1
|
+
# cascading-reel
|
|
2
|
+
|
|
3
|
+
A high-performance WebGL cascading reel animator for slot-style UIs on any `HTMLCanvasElement`.
|
|
4
|
+
|
|
5
|
+
- 3x3 reel grid with deterministic scripted outcomes.
|
|
6
|
+
- Queued spins with per-spin callbacks.
|
|
7
|
+
- Win highlight with electric border and particle burst.
|
|
8
|
+
- DPR-aware rendering for mobile and desktop.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install cascading-reel
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage (TypeScript)
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { CascadingReel } from 'cascading-reel';
|
|
20
|
+
|
|
21
|
+
const container = document.getElementById('reelWrap');
|
|
22
|
+
const canvas = document.getElementById('canvas');
|
|
23
|
+
const button = document.getElementById('spinBtn');
|
|
24
|
+
|
|
25
|
+
if (!container || !canvas || !button) {
|
|
26
|
+
throw new Error('Demo DOM is not ready');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const reel = new CascadingReel({
|
|
30
|
+
container: container as HTMLDivElement,
|
|
31
|
+
canvas: canvas as HTMLCanvasElement,
|
|
32
|
+
button: button as HTMLButtonElement,
|
|
33
|
+
sprite: new URL('./assets/reel.webp', import.meta.url).href,
|
|
34
|
+
spriteCrossOrigin: 'anonymous',
|
|
35
|
+
spriteElementsCount: 6,
|
|
36
|
+
symbolScale: 0.85,
|
|
37
|
+
initialSegments: [
|
|
38
|
+
[0, 1, 2],
|
|
39
|
+
[3, 0, 5],
|
|
40
|
+
[0, 1, 0],
|
|
41
|
+
],
|
|
42
|
+
queuedSpinStates: [
|
|
43
|
+
{
|
|
44
|
+
stopRows: [
|
|
45
|
+
[0, 4, 5],
|
|
46
|
+
[2, 1, 4],
|
|
47
|
+
[1, 3, 0],
|
|
48
|
+
],
|
|
49
|
+
finaleSequenceRows: [
|
|
50
|
+
[
|
|
51
|
+
[1, 1, 0],
|
|
52
|
+
[0, 1, 2],
|
|
53
|
+
[4, 5, 1],
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
highlightWin: true,
|
|
57
|
+
callback: () => console.log('spin complete'),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await reel.init();
|
|
63
|
+
reel.spin();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage (Vue 3)
|
|
67
|
+
|
|
68
|
+
```vue
|
|
69
|
+
<script setup lang="ts">
|
|
70
|
+
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
|
|
71
|
+
import { CascadingReel } from 'cascading-reel';
|
|
72
|
+
|
|
73
|
+
const containerRef = ref<HTMLDivElement | null>(null);
|
|
74
|
+
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
|
75
|
+
const buttonRef = ref<HTMLButtonElement | null>(null);
|
|
76
|
+
const reel = shallowRef<CascadingReel | null>(null);
|
|
77
|
+
|
|
78
|
+
onMounted(async () => {
|
|
79
|
+
if (!containerRef.value || !canvasRef.value) return;
|
|
80
|
+
reel.value = new CascadingReel({
|
|
81
|
+
container: containerRef.value,
|
|
82
|
+
canvas: canvasRef.value,
|
|
83
|
+
button: buttonRef.value ?? undefined,
|
|
84
|
+
sprite: new URL('./assets/reel.webp', import.meta.url).href,
|
|
85
|
+
spriteCrossOrigin: 'anonymous',
|
|
86
|
+
spriteElementsCount: 6,
|
|
87
|
+
symbolScale: 0.85,
|
|
88
|
+
particleColor: 'rainbow',
|
|
89
|
+
});
|
|
90
|
+
await reel.value.init();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
onBeforeUnmount(() => {
|
|
94
|
+
reel.value?.destroy();
|
|
95
|
+
reel.value = null;
|
|
96
|
+
});
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<template>
|
|
100
|
+
<button ref="buttonRef">Spin</button>
|
|
101
|
+
<div ref="containerRef">
|
|
102
|
+
<canvas ref="canvasRef"></canvas>
|
|
103
|
+
</div>
|
|
104
|
+
</template>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## HTML Layout
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<button id="spinBtn">Spin</button>
|
|
111
|
+
<div id="reelWrap">
|
|
112
|
+
<canvas id="canvas"></canvas>
|
|
113
|
+
</div>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Call `reel.spin()` to consume the next item from `queuedSpinStates`.
|
|
117
|
+
|
|
118
|
+
## SpinState
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
type SpinState = {
|
|
122
|
+
stopGrid?: number[][];
|
|
123
|
+
stopRows?: number[][];
|
|
124
|
+
finaleSequence?: number[][][];
|
|
125
|
+
finaleSequenceRows?: number[][][];
|
|
126
|
+
highlightWin?: boolean;
|
|
127
|
+
callback?: () => void;
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Use `stopRows` for row-major input (`[row][col]`).
|
|
132
|
+
- Use `stopGrid` for column-major input (`[col][row]`).
|
|
133
|
+
- `finaleSequenceRows` and `finaleSequence` follow the same row/column conventions.
|
|
134
|
+
|
|
135
|
+
## Options
|
|
136
|
+
|
|
137
|
+
| Option | Type | Default | Description |
|
|
138
|
+
|:-------------------------------|:-----------------------------------------|:-----------------:|:-------------------------------------------------------|
|
|
139
|
+
| `canvas` | `HTMLCanvasElement` | — | Canvas for rendering. |
|
|
140
|
+
| `container` | `HTMLElement` | — | Element used for responsive sizing. |
|
|
141
|
+
| `button` | `HTMLButtonElement` | — | Optional spin button. |
|
|
142
|
+
| `sprite` | `string \| HTMLImageElement` | — | Sprite sheet URL or preloaded image element. |
|
|
143
|
+
| `spriteCrossOrigin` | `'' \| 'anonymous' \| 'use-credentials'` | `'anonymous'` | `crossOrigin` mode used when `sprite` is a URL string. |
|
|
144
|
+
| `spriteElementsCount` | `number` | `6` | Number of symbols in the sprite sheet. |
|
|
145
|
+
| `symbolScale` | `number` | `0.9` | Symbol scale inside the cell. Clamped to `0.5..1.2`. |
|
|
146
|
+
| `initialSegments` | `number[][]` | randomized | Initial 3x3 state in rows format. |
|
|
147
|
+
| `highlightInitialWinningCells` | `boolean` | `true` | Show initial highlight before first spin. |
|
|
148
|
+
| `queuedSpinStates` | `SpinState[]` | `[]` | Predefined queue consumed by `spin()`. |
|
|
149
|
+
| `particleColor` | `'rainbow' \| [number, number, number]` | `[255, 235, 110]` | Win particle color mode or solid RGB color. |
|
|
150
|
+
|
|
151
|
+
## Methods
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
await reel.init();
|
|
155
|
+
reel.spin();
|
|
156
|
+
reel.destroy();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Sprite Format
|
|
160
|
+
|
|
161
|
+
- Single vertical sprite sheet.
|
|
162
|
+
- Every symbol frame is square.
|
|
163
|
+
- Total texture height equals `spriteElementsCount * frameWidth` (square-frame assumption).
|
|
164
|
+
- `PNG` and `WebP` with transparency are supported.
|
|
165
|
+
- When using a cross-origin sprite URL (CDN/sandbox), keep `spriteCrossOrigin: 'anonymous'` and ensure the host returns CORS headers.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|