cascading-reel 0.0.21 → 0.0.22
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.cjs.js +3 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.es.js +267 -221
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +3 -2
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -33,61 +33,61 @@ const q = [0.04, 0, -0.04], I = {
|
|
|
33
33
|
pixelSnapY: "half"
|
|
34
34
|
}
|
|
35
35
|
}, Y = "normal";
|
|
36
|
-
function V(
|
|
37
|
-
return I[
|
|
36
|
+
function V(s) {
|
|
37
|
+
return I[s];
|
|
38
38
|
}
|
|
39
39
|
I.normal.outroRowGapMs;
|
|
40
40
|
I.normal.rowBaseSpacingRatio;
|
|
41
|
-
const X = 5e3, G = 1800, k = 0.1,
|
|
41
|
+
const X = 5e3, G = 1800, k = 0.1, L = 720, D = 34, z = [255, 235, 110];
|
|
42
42
|
I.normal.columnStaggerMs;
|
|
43
43
|
I.normal.fallMs;
|
|
44
44
|
I.normal.outroOverlapMs;
|
|
45
45
|
const $ = 200;
|
|
46
|
-
function b(
|
|
47
|
-
return
|
|
46
|
+
function b(s, t, e) {
|
|
47
|
+
return s < t ? t : s > e ? e : s;
|
|
48
48
|
}
|
|
49
|
-
function K(
|
|
50
|
-
return Math.floor(Math.random() *
|
|
49
|
+
function K(s) {
|
|
50
|
+
return Math.floor(Math.random() * s);
|
|
51
51
|
}
|
|
52
|
-
function C(
|
|
53
|
-
return (
|
|
52
|
+
function C(s, t) {
|
|
53
|
+
return (s % t + t) % t;
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
return b(Math.round(
|
|
55
|
+
function v(s) {
|
|
56
|
+
return b(Math.round(s), 0, 255);
|
|
57
57
|
}
|
|
58
|
-
function F(
|
|
58
|
+
function F(s) {
|
|
59
59
|
const t = [];
|
|
60
|
-
for (let
|
|
60
|
+
for (let e = 0; e < 3; e += 1) {
|
|
61
61
|
const i = [];
|
|
62
62
|
for (let r = 0; r < 3; r += 1)
|
|
63
|
-
i.push(K(
|
|
63
|
+
i.push(K(s));
|
|
64
64
|
t.push(i);
|
|
65
65
|
}
|
|
66
66
|
return t;
|
|
67
67
|
}
|
|
68
|
-
function H(
|
|
68
|
+
function H(s) {
|
|
69
69
|
const t = /* @__PURE__ */ new Map();
|
|
70
70
|
for (let n = 0; n < 3; n += 1)
|
|
71
71
|
for (let o = 0; o < 3; o += 1) {
|
|
72
|
-
const
|
|
73
|
-
t.set(
|
|
72
|
+
const h = s[n][o];
|
|
73
|
+
t.set(h, (t.get(h) ?? 0) + 1);
|
|
74
74
|
}
|
|
75
|
-
let
|
|
75
|
+
let e = s[0][0], i = -1;
|
|
76
76
|
for (const [n, o] of t.entries())
|
|
77
|
-
o > i && (i = o,
|
|
77
|
+
o > i && (i = o, e = n);
|
|
78
78
|
const r = [];
|
|
79
79
|
for (let n = 0; n < 3; n += 1)
|
|
80
80
|
for (let o = 0; o < 3; o += 1)
|
|
81
|
-
|
|
81
|
+
s[n][o] === e && r.push({ col: n, row: o });
|
|
82
82
|
return r;
|
|
83
83
|
}
|
|
84
84
|
function m() {
|
|
85
85
|
return Array.from({ length: 3 }, () => Array.from({ length: 3 }, () => 0));
|
|
86
86
|
}
|
|
87
|
-
function R(
|
|
88
|
-
for (let
|
|
87
|
+
function R(s, t) {
|
|
88
|
+
for (let e = 0; e < 3; e += 1)
|
|
89
89
|
for (let i = 0; i < 3; i += 1)
|
|
90
|
-
e
|
|
90
|
+
s[e][i] = t;
|
|
91
91
|
}
|
|
92
92
|
class Q {
|
|
93
93
|
rafId = null;
|
|
@@ -113,159 +113,159 @@ class Q {
|
|
|
113
113
|
this.rafId !== null && (this.rafId = requestAnimationFrame(this.tick));
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
|
-
function
|
|
117
|
-
const t = b(
|
|
116
|
+
function j(s) {
|
|
117
|
+
const t = b(s, 0, 1);
|
|
118
118
|
return t * t * t * (t * (t * 6 - 15) + 10);
|
|
119
119
|
}
|
|
120
|
-
function y(
|
|
121
|
-
if (
|
|
122
|
-
return { value:
|
|
123
|
-
const
|
|
120
|
+
function y(s, t) {
|
|
121
|
+
if (s.endMs <= s.startMs)
|
|
122
|
+
return { value: s.to, t: 1, done: !0 };
|
|
123
|
+
const e = b((t - s.startMs) / (s.endMs - s.startMs), 0, 1), i = j(e);
|
|
124
124
|
return {
|
|
125
|
-
value:
|
|
126
|
-
t:
|
|
127
|
-
done:
|
|
125
|
+
value: s.from + (s.to - s.from) * i,
|
|
126
|
+
t: e,
|
|
127
|
+
done: e >= 1
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
-
function
|
|
130
|
+
function Z(s, t, e, i) {
|
|
131
131
|
const r = [0, 0, 0];
|
|
132
132
|
let n = 0;
|
|
133
133
|
for (let o = 2; o >= 0; o -= 1) {
|
|
134
|
-
if (
|
|
134
|
+
if (s[o] === 0) {
|
|
135
135
|
r[o] = 0;
|
|
136
136
|
continue;
|
|
137
137
|
}
|
|
138
138
|
r[o] = n;
|
|
139
|
-
const
|
|
140
|
-
n +=
|
|
139
|
+
const h = Math.floor(t * i);
|
|
140
|
+
n += h + e;
|
|
141
141
|
}
|
|
142
142
|
return r;
|
|
143
143
|
}
|
|
144
|
-
function
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
144
|
+
function x(s) {
|
|
145
|
+
const e = s.height - s.boardY + s.cellH + 2, i = [
|
|
146
|
+
e,
|
|
147
|
+
e,
|
|
148
|
+
e
|
|
149
149
|
];
|
|
150
150
|
return {
|
|
151
|
-
columnStaggerMs:
|
|
152
|
-
fallMs:
|
|
153
|
-
incomingAlphaRampMs:
|
|
154
|
-
outgoingDistance:
|
|
155
|
-
incomingFromOffsets: [-
|
|
156
|
-
rowStartDelays:
|
|
151
|
+
columnStaggerMs: s.motionProfile.columnStaggerMs,
|
|
152
|
+
fallMs: s.motionProfile.fallMs,
|
|
153
|
+
incomingAlphaRampMs: s.motionProfile.incomingAlphaRampMs,
|
|
154
|
+
outgoingDistance: e,
|
|
155
|
+
incomingFromOffsets: [-s.cellH, -s.cellH * 2, -s.cellH * 3],
|
|
156
|
+
rowStartDelays: Z(
|
|
157
157
|
i,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
s.motionProfile.fallMs,
|
|
159
|
+
s.motionProfile.outroRowGapMs,
|
|
160
|
+
s.motionProfile.rowBaseSpacingRatio
|
|
161
161
|
),
|
|
162
162
|
// Делаем небольшое перекрытие фаз: новые символы начинают входить
|
|
163
163
|
// немного раньше окончания исходящих, чтобы движение воспринималось
|
|
164
164
|
// как непрерывный поток.
|
|
165
165
|
incomingStartShift: Math.max(
|
|
166
166
|
0,
|
|
167
|
-
|
|
167
|
+
s.motionProfile.fallMs - s.motionProfile.outroOverlapMs
|
|
168
168
|
)
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
|
-
function U(
|
|
172
|
-
let t = !0,
|
|
173
|
-
for (let i = 0; i <
|
|
174
|
-
const r =
|
|
171
|
+
function U(s) {
|
|
172
|
+
let t = !0, e = !0;
|
|
173
|
+
for (let i = 0; i < s.scriptedOutgoingOffsets.length; i += 1) {
|
|
174
|
+
const r = s.elapsedMs - i * s.motionPlan.columnStaggerMs;
|
|
175
175
|
for (let n = 0; n < 3; n += 1) {
|
|
176
|
-
const o = r -
|
|
176
|
+
const o = r - s.motionPlan.rowStartDelays[n];
|
|
177
177
|
if (o <= 0) {
|
|
178
|
-
|
|
178
|
+
s.scriptedOutgoingOffsets[i][n] = 0, s.scriptedIncomingOffsets[i][n] = s.motionPlan.incomingFromOffsets[n], s.scriptedIncomingAlpha[i][n] = 0, s.scriptedIncomingVisibility[i][n] = "hidden", t = !1, e = !1;
|
|
179
179
|
continue;
|
|
180
180
|
}
|
|
181
|
-
const
|
|
181
|
+
const h = y(
|
|
182
182
|
{
|
|
183
183
|
startMs: 0,
|
|
184
|
-
endMs:
|
|
184
|
+
endMs: s.motionPlan.fallMs,
|
|
185
185
|
from: 0,
|
|
186
|
-
to:
|
|
186
|
+
to: s.motionPlan.outgoingDistance
|
|
187
187
|
},
|
|
188
188
|
o
|
|
189
189
|
);
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
if (
|
|
193
|
-
|
|
190
|
+
s.scriptedOutgoingOffsets[i][n] = h.value, s.scriptedIncomingVisibility[i][n] = h.done ? "entering" : "exiting", h.done || (t = !1);
|
|
191
|
+
const l = o - s.motionPlan.incomingStartShift;
|
|
192
|
+
if (l <= 0) {
|
|
193
|
+
s.scriptedIncomingOffsets[i][n] = s.motionPlan.incomingFromOffsets[n], s.scriptedIncomingAlpha[i][n] = 0, s.scriptedIncomingVisibility[i][n] = "hidden", e = !1;
|
|
194
194
|
continue;
|
|
195
195
|
}
|
|
196
196
|
const c = y(
|
|
197
197
|
{
|
|
198
198
|
startMs: 0,
|
|
199
|
-
endMs:
|
|
200
|
-
from:
|
|
199
|
+
endMs: s.motionPlan.fallMs,
|
|
200
|
+
from: s.motionPlan.incomingFromOffsets[n],
|
|
201
201
|
to: 0
|
|
202
202
|
},
|
|
203
|
-
|
|
203
|
+
l
|
|
204
204
|
);
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
s.scriptedIncomingOffsets[i][n] = c.value, s.scriptedIncomingAlpha[i][n] = b(
|
|
206
|
+
l / Math.max(1, s.motionPlan.incomingAlphaRampMs),
|
|
207
207
|
0,
|
|
208
208
|
1
|
|
209
|
-
),
|
|
209
|
+
), s.scriptedIncomingVisibility[i][n] = c.done ? "active" : "entering", c.done || (e = !1);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
|
-
return { allOutgoingDone: t, allIncomingDone:
|
|
212
|
+
return { allOutgoingDone: t, allIncomingDone: e };
|
|
213
213
|
}
|
|
214
|
-
function J(
|
|
215
|
-
return
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
function J(s) {
|
|
215
|
+
return s ? [
|
|
216
|
+
v(s[0]),
|
|
217
|
+
v(s[1]),
|
|
218
|
+
v(s[2])
|
|
219
219
|
] : z;
|
|
220
220
|
}
|
|
221
|
-
function tt(
|
|
222
|
-
return
|
|
221
|
+
function tt(s) {
|
|
222
|
+
return s === "rainbow" ? "rainbow" : "solid";
|
|
223
223
|
}
|
|
224
|
-
function
|
|
225
|
-
if (
|
|
224
|
+
function W(s) {
|
|
225
|
+
if (s.length !== 3)
|
|
226
226
|
throw new Error("rows must contain 3 rows");
|
|
227
227
|
for (let t = 0; t < 3; t += 1)
|
|
228
|
-
if (!Array.isArray(
|
|
228
|
+
if (!Array.isArray(s[t]) || s[t].length !== 3)
|
|
229
229
|
throw new Error(`rows[${t}] must contain 3 columns`);
|
|
230
230
|
return [
|
|
231
|
-
[
|
|
232
|
-
[
|
|
233
|
-
[
|
|
231
|
+
[s[0][0], s[1][0], s[2][0]],
|
|
232
|
+
[s[0][1], s[1][1], s[2][1]],
|
|
233
|
+
[s[0][2], s[1][2], s[2][2]]
|
|
234
234
|
];
|
|
235
235
|
}
|
|
236
|
-
function
|
|
237
|
-
if (
|
|
236
|
+
function T(s, t) {
|
|
237
|
+
if (s.length !== 3)
|
|
238
238
|
throw new Error("stopGrid must contain 3 columns");
|
|
239
|
-
const
|
|
239
|
+
const e = [];
|
|
240
240
|
for (let i = 0; i < 3; i += 1) {
|
|
241
|
-
const r =
|
|
241
|
+
const r = s[i];
|
|
242
242
|
if (!Array.isArray(r) || r.length !== 3)
|
|
243
243
|
throw new Error(`stopGrid[${i}] must contain 3 rows`);
|
|
244
|
-
|
|
244
|
+
e[i] = [
|
|
245
245
|
C(r[0], t),
|
|
246
246
|
C(r[1], t),
|
|
247
247
|
C(r[2], t)
|
|
248
248
|
];
|
|
249
249
|
}
|
|
250
|
-
return
|
|
250
|
+
return e;
|
|
251
251
|
}
|
|
252
|
-
function it(
|
|
253
|
-
return W(
|
|
252
|
+
function it(s, t) {
|
|
253
|
+
return T(W(s), t);
|
|
254
254
|
}
|
|
255
|
-
function et(
|
|
255
|
+
function et(s) {
|
|
256
256
|
return {
|
|
257
|
-
stopGrid:
|
|
258
|
-
stopRows:
|
|
259
|
-
finaleSequence:
|
|
260
|
-
finaleSequenceRows:
|
|
261
|
-
highlightWin:
|
|
262
|
-
callback:
|
|
257
|
+
stopGrid: s.stopGrid?.map((t) => [...t]),
|
|
258
|
+
stopRows: s.stopRows?.map((t) => [...t]),
|
|
259
|
+
finaleSequence: s.finaleSequence?.map((t) => t.map((e) => [...e])),
|
|
260
|
+
finaleSequenceRows: s.finaleSequenceRows?.map((t) => t.map((e) => [...e])),
|
|
261
|
+
highlightWin: s.highlightWin,
|
|
262
|
+
callback: s.callback
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
265
|
class st {
|
|
266
266
|
queue;
|
|
267
267
|
constructor(t) {
|
|
268
|
-
this.queue = (t ?? []).map((
|
|
268
|
+
this.queue = (t ?? []).map((e) => et(e));
|
|
269
269
|
}
|
|
270
270
|
hasPending() {
|
|
271
271
|
return this.queue.length > 0;
|
|
@@ -289,19 +289,19 @@ function nt() {
|
|
|
289
289
|
winEffectsEnvelope: 1
|
|
290
290
|
};
|
|
291
291
|
}
|
|
292
|
-
function rt(
|
|
293
|
-
|
|
292
|
+
function rt(s, t) {
|
|
293
|
+
s.hasStartedFirstSpin = !0, s.isSpinning = !0, s.phase = "outro", s.outroStartedAt = t.startedAt, s.activeSpinState = t.activeSpinState, s.shouldHighlightCurrentSpin = t.shouldHighlightCurrentSpin;
|
|
294
294
|
}
|
|
295
|
-
function ot(
|
|
296
|
-
|
|
295
|
+
function ot(s, t, e) {
|
|
296
|
+
s.phase = "idle", s.idleStartedAt = e, s.isSpinning = !1, s.shouldHighlightCurrentSpin = !1, s.queueFinished = !t, s.activeSpinState = null;
|
|
297
297
|
}
|
|
298
|
-
function N(
|
|
299
|
-
|
|
298
|
+
function N(s, t) {
|
|
299
|
+
s.winFlashStartedAt = t, s.phase = "winFlash";
|
|
300
300
|
}
|
|
301
|
-
function
|
|
302
|
-
|
|
301
|
+
function ht(s) {
|
|
302
|
+
s.isSpinning = !1, s.queueFinished = !0;
|
|
303
303
|
}
|
|
304
|
-
const
|
|
304
|
+
const lt = `
|
|
305
305
|
attribute vec2 a_pos;
|
|
306
306
|
uniform vec2 u_resolution;
|
|
307
307
|
uniform vec4 u_destRect;
|
|
@@ -370,14 +370,14 @@ class ct {
|
|
|
370
370
|
spriteSegmentHeight;
|
|
371
371
|
constructor(t) {
|
|
372
372
|
this.canvas = t.canvas, this.spriteImage = t.spriteImage, this.spriteElementsCount = Math.max(1, t.spriteElementsCount), this.spriteWidth = this.spriteImage.width, this.spriteHeight = this.spriteImage.height, this.spriteSegmentHeight = this.spriteHeight / this.spriteElementsCount;
|
|
373
|
-
const
|
|
373
|
+
const e = this.canvas.getContext("webgl2", {
|
|
374
374
|
alpha: !0,
|
|
375
375
|
antialias: !1
|
|
376
376
|
}) ?? this.canvas.getContext("webgl", { alpha: !0, antialias: !1 });
|
|
377
|
-
if (!
|
|
377
|
+
if (!e)
|
|
378
378
|
throw new Error("WebGL context is not available");
|
|
379
|
-
this.gl =
|
|
380
|
-
const i = this.createShader(this.gl.VERTEX_SHADER,
|
|
379
|
+
this.gl = e;
|
|
380
|
+
const i = this.createShader(this.gl.VERTEX_SHADER, lt), r = this.createShader(this.gl.FRAGMENT_SHADER, at);
|
|
381
381
|
this.program = this.createProgram(i, r), this.gl.deleteShader(i), this.gl.deleteShader(r);
|
|
382
382
|
const n = this.gl.createBuffer();
|
|
383
383
|
if (!n)
|
|
@@ -398,8 +398,8 @@ class ct {
|
|
|
398
398
|
this.gl.UNSIGNED_BYTE,
|
|
399
399
|
this.spriteImage
|
|
400
400
|
), this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0), this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR), this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR), this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE), this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE), this.gl.useProgram(this.program);
|
|
401
|
-
const
|
|
402
|
-
this.gl.enableVertexAttribArray(
|
|
401
|
+
const h = this.gl.getAttribLocation(this.program, "a_pos");
|
|
402
|
+
this.gl.enableVertexAttribArray(h), this.gl.vertexAttribPointer(h, 2, this.gl.FLOAT, !1, 8, 0), this.uniforms = {
|
|
403
403
|
resolution: this.gl.getUniformLocation(this.program, "u_resolution"),
|
|
404
404
|
destRect: this.gl.getUniformLocation(this.program, "u_destRect"),
|
|
405
405
|
srcRect: this.gl.getUniformLocation(this.program, "u_srcRect"),
|
|
@@ -409,25 +409,25 @@ class ct {
|
|
|
409
409
|
texture: this.gl.getUniformLocation(this.program, "u_texture")
|
|
410
410
|
}, this.gl.uniform1i(this.uniforms.texture, 0), this.gl.clearColor(0, 0, 0, 0), this.gl.enable(this.gl.BLEND), this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
411
411
|
}
|
|
412
|
-
resize(t,
|
|
413
|
-
this.viewportW = Math.max(1, Math.floor(t)), this.viewportH = Math.max(1, Math.floor(
|
|
412
|
+
resize(t, e) {
|
|
413
|
+
this.viewportW = Math.max(1, Math.floor(t)), this.viewportH = Math.max(1, Math.floor(e)), this.gl.viewport(0, 0, this.viewportW, this.viewportH);
|
|
414
414
|
}
|
|
415
415
|
beginFrame() {
|
|
416
416
|
this.gl.useProgram(this.program), this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer), this.gl.activeTexture(this.gl.TEXTURE0), this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture), this.gl.uniform2f(this.uniforms.resolution, this.viewportW, this.viewportH), this.gl.uniform1f(this.uniforms.shapeMode, 0), this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
417
417
|
}
|
|
418
|
-
drawSprite(t,
|
|
419
|
-
const
|
|
420
|
-
this.gl.uniform4f(this.uniforms.destRect,
|
|
418
|
+
drawSprite(t, e, i, r, n, o = 1) {
|
|
419
|
+
const l = C(t, this.spriteElementsCount) * this.spriteSegmentHeight, c = l + this.spriteSegmentHeight, a = 0.5, d = a / this.spriteWidth, f = 1 - a / this.spriteWidth, g = 1 - (c - a) / this.spriteHeight, S = 1 - (l + a) / this.spriteHeight;
|
|
420
|
+
this.gl.uniform4f(this.uniforms.destRect, e, i, r, n), this.gl.uniform4f(this.uniforms.srcRect, d, g, f, S), this.gl.uniform4f(this.uniforms.color, 1, 1, 1, o), this.gl.uniform1f(this.uniforms.shapeMode, 0), this.gl.uniform1f(this.uniforms.useTexture, 1), this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
|
421
421
|
}
|
|
422
|
-
drawSolidRect(t,
|
|
423
|
-
this.gl.uniform4f(this.uniforms.destRect, t,
|
|
422
|
+
drawSolidRect(t, e, i, r, n) {
|
|
423
|
+
this.gl.uniform4f(this.uniforms.destRect, t, e, i, r), this.gl.uniform4f(this.uniforms.srcRect, 0, 0, 1, 1), this.gl.uniform4f(this.uniforms.color, n[0], n[1], n[2], n[3]), this.gl.uniform1f(this.uniforms.shapeMode, 0), this.gl.uniform1f(this.uniforms.useTexture, 0), this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
|
424
424
|
}
|
|
425
|
-
drawSoftCircle(t,
|
|
425
|
+
drawSoftCircle(t, e, i, r) {
|
|
426
426
|
const n = i * 2;
|
|
427
427
|
this.gl.uniform4f(
|
|
428
428
|
this.uniforms.destRect,
|
|
429
429
|
t - i,
|
|
430
|
-
|
|
430
|
+
e - i,
|
|
431
431
|
n,
|
|
432
432
|
n
|
|
433
433
|
), this.gl.uniform4f(this.uniforms.srcRect, 0, 0, 1, 1), this.gl.uniform4f(this.uniforms.color, r[0], r[1], r[2], r[3]), this.gl.uniform1f(this.uniforms.useTexture, 0), this.gl.uniform1f(this.uniforms.shapeMode, 1), this.gl.drawArrays(this.gl.TRIANGLES, 0, 6), this.gl.uniform1f(this.uniforms.shapeMode, 0);
|
|
@@ -441,21 +441,21 @@ class ct {
|
|
|
441
441
|
dispose() {
|
|
442
442
|
this.gl.deleteTexture(this.texture), this.gl.deleteBuffer(this.quadBuffer), this.gl.deleteProgram(this.program);
|
|
443
443
|
}
|
|
444
|
-
createShader(t,
|
|
444
|
+
createShader(t, e) {
|
|
445
445
|
const i = this.gl.createShader(t);
|
|
446
446
|
if (!i)
|
|
447
447
|
throw new Error("Failed to create WebGL shader");
|
|
448
|
-
if (this.gl.shaderSource(i,
|
|
448
|
+
if (this.gl.shaderSource(i, e), this.gl.compileShader(i), !this.gl.getShaderParameter(i, this.gl.COMPILE_STATUS)) {
|
|
449
449
|
const r = this.gl.getShaderInfoLog(i) ?? "unknown error";
|
|
450
450
|
throw this.gl.deleteShader(i), new Error(`WebGL shader compile failed: ${r}`);
|
|
451
451
|
}
|
|
452
452
|
return i;
|
|
453
453
|
}
|
|
454
|
-
createProgram(t,
|
|
454
|
+
createProgram(t, e) {
|
|
455
455
|
const i = this.gl.createProgram();
|
|
456
456
|
if (!i)
|
|
457
457
|
throw new Error("Failed to create WebGL program");
|
|
458
|
-
if (this.gl.attachShader(i, t), this.gl.attachShader(i,
|
|
458
|
+
if (this.gl.attachShader(i, t), this.gl.attachShader(i, e), this.gl.linkProgram(i), !this.gl.getProgramParameter(i, this.gl.LINK_STATUS)) {
|
|
459
459
|
const r = this.gl.getProgramInfoLog(i) ?? "unknown error";
|
|
460
460
|
throw this.gl.deleteProgram(i), new Error(`WebGL program link failed: ${r}`);
|
|
461
461
|
}
|
|
@@ -478,6 +478,7 @@ class u {
|
|
|
478
478
|
particleColorMode;
|
|
479
479
|
motionProfile;
|
|
480
480
|
pixelSnapY;
|
|
481
|
+
debugPerf;
|
|
481
482
|
spriteImage = null;
|
|
482
483
|
webglRenderer = null;
|
|
483
484
|
rafLoop = new Q();
|
|
@@ -513,6 +514,14 @@ class u {
|
|
|
513
514
|
outroInterpolationAlpha = 1;
|
|
514
515
|
isOutroPipelineWarmedUp = !1;
|
|
515
516
|
isGpuPipelineWarmedUp = !1;
|
|
517
|
+
perfWindowStartedAt = 0;
|
|
518
|
+
perfFrameCount = 0;
|
|
519
|
+
perfDtSum = 0;
|
|
520
|
+
perfOver20MsCount = 0;
|
|
521
|
+
perfDtSamples = [];
|
|
522
|
+
perfLogLines = [];
|
|
523
|
+
static PERF_WINDOW_MS = 1500;
|
|
524
|
+
static PERF_LOG_LIMIT = 60;
|
|
516
525
|
static PRE_SPIN_MS = 150;
|
|
517
526
|
static WIN_EFFECTS_ENVELOPE_TAU_MS = 120;
|
|
518
527
|
static MAX_FRAME_DELTA_MS = 250;
|
|
@@ -523,7 +532,7 @@ class u {
|
|
|
523
532
|
this.canvas = t.canvas, this.container = t.container, this.button = t.button, this.spriteUrl = t.sprite, this.spriteElementsCount = Math.max(
|
|
524
533
|
1,
|
|
525
534
|
t.spriteElementsCount ?? 6
|
|
526
|
-
), this.highlightInitialWinningCells = t.highlightInitialWinningCells !== !1, this.spinQueueController = new st(t.queuedSpinStates), this.particleColorRgb = J(t.particleColorRgb), this.particleColorMode = tt(t.particleColorMode), this.motionProfile = V(t.motionProfile ?? Y), this.pixelSnapY = t.pixelSnapY ?? this.motionProfile.pixelSnapY, this.grid = t.initialSegments ? it(t.initialSegments, this.spriteElementsCount) : F(this.spriteElementsCount);
|
|
535
|
+
), this.highlightInitialWinningCells = t.highlightInitialWinningCells !== !1, this.spinQueueController = new st(t.queuedSpinStates), this.particleColorRgb = J(t.particleColorRgb), this.particleColorMode = tt(t.particleColorMode), this.motionProfile = V(t.motionProfile ?? Y), this.pixelSnapY = t.pixelSnapY ?? this.motionProfile.pixelSnapY, this.debugPerf = t.debugPerf === !0, this.grid = t.initialSegments ? it(t.initialSegments, this.spriteElementsCount) : F(this.spriteElementsCount);
|
|
527
536
|
}
|
|
528
537
|
async init() {
|
|
529
538
|
if (this.bindEvents(), this.resize(), await this.loadSpriteIfProvided(), !this.spriteImage)
|
|
@@ -537,7 +546,24 @@ class u {
|
|
|
537
546
|
});
|
|
538
547
|
}
|
|
539
548
|
destroy() {
|
|
540
|
-
this.unbindEvents(), this.rafLoop.stop(), this.simulationLastNow = 0, this.simulationAccumulatorMs = 0,
|
|
549
|
+
this.unbindEvents(), this.rafLoop.stop(), this.simulationLastNow = 0, this.simulationAccumulatorMs = 0, ht(this.runtime), this.webglRenderer?.dispose(), this.webglRenderer = null, this.clearWinningCells();
|
|
550
|
+
}
|
|
551
|
+
getPerfLogs() {
|
|
552
|
+
return [...this.perfLogLines];
|
|
553
|
+
}
|
|
554
|
+
clearPerfLogs() {
|
|
555
|
+
this.perfLogLines.length = 0;
|
|
556
|
+
}
|
|
557
|
+
async copyPerfLogsToClipboard() {
|
|
558
|
+
if (this.perfLogLines.length === 0) return !1;
|
|
559
|
+
const t = this.perfLogLines.join(`
|
|
560
|
+
`), e = navigator.clipboard;
|
|
561
|
+
if (e && typeof e.writeText == "function")
|
|
562
|
+
return await e.writeText(t), !0;
|
|
563
|
+
const i = document.createElement("textarea");
|
|
564
|
+
i.value = t, i.setAttribute("readonly", ""), i.style.position = "fixed", i.style.left = "-9999px", document.body.appendChild(i), i.select();
|
|
565
|
+
const r = document.execCommand("copy");
|
|
566
|
+
return document.body.removeChild(i), r;
|
|
541
567
|
}
|
|
542
568
|
spin() {
|
|
543
569
|
if (this.runtime.isSpinning || this.runtime.queueFinished) return;
|
|
@@ -545,8 +571,8 @@ class u {
|
|
|
545
571
|
this.runtime.queueFinished = !0, this.button && (this.button.disabled = !0);
|
|
546
572
|
return;
|
|
547
573
|
}
|
|
548
|
-
const t = this.spinQueueController.consume(),
|
|
549
|
-
this.runtime.isSpinning = !0, this.runtime.phase = "preSpin", this.runtime.preSpinStartedAt = performance.now(), this.runtime.activeSpinState = t, this.runtime.shouldHighlightCurrentSpin =
|
|
574
|
+
const t = this.spinQueueController.consume(), e = t?.highlightWin === !0;
|
|
575
|
+
this.runtime.isSpinning = !0, this.runtime.phase = "preSpin", this.runtime.preSpinStartedAt = performance.now(), this.runtime.activeSpinState = t, this.runtime.shouldHighlightCurrentSpin = e, this.runtime.hasStartedFirstSpin = !0, this.simulationLastNow = 0, this.simulationAccumulatorMs = 0, this.button && (this.button.disabled = !0), this.startLoop();
|
|
550
576
|
}
|
|
551
577
|
bindEvents() {
|
|
552
578
|
window.addEventListener("resize", this.resize), this.button?.addEventListener("click", this.onSpinClick);
|
|
@@ -562,7 +588,7 @@ class u {
|
|
|
562
588
|
this.runtime.isSpinning || this.spin();
|
|
563
589
|
};
|
|
564
590
|
getNextGrid(t) {
|
|
565
|
-
return t ?
|
|
591
|
+
return t ? T(t, this.spriteElementsCount) : F(this.spriteElementsCount);
|
|
566
592
|
}
|
|
567
593
|
update(t) {
|
|
568
594
|
if (this.runtime.isSpinning) {
|
|
@@ -574,9 +600,9 @@ class u {
|
|
|
574
600
|
shouldHighlightCurrentSpin: this.runtime.shouldHighlightCurrentSpin,
|
|
575
601
|
startedAt: t
|
|
576
602
|
}), this.runtime.preSpinStartedAt = 0;
|
|
577
|
-
const
|
|
578
|
-
this.scriptedCascadeQueue =
|
|
579
|
-
const i = this.runtime.activeSpinState?.stopRows ?
|
|
603
|
+
const e = this.runtime.activeSpinState?.finaleSequenceRows ? this.runtime.activeSpinState.finaleSequenceRows.map((n) => W(n)) : this.runtime.activeSpinState?.finaleSequence ?? [];
|
|
604
|
+
this.scriptedCascadeQueue = e.map((n) => n.map((o) => [...o])), this.clearWinningCells();
|
|
605
|
+
const i = this.runtime.activeSpinState?.stopRows ? W(this.runtime.activeSpinState.stopRows) : this.runtime.activeSpinState?.stopGrid, r = this.getNextGrid(i);
|
|
580
606
|
this.startOutroTransition(r, t);
|
|
581
607
|
}
|
|
582
608
|
if (this.runtime.phase !== "outro" && this.runtime.phase === "winFlash") {
|
|
@@ -590,13 +616,13 @@ class u {
|
|
|
590
616
|
this.finishSpinWithUi();
|
|
591
617
|
return;
|
|
592
618
|
}
|
|
593
|
-
this.outroMotionPlan || (this.outroMotionPlan =
|
|
619
|
+
this.outroMotionPlan || (this.outroMotionPlan = x({
|
|
594
620
|
height: this.height,
|
|
595
621
|
boardY: this.boardY,
|
|
596
622
|
cellH: this.cellH,
|
|
597
623
|
motionProfile: this.motionProfile
|
|
598
624
|
})), this.scriptedOutroElapsedMs += t;
|
|
599
|
-
const { allOutgoingDone:
|
|
625
|
+
const { allOutgoingDone: e, allIncomingDone: i } = U({
|
|
600
626
|
elapsedMs: this.scriptedOutroElapsedMs,
|
|
601
627
|
scriptedOutgoingOffsets: this.scriptedOutgoingOffsets,
|
|
602
628
|
scriptedIncomingOffsets: this.scriptedIncomingOffsets,
|
|
@@ -604,7 +630,7 @@ class u {
|
|
|
604
630
|
scriptedIncomingVisibility: this.scriptedIncomingVisibility,
|
|
605
631
|
motionPlan: this.outroMotionPlan
|
|
606
632
|
});
|
|
607
|
-
if (!(!
|
|
633
|
+
if (!(!e || !i) && (this.grid = this.scriptedPendingGrid, this.scriptedOutgoingGrid = null, this.scriptedPendingGrid = null, this.outroMotionPlan = null, this.clearWinningCells(), this.resetOutroBuffers(1, "active"), !this.tryStartScriptedCascade(this.scriptedOutroStartedAt + this.scriptedOutroElapsedMs))) {
|
|
608
634
|
if (!this.runtime.shouldHighlightCurrentSpin) {
|
|
609
635
|
this.finishSpinWithUi();
|
|
610
636
|
return;
|
|
@@ -614,20 +640,20 @@ class u {
|
|
|
614
640
|
}
|
|
615
641
|
tryStartScriptedCascade(t) {
|
|
616
642
|
if (this.scriptedCascadeQueue.length === 0) return !1;
|
|
617
|
-
const
|
|
618
|
-
return
|
|
643
|
+
const e = this.scriptedCascadeQueue.shift();
|
|
644
|
+
return e ? (this.startOutroTransition(T(e, this.spriteElementsCount), t), !0) : !1;
|
|
619
645
|
}
|
|
620
|
-
startOutroTransition(t,
|
|
621
|
-
this.scriptedOutgoingGrid = this.grid.map((i) => [...i]), this.scriptedPendingGrid = t.map((i) => [...i]), this.outroMotionPlan =
|
|
646
|
+
startOutroTransition(t, e) {
|
|
647
|
+
this.scriptedOutgoingGrid = this.grid.map((i) => [...i]), this.scriptedPendingGrid = t.map((i) => [...i]), this.outroMotionPlan = x({
|
|
622
648
|
height: this.height,
|
|
623
649
|
boardY: this.boardY,
|
|
624
650
|
cellH: this.cellH,
|
|
625
651
|
motionProfile: this.motionProfile
|
|
626
|
-
}), this.resetOutroBuffers(0, "hidden"), this.clearWinningCells(), this.runtime.phase = "outro", this.scriptedOutroStartedAt =
|
|
652
|
+
}), this.resetOutroBuffers(0, "hidden"), this.clearWinningCells(), this.runtime.phase = "outro", this.scriptedOutroStartedAt = e, this.scriptedOutroElapsedMs = 0, this.outroInterpolationAlpha = 1;
|
|
627
653
|
}
|
|
628
654
|
/** @param skipCallback true при закрытии подсветки по клику (callback уже вызван по окончании прокрутки) */
|
|
629
655
|
finishSpinWithUi(t = !1) {
|
|
630
|
-
const
|
|
656
|
+
const e = this.runtime.activeSpinState, i = t ? void 0 : e?.callback, r = this.spinQueueController.hasPending();
|
|
631
657
|
ot(this.runtime, r, performance.now()), this.button && (this.button.disabled = this.runtime.queueFinished), i?.();
|
|
632
658
|
}
|
|
633
659
|
applyInitialHighlightIfNeeded() {
|
|
@@ -635,21 +661,21 @@ class u {
|
|
|
635
661
|
}
|
|
636
662
|
warmUpOutroPipeline() {
|
|
637
663
|
if (this.isOutroPipelineWarmedUp) return;
|
|
638
|
-
const t =
|
|
664
|
+
const t = x({
|
|
639
665
|
height: this.height,
|
|
640
666
|
boardY: this.boardY,
|
|
641
667
|
cellH: this.cellH,
|
|
642
668
|
motionProfile: this.motionProfile
|
|
643
|
-
}),
|
|
669
|
+
}), e = m(), i = m(), r = m(), n = u.createVisibilityGrid("hidden"), o = Math.max(...t.rowStartDelays), h = 2 * t.columnStaggerMs, l = [
|
|
644
670
|
0,
|
|
645
671
|
this.motionProfile.fixedStepMs,
|
|
646
672
|
t.incomingStartShift + this.motionProfile.fixedStepMs,
|
|
647
|
-
t.fallMs + o +
|
|
673
|
+
t.fallMs + o + h + this.motionProfile.fixedStepMs
|
|
648
674
|
];
|
|
649
|
-
for (const c of
|
|
675
|
+
for (const c of l)
|
|
650
676
|
U({
|
|
651
677
|
elapsedMs: c,
|
|
652
|
-
scriptedOutgoingOffsets:
|
|
678
|
+
scriptedOutgoingOffsets: e,
|
|
653
679
|
scriptedIncomingOffsets: i,
|
|
654
680
|
scriptedIncomingAlpha: r,
|
|
655
681
|
scriptedIncomingVisibility: n,
|
|
@@ -661,22 +687,42 @@ class u {
|
|
|
661
687
|
if (this.isGpuPipelineWarmedUp) return;
|
|
662
688
|
const t = this.webglRenderer;
|
|
663
689
|
if (!t) return;
|
|
664
|
-
const
|
|
665
|
-
t.beginFrame(), t.drawSprite(0, r, n,
|
|
666
|
-
r +
|
|
690
|
+
const e = Math.max(8, this.cellW * 0.2), i = Math.max(8, this.cellH * 0.2), r = this.boardX + 2, n = this.boardY + 2;
|
|
691
|
+
t.beginFrame(), t.drawSprite(0, r, n, e, i, 1), t.drawSolidRect(r + e + 2, n, e, i, [1, 1, 1, 0.35]), t.beginAdditiveBlend(), t.drawSoftCircle(
|
|
692
|
+
r + e * 0.5,
|
|
667
693
|
n + i * 0.5,
|
|
668
|
-
Math.max(2,
|
|
694
|
+
Math.max(2, e * 0.25),
|
|
669
695
|
[1, 0.9, 0.4, 0.4]
|
|
670
696
|
), t.endAdditiveBlend(), this.isGpuPipelineWarmedUp = !0;
|
|
671
697
|
}
|
|
698
|
+
trackOutroPerf(t, e) {
|
|
699
|
+
if (this.debugPerf) {
|
|
700
|
+
if (this.runtime.phase !== "outro") {
|
|
701
|
+
this.resetPerfWindow();
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
this.perfWindowStartedAt <= 0 && (this.perfWindowStartedAt = e), this.perfFrameCount += 1, this.perfDtSum += t, t > 20 && (this.perfOver20MsCount += 1), this.perfDtSamples.push(t), !(e - this.perfWindowStartedAt < u.PERF_WINDOW_MS) && (this.flushPerfWindow(), this.perfWindowStartedAt = e);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
resetPerfWindow() {
|
|
708
|
+
this.perfWindowStartedAt = 0, this.perfFrameCount = 0, this.perfDtSum = 0, this.perfOver20MsCount = 0, this.perfDtSamples.length = 0;
|
|
709
|
+
}
|
|
710
|
+
flushPerfWindow() {
|
|
711
|
+
if (this.perfFrameCount === 0) return;
|
|
712
|
+
const t = this.perfDtSum / this.perfFrameCount, e = [...this.perfDtSamples].sort((l, c) => l - c), i = Math.max(0, Math.min(e.length - 1, Math.floor(e.length * 0.95))), r = e[i], n = e[e.length - 1], o = t > 0 ? 1e3 / t : 0, h = `[CascadingReel][outro perf] avg=${t.toFixed(2)}ms p95=${r.toFixed(2)}ms max=${n.toFixed(2)}ms fps=${o.toFixed(1)} slow>20ms=${this.perfOver20MsCount}/${this.perfFrameCount}`;
|
|
713
|
+
this.perfLogLines.push(h), this.perfLogLines.length > u.PERF_LOG_LIMIT && this.perfLogLines.splice(0, this.perfLogLines.length - u.PERF_LOG_LIMIT), console.log(h), this.perfFrameCount = 0, this.perfDtSum = 0, this.perfOver20MsCount = 0, this.perfDtSamples.length = 0;
|
|
714
|
+
}
|
|
672
715
|
render(t) {
|
|
673
716
|
if (!this.webglRenderer) return;
|
|
674
717
|
this.initialHighlightRequestedAt > 0 && t - this.initialHighlightRequestedAt >= $ && (N(this.runtime, this.initialHighlightRequestedAt), this.runtime.winEffectsEnvelope = 1, this.initialHighlightRequestedAt = 0, this.button && (this.button.disabled = !1));
|
|
675
|
-
const
|
|
718
|
+
const e = this.runtime.phase === "preSpin" ? 0 : this.runtime.phase === "winFlash" ? 1 : 0;
|
|
676
719
|
if (this.lastRafTime > 0) {
|
|
677
|
-
const
|
|
678
|
-
this.
|
|
679
|
-
|
|
720
|
+
const h = Math.min(t - this.lastRafTime, 50);
|
|
721
|
+
this.trackOutroPerf(h, t);
|
|
722
|
+
const l = 1 - Math.exp(-h / u.WIN_EFFECTS_ENVELOPE_TAU_MS);
|
|
723
|
+
this.runtime.winEffectsEnvelope += (e - this.runtime.winEffectsEnvelope) * l;
|
|
724
|
+
} else
|
|
725
|
+
this.resetPerfWindow();
|
|
680
726
|
this.lastRafTime = t, this.webglRenderer.beginFrame();
|
|
681
727
|
const i = this.runtime.phase === "winFlash" || this.runtime.phase === "preSpin" || this.initialHighlightRequestedAt > 0 && this.winningCells.length > 0;
|
|
682
728
|
this.runtime.phase === "outro" && this.scriptedOutgoingGrid && this.scriptedPendingGrid ? (this.drawGridInterpolated(
|
|
@@ -703,53 +749,53 @@ class u {
|
|
|
703
749
|
winEffectsEnvelope: o
|
|
704
750
|
});
|
|
705
751
|
}
|
|
706
|
-
isWinningCell = (t,
|
|
752
|
+
isWinningCell = (t, e) => this.winningCellKeys.has(`${t}:${e}`);
|
|
707
753
|
getRowCompactOffset(t) {
|
|
708
754
|
return (q[t] ?? 0) * this.cellH;
|
|
709
755
|
}
|
|
710
756
|
applyPixelSnapY(t) {
|
|
711
757
|
return this.pixelSnapY === "integer" ? Math.round(t) : this.pixelSnapY === "half" ? Math.round(t * 2) / 2 : t;
|
|
712
758
|
}
|
|
713
|
-
drawGrid(t,
|
|
759
|
+
drawGrid(t, e, i) {
|
|
714
760
|
this.drawGridWithSampler({
|
|
715
761
|
grid: t,
|
|
716
762
|
skipWinningCells: i,
|
|
717
|
-
sampleOffsetY: (r, n) =>
|
|
763
|
+
sampleOffsetY: (r, n) => e ? e[r][n] : 0,
|
|
718
764
|
sampleAlpha: () => 1,
|
|
719
765
|
isVisible: () => !0
|
|
720
766
|
});
|
|
721
767
|
}
|
|
722
|
-
drawGridInterpolated(t,
|
|
768
|
+
drawGridInterpolated(t, e, i, r, n, o, h, l) {
|
|
723
769
|
this.drawGridWithSampler({
|
|
724
770
|
grid: t,
|
|
725
771
|
skipWinningCells: n,
|
|
726
|
-
sampleOffsetY: (c, a) =>
|
|
727
|
-
sampleAlpha: (c, a) => o &&
|
|
728
|
-
isVisible: (c, a) => !
|
|
772
|
+
sampleOffsetY: (c, a) => e[c][a] + (i[c][a] - e[c][a]) * r,
|
|
773
|
+
sampleAlpha: (c, a) => o && h ? o[c][a] + (h[c][a] - o[c][a]) * r : 1,
|
|
774
|
+
isVisible: (c, a) => !l || l[c][a] !== "hidden"
|
|
729
775
|
});
|
|
730
776
|
}
|
|
731
777
|
drawGridWithSampler(t) {
|
|
732
|
-
const
|
|
733
|
-
if (
|
|
778
|
+
const e = this.webglRenderer;
|
|
779
|
+
if (e)
|
|
734
780
|
for (let i = 0; i < 3; i += 1) {
|
|
735
781
|
const r = this.boardX + i * this.cellW;
|
|
736
782
|
for (let n = 0; n < 3; n += 1) {
|
|
737
783
|
if (t.skipWinningCells && this.isWinningCell(i, n) || !t.isVisible(i, n)) continue;
|
|
738
|
-
const o = t.sampleOffsetY(i, n),
|
|
784
|
+
const o = t.sampleOffsetY(i, n), h = this.applyPixelSnapY(
|
|
739
785
|
this.boardY + n * this.cellH + o + this.getRowCompactOffset(n)
|
|
740
786
|
);
|
|
741
|
-
if (
|
|
742
|
-
const
|
|
743
|
-
|
|
787
|
+
if (h > this.height || h + this.cellH < 0) continue;
|
|
788
|
+
const l = t.sampleAlpha(i, n);
|
|
789
|
+
l <= 0 || e.drawSprite(t.grid[i][n], r, h, this.cellW, this.cellH, l);
|
|
744
790
|
}
|
|
745
791
|
}
|
|
746
792
|
}
|
|
747
793
|
drawWinningEffects(t) {
|
|
748
|
-
const
|
|
749
|
-
if (!
|
|
750
|
-
const i = Math.max(0, Math.min(1, t.winEffectsEnvelope)), r = Math.max(0, t.now - t.winFlashStartedAt), n = r % G / G, o = 1 + Math.sin(n * Math.PI * 2) * k * i,
|
|
794
|
+
const e = this.webglRenderer;
|
|
795
|
+
if (!e || this.winningCells.length === 0 || t.phase !== "winFlash" && t.phase !== "preSpin") return;
|
|
796
|
+
const i = Math.max(0, Math.min(1, t.winEffectsEnvelope)), r = Math.max(0, t.now - t.winFlashStartedAt), n = r % G / G, o = 1 + Math.sin(n * Math.PI * 2) * k * i, h = Math.max(1, this.cellW * u.WIN_BORDER_INSET_RATIO), l = Math.max(1, this.cellW * 0.03), c = this.runtime.phase === "winFlash" && this.runtime.shouldHighlightCurrentSpin && this.runtime.hasStartedFirstSpin;
|
|
751
797
|
for (const a of this.winningCells) {
|
|
752
|
-
const d = this.boardX + a.col * this.cellW,
|
|
798
|
+
const d = this.boardX + a.col * this.cellW, f = this.boardY + a.row * this.cellH + this.getRowCompactOffset(a.row), g = this.grid[a.col][a.row], S = u.WIN_BORDER_ALPHA * i, p = this.particleColorMode === "rainbow" ? u.hslToRgb01(
|
|
753
799
|
(r * 0.2 + a.col * 36 + a.row * 22) % 360,
|
|
754
800
|
0.96,
|
|
755
801
|
0.64
|
|
@@ -757,90 +803,90 @@ class u {
|
|
|
757
803
|
this.particleColorRgb[0] / 255,
|
|
758
804
|
this.particleColorRgb[1] / 255,
|
|
759
805
|
this.particleColorRgb[2] / 255
|
|
760
|
-
],
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
|
|
806
|
+
], A = this.cellW * o, w = this.cellH * o, M = (this.cellW - A) * 0.5, B = (this.cellH - w) * 0.5;
|
|
807
|
+
e.drawSprite(g, d + M, f + B, A, w, 1);
|
|
808
|
+
const O = d + h, E = f + h, _ = this.cellW - h * 2, P = this.cellH - h * 2;
|
|
809
|
+
_ <= l * 2 || P <= l * 2 || (e.drawSolidRect(O, E, _, l, [
|
|
764
810
|
p[0],
|
|
765
811
|
p[1],
|
|
766
812
|
p[2],
|
|
767
813
|
S
|
|
768
|
-
]),
|
|
814
|
+
]), e.drawSolidRect(O, E + P - l, _, l, [
|
|
769
815
|
p[0],
|
|
770
816
|
p[1],
|
|
771
817
|
p[2],
|
|
772
818
|
S
|
|
773
|
-
]),
|
|
819
|
+
]), e.drawSolidRect(O, E, l, P, [
|
|
774
820
|
p[0],
|
|
775
821
|
p[1],
|
|
776
822
|
p[2],
|
|
777
823
|
S
|
|
778
|
-
]),
|
|
824
|
+
]), e.drawSolidRect(O + _ - l, E, l, P, [
|
|
779
825
|
p[0],
|
|
780
826
|
p[1],
|
|
781
827
|
p[2],
|
|
782
828
|
S
|
|
783
829
|
]), c && this.drawCellParticleBurst({
|
|
784
|
-
renderer:
|
|
830
|
+
renderer: e,
|
|
785
831
|
cell: a,
|
|
786
832
|
centerX: d + this.cellW * 0.5,
|
|
787
|
-
centerY:
|
|
833
|
+
centerY: f + this.cellH * 0.5,
|
|
788
834
|
elapsed: r,
|
|
789
835
|
envelope: i
|
|
790
836
|
}));
|
|
791
837
|
}
|
|
792
838
|
}
|
|
793
839
|
drawCellParticleBurst(t) {
|
|
794
|
-
const
|
|
840
|
+
const e = Math.min(this.cellW, this.cellH) * u.PARTICLE_MAX_DISTANCE, i = Math.min(this.cellW, this.cellH) * u.PARTICLE_BASE_RADIUS, r = u.getParticleSeeds(t.cell.col, t.cell.row), n = [
|
|
795
841
|
this.particleColorRgb[0] / 255,
|
|
796
842
|
this.particleColorRgb[1] / 255,
|
|
797
843
|
this.particleColorRgb[2] / 255
|
|
798
844
|
];
|
|
799
845
|
t.renderer.beginAdditiveBlend();
|
|
800
846
|
for (let o = 0; o < this.particlesPerCell; o += 1) {
|
|
801
|
-
const
|
|
847
|
+
const h = r[o], l = h.phaseOffset * L, c = t.elapsed - l;
|
|
802
848
|
if (c < 0) continue;
|
|
803
|
-
const a = c %
|
|
849
|
+
const a = c % L / L, d = h.seedA * Math.PI * 2, f = e * a * (0.35 + h.seedB * 0.65), g = t.centerX + Math.cos(d) * f, S = t.centerY + Math.sin(d) * f, p = 0.7 + 0.9 * Math.max(0, Math.sin((t.elapsed * 0.012 + h.twinkleSeed * 2) * Math.PI * 2)), A = Math.max(1, i * (0.55 + h.seedC * 0.6) * (1 - a * 0.5)), w = Math.max(
|
|
804
850
|
0,
|
|
805
851
|
Math.min(1, (0.9 + p * 0.2) * u.PARTICLE_GLOBAL_ALPHA * t.envelope)
|
|
806
852
|
);
|
|
807
|
-
if (
|
|
808
|
-
const
|
|
853
|
+
if (w <= 0) continue;
|
|
854
|
+
const M = this.particleColorMode === "rainbow" ? u.getRainbowParticleColor(
|
|
809
855
|
t.elapsed,
|
|
810
856
|
t.cell.col,
|
|
811
857
|
t.cell.row,
|
|
812
|
-
|
|
858
|
+
h.seedA
|
|
813
859
|
) : n;
|
|
814
|
-
t.renderer.drawSoftCircle(
|
|
860
|
+
t.renderer.drawSoftCircle(g, S, A, [M[0], M[1], M[2], w]);
|
|
815
861
|
}
|
|
816
862
|
t.renderer.endAdditiveBlend();
|
|
817
863
|
}
|
|
818
|
-
static hslToRgb01(t,
|
|
819
|
-
const r = (t % 360 + 360) % 360, n = Math.max(0, Math.min(1,
|
|
820
|
-
let a = 0, d = 0,
|
|
821
|
-
|
|
822
|
-
const
|
|
823
|
-
return [a +
|
|
864
|
+
static hslToRgb01(t, e, i) {
|
|
865
|
+
const r = (t % 360 + 360) % 360, n = Math.max(0, Math.min(1, e)), o = Math.max(0, Math.min(1, i)), h = (1 - Math.abs(2 * o - 1)) * n, l = r / 60, c = h * (1 - Math.abs(l % 2 - 1));
|
|
866
|
+
let a = 0, d = 0, f = 0;
|
|
867
|
+
l >= 0 && l < 1 ? (a = h, d = c) : l < 2 ? (a = c, d = h) : l < 3 ? (d = h, f = c) : l < 4 ? (d = c, f = h) : l < 5 ? (a = c, f = h) : (a = h, f = c);
|
|
868
|
+
const g = o - h * 0.5;
|
|
869
|
+
return [a + g, d + g, f + g];
|
|
824
870
|
}
|
|
825
|
-
static getRainbowParticleColor(t,
|
|
826
|
-
const n = (r * 360 + t * 0.24 +
|
|
827
|
-
return u.hslToRgb01(
|
|
871
|
+
static getRainbowParticleColor(t, e, i, r) {
|
|
872
|
+
const n = (r * 360 + t * 0.24 + e * 38 + i * 22) % 360, o = 360 / u.RAINBOW_HUE_BUCKETS, h = Math.floor(n / o) * o;
|
|
873
|
+
return u.hslToRgb01(h, 0.98, 0.64);
|
|
828
874
|
}
|
|
829
|
-
static hash01(t,
|
|
830
|
-
const n = Math.sin(t * 127.1 +
|
|
875
|
+
static hash01(t, e, i, r) {
|
|
876
|
+
const n = Math.sin(t * 127.1 + e * 311.7 + i * 74.7 + r * 19.3) * 43758.5453;
|
|
831
877
|
return n - Math.floor(n);
|
|
832
878
|
}
|
|
833
|
-
static getParticleSeeds(t,
|
|
834
|
-
const i = `${t},${
|
|
879
|
+
static getParticleSeeds(t, e) {
|
|
880
|
+
const i = `${t},${e}`, r = u.particleSeedsCache.get(i);
|
|
835
881
|
if (r) return r;
|
|
836
882
|
const n = [];
|
|
837
883
|
for (let o = 0; o < D; o += 1)
|
|
838
884
|
n.push({
|
|
839
|
-
seedA: u.hash01(t,
|
|
840
|
-
seedB: u.hash01(t,
|
|
841
|
-
seedC: u.hash01(t,
|
|
842
|
-
phaseOffset: u.hash01(t,
|
|
843
|
-
twinkleSeed: u.hash01(t,
|
|
885
|
+
seedA: u.hash01(t, e, o, 1),
|
|
886
|
+
seedB: u.hash01(t, e, o, 2),
|
|
887
|
+
seedC: u.hash01(t, e, o, 3),
|
|
888
|
+
phaseOffset: u.hash01(t, e, o, 4),
|
|
889
|
+
twinkleSeed: u.hash01(t, e, o, 5)
|
|
844
890
|
});
|
|
845
891
|
return u.particleSeedsCache.set(i, n), n;
|
|
846
892
|
}
|
|
@@ -849,8 +895,8 @@ class u {
|
|
|
849
895
|
}
|
|
850
896
|
setWinningCells(t) {
|
|
851
897
|
this.winningCells = t, this.winningCellKeys.clear();
|
|
852
|
-
for (const
|
|
853
|
-
this.winningCellKeys.add(`${
|
|
898
|
+
for (const e of t)
|
|
899
|
+
this.winningCellKeys.add(`${e.col}:${e.row}`);
|
|
854
900
|
}
|
|
855
901
|
resize = () => {
|
|
856
902
|
const t = this.container.getBoundingClientRect(), i = typeof window.matchMedia == "function" && window.matchMedia("(pointer: coarse)").matches || navigator.maxTouchPoints > 0 ? 1.5 : 2, r = Math.max(1, Math.min(window.devicePixelRatio || 1, i)), n = Math.max(300, Math.floor(t.width * r));
|
|
@@ -873,7 +919,7 @@ class u {
|
|
|
873
919
|
this.simulationLastNow = t, this.update(t);
|
|
874
920
|
return;
|
|
875
921
|
}
|
|
876
|
-
const
|
|
922
|
+
const e = Math.max(
|
|
877
923
|
0,
|
|
878
924
|
Math.min(t - this.simulationLastNow, u.MAX_FRAME_DELTA_MS)
|
|
879
925
|
);
|
|
@@ -881,7 +927,7 @@ class u {
|
|
|
881
927
|
this.outroInterpolationAlpha = 1;
|
|
882
928
|
return;
|
|
883
929
|
}
|
|
884
|
-
this.snapshotOutroState(), this.simulationAccumulatorMs +=
|
|
930
|
+
this.snapshotOutroState(), this.simulationAccumulatorMs += e;
|
|
885
931
|
const i = this.motionProfile.fixedStepMs;
|
|
886
932
|
let r = 0;
|
|
887
933
|
for (; this.simulationAccumulatorMs >= i && r < this.motionProfile.maxCatchUpStepsPerFrame && this.runtime.phase === "outro"; )
|
|
@@ -895,26 +941,26 @@ class u {
|
|
|
895
941
|
snapshotOutroState() {
|
|
896
942
|
this.copyOffsets(this.scriptedOutgoingOffsetsPrev, this.scriptedOutgoingOffsets), this.copyOffsets(this.scriptedIncomingOffsetsPrev, this.scriptedIncomingOffsets), this.copyOffsets(this.scriptedIncomingAlphaPrev, this.scriptedIncomingAlpha), this.copyVisibility(this.scriptedIncomingVisibilityPrev, this.scriptedIncomingVisibility);
|
|
897
943
|
}
|
|
898
|
-
copyOffsets(t,
|
|
944
|
+
copyOffsets(t, e) {
|
|
899
945
|
for (let i = 0; i < 3; i += 1)
|
|
900
946
|
for (let r = 0; r < 3; r += 1)
|
|
901
|
-
t[i][r] =
|
|
947
|
+
t[i][r] = e[i][r];
|
|
902
948
|
}
|
|
903
|
-
copyVisibility(t,
|
|
949
|
+
copyVisibility(t, e) {
|
|
904
950
|
for (let i = 0; i < 3; i += 1)
|
|
905
951
|
for (let r = 0; r < 3; r += 1)
|
|
906
|
-
t[i][r] =
|
|
952
|
+
t[i][r] = e[i][r];
|
|
907
953
|
}
|
|
908
|
-
resetOutroBuffers(t,
|
|
909
|
-
R(this.scriptedOutgoingOffsets, 0), R(this.scriptedIncomingOffsets, 0), R(this.scriptedOutgoingOffsetsPrev, 0), R(this.scriptedIncomingOffsetsPrev, 0), R(this.scriptedIncomingAlpha, t), R(this.scriptedIncomingAlphaPrev, t), this.fillVisibilityGrid(this.scriptedIncomingVisibility,
|
|
954
|
+
resetOutroBuffers(t, e) {
|
|
955
|
+
R(this.scriptedOutgoingOffsets, 0), R(this.scriptedIncomingOffsets, 0), R(this.scriptedOutgoingOffsetsPrev, 0), R(this.scriptedIncomingOffsetsPrev, 0), R(this.scriptedIncomingAlpha, t), R(this.scriptedIncomingAlphaPrev, t), this.fillVisibilityGrid(this.scriptedIncomingVisibility, e), this.fillVisibilityGrid(this.scriptedIncomingVisibilityPrev, e);
|
|
910
956
|
}
|
|
911
957
|
static createVisibilityGrid(t) {
|
|
912
958
|
return Array.from({ length: 3 }, () => Array.from({ length: 3 }, () => t));
|
|
913
959
|
}
|
|
914
|
-
fillVisibilityGrid(t,
|
|
960
|
+
fillVisibilityGrid(t, e) {
|
|
915
961
|
for (let i = 0; i < 3; i += 1)
|
|
916
962
|
for (let r = 0; r < 3; r += 1)
|
|
917
|
-
t[i][r] =
|
|
963
|
+
t[i][r] = e;
|
|
918
964
|
}
|
|
919
965
|
startLoop() {
|
|
920
966
|
this.rafLoop.isRunning() || this.rafLoop.start((t) => (this.advanceSimulation(t), this.render(t), this.shouldKeepAnimating()));
|