reel-deal 0.1.0 → 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,4 +1,22 @@
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,
@@ -6,63 +24,576 @@ const T = {
6
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
- }, C = 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 <= C) {
23
- const i = t / C;
24
- return F(i) * C;
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)), R = (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: R(t.minSpins, T.minSpins),
34
- durationMs: R(t.durationMs, T.durationMs ?? 0),
35
- speedPxS: R(t.speedPxS, T.speedPxS ?? 0),
36
- staggerMs: R(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 = { ...B, ...a ?? {} };
62
+ }, re = (r) => {
63
+ const e = { ...B, ...r ?? {} };
40
64
  return {
41
- maxPx: _(t.maxPx, B.maxPx),
42
- speedAtMax: _(t.speedAtMax, B.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 ?? {} };
71
+ return {
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)
76
+ };
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);
47
120
  return {
48
- amplitudePx: _(t.amplitudePx, E.amplitudePx),
49
- speedHz: _(t.speedHz, E.speedHz),
50
- phaseOffsetRad: L(t.phaseOffsetRad, E.phaseOffsetRad),
51
- rampMs: R(t.rampMs, E.rampMs)
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
+ }
52
257
  };
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 = 30, at = 500, ot = 1.25, lt = 0.25, N = {
59
- warpAngleDeg: 360,
60
- edgePower: 0.5
61
- }, ht = (a) => ({
62
- warpAngleDeg: _(a?.warpAngleDeg, N.warpAngleDeg),
63
- edgePower: _(a?.edgePower, N.edgePower)
64
- });
65
- class ut {
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,128 +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(
109
- t.webglShading
110
- ), 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
+ }
111
673
  }
112
674
  async init() {
113
- 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)
114
677
  throw new Error(
115
678
  `WebGL is not supported or failed to initialize. ${this.webglInitError ?? ""}`.trim()
116
679
  );
117
- 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();
118
681
  }
119
682
  destroy() {
120
- 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);
121
684
  }
122
685
  ensureCanvasCoversContainer() {
123
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"));
124
687
  }
125
688
  syncContainerLayoutVars() {
126
- const t = this.canvas === this.container ? this.canvas : this.container;
127
- 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");
128
691
  }
129
- setSegments(t) {
692
+ setSegments(e) {
130
693
  this.ensureReady();
131
- const s = t ?? [];
694
+ const t = e ?? [];
132
695
  for (let i = 0; i < this.reels; i += 1) {
133
- const e = s[i] ?? 0, r = O(e, 0, this.opts.slotCount - 1);
134
- 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];
135
698
  }
136
699
  this.lastVelT = null, this.idleStartTime = null, this.anim = null, this.stop(), this.render(), this.startLoop();
137
700
  }
138
- setSegment(t) {
139
- this.setSegments(new Array(this.reels).fill(t));
701
+ setSegment(e) {
702
+ this.setSegments(new Array(this.reels).fill(e));
140
703
  }
141
- spinOnce(t, s) {
704
+ spinOnce(e, t) {
142
705
  this.ensureReady();
143
- 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);
144
- for (let o = 0; o < this.reels; o += 1) {
145
- const k = O(t[o] ?? 0, 0, this.opts.slotCount - 1) * this.frameHeight - this.centerIndex * this.frameHeight, Y = I(k, this.spriteHeight), q = I(this.offsets[o], this.spriteHeight), H = I(q - Y, this.spriteHeight);
146
- let x = -(i * this.spriteHeight + H);
147
- if (u && l > 0) {
148
- const M = r * l / 1e3, P = Math.max(
149
- i,
150
- Math.ceil(Math.max(0, M - H) / this.spriteHeight)
151
- );
152
- x = -(H + P * this.spriteHeight);
153
- }
154
- if (e > 0 && u) {
155
- const M = r * e * o / 1e3, P = Math.ceil(M / this.spriteHeight);
156
- x -= P * this.spriteHeight;
157
- }
158
- h[o] = this.offsets[o], m[o] = this.offsets[o] + x;
159
- let D = x, G = 0;
160
- if (n && x !== 0 && f > 0) {
161
- const P = Math.sign(x) * f;
162
- D += P, G = c;
163
- }
164
- 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);
165
- }
166
- const S = g.reduce((o, w) => o + Math.abs(w), 0), b = p.every((o) => o <= 0), W = d.every((o) => o <= 0);
167
- if (S === 0 || b && W) {
168
- for (let o = 0; o < this.reels; o += 1)
169
- 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];
170
727
  return this.anim = null, this.resolvePendingSpins(), this.render(), Promise.resolve();
171
728
  }
172
- const y = performance.now();
173
- return this.anim = {
174
- startTime: y,
175
- startOffsets: h,
176
- deltas: g,
177
- durationMs: p,
178
- settleDurationMs: d,
179
- targets: m
180
- }, this.idleStartTime = null, this.startLoop(), new Promise((o) => {
181
- 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
+ });
182
767
  });
183
768
  }
184
- getSpinConfig(t) {
185
- return t ? X({ ...this.spinConfig, ...t }) : this.spinConfig;
769
+ getSpinConfig(e) {
770
+ return e ? N({ ...this.spinConfig, ...e }) : this.spinConfig;
186
771
  }
187
772
  getStopSpringOvershootPx() {
188
- const t = this.frameHeight * lt, s = Math.max(0, nt);
189
- return Math.min(s, t);
190
- }
191
- getStopSpringOffset(t, s) {
192
- if (t === 0) return 0;
193
- const i = Math.exp(-4 * s), e = Math.PI * 2 * ot * s;
194
- return t * i * Math.cos(e);
195
- }
196
- async spinQueue(t) {
197
- for (let s = 0; s < t.length; s += 1) {
198
- const i = t[s];
199
- 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);
200
781
  }
782
+ this.uiController?.updateAvailability(!0);
201
783
  }
202
- stop() {
203
- this.rafId !== null && cancelAnimationFrame(this.rafId), this.rafId = null, this.anim = null, this.resolvePendingSpins(), this.lastVelT = null;
204
- for (let t = 0; t < this.reels; t += 1)
205
- 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);
206
786
  }
207
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) {
208
795
  if (this.pendingSpinResolvers.length === 0) return;
209
796
  const t = this.pendingSpinResolvers;
210
797
  this.pendingSpinResolvers = [];
211
- for (const s of t)
212
- s();
798
+ for (const { reject: i, cleanup: s } of t)
799
+ s(), i(e);
213
800
  }
214
801
  requestResize() {
215
802
  this.queueResize();
@@ -218,142 +805,85 @@ class ut {
218
805
  if (!this.spriteImg || this.spriteWidth <= 0 || this.spriteHeight <= 0 || this.frameHeight <= 0)
219
806
  throw new Error("Sprite is not ready. Call init() and await it first.");
220
807
  }
221
- attachButtonHandler() {
222
- !this.button || this.buttonHandlerAttached || (this.button.addEventListener("click", this.handleButtonClick, { passive: !0 }), this.buttonHandlerAttached = !0);
223
- }
224
808
  handleButtonClick = async () => {
225
- if (this.spinning) return;
226
- const t = this.consumeNextSpin() ?? {
227
- stopAtSegments: this.buildRandomSegments()
228
- };
229
- this.spinning = !0, this.setButtonDisabled(!0);
230
- try {
231
- await this.spinOnce(t.stopAtSegments);
232
- } finally {
233
- this.queuedSpins && this.queuedSpins.length === 0 ? this.setButtonDisabled(!0) : this.setButtonDisabled(!1), this.spinning = !1;
234
- }
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();
235
812
  };
236
813
  resolveButton() {
237
- return this.opts.button ? U(this.opts.button, "Button") : null;
238
- }
239
- resolveSpinQueue() {
240
- return this.opts.queuedSpinStates ?? null;
241
- }
242
- consumeNextSpin() {
243
- return this.queuedSpins || (this.queuedSpins = this.resolveSpinQueue()), !this.queuedSpins || this.queuedSpins.length === 0 ? null : this.queuedSpins.shift() ?? null;
244
- }
245
- buildRandomSegments() {
246
- const t = Math.max(1, Math.floor(this.opts.slotCount)), s = [];
247
- for (let i = 0; i < this.reels; i += 1)
248
- s.push(Math.floor(Math.random() * t));
249
- return s;
250
- }
251
- setButtonDisabled(t) {
252
- 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;
253
815
  }
254
816
  shouldAnimate() {
255
- return this.anim !== null || this.idleBob !== null;
817
+ return this.anim !== null || this.idleBob !== null || this.showFinalLine;
256
818
  }
257
819
  startLoop() {
258
- this.rafId === null && this.shouldAnimate() && (this.rafId = requestAnimationFrame(this.loop));
820
+ this.loop.isRunning() || this.shouldAnimate() && this.loop.start(this.tick);
259
821
  }
260
- loop = (t) => {
822
+ tick = (e) => {
261
823
  if (this.anim) {
262
- const { startTime: s, durationMs: i, startOffsets: e, deltas: r, settleDurationMs: l, targets: u } = this.anim, f = t - s;
263
- let c = !0;
264
- for (let n = 0; n < this.reels; n += 1) {
265
- const h = i[n] ?? 0, g = l[n] ?? 0, p = u[n] ?? e[n] + r[n];
266
- if (h > 0 && f < h) {
267
- const d = Math.min(1, f / h), m = Q(d);
268
- d < 1 && (c = !1);
269
- const S = e[n] + r[n] * m;
270
- let b = 0;
271
- if (d > z && this.frameHeight > 0) {
272
- const y = (1 - v((d - z) / st)) ** 2, o = S / this.frameHeight * Math.PI * 2, w = Math.min(it, this.frameHeight * 0.06);
273
- b = Math.sin(o) * y * w;
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;
274
836
  }
275
- this.offsets[n] = S + b;
276
- } else if (g > 0) {
277
- const d = h <= 0 ? f / g : (f - h) / g, m = v(d), S = e[n] + r[n] - p, b = this.getStopSpringOffset(S, m);
278
- m < 1 && (c = !1), this.offsets[n] = p + b;
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;
279
841
  } else
280
- this.offsets[n] = p;
842
+ this.offsets[o] = p;
281
843
  }
282
- if (this.updateVelocity(t), this.render(), c) {
283
- for (let n = 0; n < this.reels; n += 1) {
284
- const h = this.anim.targets[n] ?? this.anim.startOffsets[n] + this.anim.deltas[n];
285
- 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];
286
848
  }
287
- this.updateVelocity(t);
288
- for (let n = 0; n < this.reels; n += 1)
289
- this.velocities[n] = 0;
849
+ this.updateVelocity(e);
850
+ for (let o = 0; o < this.reels; o += 1)
851
+ this.velocities[o] = 0;
290
852
  this.anim = null, this.idleStartTime = null, this.render(), this.resolvePendingSpins();
291
853
  }
292
- } else this.idleBob && (this.updateIdle(t), this.render());
293
- if (!this.shouldAnimate()) {
294
- this.rafId = null;
295
- return;
296
- }
297
- this.rafId !== null && (this.rafId = requestAnimationFrame(this.loop));
854
+ } else this.idleBob && (this.updateIdle(e), this.render());
855
+ return this.shouldAnimate();
298
856
  };
299
857
  render() {
300
- this.spriteImg && (this.width <= 0 || this.height <= 0 || this.gl && this.renderWebGL());
301
- }
302
- getSpinBlurPxForReel(t) {
303
- if (!this.anim) return 0;
304
- const s = Math.abs(this.velocities[t] ?? 0), i = Math.max(1, this.spinBlur.speedAtMax);
305
- return v(s / i) * Math.max(0, this.spinBlur.maxPx);
306
- }
307
- renderWebGL() {
308
- if (!this.gl || !this.glProgram || !this.glAttribs || !this.glUniforms || !this.glTexture || !this.glBuffer || !this.spriteImg) return;
309
- const t = this.gl;
310
- 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));
311
- const s = this.webglShading, i = Math.max(0, s.warpAngleDeg) * Math.PI / 180;
312
- t.uniform1f(this.glUniforms.warpAngle, i), t.clear(t.COLOR_BUFFER_BIT);
313
- const e = 1 / this.reels;
314
- for (let r = 0; r < this.reels; r += 1) {
315
- t.uniform1f(this.glUniforms.reelX, r * e), t.uniform1f(this.glUniforms.reelW, e);
316
- const l = I(this.offsets[r], this.spriteHeight);
317
- t.uniform1f(this.glUniforms.offsetPx, l), t.uniform1f(this.glUniforms.blurPx, this.getSpinBlurPxForReel(r)), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
318
- }
319
- }
320
- updateVelocity(t) {
321
- if (this.lastVelT === null) {
322
- this.lastVelT = t;
323
- for (let i = 0; i < this.reels; i += 1)
324
- this.lastVelOffsets[i] = this.offsets[i], this.velocities[i] = 0;
325
- return;
326
- }
327
- const s = (t - this.lastVelT) / 1e3;
328
- if (!(s <= 0)) {
329
- for (let i = 0; i < this.reels; i += 1) {
330
- const e = (this.offsets[i] - this.lastVelOffsets[i]) / s;
331
- this.velocities[i] = this.velocities[i] * V + e * rt, this.lastVelOffsets[i] = this.offsets[i];
332
- }
333
- this.lastVelT = t;
334
- }
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
+ }));
335
863
  }
336
- updateIdle(t) {
337
- if (!this.idleBob) return;
338
- this.idleStartTime === null && (this.idleStartTime = t);
339
- 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;
340
- for (let h = 0; h < this.reels; h += 1) {
341
- const g = u * n + h * e;
342
- this.offsets[h] = this.idleBaseOffsets[h] + Math.sin(g) * (s * c), this.velocities[h] = 0;
343
- }
344
- }
345
- async loadSprite() {
346
- const { sprite: t } = this.opts, s = typeof t == "string" ? new Image() : t;
347
- typeof t == "string" && (s.src = t), (!s.complete || s.naturalWidth <= 0) && await new Promise((c, n) => {
348
- const h = () => c(), g = () => n(new Error("Failed to load sprite image"));
349
- s.addEventListener("load", h, { once: !0 }), s.addEventListener("error", g, { once: !0 });
350
- });
351
- const i = Math.max(1, Math.floor(this.opts.slotCount)), e = s.naturalWidth, r = e, l = r * i, u = s.naturalHeight;
352
- if (Math.abs(u - l) > 2)
353
- throw new Error(
354
- `Sprite size mismatch. Expected height ~${Math.round(l)}px (slotCount=${i}, slot aspect 1/1), got ${u}px.`
355
- );
356
- 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
+ ));
357
887
  }
358
888
  setupResizeWatcher() {
359
889
  typeof ResizeObserver > "u" || this.resizeObserver || (this.resizeObserver = new ResizeObserver(() => this.queueResize()), this.resizeObserver.observe(this.container));
@@ -364,191 +894,47 @@ class ut {
364
894
  }));
365
895
  };
366
896
  resizeToContainer() {
367
- const t = this.container.clientWidth, s = this.container.clientHeight, i = this.visibleSlots * this.heightScale;
368
- 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) {
369
899
  this.applyResize(1, 1);
370
900
  return;
371
901
  }
372
- const e = i, r = this.reels, l = t / r * e;
373
- let u = t, f = l;
374
- f > s && (f = s, u = s / e * r);
375
- const c = Math.max(1, Math.floor(u)), n = Math.max(1, Math.floor(f));
376
- 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();
377
907
  }
378
908
  applyViewportCrop() {
379
- this.canvas.style.width = "100%", this.canvas.style.height = "100%", this.canvas.style.transform = "";
909
+ this.ensureCanvasCoversContainer(), this.canvas.style.transform = "";
380
910
  }
381
- applyResize(t, s) {
382
- const i = Math.max(1, Math.floor(t)), e = Math.max(1, Math.floor(s)), r = this.getTargetDpr();
383
- 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();
384
914
  }
385
915
  getTargetDpr() {
386
- const t = window.devicePixelRatio || 1, s = Math.max(1, t);
387
- return Math.min(this.maxDpr, s);
916
+ const e = window.devicePixelRatio || 1, t = Math.max(1, e);
917
+ return Math.min(this.maxDpr, t);
388
918
  }
389
- tryInitWebGL() {
390
- if (!this.spriteImg) return;
391
- this.releaseWebGLResources(), this.webglInitError = null;
392
- const t = this.canvas.getContext("webgl2", {
393
- antialias: !0,
394
- alpha: !0
395
- }) ?? this.canvas.getContext("webgl", {
396
- antialias: !0,
397
- alpha: !0
398
- }) ?? this.canvas.getContext("experimental-webgl", {
399
- antialias: !0,
400
- alpha: !0
401
- });
402
- if (!t) {
403
- const n = document.createElement("canvas"), h = typeof WebGLRenderingContext < "u", g = n.getContext("webgl2") ?? n.getContext("webgl");
404
- this.webglInitError = `context is null (browser WebGL=${h ? "yes" : "no"}, fallback canvas=${g ? "yes" : "no"})`, console.warn("ReelDeal WebGL:", this.webglInitError);
405
- return;
406
- }
407
- const e = this.createWebGLProgram(t, `
408
- attribute vec2 a_pos;
409
- attribute vec2 a_uv;
410
- varying vec2 v_uv;
411
- void main() {
412
- v_uv = a_uv;
413
- gl_Position = vec4(a_pos, 0.0, 1.0);
414
- }
415
- `, `
416
- #ifdef GL_FRAGMENT_PRECISION_HIGH
417
- precision highp float;
418
- #else
419
- precision mediump float;
420
- #endif
421
-
422
- varying vec2 v_uv;
423
- uniform sampler2D u_tex;
424
- uniform float u_reelX;
425
- uniform float u_reelW;
426
- uniform float u_offsetPx;
427
- uniform float u_frameHeight;
428
- uniform float u_spriteHeight;
429
- uniform float u_visibleSlots;
430
- uniform float u_heightScale;
431
- uniform float u_edgePower;
432
- uniform float u_warpAngle;
433
- uniform float u_blurPx;
434
-
435
- const float HALF_PI = 1.5707963;
436
-
437
- float saturate(float x) { return clamp(x, 0.0, 1.0); }
438
-
439
- void main() {
440
- if (v_uv.x < u_reelX || v_uv.x > (u_reelX + u_reelW)) {
441
- discard;
442
- }
443
-
444
- float localX = (v_uv.x - u_reelX) / u_reelW;
445
- float localY = v_uv.y;
446
- float hs = max(0.0001, u_heightScale);
447
- float fullY = localY * hs + (1.0 - hs) * 0.5;
448
-
449
- float warp = max(0.0, u_warpAngle);
450
- float warpStrength = saturate(warp / 1.2);
451
- float center = 0.5;
452
- float centerBand = 1.0 / 3.0;
453
- float halfBand = centerBand * 0.5;
454
- float dist = abs(fullY - center);
455
- float edgeWeight = smoothstep(halfBand, 0.5, dist);
456
- float edgePow = max(0.5, u_edgePower);
457
- edgeWeight = pow(edgeWeight, edgePow) * warpStrength;
458
- float yCentered = (fullY - 0.5) * 2.0;
459
- float sinY = 0.5 + 0.5 * sin(yCentered * HALF_PI);
460
- float warpedY = mix(fullY, sinY, edgeWeight);
461
-
462
- float yPx = u_offsetPx + warpedY * (u_frameHeight * u_visibleSlots);
463
- float v = fract((u_offsetPx / u_spriteHeight) +
464
- warpedY * ((u_frameHeight * u_visibleSlots) / u_spriteHeight));
465
-
466
- vec4 base = texture2D(u_tex, vec2(localX, v));
467
-
468
- if (u_blurPx > 0.0) {
469
- float maxStepPx = 1.0 + 3.0 * saturate(u_blurPx / 4.0);
470
- float blurPx = min(u_blurPx, maxStepPx);
471
- float blurStep = blurPx / max(1.0, u_spriteHeight);
472
- vec4 sum = base * 0.227027;
473
- sum += texture2D(u_tex, vec2(localX, fract(v + blurStep))) * 0.1945946;
474
- sum += texture2D(u_tex, vec2(localX, fract(v - blurStep))) * 0.1945946;
475
- sum += texture2D(u_tex, vec2(localX, fract(v + 2.0 * blurStep))) * 0.1216216;
476
- sum += texture2D(u_tex, vec2(localX, fract(v - 2.0 * blurStep))) * 0.1216216;
477
- sum += texture2D(u_tex, vec2(localX, fract(v + 3.0 * blurStep))) * 0.054054;
478
- sum += texture2D(u_tex, vec2(localX, fract(v - 3.0 * blurStep))) * 0.054054;
479
- sum += texture2D(u_tex, vec2(localX, fract(v + 4.0 * blurStep))) * 0.016216;
480
- sum += texture2D(u_tex, vec2(localX, fract(v - 4.0 * blurStep))) * 0.016216;
481
- base = sum;
482
- }
483
-
484
- gl_FragColor = base;
485
- }
486
- `);
487
- if (!e) {
488
- this.webglInitError = "shader program failed to compile/link (see console)", console.warn("ReelDeal WebGL:", this.webglInitError);
489
- return;
490
- }
491
- const r = t.createBuffer();
492
- if (!r) {
493
- this.webglInitError = "failed to create vertex buffer", console.warn("ReelDeal WebGL:", this.webglInitError), t.deleteProgram(e);
494
- return;
495
- }
496
- t.bindBuffer(t.ARRAY_BUFFER, r);
497
- const l = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, 1, 1, 1, 0]);
498
- t.bufferData(t.ARRAY_BUFFER, l, t.STATIC_DRAW);
499
- const u = t.createTexture();
500
- if (!u) {
501
- this.webglInitError = "failed to create texture", console.warn("ReelDeal WebGL:", this.webglInitError), t.deleteBuffer(r), t.deleteProgram(e);
502
- return;
503
- }
504
- 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);
505
- const f = (n) => n > 0 && (n & n - 1) === 0;
506
- 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 = {
507
- pos: t.getAttribLocation(e, "a_pos"),
508
- uv: t.getAttribLocation(e, "a_uv")
509
- }, this.glUniforms = {
510
- texture: t.getUniformLocation(e, "u_tex"),
511
- reelX: t.getUniformLocation(e, "u_reelX"),
512
- reelW: t.getUniformLocation(e, "u_reelW"),
513
- offsetPx: t.getUniformLocation(e, "u_offsetPx"),
514
- frameHeight: t.getUniformLocation(e, "u_frameHeight"),
515
- spriteHeight: t.getUniformLocation(e, "u_spriteHeight"),
516
- visibleSlots: t.getUniformLocation(e, "u_visibleSlots"),
517
- heightScale: t.getUniformLocation(e, "u_heightScale"),
518
- edgePower: t.getUniformLocation(e, "u_edgePower"),
519
- warpAngle: t.getUniformLocation(e, "u_warpAngle"),
520
- blurPx: t.getUniformLocation(e, "u_blurPx")
521
- };
522
- }
523
- createWebGLProgram(t, s, i) {
524
- const e = this.createWebGLShader(t, t.VERTEX_SHADER, s), r = this.createWebGLShader(t, t.FRAGMENT_SHADER, i);
525
- if (!e || !r)
526
- return e && t.deleteShader(e), r && t.deleteShader(r), null;
527
- const l = t.createProgram();
528
- if (!l) return null;
529
- if (t.attachShader(l, e), t.attachShader(l, r), t.linkProgram(l), !t.getProgramParameter(l, t.LINK_STATUS)) {
530
- const u = t.getProgramInfoLog(l) ?? "unknown link error";
531
- 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;
532
- }
533
- return t.detachShader(l, e), t.detachShader(l, r), t.deleteShader(e), t.deleteShader(r), l;
534
- }
535
- createWebGLShader(t, s, i) {
536
- const e = t.createShader(s);
537
- if (!e) return null;
538
- if (t.shaderSource(e, i), t.compileShader(e), !t.getShaderParameter(e, t.COMPILE_STATUS)) {
539
- const r = t.getShaderInfoLog(e) ?? "unknown compile error";
540
- return this.webglInitError = `shader compile failed: ${r}`, console.warn("ReelDeal WebGL: shader compile failed", r), t.deleteShader(e), null;
541
- }
542
- return e;
919
+ hideFinalLine() {
920
+ this.showFinalLine = !1, this.renderer?.hideFinalLine(), this.render();
543
921
  }
544
- releaseWebGLResources() {
545
- 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());
546
924
  }
547
925
  }
548
926
  export {
549
- ut as ReelDeal,
550
- E as defaultIdleBob,
927
+ Me as ReelDeal,
928
+ _e as WebGLRenderer,
929
+ R as defaultIdleBob,
551
930
  B as defaultSpinBlur,
552
- T as defaultSpinConfig
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
553
939
  };
554
940
  //# sourceMappingURL=index.es.js.map