reel-deal 0.1.1 → 0.1.2

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/dist/index.es.js CHANGED
@@ -1,68 +1,599 @@
1
- const T = {
1
+ const Z = (r) => new Promise((e, t) => {
2
+ const i = () => e(), s = () => t(new Error("Failed to load sprite image"));
3
+ r.addEventListener("load", i, { once: !0 }), r.addEventListener("error", s, { once: !0 });
4
+ }), J = async (r, e) => {
5
+ const t = typeof r == "string" ? new Image() : r;
6
+ typeof r == "string" && (t.src = r), (!t.complete || t.naturalWidth <= 0) && await Z(t);
7
+ const i = Math.max(1, Math.floor(e)), s = t.naturalWidth, n = s, a = n * i, u = t.naturalHeight;
8
+ if (Math.abs(u - a) > 2)
9
+ throw new Error(
10
+ `Sprite size mismatch. Expected height ~${Math.round(a)}px (slotCount=${i}, slot aspect 1/1), got ${u}px.`
11
+ );
12
+ return {
13
+ image: t,
14
+ spriteWidth: s,
15
+ frameHeight: Math.max(1, Math.round(n)),
16
+ spriteHeight: Math.max(1, Math.round(n * i)),
17
+ slotCount: i
18
+ };
19
+ }, P = {
2
20
  minSpins: 2,
3
21
  durationMs: 4e3,
4
22
  speedPxS: 4e3,
5
23
  staggerMs: 300
6
- }, C = {
24
+ }, B = {
7
25
  maxPx: 4,
8
26
  speedAtMax: 2200
9
- }, E = {
27
+ }, R = {
10
28
  amplitudePx: 9,
11
29
  speedHz: 0.25,
12
30
  phaseOffsetRad: 0.9,
13
31
  rampMs: 800
14
- }, B = 0.1, A = 0.6, O = (a, t, s) => Math.max(t, Math.min(s, Math.floor(a))), I = (a, t) => (a % t + t) % t, v = (a) => Math.max(0, Math.min(1, a)), F = (a) => {
15
- const t = v(a);
16
- return t ** 2 * (2 - t);
17
- }, $ = (a) => {
18
- const t = v(a);
19
- return t + t ** 2 - t ** 3;
20
- }, Q = (a) => {
21
- const t = v(a);
22
- if (t <= B) {
23
- const i = t / B;
24
- return F(i) * B;
25
- }
26
- if (t < A)
27
- return t;
28
- const s = (t - A) / (1 - A);
29
- return A + $(s) * (1 - A);
30
- }, L = (a, t) => typeof a == "number" && Number.isFinite(a) ? a : t, _ = (a, t) => Math.max(0, L(a, t)), w = (a, t) => Math.max(0, Math.floor(L(a, t))), K = 2, X = (a) => {
31
- const t = { ...T, ...a ?? {} };
32
+ }, k = {
33
+ warpAngleDeg: 60,
34
+ edgePower: 4.8
35
+ }, z = {
36
+ thickness: 6,
37
+ intensity: 1
38
+ }, F = 0.1, T = 0.6, M = (r, e, t) => Math.max(e, Math.min(t, Math.floor(r))), y = (r, e) => (r % e + e) % e, v = (r) => Math.max(0, Math.min(1, r)), ee = (r) => {
39
+ const e = v(r);
40
+ return e ** 2 * (2 - e);
41
+ }, te = (r) => {
42
+ const e = v(r);
43
+ return e + e ** 2 - e ** 3;
44
+ }, ie = (r) => {
45
+ const e = v(r);
46
+ if (e <= F) {
47
+ const i = e / F;
48
+ return ee(i) * F;
49
+ }
50
+ if (e < T)
51
+ return e;
52
+ const t = (e - T) / (1 - T);
53
+ return T + te(t) * (1 - T);
54
+ }, D = (r, e) => typeof r == "number" && Number.isFinite(r) ? r : e, x = (r, e) => Math.max(0, D(r, e)), L = (r, e) => Math.max(0, Math.floor(D(r, e))), se = 2, N = (r) => {
55
+ const e = { ...P, ...r ?? {} };
32
56
  return {
33
- minSpins: w(t.minSpins, T.minSpins),
34
- durationMs: w(t.durationMs, T.durationMs ?? 0),
35
- speedPxS: w(t.speedPxS, T.speedPxS ?? 0),
36
- staggerMs: w(t.staggerMs, T.staggerMs ?? 0)
57
+ minSpins: L(e.minSpins, P.minSpins ?? 0),
58
+ durationMs: L(e.durationMs, P.durationMs ?? 0),
59
+ speedPxS: L(e.speedPxS, P.speedPxS ?? 0),
60
+ staggerMs: L(e.staggerMs, P.staggerMs ?? 0)
37
61
  };
38
- }, Z = (a) => {
39
- const t = { ...C, ...a ?? {} };
62
+ }, re = (r) => {
63
+ const e = { ...B, ...r ?? {} };
40
64
  return {
41
- maxPx: _(t.maxPx, C.maxPx),
42
- speedAtMax: _(t.speedAtMax, C.speedAtMax)
65
+ maxPx: x(e.maxPx, B.maxPx),
66
+ speedAtMax: x(e.speedAtMax, B.speedAtMax)
43
67
  };
44
- }, j = (a) => {
45
- if (a === !1) return null;
46
- const t = { ...E, ...a ?? {} };
68
+ }, ne = (r) => {
69
+ if (r === !1) return null;
70
+ const e = { ...R, ...r ?? {} };
47
71
  return {
48
- amplitudePx: _(t.amplitudePx, E.amplitudePx),
49
- speedHz: _(t.speedHz, E.speedHz),
50
- phaseOffsetRad: L(t.phaseOffsetRad, E.phaseOffsetRad),
51
- rampMs: w(t.rampMs, E.rampMs)
72
+ amplitudePx: x(e.amplitudePx, R.amplitudePx),
73
+ speedHz: x(e.speedHz, R.speedHz),
74
+ phaseOffsetRad: D(e.phaseOffsetRad, R.phaseOffsetRad),
75
+ rampMs: L(e.rampMs, R.rampMs)
52
76
  };
53
- }, J = (a) => Math.max(1, L(a, K)), tt = (a, t) => {
54
- const s = document.getElementById(a);
55
- if (!s)
56
- throw new Error(`${t} not found: ${a}`);
57
- return s;
58
- }, U = (a, t) => typeof a == "string" ? tt(a, t) : a, et = 5, z = 0.72, st = 0.28, it = 7, V = 0.85, rt = 1 - V, nt = 55, at = 300, ot = 1.25, lt = 0.35, N = {
59
- warpAngleDeg: 60,
60
- edgePower: 4.8
61
- }, ht = (a) => ({
62
- warpAngleDeg: _(a?.warpAngleDeg, N.warpAngleDeg),
63
- edgePower: _(a?.edgePower, N.edgePower)
64
- });
65
- class ut {
77
+ }, ae = (r) => Math.max(1, D(r, se)), oe = (r) => ({
78
+ warpAngleDeg: x(r?.warpAngleDeg, k.warpAngleDeg),
79
+ edgePower: x(r?.edgePower, k.edgePower)
80
+ }), le = (r) => r === !1 || !r ? null : {
81
+ thickness: x(r.thickness, z.thickness),
82
+ intensity: v(r.intensity ?? z.intensity)
83
+ }, he = (r) => {
84
+ const {
85
+ stopAtSegments: e,
86
+ currentOffsets: t,
87
+ reels: i,
88
+ frameHeight: s,
89
+ spriteHeight: n,
90
+ centerIndex: a,
91
+ slotCount: u,
92
+ spinConfig: l,
93
+ stopSpringOvershootPx: d,
94
+ stopSpringSettleMs: o,
95
+ useSpeed: c
96
+ } = r, b = new Array(i), p = new Array(i), h = new Array(i), g = new Array(i), m = new Array(i), { minSpins: S, staggerMs: I, speedPxS: w, durationMs: E } = l, H = o > 0 && d > 0;
97
+ for (let f = 0; f < i; f += 1) {
98
+ const Q = M(e[f] ?? 0, 0, u - 1) * s - a * s, K = y(Q, n), j = y(t[f], n), O = y(j - K, n);
99
+ let _ = -(S * n + O);
100
+ if (c && E > 0) {
101
+ const C = w * E / 1e3, A = Math.max(
102
+ S,
103
+ Math.ceil(Math.max(0, C - O) / n)
104
+ );
105
+ _ = -(O + A * n);
106
+ }
107
+ if (I > 0 && c) {
108
+ const C = w * I * f / 1e3, A = Math.ceil(C / n);
109
+ _ -= A * n;
110
+ }
111
+ b[f] = t[f], m[f] = t[f] + _;
112
+ let U = _, X = 0;
113
+ if (H && _ !== 0 && d > 0) {
114
+ const A = Math.sign(_) * d;
115
+ U += A, X = o;
116
+ }
117
+ p[f] = U, g[f] = X, c ? h[f] = Math.max(0, Math.round(Math.abs(U) / w * 1e3)) : h[f] = Math.max(0, E + I * f);
118
+ }
119
+ const Y = p.reduce((f, G) => f + Math.abs(G), 0), q = h.every((f) => f <= 0), $ = g.every((f) => f <= 0);
120
+ return {
121
+ startOffsets: b,
122
+ deltas: p,
123
+ durations: h,
124
+ settleDurationMs: g,
125
+ targets: m,
126
+ totalDelta: Y,
127
+ allSpinZero: q,
128
+ allSettleZero: $
129
+ };
130
+ }, ue = (r, e) => {
131
+ if (r === 0) return 0;
132
+ const t = Math.exp(-5 * e), i = Math.PI * 2 * 1.25 * e;
133
+ return r * t * Math.cos(i);
134
+ }, fe = (r, e, t) => {
135
+ if (e.lastVelT === null) {
136
+ e.lastVelT = r;
137
+ for (let a = 0; a < t.length; a += 1)
138
+ e.lastVelOffsets[a] = t[a], e.velocities[a] = 0;
139
+ return e.lastVelT;
140
+ }
141
+ const i = (r - e.lastVelT) / 1e3;
142
+ if (i <= 0) return e.lastVelT;
143
+ const s = 0.85, n = 1 - s;
144
+ for (let a = 0; a < t.length; a += 1) {
145
+ const u = (t[a] - e.lastVelOffsets[a]) / i;
146
+ e.velocities[a] = e.velocities[a] * s + u * n, e.lastVelOffsets[a] = t[a];
147
+ }
148
+ return e.lastVelT = r, e.lastVelT;
149
+ }, ce = (r, e, t, i, s) => {
150
+ e.idleStartTime === null && (e.idleStartTime = r);
151
+ const { amplitudePx: n, speedHz: a, phaseOffsetRad: u, rampMs: l } = t, d = r - e.idleStartTime, o = d / 1e3, c = Math.max(0, Math.min(1, d / Math.max(1, l))), b = Math.min(1, Math.max(0, c * c * (2 - c))), p = a * Math.PI * 2;
152
+ for (let h = 0; h < s; h += 1) {
153
+ const g = o * p + h * u;
154
+ i[h] = e.idleBaseOffsets[h] + Math.sin(g) * (n * b), e.velocities[h] = 0;
155
+ }
156
+ return e.idleStartTime;
157
+ };
158
+ class de {
159
+ rafId = null;
160
+ step = null;
161
+ abortListener = null;
162
+ start(e, t) {
163
+ this.rafId === null && (this.step = e, this.attachAbort(t), this.rafId = requestAnimationFrame(this.tick));
164
+ }
165
+ stop() {
166
+ this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.step = null, this.detachAbort();
167
+ }
168
+ isRunning() {
169
+ return this.rafId !== null;
170
+ }
171
+ tick = (e) => {
172
+ if (!this.step) {
173
+ this.stop();
174
+ return;
175
+ }
176
+ if (this.step(e) === !1) {
177
+ this.stop();
178
+ return;
179
+ }
180
+ this.rafId !== null && (this.rafId = requestAnimationFrame(this.tick));
181
+ };
182
+ attachAbort(e) {
183
+ if (!e) return;
184
+ if (e.aborted) {
185
+ this.stop();
186
+ return;
187
+ }
188
+ const t = () => {
189
+ this.stop();
190
+ };
191
+ e.addEventListener("abort", t, { once: !0 }), this.abortListener = () => e.removeEventListener("abort", t);
192
+ }
193
+ detachAbort() {
194
+ this.abortListener && this.abortListener(), this.abortListener = null;
195
+ }
196
+ }
197
+ class pe {
198
+ slotCount;
199
+ reels;
200
+ queue;
201
+ constructor(e) {
202
+ this.slotCount = Math.max(1, Math.floor(e.slotCount)), this.reels = Math.max(1, Math.floor(e.reels)), this.queue = [...e.initialQueue ?? []];
203
+ }
204
+ reset(e) {
205
+ this.queue = [...e ?? []];
206
+ }
207
+ hasPending() {
208
+ return this.queue.length > 0;
209
+ }
210
+ consume() {
211
+ return this.queue.length === 0 ? {
212
+ state: { stopAtSegments: this.buildRandomSegments() },
213
+ remaining: 0,
214
+ isLast: !0
215
+ } : {
216
+ state: this.queue.shift() ?? { stopAtSegments: this.buildRandomSegments() },
217
+ remaining: this.queue.length,
218
+ isLast: this.queue.length === 0
219
+ };
220
+ }
221
+ buildRandomSegments() {
222
+ const e = this.slotCount, t = [];
223
+ for (let i = 0; i < this.reels; i += 1)
224
+ t.push(M(Math.floor(Math.random() * e), 0, e - 1));
225
+ return t;
226
+ }
227
+ }
228
+ class ge {
229
+ button;
230
+ handler;
231
+ attached = !1;
232
+ spinning = !1;
233
+ constructor(e, t) {
234
+ this.button = e, this.handler = t, this.attach();
235
+ }
236
+ updateAvailability(e) {
237
+ this.button && this.setDisabled(!e);
238
+ }
239
+ dispose() {
240
+ this.button && this.attached && (this.button.removeEventListener("click", this.onClick), this.attached = !1), this.spinning = !1;
241
+ }
242
+ attach() {
243
+ !this.button || this.attached || (this.button.addEventListener("click", this.onClick, { passive: !0 }), this.attached = !0);
244
+ }
245
+ setDisabled(e) {
246
+ this.button && (this.button.disabled = e, e ? this.button.setAttribute("aria-busy", "true") : this.button.removeAttribute("aria-busy"));
247
+ }
248
+ onClick = async () => {
249
+ if (!this.spinning) {
250
+ this.spinning = !0, this.setDisabled(!0);
251
+ try {
252
+ await this.handler();
253
+ } finally {
254
+ this.spinning = !1, this.setDisabled(!1);
255
+ }
256
+ }
257
+ };
258
+ }
259
+ const me = `
260
+ attribute vec2 a_pos;
261
+ attribute vec2 a_uv;
262
+ varying vec2 v_uv;
263
+ void main() {
264
+ v_uv = a_uv;
265
+ gl_Position = vec4(a_pos, 0.0, 1.0);
266
+ }
267
+ `, be = `
268
+ #ifdef GL_FRAGMENT_PRECISION_HIGH
269
+ precision highp float;
270
+ #else
271
+ precision mediump float;
272
+ #endif
273
+
274
+ varying vec2 v_uv;
275
+ uniform sampler2D u_tex;
276
+ uniform float u_reelX;
277
+ uniform float u_reelW;
278
+ uniform float u_offsetPx;
279
+ uniform float u_frameHeight;
280
+ uniform float u_spriteHeight;
281
+ uniform float u_visibleSlots;
282
+ uniform float u_heightScale;
283
+ uniform float u_edgePower;
284
+ uniform float u_warpAngle;
285
+ uniform float u_blurPx;
286
+
287
+ const float HALF_PI = 1.5707963;
288
+
289
+ float saturate(float x) { return clamp(x, 0.0, 1.0); }
290
+
291
+ void main() {
292
+ if (v_uv.x < u_reelX || v_uv.x > (u_reelX + u_reelW)) {
293
+ discard;
294
+ }
295
+
296
+ float localX = (v_uv.x - u_reelX) / u_reelW;
297
+ float localY = v_uv.y;
298
+ float hs = max(0.0001, u_heightScale);
299
+ float fullY = localY * hs + (1.0 - hs) * 0.5;
300
+
301
+ float warp = max(0.0, u_warpAngle);
302
+ float warpStrength = saturate(warp / HALF_PI);
303
+ float distNorm = abs(fullY - 0.5) * 2.0;
304
+ float edgePow = max(0.5, u_edgePower);
305
+ float edgeWeight = pow(saturate(distNorm), edgePow) * warpStrength;
306
+
307
+ float stretchMax = 6.0;
308
+ float stretch = mix(1.0, stretchMax, edgeWeight);
309
+ float warpedY = 0.5 + (fullY - 0.5) * stretch;
310
+
311
+ float arcY = 0.5 + 0.5 * sin((warpedY - 0.5) * HALF_PI);
312
+ warpedY = mix(warpedY, arcY, 0.2);
313
+
314
+ float yPx = u_offsetPx + warpedY * (u_frameHeight * u_visibleSlots);
315
+ float v = fract((u_offsetPx / u_spriteHeight) +
316
+ warpedY * ((u_frameHeight * u_visibleSlots) / u_spriteHeight));
317
+
318
+ vec4 base = texture2D(u_tex, vec2(localX, v));
319
+
320
+ if (u_blurPx > 0.0) {
321
+ float maxStepPx = 1.0 + 3.0 * saturate(u_blurPx / 4.0);
322
+ float blurPx = min(u_blurPx, maxStepPx);
323
+ float blurStep = blurPx / max(1.0, u_spriteHeight);
324
+ vec4 sum = base * 0.227027;
325
+ sum += texture2D(u_tex, vec2(localX, fract(v + blurStep))) * 0.1945946;
326
+ sum += texture2D(u_tex, vec2(localX, fract(v - blurStep))) * 0.1945946;
327
+ sum += texture2D(u_tex, vec2(localX, fract(v + 2.0 * blurStep))) * 0.1216216;
328
+ sum += texture2D(u_tex, vec2(localX, fract(v - 2.0 * blurStep))) * 0.1216216;
329
+ sum += texture2D(u_tex, vec2(localX, fract(v + 3.0 * blurStep))) * 0.054054;
330
+ sum += texture2D(u_tex, vec2(localX, fract(v - 3.0 * blurStep))) * 0.054054;
331
+ sum += texture2D(u_tex, vec2(localX, fract(v + 4.0 * blurStep))) * 0.016216;
332
+ sum += texture2D(u_tex, vec2(localX, fract(v - 4.0 * blurStep))) * 0.016216;
333
+ base = sum;
334
+ }
335
+
336
+ gl_FragColor = base;
337
+ }
338
+ `, Se = `
339
+ attribute vec2 a_pos;
340
+ varying vec2 v_pos;
341
+ void main() {
342
+ v_pos = a_pos;
343
+ gl_Position = vec4(a_pos, 0.0, 1.0);
344
+ }
345
+ `, ve = `
346
+ #ifdef GL_FRAGMENT_PRECISION_HIGH
347
+ precision highp float;
348
+ #else
349
+ precision mediump float;
350
+ #endif
351
+
352
+ varying vec2 v_pos;
353
+ uniform float u_time;
354
+ uniform vec2 u_resolution;
355
+ uniform float u_thickness;
356
+ uniform float u_intensity;
357
+
358
+ void main() {
359
+ vec2 uv = v_pos;
360
+ float centerY = 0.0;
361
+ float distY = abs(uv.y - centerY);
362
+ float thicknessPx = u_thickness / u_resolution.y * 2.0;
363
+
364
+ float lineMask = 1.0 - smoothstep(0.0, thicknessPx * 2.0, distY);
365
+
366
+ if (lineMask <= 0.001) {
367
+ discard;
368
+ }
369
+
370
+ vec3 color;
371
+ float alpha = lineMask * u_intensity;
372
+
373
+ float warm = 1.0 - exp(-u_time * 2.6);
374
+ float flicker = (sin(u_time * 37.0) * sin(u_time * 13.0)) * 0.28;
375
+ flicker *= exp(-u_time * 2.2);
376
+ warm = clamp(warm + flicker, 0.0, 1.0);
377
+ float warmColor = mix(0.65, 1.0, warm);
378
+ alpha *= warm;
379
+
380
+ float pulse = sin(u_time * 4.0) * 0.3 + 0.7;
381
+ float x = (uv.x + 1.0) * 0.5;
382
+ float wave = sin(x * 30.0 - u_time * 8.0) * 0.2;
383
+
384
+ color = vec3(1.0, 0.8, 0.2) * (pulse + wave);
385
+
386
+ float core = exp(-distY * 120.0 / thicknessPx);
387
+ color = mix(color, vec3(1.0), core * 0.6);
388
+
389
+ color *= warmColor;
390
+ gl_FragColor = vec4(color, alpha);
391
+ }
392
+ `;
393
+ class xe {
394
+ program = null;
395
+ buffer = null;
396
+ attribs = null;
397
+ uniforms = null;
398
+ startTime = null;
399
+ show = !1;
400
+ init(e, t) {
401
+ const i = this.createProgram(e, Se, ve);
402
+ if (!i) return;
403
+ const s = e.createBuffer();
404
+ if (!s) {
405
+ e.deleteProgram(i);
406
+ return;
407
+ }
408
+ e.bindBuffer(e.ARRAY_BUFFER, s);
409
+ const n = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
410
+ e.bufferData(e.ARRAY_BUFFER, n, e.STATIC_DRAW), this.program = i, this.buffer = s, this.attribs = { pos: e.getAttribLocation(i, "a_pos") }, this.uniforms = {
411
+ time: e.getUniformLocation(i, "u_time"),
412
+ resolution: e.getUniformLocation(i, "u_resolution"),
413
+ thickness: e.getUniformLocation(i, "u_thickness"),
414
+ intensity: e.getUniformLocation(i, "u_intensity")
415
+ }, this.startTime = null, this.show = !1;
416
+ }
417
+ showLine() {
418
+ this.show = !0, this.startTime = null;
419
+ }
420
+ hideLine() {
421
+ this.show = !1, this.startTime = null;
422
+ }
423
+ dispose(e) {
424
+ this.program && e.deleteProgram(this.program), this.buffer && e.deleteBuffer(this.buffer), this.program = null, this.buffer = null, this.attribs = null, this.uniforms = null, this.startTime = null, this.show = !1;
425
+ }
426
+ render(e, t, i, s) {
427
+ if (!this.show || !this.program || !this.buffer || !this.attribs || !this.uniforms) return;
428
+ const n = performance.now();
429
+ this.startTime === null && (this.startTime = n);
430
+ const a = (n - this.startTime) / 1e3;
431
+ e.useProgram(this.program), e.bindBuffer(e.ARRAY_BUFFER, this.buffer), e.enableVertexAttribArray(this.attribs.pos), e.vertexAttribPointer(this.attribs.pos, 2, e.FLOAT, !1, 0, 0), e.uniform1f(this.uniforms.time, a), e.uniform2f(this.uniforms.resolution, t.width, t.height), e.uniform1f(this.uniforms.thickness, i.thickness * s), e.uniform1f(this.uniforms.intensity, i.intensity), e.drawArrays(e.TRIANGLE_STRIP, 0, 4);
432
+ }
433
+ createProgram(e, t, i) {
434
+ const s = this.createShader(e, e.VERTEX_SHADER, t), n = this.createShader(e, e.FRAGMENT_SHADER, i);
435
+ if (!s || !n)
436
+ return s && e.deleteShader(s), n && e.deleteShader(n), null;
437
+ const a = e.createProgram();
438
+ return a ? (e.attachShader(a, s), e.attachShader(a, n), e.linkProgram(a), e.getProgramParameter(a, e.LINK_STATUS) ? (e.detachShader(a, s), e.detachShader(a, n), e.deleteShader(s), e.deleteShader(n), a) : (e.deleteProgram(a), e.deleteShader(s), e.deleteShader(n), null)) : null;
439
+ }
440
+ createShader(e, t, i) {
441
+ const s = e.createShader(t);
442
+ return s ? (e.shaderSource(s, i), e.compileShader(s), e.getShaderParameter(s, e.COMPILE_STATUS) ? s : (e.deleteShader(s), null)) : null;
443
+ }
444
+ }
445
+ class _e {
446
+ gl = null;
447
+ glProgram = null;
448
+ glBuffer = null;
449
+ glTexture = null;
450
+ glAttribs = null;
451
+ glUniforms = null;
452
+ config = null;
453
+ canvas = null;
454
+ spriteImg = null;
455
+ webglInitError = null;
456
+ lineRenderer = null;
457
+ showLine = !1;
458
+ init(e) {
459
+ if (this.canvas = e.canvas, this.spriteImg = e.spriteImg, this.config = {
460
+ spriteWidth: e.spriteWidth,
461
+ spriteHeight: e.spriteHeight,
462
+ frameHeight: e.frameHeight,
463
+ reels: e.reels,
464
+ visibleSlots: e.visibleSlots,
465
+ heightScale: e.heightScale,
466
+ spinBlur: e.spinBlur,
467
+ webglShading: e.webglShading,
468
+ finalSpinLine: e.finalSpinLine
469
+ }, this.lineRenderer = e.finalSpinLine ? new xe() : null, this.tryInitWebGL(), !this.gl)
470
+ throw new Error(
471
+ `WebGL is not supported or failed to initialize. ${this.webglInitError ?? ""}`.trim()
472
+ );
473
+ }
474
+ getError() {
475
+ return this.webglInitError;
476
+ }
477
+ render(e) {
478
+ !this.gl || !this.config || !this.spriteImg || !this.glProgram || !this.glAttribs || !this.glUniforms || !this.glBuffer || (this.renderWebGL(e), this.renderFinalLine(e));
479
+ }
480
+ onResize(e, t) {
481
+ !this.gl || !this.canvas || this.gl.viewport(0, 0, e, t);
482
+ }
483
+ showFinalLine() {
484
+ this.config?.finalSpinLine && (this.showLine = !0, this.lineRenderer?.showLine());
485
+ }
486
+ hideFinalLine() {
487
+ this.showLine = !1, this.lineRenderer?.hideLine();
488
+ }
489
+ dispose() {
490
+ this.gl && (this.glTexture && this.gl.deleteTexture(this.glTexture), this.glBuffer && this.gl.deleteBuffer(this.glBuffer), this.glProgram && this.gl.deleteProgram(this.glProgram), this.lineRenderer && this.lineRenderer.dispose(this.gl), this.glTexture = null, this.glBuffer = null, this.glProgram = null, this.glAttribs = null, this.glUniforms = null, this.gl = null, this.webglInitError = null);
491
+ }
492
+ tryInitWebGL() {
493
+ if (!this.canvas || !this.spriteImg || !this.config) return;
494
+ this.dispose(), this.webglInitError = null;
495
+ const e = this.canvas.getContext("webgl2", {
496
+ antialias: !0,
497
+ alpha: !0
498
+ }) ?? this.canvas.getContext("webgl", {
499
+ antialias: !0,
500
+ alpha: !0
501
+ }) ?? this.canvas.getContext("experimental-webgl", {
502
+ antialias: !0,
503
+ alpha: !0
504
+ });
505
+ if (!e) {
506
+ const l = document.createElement("canvas"), d = typeof WebGLRenderingContext < "u", o = l.getContext("webgl2") ?? l.getContext("webgl");
507
+ this.webglInitError = `context is null (browser WebGL=${d ? "yes" : "no"}, fallback canvas=${o ? "yes" : "no"})`, console.warn("ReelDeal WebGL:", this.webglInitError);
508
+ return;
509
+ }
510
+ const t = this.createWebGLProgram(e, me, be);
511
+ if (!t) {
512
+ this.webglInitError = "shader program failed to compile/link (see console)", console.warn("ReelDeal WebGL:", this.webglInitError);
513
+ return;
514
+ }
515
+ const i = e.createBuffer();
516
+ if (!i) {
517
+ this.webglInitError = "failed to create vertex buffer", console.warn("ReelDeal WebGL:", this.webglInitError), e.deleteProgram(t);
518
+ return;
519
+ }
520
+ e.bindBuffer(e.ARRAY_BUFFER, i);
521
+ const s = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, 1, 1, 1, 0]);
522
+ e.bufferData(e.ARRAY_BUFFER, s, e.STATIC_DRAW);
523
+ const n = e.createTexture();
524
+ if (!n) {
525
+ this.webglInitError = "failed to create texture", console.warn("ReelDeal WebGL:", this.webglInitError), e.deleteBuffer(i), e.deleteProgram(t);
526
+ return;
527
+ }
528
+ e.bindTexture(e.TEXTURE_2D, n), e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL, 0), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, this.spriteImg);
529
+ const a = (l) => l > 0 && (l & l - 1) === 0;
530
+ a(this.config.spriteWidth) && a(this.config.spriteHeight) ? (e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.REPEAT), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.REPEAT), e.generateMipmap(e.TEXTURE_2D), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR_MIPMAP_LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR)) : (e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE)), e.useProgram(t), e.clearColor(0, 0, 0, 0), e.enable(e.BLEND), e.blendFunc(e.SRC_ALPHA, e.ONE_MINUS_SRC_ALPHA), this.gl = e, this.glProgram = t, this.glBuffer = i, this.glTexture = n, this.glAttribs = {
531
+ pos: e.getAttribLocation(t, "a_pos"),
532
+ uv: e.getAttribLocation(t, "a_uv")
533
+ }, this.glUniforms = {
534
+ texture: e.getUniformLocation(t, "u_tex"),
535
+ reelX: e.getUniformLocation(t, "u_reelX"),
536
+ reelW: e.getUniformLocation(t, "u_reelW"),
537
+ offsetPx: e.getUniformLocation(t, "u_offsetPx"),
538
+ frameHeight: e.getUniformLocation(t, "u_frameHeight"),
539
+ spriteHeight: e.getUniformLocation(t, "u_spriteHeight"),
540
+ visibleSlots: e.getUniformLocation(t, "u_visibleSlots"),
541
+ heightScale: e.getUniformLocation(t, "u_heightScale"),
542
+ edgePower: e.getUniformLocation(t, "u_edgePower"),
543
+ warpAngle: e.getUniformLocation(t, "u_warpAngle"),
544
+ blurPx: e.getUniformLocation(t, "u_blurPx")
545
+ }, this.config.finalSpinLine && this.lineRenderer && this.lineRenderer.init(e, this.config.finalSpinLine);
546
+ }
547
+ createWebGLProgram(e, t, i) {
548
+ const s = this.createWebGLShader(e, e.VERTEX_SHADER, t), n = this.createWebGLShader(e, e.FRAGMENT_SHADER, i);
549
+ if (!s || !n)
550
+ return s && e.deleteShader(s), n && e.deleteShader(n), null;
551
+ const a = e.createProgram();
552
+ if (!a) return null;
553
+ if (e.attachShader(a, s), e.attachShader(a, n), e.linkProgram(a), !e.getProgramParameter(a, e.LINK_STATUS)) {
554
+ const u = e.getProgramInfoLog(a) ?? "unknown link error";
555
+ return this.webglInitError = `program link failed: ${u}`, console.warn("ReelDeal WebGL: program link failed", u), e.deleteProgram(a), e.deleteShader(s), e.deleteShader(n), null;
556
+ }
557
+ return e.detachShader(a, s), e.detachShader(a, n), e.deleteShader(s), e.deleteShader(n), a;
558
+ }
559
+ createWebGLShader(e, t, i) {
560
+ const s = e.createShader(t);
561
+ if (!s) return null;
562
+ if (e.shaderSource(s, i), e.compileShader(s), !e.getShaderParameter(s, e.COMPILE_STATUS)) {
563
+ const n = e.getShaderInfoLog(s) ?? "unknown compile error";
564
+ return this.webglInitError = `shader compile failed: ${n}`, console.warn("ReelDeal WebGL: shader compile failed", n), e.deleteShader(s), null;
565
+ }
566
+ return s;
567
+ }
568
+ getSpinBlurPxForReel(e, t) {
569
+ if (!this.config) return 0;
570
+ const i = Math.abs(t[e] ?? 0), s = Math.max(1, this.config.spinBlur.speedAtMax);
571
+ return v(i / s) * Math.max(0, this.config.spinBlur.maxPx);
572
+ }
573
+ renderWebGL(e) {
574
+ if (!this.gl || !this.glProgram || !this.glAttribs || !this.glUniforms || !this.glTexture || !this.glBuffer || !this.config || !this.spriteImg || !this.canvas) return;
575
+ const t = this.gl;
576
+ t.useProgram(this.glProgram), t.bindBuffer(t.ARRAY_BUFFER, this.glBuffer), t.enableVertexAttribArray(this.glAttribs.pos), t.vertexAttribPointer(this.glAttribs.pos, 2, t.FLOAT, !1, 16, 0), t.enableVertexAttribArray(this.glAttribs.uv), t.vertexAttribPointer(this.glAttribs.uv, 2, t.FLOAT, !1, 16, 8), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.glTexture), t.uniform1i(this.glUniforms.texture, 0), t.uniform1f(this.glUniforms.frameHeight, this.config.frameHeight), t.uniform1f(this.glUniforms.spriteHeight, this.config.spriteHeight), t.uniform1f(this.glUniforms.visibleSlots, this.config.visibleSlots), t.uniform1f(this.glUniforms.heightScale, this.config.heightScale), t.uniform1f(this.glUniforms.edgePower, Math.max(0.5, this.config.webglShading.edgePower));
577
+ const i = this.config.webglShading, s = Math.max(0, i.warpAngleDeg) * Math.PI / 180;
578
+ t.uniform1f(this.glUniforms.warpAngle, s), t.clear(t.COLOR_BUFFER_BIT);
579
+ const n = 1 / this.config.reels;
580
+ for (let a = 0; a < this.config.reels; a += 1) {
581
+ t.uniform1f(this.glUniforms.reelX, a * n), t.uniform1f(this.glUniforms.reelW, n);
582
+ const u = y(e.offsets[a], this.config.spriteHeight);
583
+ t.uniform1f(this.glUniforms.offsetPx, u), t.uniform1f(this.glUniforms.blurPx, this.getSpinBlurPxForReel(a, e.velocities)), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
584
+ }
585
+ }
586
+ renderFinalLine(e) {
587
+ !this.showLine || !this.config?.finalSpinLine || !this.gl || !this.canvas || !this.lineRenderer || this.lineRenderer.render(this.gl, this.canvas, this.config.finalSpinLine, e.dpr);
588
+ }
589
+ }
590
+ const we = (r, e) => {
591
+ const t = document.getElementById(r);
592
+ if (!t)
593
+ throw new Error(`${e} not found: ${r}`);
594
+ return t;
595
+ }, W = (r, e) => typeof r == "string" ? we(r, e) : r, Ee = 5, V = 0.72, Ae = 0.28, Pe = 7, Re = 55, Te = 300, Le = 0.35;
596
+ class Me {
66
597
  canvas;
67
598
  container;
68
599
  opts;
@@ -75,6 +606,7 @@ class ut {
75
606
  webglShading;
76
607
  idleBob;
77
608
  maxDpr;
609
+ finalSpinLine;
78
610
  spriteImg = null;
79
611
  spriteWidth = 0;
80
612
  spriteHeight = 0;
@@ -88,126 +620,183 @@ class ut {
88
620
  lastVelOffsets;
89
621
  idleStartTime = null;
90
622
  idleBaseOffsets;
91
- gl = null;
92
- glProgram = null;
93
- glBuffer = null;
94
- glTexture = null;
95
- glAttribs = null;
623
+ renderer = null;
96
624
  webglInitError = null;
97
- glUniforms = null;
98
625
  anim = null;
99
- rafId = null;
626
+ loop = new de();
100
627
  pendingSpinResolvers = [];
628
+ showFinalLine = !1;
629
+ isLastSpin = !1;
101
630
  resizeObserver = null;
102
631
  resizeQueued = !1;
103
632
  button = null;
104
- buttonHandlerAttached = !1;
105
- spinning = !1;
106
- queuedSpins = null;
107
- constructor(t) {
108
- this.opts = t, this.reels = O(t.reels ?? 1, 1, et), this.spinConfig = X(t.spinConfig), this.spinBlur = Z(t.spinBlur), this.webglShading = ht(t.webglShading), this.idleBob = j(t.idleBob), this.maxDpr = J(t.maxDpr), this.canvas = U(t.canvas, "Canvas"), this.container = U(t.container, "Container"), this.offsets = new Array(this.reels).fill(0), this.velocities = new Array(this.reels).fill(0), this.lastVelOffsets = new Array(this.reels).fill(0), this.idleBaseOffsets = new Array(this.reels).fill(0);
633
+ uiController = null;
634
+ spinQueueController;
635
+ constructor(e) {
636
+ if (!e.canvas) throw new Error("ReelDeal: canvas is required");
637
+ if (!e.container) throw new Error("ReelDeal: container is required");
638
+ if (!e.sprite) throw new Error("ReelDeal: sprite is required");
639
+ if (e.slotCount === void 0) throw new Error("ReelDeal: slotCount is required");
640
+ const t = {
641
+ ...e,
642
+ canvas: e.canvas,
643
+ container: e.container,
644
+ sprite: e.sprite,
645
+ slotCount: M(e.slotCount, 1, Number.MAX_SAFE_INTEGER)
646
+ };
647
+ this.opts = t, this.reels = M(e.reels ?? 1, 1, Ee), this.spinConfig = N(e.spinConfig), this.spinBlur = re(e.spinBlur), this.webglShading = oe(e.webglShading), this.idleBob = ne(e.idleBob), this.maxDpr = ae(e.maxDpr), this.finalSpinLine = le(e.finalSpinLine), this.canvas = W(t.canvas, "Canvas"), this.container = W(t.container, "Container"), this.offsets = new Float32Array(this.reels), this.velocities = new Float32Array(this.reels), this.lastVelOffsets = new Float32Array(this.reels), this.idleBaseOffsets = new Float32Array(this.reels), this.spinQueueController = new pe({
648
+ slotCount: t.slotCount,
649
+ reels: this.reels,
650
+ initialQueue: t.queuedSpinStates
651
+ });
652
+ }
653
+ initRenderer() {
654
+ if (!this.spriteImg) return;
655
+ const e = new _e();
656
+ try {
657
+ e.init({
658
+ canvas: this.canvas,
659
+ spriteImg: this.spriteImg,
660
+ spriteWidth: this.spriteWidth,
661
+ spriteHeight: this.spriteHeight,
662
+ frameHeight: this.frameHeight,
663
+ reels: this.reels,
664
+ visibleSlots: this.visibleSlots,
665
+ heightScale: this.heightScale,
666
+ spinBlur: this.spinBlur,
667
+ webglShading: this.webglShading,
668
+ finalSpinLine: this.finalSpinLine
669
+ }), this.webglInitError = e.getError(), this.renderer = e;
670
+ } catch (t) {
671
+ throw this.webglInitError = e.getError() ?? (t instanceof Error ? t.message : String(t)), t;
672
+ }
109
673
  }
110
674
  async init() {
111
- if (await this.loadSprite(), this.tryInitWebGL(), !this.gl)
675
+ const e = await J(this.opts.sprite, this.opts.slotCount);
676
+ if (this.spriteImg = e.image, this.spriteWidth = e.spriteWidth, this.frameHeight = e.frameHeight, this.spriteHeight = e.spriteHeight, this.initRenderer(), !this.renderer)
112
677
  throw new Error(
113
678
  `WebGL is not supported or failed to initialize. ${this.webglInitError ?? ""}`.trim()
114
679
  );
115
- this.syncContainerLayoutVars(), this.ensureCanvasCoversContainer(), this.setupResizeWatcher(), this.resizeToContainer(), this.setSegments(this.opts.initialSegments), this.button = this.resolveButton(), this.queuedSpins = this.resolveSpinQueue(), this.attachButtonHandler(), this.render(), this.startLoop();
680
+ this.syncContainerLayoutVars(), this.ensureCanvasCoversContainer(), this.setupResizeWatcher(), this.resizeToContainer(), this.setSegments(this.opts.initialSegments), this.button = this.resolveButton(), this.uiController = new ge(this.button, this.handleButtonClick), this.uiController.updateAvailability(!0), this.render(), this.startLoop();
116
681
  }
117
682
  destroy() {
118
- this.stop(), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.button && this.buttonHandlerAttached && (this.button.removeEventListener("click", this.handleButtonClick), this.buttonHandlerAttached = !1), this.releaseWebGLResources();
683
+ this.stop(), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.uiController?.dispose(), this.uiController = null, this.renderer && (this.renderer.dispose(), this.renderer = null);
119
684
  }
120
685
  ensureCanvasCoversContainer() {
121
686
  this.canvas !== this.container && this.container.contains(this.canvas) && (this.canvas.style.width || (this.canvas.style.width = "100%"), this.canvas.style.height || (this.canvas.style.height = "100%"), this.canvas.style.display || (this.canvas.style.display = "block"));
122
687
  }
123
688
  syncContainerLayoutVars() {
124
- const t = this.canvas === this.container ? this.canvas : this.container;
125
- t.style.setProperty("--reels", String(this.reels)), t.style.setProperty("--visible-slots", String(this.visibleSlots)), t.style.aspectRatio = `${this.reels} / ${this.visibleSlots * this.heightScale}`, this.canvas !== this.container && (this.container.style.overflow = "hidden");
689
+ const e = this.canvas === this.container ? this.canvas : this.container;
690
+ e.style.setProperty("--reels", String(this.reels)), e.style.setProperty("--visible-slots", String(this.visibleSlots)), e.style.aspectRatio = `${this.reels} / ${this.visibleSlots * this.heightScale}`, this.canvas !== this.container && (this.container.style.overflow = "hidden");
126
691
  }
127
- setSegments(t) {
692
+ setSegments(e) {
128
693
  this.ensureReady();
129
- const s = t ?? [];
694
+ const t = e ?? [];
130
695
  for (let i = 0; i < this.reels; i += 1) {
131
- const e = s[i] ?? 0, r = O(e, 0, this.opts.slotCount - 1);
132
- this.offsets[i] = r * this.frameHeight - this.centerIndex * this.frameHeight, this.lastVelOffsets[i] = this.offsets[i], this.velocities[i] = 0, this.idleBaseOffsets[i] = this.offsets[i];
696
+ const s = t[i] ?? 0, n = M(s, 0, this.opts.slotCount - 1);
697
+ this.offsets[i] = n * this.frameHeight - this.centerIndex * this.frameHeight, this.lastVelOffsets[i] = this.offsets[i], this.velocities[i] = 0, this.idleBaseOffsets[i] = this.offsets[i];
133
698
  }
134
699
  this.lastVelT = null, this.idleStartTime = null, this.anim = null, this.stop(), this.render(), this.startLoop();
135
700
  }
136
- setSegment(t) {
137
- this.setSegments(new Array(this.reels).fill(t));
701
+ setSegment(e) {
702
+ this.setSegments(new Array(this.reels).fill(e));
138
703
  }
139
- spinOnce(t, s) {
704
+ spinOnce(e, t) {
140
705
  this.ensureReady();
141
- const { minSpins: i, staggerMs: e, speedPxS: r, durationMs: l } = this.getSpinConfig(s), u = r > 0, f = this.getStopSpringOvershootPx(), c = Math.max(0, at), n = c > 0 && f > 0, h = new Array(this.reels), g = new Array(this.reels), p = new Array(this.reels), d = new Array(this.reels), m = new Array(this.reels);
142
- for (let o = 0; o < this.reels; o += 1) {
143
- const Y = O(t[o] ?? 0, 0, this.opts.slotCount - 1) * this.frameHeight - this.centerIndex * this.frameHeight, k = I(Y, this.spriteHeight), q = I(this.offsets[o], this.spriteHeight), H = I(q - k, this.spriteHeight);
144
- let b = -(i * this.spriteHeight + H);
145
- if (u && l > 0) {
146
- const R = r * l / 1e3, P = Math.max(
147
- i,
148
- Math.ceil(Math.max(0, R - H) / this.spriteHeight)
149
- );
150
- b = -(H + P * this.spriteHeight);
151
- }
152
- if (e > 0 && u) {
153
- const R = r * e * o / 1e3, P = Math.ceil(R / this.spriteHeight);
154
- b -= P * this.spriteHeight;
155
- }
156
- h[o] = this.offsets[o], m[o] = this.offsets[o] + b;
157
- let D = b, G = 0;
158
- if (n && b !== 0 && f > 0) {
159
- const P = Math.sign(b) * f;
160
- D += P, G = c;
161
- }
162
- g[o] = D, d[o] = G, u ? p[o] = Math.max(0, Math.round(Math.abs(D) / r * 1e3)) : p[o] = Math.max(0, l + e * o);
163
- }
164
- const S = g.reduce((o, M) => o + Math.abs(M), 0), x = p.every((o) => o <= 0), W = d.every((o) => o <= 0);
165
- if (S === 0 || x && W) {
166
- for (let o = 0; o < this.reels; o += 1)
167
- this.offsets[o] = m[o];
706
+ const i = Array.isArray(e) ? { stopAtSegments: e, config: t } : e;
707
+ if (i.signal?.aborted)
708
+ return Promise.reject(
709
+ i.signal.reason ?? new DOMException("Aborted", "AbortError")
710
+ );
711
+ const s = this.getSpinConfig(i.config ?? t), n = s.speedPxS > 0, a = this.getStopSpringOvershootPx(), u = Math.max(0, Te), l = he({
712
+ stopAtSegments: i.stopAtSegments,
713
+ currentOffsets: this.offsets,
714
+ reels: this.reels,
715
+ frameHeight: this.frameHeight,
716
+ spriteHeight: this.spriteHeight,
717
+ centerIndex: this.centerIndex,
718
+ slotCount: this.opts.slotCount,
719
+ spinConfig: s,
720
+ stopSpringOvershootPx: a,
721
+ stopSpringSettleMs: u,
722
+ useSpeed: n
723
+ });
724
+ if (l.totalDelta === 0 || l.allSpinZero && l.allSettleZero) {
725
+ for (let h = 0; h < this.reels; h += 1)
726
+ this.offsets[h] = l.targets[h];
168
727
  return this.anim = null, this.resolvePendingSpins(), this.render(), Promise.resolve();
169
728
  }
170
- const y = performance.now();
171
- return this.anim = {
172
- startTime: y,
173
- startOffsets: h,
174
- deltas: g,
175
- durationMs: p,
176
- settleDurationMs: d,
177
- targets: m
178
- }, this.idleStartTime = null, this.startLoop(), new Promise((o) => {
179
- this.pendingSpinResolvers.push(o);
729
+ const d = performance.now();
730
+ this.anim = {
731
+ startTime: d,
732
+ startOffsets: l.startOffsets,
733
+ deltas: l.deltas,
734
+ durationMs: l.durations,
735
+ settleDurationMs: l.settleDurationMs,
736
+ targets: l.targets
737
+ }, this.idleStartTime = null, this.startLoop();
738
+ const o = new AbortController(), c = () => {
739
+ const h = o.signal.reason ?? i.signal?.reason ?? "Spin aborted";
740
+ this.stop(h);
741
+ }, b = () => {
742
+ o.abort(
743
+ i.signal?.reason ?? new DOMException("Aborted", "AbortError")
744
+ );
745
+ };
746
+ i.signal && i.signal.addEventListener("abort", b, { once: !0 });
747
+ let p = null;
748
+ return i.timeoutMs && i.timeoutMs > 0 && (p = window.setTimeout(() => {
749
+ o.abort(new DOMException("Spin timed out", "TimeoutError"));
750
+ }, i.timeoutMs)), new Promise((h, g) => {
751
+ const m = () => {
752
+ p !== null && window.clearTimeout(p), o.signal.removeEventListener("abort", c), i.signal && i.signal.removeEventListener("abort", b);
753
+ };
754
+ if (o.signal.aborted) {
755
+ m(), g(o.signal.reason ?? new DOMException("Aborted", "AbortError"));
756
+ return;
757
+ }
758
+ o.signal.addEventListener("abort", c, { once: !0 }), this.pendingSpinResolvers.push({
759
+ resolve: () => {
760
+ m(), h();
761
+ },
762
+ reject: (S) => {
763
+ m(), g(S);
764
+ },
765
+ cleanup: m
766
+ });
180
767
  });
181
768
  }
182
- getSpinConfig(t) {
183
- return t ? X({ ...this.spinConfig, ...t }) : this.spinConfig;
769
+ getSpinConfig(e) {
770
+ return e ? N({ ...this.spinConfig, ...e }) : this.spinConfig;
184
771
  }
185
772
  getStopSpringOvershootPx() {
186
- const t = this.frameHeight * lt, s = Math.max(0, nt);
187
- return Math.min(s, t);
188
- }
189
- getStopSpringOffset(t, s) {
190
- if (t === 0) return 0;
191
- const i = Math.exp(-5 * s), e = Math.PI * 2 * ot * s;
192
- return t * i * Math.cos(e);
193
- }
194
- async spinQueue(t) {
195
- for (let s = 0; s < t.length; s += 1) {
196
- const i = t[s];
197
- await this.spinOnce(i.stopAtSegments), i.callback?.(s, i.stopAtSegments);
773
+ const e = this.frameHeight * Le, t = Math.max(0, Re);
774
+ return Math.min(t, e);
775
+ }
776
+ async spinQueue(e) {
777
+ this.spinQueueController.reset(e), this.uiController?.updateAvailability(!0);
778
+ for (let t = 0; t < e.length; t += 1) {
779
+ const i = e[t];
780
+ await this.spinOnce(i.stopAtSegments), i.callback?.(t, i.stopAtSegments);
198
781
  }
782
+ this.uiController?.updateAvailability(!0);
199
783
  }
200
- stop() {
201
- this.rafId !== null && cancelAnimationFrame(this.rafId), this.rafId = null, this.anim = null, this.resolvePendingSpins(), this.lastVelT = null;
202
- for (let t = 0; t < this.reels; t += 1)
203
- this.velocities[t] = 0;
784
+ stop(e) {
785
+ this.loop.stop(), this.anim = null, e !== void 0 ? this.rejectPendingSpins(e) : this.resolvePendingSpins(), this.lastVelT = null, this.velocities.fill(0);
204
786
  }
205
787
  resolvePendingSpins() {
788
+ if (this.pendingSpinResolvers.length === 0) return;
789
+ const e = this.pendingSpinResolvers;
790
+ this.pendingSpinResolvers = [];
791
+ for (const { resolve: t, cleanup: i } of e)
792
+ i(), t();
793
+ }
794
+ rejectPendingSpins(e) {
206
795
  if (this.pendingSpinResolvers.length === 0) return;
207
796
  const t = this.pendingSpinResolvers;
208
797
  this.pendingSpinResolvers = [];
209
- for (const s of t)
210
- s();
798
+ for (const { reject: i, cleanup: s } of t)
799
+ s(), i(e);
211
800
  }
212
801
  requestResize() {
213
802
  this.queueResize();
@@ -216,142 +805,85 @@ class ut {
216
805
  if (!this.spriteImg || this.spriteWidth <= 0 || this.spriteHeight <= 0 || this.frameHeight <= 0)
217
806
  throw new Error("Sprite is not ready. Call init() and await it first.");
218
807
  }
219
- attachButtonHandler() {
220
- !this.button || this.buttonHandlerAttached || (this.button.addEventListener("click", this.handleButtonClick, { passive: !0 }), this.buttonHandlerAttached = !0);
221
- }
222
808
  handleButtonClick = async () => {
223
- if (this.spinning) return;
224
- const t = this.consumeNextSpin() ?? {
225
- stopAtSegments: this.buildRandomSegments()
226
- };
227
- this.spinning = !0, this.setButtonDisabled(!0);
228
- try {
229
- await this.spinOnce(t.stopAtSegments);
230
- } finally {
231
- this.queuedSpins && this.queuedSpins.length === 0 ? this.setButtonDisabled(!0) : this.setButtonDisabled(!1), this.spinning = !1;
232
- }
809
+ this.hideFinalLine();
810
+ const e = this.spinQueueController.consume();
811
+ this.isLastSpin = e.isLast, this.uiController?.updateAvailability(!0), await this.spinOnce(e.state.stopAtSegments), this.isLastSpin && this.finalSpinLine && this.showFinalLineEffect();
233
812
  };
234
813
  resolveButton() {
235
- return this.opts.button ? U(this.opts.button, "Button") : null;
236
- }
237
- resolveSpinQueue() {
238
- return this.opts.queuedSpinStates ?? null;
239
- }
240
- consumeNextSpin() {
241
- return this.queuedSpins || (this.queuedSpins = this.resolveSpinQueue()), !this.queuedSpins || this.queuedSpins.length === 0 ? null : this.queuedSpins.shift() ?? null;
242
- }
243
- buildRandomSegments() {
244
- const t = Math.max(1, Math.floor(this.opts.slotCount)), s = [];
245
- for (let i = 0; i < this.reels; i += 1)
246
- s.push(Math.floor(Math.random() * t));
247
- return s;
248
- }
249
- setButtonDisabled(t) {
250
- this.button && (this.button.disabled = t, t ? this.button.setAttribute("aria-busy", "true") : this.button.removeAttribute("aria-busy"));
814
+ return this.opts.button ? W(this.opts.button, "Button") : null;
251
815
  }
252
816
  shouldAnimate() {
253
- return this.anim !== null || this.idleBob !== null;
817
+ return this.anim !== null || this.idleBob !== null || this.showFinalLine;
254
818
  }
255
819
  startLoop() {
256
- this.rafId === null && this.shouldAnimate() && (this.rafId = requestAnimationFrame(this.loop));
820
+ this.loop.isRunning() || this.shouldAnimate() && this.loop.start(this.tick);
257
821
  }
258
- loop = (t) => {
822
+ tick = (e) => {
259
823
  if (this.anim) {
260
- const { startTime: s, durationMs: i, startOffsets: e, deltas: r, settleDurationMs: l, targets: u } = this.anim, f = t - s;
261
- let c = !0;
262
- for (let n = 0; n < this.reels; n += 1) {
263
- const h = i[n] ?? 0, g = l[n] ?? 0, p = u[n] ?? e[n] + r[n];
264
- if (h > 0 && f < h) {
265
- const d = Math.min(1, f / h), m = Q(d);
266
- d < 1 && (c = !1);
267
- const S = e[n] + r[n] * m;
268
- let x = 0;
269
- if (d > z && this.frameHeight > 0) {
270
- const y = (1 - v((d - z) / st)) ** 2, o = S / this.frameHeight * Math.PI * 2, M = Math.min(it, this.frameHeight * 0.06);
271
- x = Math.sin(o) * y * M;
824
+ const { startTime: t, durationMs: i, startOffsets: s, deltas: n, settleDurationMs: a, targets: u } = this.anim, l = e - t;
825
+ let d = !0;
826
+ for (let o = 0; o < this.reels; o += 1) {
827
+ const c = i[o] ?? 0, b = a[o] ?? 0, p = u[o] ?? s[o] + n[o];
828
+ if (c > 0 && l < c) {
829
+ const h = Math.min(1, l / c), g = ie(h);
830
+ h < 1 && (d = !1);
831
+ const m = s[o] + n[o] * g;
832
+ let S = 0;
833
+ if (h > V && this.frameHeight > 0) {
834
+ const w = (1 - v((h - V) / Ae)) ** 2, E = m / this.frameHeight * Math.PI * 2, H = Math.min(Pe, this.frameHeight * 0.06);
835
+ S = Math.sin(E) * w * H;
272
836
  }
273
- this.offsets[n] = S + x;
274
- } else if (g > 0) {
275
- const d = h <= 0 ? f / g : (f - h) / g, m = v(d), S = e[n] + r[n] - p, x = this.getStopSpringOffset(S, m);
276
- m < 1 && (c = !1), this.offsets[n] = p + x;
837
+ this.offsets[o] = m + S;
838
+ } else if (b > 0) {
839
+ const h = c <= 0 ? l / b : (l - c) / b, g = v(h), m = s[o] + n[o] - p, S = ue(m, g);
840
+ g < 1 && (d = !1), this.offsets[o] = p + S;
277
841
  } else
278
- this.offsets[n] = p;
842
+ this.offsets[o] = p;
279
843
  }
280
- if (this.updateVelocity(t), this.render(), c) {
281
- for (let n = 0; n < this.reels; n += 1) {
282
- const h = this.anim.targets[n] ?? this.anim.startOffsets[n] + this.anim.deltas[n];
283
- this.offsets[n] = h, this.idleBaseOffsets[n] = this.offsets[n];
844
+ if (this.updateVelocity(e), this.render(), d) {
845
+ for (let o = 0; o < this.reels; o += 1) {
846
+ const c = this.anim.targets[o] ?? this.anim.startOffsets[o] + this.anim.deltas[o];
847
+ this.offsets[o] = c, this.idleBaseOffsets[o] = this.offsets[o];
284
848
  }
285
- this.updateVelocity(t);
286
- for (let n = 0; n < this.reels; n += 1)
287
- this.velocities[n] = 0;
849
+ this.updateVelocity(e);
850
+ for (let o = 0; o < this.reels; o += 1)
851
+ this.velocities[o] = 0;
288
852
  this.anim = null, this.idleStartTime = null, this.render(), this.resolvePendingSpins();
289
853
  }
290
- } else this.idleBob && (this.updateIdle(t), this.render());
291
- if (!this.shouldAnimate()) {
292
- this.rafId = null;
293
- return;
294
- }
295
- this.rafId !== null && (this.rafId = requestAnimationFrame(this.loop));
854
+ } else this.idleBob && (this.updateIdle(e), this.render());
855
+ return this.shouldAnimate();
296
856
  };
297
857
  render() {
298
- this.spriteImg && (this.width <= 0 || this.height <= 0 || this.gl && this.renderWebGL());
299
- }
300
- getSpinBlurPxForReel(t) {
301
- if (!this.anim) return 0;
302
- const s = Math.abs(this.velocities[t] ?? 0), i = Math.max(1, this.spinBlur.speedAtMax);
303
- return v(s / i) * Math.max(0, this.spinBlur.maxPx);
304
- }
305
- renderWebGL() {
306
- if (!this.gl || !this.glProgram || !this.glAttribs || !this.glUniforms || !this.glTexture || !this.glBuffer || !this.spriteImg) return;
307
- const t = this.gl;
308
- t.useProgram(this.glProgram), t.bindBuffer(t.ARRAY_BUFFER, this.glBuffer), t.enableVertexAttribArray(this.glAttribs.pos), t.vertexAttribPointer(this.glAttribs.pos, 2, t.FLOAT, !1, 16, 0), t.enableVertexAttribArray(this.glAttribs.uv), t.vertexAttribPointer(this.glAttribs.uv, 2, t.FLOAT, !1, 16, 8), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.glTexture), t.uniform1i(this.glUniforms.texture, 0), t.uniform1f(this.glUniforms.frameHeight, this.frameHeight), t.uniform1f(this.glUniforms.spriteHeight, this.spriteHeight), t.uniform1f(this.glUniforms.visibleSlots, this.visibleSlots), t.uniform1f(this.glUniforms.heightScale, this.heightScale), t.uniform1f(this.glUniforms.edgePower, Math.max(0.5, this.webglShading.edgePower));
309
- const s = this.webglShading, i = Math.max(0, s.warpAngleDeg) * Math.PI / 180;
310
- t.uniform1f(this.glUniforms.warpAngle, i), t.clear(t.COLOR_BUFFER_BIT);
311
- const e = 1 / this.reels;
312
- for (let r = 0; r < this.reels; r += 1) {
313
- t.uniform1f(this.glUniforms.reelX, r * e), t.uniform1f(this.glUniforms.reelW, e);
314
- const l = I(this.offsets[r], this.spriteHeight);
315
- t.uniform1f(this.glUniforms.offsetPx, l), t.uniform1f(this.glUniforms.blurPx, this.getSpinBlurPxForReel(r)), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
316
- }
317
- }
318
- updateVelocity(t) {
319
- if (this.lastVelT === null) {
320
- this.lastVelT = t;
321
- for (let i = 0; i < this.reels; i += 1)
322
- this.lastVelOffsets[i] = this.offsets[i], this.velocities[i] = 0;
323
- return;
324
- }
325
- const s = (t - this.lastVelT) / 1e3;
326
- if (!(s <= 0)) {
327
- for (let i = 0; i < this.reels; i += 1) {
328
- const e = (this.offsets[i] - this.lastVelOffsets[i]) / s;
329
- this.velocities[i] = this.velocities[i] * V + e * rt, this.lastVelOffsets[i] = this.offsets[i];
330
- }
331
- this.lastVelT = t;
332
- }
333
- }
334
- updateIdle(t) {
335
- if (!this.idleBob) return;
336
- this.idleStartTime === null && (this.idleStartTime = t);
337
- const { amplitudePx: s, speedHz: i, phaseOffsetRad: e, rampMs: r } = this.idleBob, l = t - this.idleStartTime, u = l / 1e3, f = Math.max(0, Math.min(1, l / Math.max(1, r))), c = F(f), n = i * Math.PI * 2;
338
- for (let h = 0; h < this.reels; h += 1) {
339
- const g = u * n + h * e;
340
- this.offsets[h] = this.idleBaseOffsets[h] + Math.sin(g) * (s * c), this.velocities[h] = 0;
341
- }
858
+ this.spriteImg && (this.width <= 0 || this.height <= 0 || this.renderer && this.renderer.render({
859
+ offsets: this.offsets,
860
+ velocities: this.velocities,
861
+ dpr: this.dpr
862
+ }));
342
863
  }
343
- async loadSprite() {
344
- const { sprite: t } = this.opts, s = typeof t == "string" ? new Image() : t;
345
- typeof t == "string" && (s.src = t), (!s.complete || s.naturalWidth <= 0) && await new Promise((c, n) => {
346
- const h = () => c(), g = () => n(new Error("Failed to load sprite image"));
347
- s.addEventListener("load", h, { once: !0 }), s.addEventListener("error", g, { once: !0 });
348
- });
349
- const i = Math.max(1, Math.floor(this.opts.slotCount)), e = s.naturalWidth, r = e, l = r * i, u = s.naturalHeight;
350
- if (Math.abs(u - l) > 2)
351
- throw new Error(
352
- `Sprite size mismatch. Expected height ~${Math.round(l)}px (slotCount=${i}, slot aspect 1/1), got ${u}px.`
353
- );
354
- this.spriteImg = s, this.spriteWidth = e, this.frameHeight = Math.max(1, Math.round(r)), this.spriteHeight = Math.max(1, Math.round(this.frameHeight * i));
864
+ updateVelocity(e) {
865
+ this.lastVelT = fe(
866
+ e,
867
+ {
868
+ lastVelT: this.lastVelT,
869
+ lastVelOffsets: this.lastVelOffsets,
870
+ velocities: this.velocities
871
+ },
872
+ this.offsets
873
+ );
874
+ }
875
+ updateIdle(e) {
876
+ this.idleBob && (this.idleStartTime = ce(
877
+ e,
878
+ {
879
+ idleStartTime: this.idleStartTime,
880
+ idleBaseOffsets: this.idleBaseOffsets,
881
+ velocities: this.velocities
882
+ },
883
+ this.idleBob,
884
+ this.offsets,
885
+ this.reels
886
+ ));
355
887
  }
356
888
  setupResizeWatcher() {
357
889
  typeof ResizeObserver > "u" || this.resizeObserver || (this.resizeObserver = new ResizeObserver(() => this.queueResize()), this.resizeObserver.observe(this.container));
@@ -362,191 +894,47 @@ class ut {
362
894
  }));
363
895
  };
364
896
  resizeToContainer() {
365
- const t = this.container.clientWidth, s = this.container.clientHeight, i = this.visibleSlots * this.heightScale;
366
- if (t <= 0 || s <= 0) {
897
+ const e = this.container.clientWidth, t = this.container.clientHeight, i = this.visibleSlots * this.heightScale;
898
+ if (e <= 0 || t <= 0) {
367
899
  this.applyResize(1, 1);
368
900
  return;
369
901
  }
370
- const e = i, r = this.reels, l = t / r * e;
371
- let u = t, f = l;
372
- f > s && (f = s, u = s / e * r);
373
- const c = Math.max(1, Math.floor(u)), n = Math.max(1, Math.floor(f));
374
- this.applyResize(c, n), this.render();
902
+ const s = i, n = this.reels, a = e / n * s;
903
+ let u = e, l = a;
904
+ l > t && (l = t, u = t / s * n);
905
+ const d = Math.max(1, Math.floor(u)), o = Math.max(1, Math.floor(l));
906
+ this.applyResize(d, o), this.render();
375
907
  }
376
908
  applyViewportCrop() {
377
909
  this.ensureCanvasCoversContainer(), this.canvas.style.transform = "";
378
910
  }
379
- applyResize(t, s) {
380
- const i = Math.max(1, Math.floor(t)), e = Math.max(1, Math.floor(s)), r = this.getTargetDpr();
381
- this.width = i, this.height = e, this.dpr = r, this.canvas.width = Math.floor(this.width * this.dpr), this.canvas.height = Math.floor(this.height * this.dpr), this.gl && this.gl.viewport(0, 0, this.canvas.width, this.canvas.height), this.applyViewportCrop();
911
+ applyResize(e, t) {
912
+ const i = Math.max(1, Math.floor(e)), s = Math.max(1, Math.floor(t)), n = this.getTargetDpr();
913
+ this.width = i, this.height = s, this.dpr = n, this.canvas.width = Math.floor(this.width * this.dpr), this.canvas.height = Math.floor(this.height * this.dpr), this.renderer && this.renderer.onResize(this.canvas.width, this.canvas.height), this.applyViewportCrop();
382
914
  }
383
915
  getTargetDpr() {
384
- const t = window.devicePixelRatio || 1, s = Math.max(1, t);
385
- return Math.min(this.maxDpr, s);
916
+ const e = window.devicePixelRatio || 1, t = Math.max(1, e);
917
+ return Math.min(this.maxDpr, t);
386
918
  }
387
- tryInitWebGL() {
388
- if (!this.spriteImg) return;
389
- this.releaseWebGLResources(), this.webglInitError = null;
390
- const t = this.canvas.getContext("webgl2", {
391
- antialias: !0,
392
- alpha: !0
393
- }) ?? this.canvas.getContext("webgl", {
394
- antialias: !0,
395
- alpha: !0
396
- }) ?? this.canvas.getContext("experimental-webgl", {
397
- antialias: !0,
398
- alpha: !0
399
- });
400
- if (!t) {
401
- const n = document.createElement("canvas"), h = typeof WebGLRenderingContext < "u", g = n.getContext("webgl2") ?? n.getContext("webgl");
402
- this.webglInitError = `context is null (browser WebGL=${h ? "yes" : "no"}, fallback canvas=${g ? "yes" : "no"})`, console.warn("ReelDeal WebGL:", this.webglInitError);
403
- return;
404
- }
405
- const e = this.createWebGLProgram(t, `
406
- attribute vec2 a_pos;
407
- attribute vec2 a_uv;
408
- varying vec2 v_uv;
409
- void main() {
410
- v_uv = a_uv;
411
- gl_Position = vec4(a_pos, 0.0, 1.0);
412
- }
413
- `, `
414
- #ifdef GL_FRAGMENT_PRECISION_HIGH
415
- precision highp float;
416
- #else
417
- precision mediump float;
418
- #endif
419
-
420
- varying vec2 v_uv;
421
- uniform sampler2D u_tex;
422
- uniform float u_reelX;
423
- uniform float u_reelW;
424
- uniform float u_offsetPx;
425
- uniform float u_frameHeight;
426
- uniform float u_spriteHeight;
427
- uniform float u_visibleSlots;
428
- uniform float u_heightScale;
429
- uniform float u_edgePower;
430
- uniform float u_warpAngle;
431
- uniform float u_blurPx;
432
-
433
- const float HALF_PI = 1.5707963;
434
-
435
- float saturate(float x) { return clamp(x, 0.0, 1.0); }
436
-
437
- void main() {
438
- if (v_uv.x < u_reelX || v_uv.x > (u_reelX + u_reelW)) {
439
- discard;
440
- }
441
-
442
- float localX = (v_uv.x - u_reelX) / u_reelW;
443
- float localY = v_uv.y;
444
- float hs = max(0.0001, u_heightScale);
445
- float fullY = localY * hs + (1.0 - hs) * 0.5;
446
-
447
- float warp = max(0.0, u_warpAngle);
448
- float warpStrength = saturate(warp / HALF_PI);
449
- float distNorm = abs(fullY - 0.5) * 2.0;
450
- float edgePow = max(0.5, u_edgePower);
451
- float edgeWeight = pow(saturate(distNorm), edgePow) * warpStrength;
452
-
453
- float stretchMax = 6.0;
454
- float stretch = mix(1.0, stretchMax, edgeWeight);
455
- float warpedY = 0.5 + (fullY - 0.5) * stretch;
456
-
457
- float arcY = 0.5 + 0.5 * sin((warpedY - 0.5) * HALF_PI);
458
- warpedY = mix(warpedY, arcY, 0.2);
459
-
460
- float yPx = u_offsetPx + warpedY * (u_frameHeight * u_visibleSlots);
461
- float v = fract((u_offsetPx / u_spriteHeight) +
462
- warpedY * ((u_frameHeight * u_visibleSlots) / u_spriteHeight));
463
-
464
- vec4 base = texture2D(u_tex, vec2(localX, v));
465
-
466
- if (u_blurPx > 0.0) {
467
- float maxStepPx = 1.0 + 3.0 * saturate(u_blurPx / 4.0);
468
- float blurPx = min(u_blurPx, maxStepPx);
469
- float blurStep = blurPx / max(1.0, u_spriteHeight);
470
- vec4 sum = base * 0.227027;
471
- sum += texture2D(u_tex, vec2(localX, fract(v + blurStep))) * 0.1945946;
472
- sum += texture2D(u_tex, vec2(localX, fract(v - blurStep))) * 0.1945946;
473
- sum += texture2D(u_tex, vec2(localX, fract(v + 2.0 * blurStep))) * 0.1216216;
474
- sum += texture2D(u_tex, vec2(localX, fract(v - 2.0 * blurStep))) * 0.1216216;
475
- sum += texture2D(u_tex, vec2(localX, fract(v + 3.0 * blurStep))) * 0.054054;
476
- sum += texture2D(u_tex, vec2(localX, fract(v - 3.0 * blurStep))) * 0.054054;
477
- sum += texture2D(u_tex, vec2(localX, fract(v + 4.0 * blurStep))) * 0.016216;
478
- sum += texture2D(u_tex, vec2(localX, fract(v - 4.0 * blurStep))) * 0.016216;
479
- base = sum;
480
- }
481
-
482
- gl_FragColor = base;
483
- }
484
- `);
485
- if (!e) {
486
- this.webglInitError = "shader program failed to compile/link (see console)", console.warn("ReelDeal WebGL:", this.webglInitError);
487
- return;
488
- }
489
- const r = t.createBuffer();
490
- if (!r) {
491
- this.webglInitError = "failed to create vertex buffer", console.warn("ReelDeal WebGL:", this.webglInitError), t.deleteProgram(e);
492
- return;
493
- }
494
- t.bindBuffer(t.ARRAY_BUFFER, r);
495
- const l = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, 1, 1, 1, 0]);
496
- t.bufferData(t.ARRAY_BUFFER, l, t.STATIC_DRAW);
497
- const u = t.createTexture();
498
- if (!u) {
499
- this.webglInitError = "failed to create texture", console.warn("ReelDeal WebGL:", this.webglInitError), t.deleteBuffer(r), t.deleteProgram(e);
500
- return;
501
- }
502
- t.bindTexture(t.TEXTURE_2D, u), t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL, 0), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, this.spriteImg);
503
- const f = (n) => n > 0 && (n & n - 1) === 0;
504
- f(this.spriteWidth) && f(this.spriteHeight) ? (t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.REPEAT), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.REPEAT), t.generateMipmap(t.TEXTURE_2D), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR_MIPMAP_LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR)) : (t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.CLAMP_TO_EDGE)), t.useProgram(e), t.clearColor(0, 0, 0, 0), t.enable(t.BLEND), t.blendFunc(t.SRC_ALPHA, t.ONE_MINUS_SRC_ALPHA), this.gl = t, this.glProgram = e, this.glBuffer = r, this.glTexture = u, this.glAttribs = {
505
- pos: t.getAttribLocation(e, "a_pos"),
506
- uv: t.getAttribLocation(e, "a_uv")
507
- }, this.glUniforms = {
508
- texture: t.getUniformLocation(e, "u_tex"),
509
- reelX: t.getUniformLocation(e, "u_reelX"),
510
- reelW: t.getUniformLocation(e, "u_reelW"),
511
- offsetPx: t.getUniformLocation(e, "u_offsetPx"),
512
- frameHeight: t.getUniformLocation(e, "u_frameHeight"),
513
- spriteHeight: t.getUniformLocation(e, "u_spriteHeight"),
514
- visibleSlots: t.getUniformLocation(e, "u_visibleSlots"),
515
- heightScale: t.getUniformLocation(e, "u_heightScale"),
516
- edgePower: t.getUniformLocation(e, "u_edgePower"),
517
- warpAngle: t.getUniformLocation(e, "u_warpAngle"),
518
- blurPx: t.getUniformLocation(e, "u_blurPx")
519
- };
520
- }
521
- createWebGLProgram(t, s, i) {
522
- const e = this.createWebGLShader(t, t.VERTEX_SHADER, s), r = this.createWebGLShader(t, t.FRAGMENT_SHADER, i);
523
- if (!e || !r)
524
- return e && t.deleteShader(e), r && t.deleteShader(r), null;
525
- const l = t.createProgram();
526
- if (!l) return null;
527
- if (t.attachShader(l, e), t.attachShader(l, r), t.linkProgram(l), !t.getProgramParameter(l, t.LINK_STATUS)) {
528
- const u = t.getProgramInfoLog(l) ?? "unknown link error";
529
- return this.webglInitError = `program link failed: ${u}`, console.warn("ReelDeal WebGL: program link failed", u), t.deleteProgram(l), t.deleteShader(e), t.deleteShader(r), null;
530
- }
531
- return t.detachShader(l, e), t.detachShader(l, r), t.deleteShader(e), t.deleteShader(r), l;
532
- }
533
- createWebGLShader(t, s, i) {
534
- const e = t.createShader(s);
535
- if (!e) return null;
536
- if (t.shaderSource(e, i), t.compileShader(e), !t.getShaderParameter(e, t.COMPILE_STATUS)) {
537
- const r = t.getShaderInfoLog(e) ?? "unknown compile error";
538
- return this.webglInitError = `shader compile failed: ${r}`, console.warn("ReelDeal WebGL: shader compile failed", r), t.deleteShader(e), null;
539
- }
540
- return e;
919
+ hideFinalLine() {
920
+ this.showFinalLine = !1, this.renderer?.hideFinalLine(), this.render();
541
921
  }
542
- releaseWebGLResources() {
543
- this.gl && (this.glTexture && this.gl.deleteTexture(this.glTexture), this.glBuffer && this.gl.deleteBuffer(this.glBuffer), this.glProgram && this.gl.deleteProgram(this.glProgram), this.glTexture = null, this.glBuffer = null, this.glProgram = null, this.glAttribs = null, this.glUniforms = null, this.gl = null);
922
+ showFinalLineEffect() {
923
+ this.finalSpinLine && (this.showFinalLine = !0, this.renderer?.showFinalLine(), this.startLoop());
544
924
  }
545
925
  }
546
926
  export {
547
- ut as ReelDeal,
548
- E as defaultIdleBob,
549
- C as defaultSpinBlur,
550
- T as defaultSpinConfig
927
+ Me as ReelDeal,
928
+ _e as WebGLRenderer,
929
+ R as defaultIdleBob,
930
+ B as defaultSpinBlur,
931
+ P as defaultSpinConfig,
932
+ J as loadSprite,
933
+ le as normalizeFinalSpinLine,
934
+ ne as normalizeIdleBob,
935
+ ae as normalizeMaxDpr,
936
+ re as normalizeSpinBlur,
937
+ N as normalizeSpinConfig,
938
+ oe as normalizeWebGLShading
551
939
  };
552
940
  //# sourceMappingURL=index.es.js.map