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.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(R,M){typeof exports=="object"&&typeof module<"u"?M(exports):typeof define=="function"&&define.amd?define(["exports"],M):(R=typeof globalThis<"u"?globalThis:R||self,M(R.CascadingReel={}))})(this,(function(R){"use strict";const Y=[.04,0,-.04],I={normal:{columnStaggerMs:76,fallMs:800,outroOverlapMs:88,outroRowGapMs:14,rowBaseSpacingRatio:.05,incomingAlphaRampMs:34,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:6,pixelSnapY:"none"},cinematic:{columnStaggerMs:170,fallMs:2200,outroOverlapMs:300,outroRowGapMs:28,rowBaseSpacingRatio:.05,incomingAlphaRampMs:90,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:6,pixelSnapY:"none"},turbo:{columnStaggerMs:120,fallMs:1200,outroOverlapMs:180,outroRowGapMs:20,rowBaseSpacingRatio:.04,incomingAlphaRampMs:50,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:4,pixelSnapY:"half"}},V="normal";function X(e){return I[e]}I.normal.outroRowGapMs,I.normal.rowBaseSpacingRatio;const k=5e3,F=1800,z=.1,T=720,H=34,$=[255,235,110];I.normal.columnStaggerMs,I.normal.fallMs,I.normal.outroOverlapMs;const K=200;function _(e,t,s){return e<t?t:e>s?s:e}function Q(e){return Math.floor(Math.random()*e)}function O(e,t){return(e%t+t)%t}function x(e){return _(Math.round(e),0,255)}function y(e){const t=[];for(let s=0;s<3;s+=1){const i=[];for(let r=0;r<3;r+=1)i.push(Q(e));t.push(i)}return t}function U(e){const t=new Map;for(let n=0;n<3;n+=1)for(let o=0;o<3;o+=1){const l=e[n][o];t.set(l,(t.get(l)??0)+1)}let s=e[0][0],i=-1;for(const[n,o]of t.entries())o>i&&(i=o,s=n);const r=[];for(let n=0;n<3;n+=1)for(let o=0;o<3;o+=1)e[n][o]===s&&r.push({col:n,row:o});return r}function p(){return Array.from({length:3},()=>Array.from({length:3},()=>0))}function A(e,t){for(let s=0;s<3;s+=1)for(let i=0;i<3;i+=1)e[s][i]=t}class j{rafId=null;step=null;start(t){this.rafId===null&&(this.step=t,this.rafId=requestAnimationFrame(this.tick))}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.step=null}isRunning(){return this.rafId!==null}tick=t=>{if(!this.step){this.stop();return}if(this.step(t)===!1){this.stop();return}this.rafId!==null&&(this.rafId=requestAnimationFrame(this.tick))}}function Z(e){const t=_(e,0,1);return t*t*t*(t*(t*6-15)+10)}function N(e,t){if(e.endMs<=e.startMs)return{value:e.to,t:1,done:!0};const s=_((t-e.startMs)/(e.endMs-e.startMs),0,1),i=Z(s);return{value:e.from+(e.to-e.from)*i,t:s,done:s>=1}}function J(e,t,s,i){const r=[0,0,0];let n=0;for(let o=2;o>=0;o-=1){if(e[o]===0){r[o]=0;continue}r[o]=n;const l=Math.floor(t*i);n+=l+s}return r}function W(e){const s=e.height-e.boardY+e.cellH+2,i=[s,s,s];return{columnStaggerMs:e.motionProfile.columnStaggerMs,fallMs:e.motionProfile.fallMs,incomingAlphaRampMs:e.motionProfile.incomingAlphaRampMs,outgoingDistance:s,incomingFromOffsets:[-e.cellH,-e.cellH*2,-e.cellH*3],rowStartDelays:J(i,e.motionProfile.fallMs,e.motionProfile.outroRowGapMs,e.motionProfile.rowBaseSpacingRatio),incomingStartShift:Math.max(0,e.motionProfile.fallMs-e.motionProfile.outroOverlapMs)}}function B(e){let t=!0,s=!0;for(let i=0;i<e.scriptedOutgoingOffsets.length;i+=1){const r=e.elapsedMs-i*e.motionPlan.columnStaggerMs;for(let n=0;n<3;n+=1){const o=r-e.motionPlan.rowStartDelays[n];if(o<=0){e.scriptedOutgoingOffsets[i][n]=0,e.scriptedIncomingOffsets[i][n]=e.motionPlan.incomingFromOffsets[n],e.scriptedIncomingAlpha[i][n]=0,e.scriptedIncomingVisibility[i][n]="hidden",t=!1,s=!1;continue}const l=N({startMs:0,endMs:e.motionPlan.fallMs,from:0,to:e.motionPlan.outgoingDistance},o);e.scriptedOutgoingOffsets[i][n]=l.value,e.scriptedIncomingVisibility[i][n]=l.done?"entering":"exiting",l.done||(t=!1);const h=o-e.motionPlan.incomingStartShift;if(h<=0){e.scriptedIncomingOffsets[i][n]=e.motionPlan.incomingFromOffsets[n],e.scriptedIncomingAlpha[i][n]=0,e.scriptedIncomingVisibility[i][n]="hidden",s=!1;continue}const c=N({startMs:0,endMs:e.motionPlan.fallMs,from:e.motionPlan.incomingFromOffsets[n],to:0},h);e.scriptedIncomingOffsets[i][n]=c.value,e.scriptedIncomingAlpha[i][n]=_(h/Math.max(1,e.motionPlan.incomingAlphaRampMs),0,1),e.scriptedIncomingVisibility[i][n]=c.done?"active":"entering",c.done||(s=!1)}}return{allOutgoingDone:t,allIncomingDone:s}}function tt(e){return e?[x(e[0]),x(e[1]),x(e[2])]:$}function it(e){return e==="rainbow"?"rainbow":"solid"}function G(e){if(e.length!==3)throw new Error("rows must contain 3 rows");for(let t=0;t<3;t+=1)if(!Array.isArray(e[t])||e[t].length!==3)throw new Error(`rows[${t}] must contain 3 columns`);return[[e[0][0],e[1][0],e[2][0]],[e[0][1],e[1][1],e[2][1]],[e[0][2],e[1][2],e[2][2]]]}function D(e,t){if(e.length!==3)throw new Error("stopGrid must contain 3 columns");const s=[];for(let i=0;i<3;i+=1){const r=e[i];if(!Array.isArray(r)||r.length!==3)throw new Error(`stopGrid[${i}] must contain 3 rows`);s[i]=[O(r[0],t),O(r[1],t),O(r[2],t)]}return s}function et(e,t){return D(G(e),t)}function st(e){return{stopGrid:e.stopGrid?.map(t=>[...t]),stopRows:e.stopRows?.map(t=>[...t]),finaleSequence:e.finaleSequence?.map(t=>t.map(s=>[...s])),finaleSequenceRows:e.finaleSequenceRows?.map(t=>t.map(s=>[...s])),highlightWin:e.highlightWin,callback:e.callback}}class nt{queue;constructor(t){this.queue=(t??[]).map(s=>st(s))}hasPending(){return this.queue.length>0}consume(){return this.queue.length===0?null:this.queue.shift()??null}}function rt(){return{isSpinning:!1,hasStartedFirstSpin:!1,queueFinished:!1,shouldHighlightCurrentSpin:!1,activeSpinState:null,phase:"idle",winFlashStartedAt:0,outroStartedAt:0,idleStartedAt:0,preSpinStartedAt:0,winEffectsEnvelope:1}}function ot(e,t){e.hasStartedFirstSpin=!0,e.isSpinning=!0,e.phase="outro",e.outroStartedAt=t.startedAt,e.activeSpinState=t.activeSpinState,e.shouldHighlightCurrentSpin=t.shouldHighlightCurrentSpin}function lt(e,t,s){e.phase="idle",e.idleStartedAt=s,e.isSpinning=!1,e.shouldHighlightCurrentSpin=!1,e.queueFinished=!t,e.activeSpinState=null}function q(e,t){e.winFlashStartedAt=t,e.phase="winFlash"}function ht(e){e.isSpinning=!1,e.queueFinished=!0}const at=`
1
+ (function(R,O){typeof exports=="object"&&typeof module<"u"?O(exports):typeof define=="function"&&define.amd?define(["exports"],O):(R=typeof globalThis<"u"?globalThis:R||self,O(R.CascadingReel={}))})(this,(function(R){"use strict";const Y=[.04,0,-.04],I={normal:{columnStaggerMs:76,fallMs:800,outroOverlapMs:88,outroRowGapMs:14,rowBaseSpacingRatio:.05,incomingAlphaRampMs:34,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:6,pixelSnapY:"none"},cinematic:{columnStaggerMs:170,fallMs:2200,outroOverlapMs:300,outroRowGapMs:28,rowBaseSpacingRatio:.05,incomingAlphaRampMs:90,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:6,pixelSnapY:"none"},turbo:{columnStaggerMs:120,fallMs:1200,outroOverlapMs:180,outroRowGapMs:20,rowBaseSpacingRatio:.04,incomingAlphaRampMs:50,fixedStepMs:1e3/120,maxCatchUpStepsPerFrame:4,pixelSnapY:"half"}},V="normal";function X(s){return I[s]}I.normal.outroRowGapMs,I.normal.rowBaseSpacingRatio;const k=5e3,F=1800,z=.1,x=720,y=34,$=[255,235,110];I.normal.columnStaggerMs,I.normal.fallMs,I.normal.outroOverlapMs;const K=200;function E(s,t,e){return s<t?t:s>e?e:s}function Q(s){return Math.floor(Math.random()*s)}function _(s,t){return(s%t+t)%t}function W(s){return E(Math.round(s),0,255)}function H(s){const t=[];for(let e=0;e<3;e+=1){const i=[];for(let r=0;r<3;r+=1)i.push(Q(s));t.push(i)}return t}function U(s){const t=new Map;for(let n=0;n<3;n+=1)for(let o=0;o<3;o+=1){const h=s[n][o];t.set(h,(t.get(h)??0)+1)}let e=s[0][0],i=-1;for(const[n,o]of t.entries())o>i&&(i=o,e=n);const r=[];for(let n=0;n<3;n+=1)for(let o=0;o<3;o+=1)s[n][o]===e&&r.push({col:n,row:o});return r}function g(){return Array.from({length:3},()=>Array.from({length:3},()=>0))}function w(s,t){for(let e=0;e<3;e+=1)for(let i=0;i<3;i+=1)s[e][i]=t}class j{rafId=null;step=null;start(t){this.rafId===null&&(this.step=t,this.rafId=requestAnimationFrame(this.tick))}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.step=null}isRunning(){return this.rafId!==null}tick=t=>{if(!this.step){this.stop();return}if(this.step(t)===!1){this.stop();return}this.rafId!==null&&(this.rafId=requestAnimationFrame(this.tick))}}function Z(s){const t=E(s,0,1);return t*t*t*(t*(t*6-15)+10)}function N(s,t){if(s.endMs<=s.startMs)return{value:s.to,t:1,done:!0};const e=E((t-s.startMs)/(s.endMs-s.startMs),0,1),i=Z(e);return{value:s.from+(s.to-s.from)*i,t:e,done:e>=1}}function J(s,t,e,i){const r=[0,0,0];let n=0;for(let o=2;o>=0;o-=1){if(s[o]===0){r[o]=0;continue}r[o]=n;const h=Math.floor(t*i);n+=h+e}return r}function T(s){const e=s.height-s.boardY+s.cellH+2,i=[e,e,e];return{columnStaggerMs:s.motionProfile.columnStaggerMs,fallMs:s.motionProfile.fallMs,incomingAlphaRampMs:s.motionProfile.incomingAlphaRampMs,outgoingDistance:e,incomingFromOffsets:[-s.cellH,-s.cellH*2,-s.cellH*3],rowStartDelays:J(i,s.motionProfile.fallMs,s.motionProfile.outroRowGapMs,s.motionProfile.rowBaseSpacingRatio),incomingStartShift:Math.max(0,s.motionProfile.fallMs-s.motionProfile.outroOverlapMs)}}function B(s){let t=!0,e=!0;for(let i=0;i<s.scriptedOutgoingOffsets.length;i+=1){const r=s.elapsedMs-i*s.motionPlan.columnStaggerMs;for(let n=0;n<3;n+=1){const o=r-s.motionPlan.rowStartDelays[n];if(o<=0){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;continue}const h=N({startMs:0,endMs:s.motionPlan.fallMs,from:0,to:s.motionPlan.outgoingDistance},o);s.scriptedOutgoingOffsets[i][n]=h.value,s.scriptedIncomingVisibility[i][n]=h.done?"entering":"exiting",h.done||(t=!1);const l=o-s.motionPlan.incomingStartShift;if(l<=0){s.scriptedIncomingOffsets[i][n]=s.motionPlan.incomingFromOffsets[n],s.scriptedIncomingAlpha[i][n]=0,s.scriptedIncomingVisibility[i][n]="hidden",e=!1;continue}const c=N({startMs:0,endMs:s.motionPlan.fallMs,from:s.motionPlan.incomingFromOffsets[n],to:0},l);s.scriptedIncomingOffsets[i][n]=c.value,s.scriptedIncomingAlpha[i][n]=E(l/Math.max(1,s.motionPlan.incomingAlphaRampMs),0,1),s.scriptedIncomingVisibility[i][n]=c.done?"active":"entering",c.done||(e=!1)}}return{allOutgoingDone:t,allIncomingDone:e}}function tt(s){return s?[W(s[0]),W(s[1]),W(s[2])]:$}function it(s){return s==="rainbow"?"rainbow":"solid"}function G(s){if(s.length!==3)throw new Error("rows must contain 3 rows");for(let t=0;t<3;t+=1)if(!Array.isArray(s[t])||s[t].length!==3)throw new Error(`rows[${t}] must contain 3 columns`);return[[s[0][0],s[1][0],s[2][0]],[s[0][1],s[1][1],s[2][1]],[s[0][2],s[1][2],s[2][2]]]}function D(s,t){if(s.length!==3)throw new Error("stopGrid must contain 3 columns");const e=[];for(let i=0;i<3;i+=1){const r=s[i];if(!Array.isArray(r)||r.length!==3)throw new Error(`stopGrid[${i}] must contain 3 rows`);e[i]=[_(r[0],t),_(r[1],t),_(r[2],t)]}return e}function et(s,t){return D(G(s),t)}function st(s){return{stopGrid:s.stopGrid?.map(t=>[...t]),stopRows:s.stopRows?.map(t=>[...t]),finaleSequence:s.finaleSequence?.map(t=>t.map(e=>[...e])),finaleSequenceRows:s.finaleSequenceRows?.map(t=>t.map(e=>[...e])),highlightWin:s.highlightWin,callback:s.callback}}class nt{queue;constructor(t){this.queue=(t??[]).map(e=>st(e))}hasPending(){return this.queue.length>0}consume(){return this.queue.length===0?null:this.queue.shift()??null}}function rt(){return{isSpinning:!1,hasStartedFirstSpin:!1,queueFinished:!1,shouldHighlightCurrentSpin:!1,activeSpinState:null,phase:"idle",winFlashStartedAt:0,outroStartedAt:0,idleStartedAt:0,preSpinStartedAt:0,winEffectsEnvelope:1}}function ot(s,t){s.hasStartedFirstSpin=!0,s.isSpinning=!0,s.phase="outro",s.outroStartedAt=t.startedAt,s.activeSpinState=t.activeSpinState,s.shouldHighlightCurrentSpin=t.shouldHighlightCurrentSpin}function ht(s,t,e){s.phase="idle",s.idleStartedAt=e,s.isSpinning=!1,s.shouldHighlightCurrentSpin=!1,s.queueFinished=!t,s.activeSpinState=null}function q(s,t){s.winFlashStartedAt=t,s.phase="winFlash"}function lt(s){s.isSpinning=!1,s.queueFinished=!0}const at=`
2
2
  attribute vec2 a_pos;
3
3
  uniform vec2 u_resolution;
4
4
  uniform vec4 u_destRect;
@@ -50,5 +50,6 @@ void main() {
50
50
  gl_FragColor = u_color;
51
51
  }
52
52
  }
53
- `;class ut{canvas;spriteImage;spriteElementsCount;gl;program;uniforms;quadBuffer;texture;viewportW=1;viewportH=1;spriteWidth;spriteHeight;spriteSegmentHeight;constructor(t){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;const s=this.canvas.getContext("webgl2",{alpha:!0,antialias:!1})??this.canvas.getContext("webgl",{alpha:!0,antialias:!1});if(!s)throw new Error("WebGL context is not available");this.gl=s;const i=this.createShader(this.gl.VERTEX_SHADER,at),r=this.createShader(this.gl.FRAGMENT_SHADER,ct);this.program=this.createProgram(i,r),this.gl.deleteShader(i),this.gl.deleteShader(r);const n=this.gl.createBuffer();if(!n)throw new Error("Failed to create WebGL quad buffer");this.quadBuffer=n,this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.quadBuffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),this.gl.STATIC_DRAW);const o=this.gl.createTexture();if(!o)throw new Error("Failed to create WebGL texture");this.texture=o,this.gl.bindTexture(this.gl.TEXTURE_2D,this.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,0),this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,1),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.spriteImage),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);const l=this.gl.getAttribLocation(this.program,"a_pos");this.gl.enableVertexAttribArray(l),this.gl.vertexAttribPointer(l,2,this.gl.FLOAT,!1,8,0),this.uniforms={resolution:this.gl.getUniformLocation(this.program,"u_resolution"),destRect:this.gl.getUniformLocation(this.program,"u_destRect"),srcRect:this.gl.getUniformLocation(this.program,"u_srcRect"),color:this.gl.getUniformLocation(this.program,"u_color"),useTexture:this.gl.getUniformLocation(this.program,"u_useTexture"),shapeMode:this.gl.getUniformLocation(this.program,"u_shapeMode"),texture:this.gl.getUniformLocation(this.program,"u_texture")},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)}resize(t,s){this.viewportW=Math.max(1,Math.floor(t)),this.viewportH=Math.max(1,Math.floor(s)),this.gl.viewport(0,0,this.viewportW,this.viewportH)}beginFrame(){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)}drawSprite(t,s,i,r,n,o=1){const h=O(t,this.spriteElementsCount)*this.spriteSegmentHeight,c=h+this.spriteSegmentHeight,a=.5,d=a/this.spriteWidth,f=1-a/this.spriteWidth,m=1-(c-a)/this.spriteHeight,S=1-(h+a)/this.spriteHeight;this.gl.uniform4f(this.uniforms.destRect,s,i,r,n),this.gl.uniform4f(this.uniforms.srcRect,d,m,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)}drawSolidRect(t,s,i,r,n){this.gl.uniform4f(this.uniforms.destRect,t,s,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)}drawSoftCircle(t,s,i,r){const n=i*2;this.gl.uniform4f(this.uniforms.destRect,t-i,s-i,n,n),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)}beginAdditiveBlend(){this.gl.blendFunc(this.gl.SRC_ALPHA,this.gl.ONE)}endAdditiveBlend(){this.gl.blendFunc(this.gl.ONE,this.gl.ONE_MINUS_SRC_ALPHA)}dispose(){this.gl.deleteTexture(this.texture),this.gl.deleteBuffer(this.quadBuffer),this.gl.deleteProgram(this.program)}createShader(t,s){const i=this.gl.createShader(t);if(!i)throw new Error("Failed to create WebGL shader");if(this.gl.shaderSource(i,s),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS)){const r=this.gl.getShaderInfoLog(i)??"unknown error";throw this.gl.deleteShader(i),new Error(`WebGL shader compile failed: ${r}`)}return i}createProgram(t,s){const i=this.gl.createProgram();if(!i)throw new Error("Failed to create WebGL program");if(this.gl.attachShader(i,t),this.gl.attachShader(i,s),this.gl.linkProgram(i),!this.gl.getProgramParameter(i,this.gl.LINK_STATUS)){const r=this.gl.getProgramInfoLog(i)??"unknown error";throw this.gl.deleteProgram(i),new Error(`WebGL program link failed: ${r}`)}return i}}class u{static RAINBOW_HUE_BUCKETS=24;static PARTICLE_GLOBAL_ALPHA=.9;static PARTICLE_MAX_DISTANCE=.72;static PARTICLE_BASE_RADIUS=.028;canvas;container;button;spinQueueController;spriteUrl;spriteElementsCount;highlightInitialWinningCells;particleColorRgb;particleColorMode;motionProfile;pixelSnapY;spriteImage=null;webglRenderer=null;rafLoop=new j;runtime=rt();width=0;height=0;cellW=0;cellH=0;boardX=0;boardY=0;scriptedCascadeQueue=[];scriptedOutgoingGrid=null;scriptedPendingGrid=null;scriptedOutroStartedAt=0;scriptedOutroElapsedMs=0;outroMotionPlan=null;scriptedOutgoingOffsets=p();scriptedOutgoingOffsetsPrev=p();scriptedIncomingOffsets=p();scriptedIncomingOffsetsPrev=p();scriptedIncomingAlpha=p();scriptedIncomingAlphaPrev=p();scriptedIncomingVisibility=u.createVisibilityGrid("hidden");scriptedIncomingVisibilityPrev=u.createVisibilityGrid("hidden");winningCells=[];winningCellKeys=new Set;grid;particlesPerCell=H;lastRafTime=0;initialHighlightRequestedAt=0;simulationLastNow=0;simulationAccumulatorMs=0;outroInterpolationAlpha=1;isOutroPipelineWarmedUp=!1;isGpuPipelineWarmedUp=!1;static PRE_SPIN_MS=150;static WIN_EFFECTS_ENVELOPE_TAU_MS=120;static MAX_FRAME_DELTA_MS=250;static WIN_BORDER_ALPHA=.72;static WIN_BORDER_INSET_RATIO=.06;static particleSeedsCache=new Map;constructor(t){this.canvas=t.canvas,this.container=t.container,this.button=t.button,this.spriteUrl=t.sprite,this.spriteElementsCount=Math.max(1,t.spriteElementsCount??6),this.highlightInitialWinningCells=t.highlightInitialWinningCells!==!1,this.spinQueueController=new nt(t.queuedSpinStates),this.particleColorRgb=tt(t.particleColorRgb),this.particleColorMode=it(t.particleColorMode),this.motionProfile=X(t.motionProfile??V),this.pixelSnapY=t.pixelSnapY??this.motionProfile.pixelSnapY,this.grid=t.initialSegments?et(t.initialSegments,this.spriteElementsCount):y(this.spriteElementsCount)}async init(){if(this.bindEvents(),this.resize(),await this.loadSpriteIfProvided(),!this.spriteImage)throw new Error("sprite is required for WebGL renderer");this.webglRenderer=new ut({canvas:this.canvas,spriteImage:this.spriteImage,spriteElementsCount:this.spriteElementsCount}),this.webglRenderer.resize(this.width,this.height),this.warmUpOutroPipeline(),this.warmUpGpuPipeline(),this.applyInitialHighlightIfNeeded(),requestAnimationFrame(t=>{this.render(t),this.startLoop()})}destroy(){this.unbindEvents(),this.rafLoop.stop(),this.simulationLastNow=0,this.simulationAccumulatorMs=0,ht(this.runtime),this.webglRenderer?.dispose(),this.webglRenderer=null,this.clearWinningCells()}spin(){if(this.runtime.isSpinning||this.runtime.queueFinished)return;if(!this.spinQueueController.hasPending()){this.runtime.queueFinished=!0,this.button&&(this.button.disabled=!0);return}const t=this.spinQueueController.consume(),s=t?.highlightWin===!0;this.runtime.isSpinning=!0,this.runtime.phase="preSpin",this.runtime.preSpinStartedAt=performance.now(),this.runtime.activeSpinState=t,this.runtime.shouldHighlightCurrentSpin=s,this.runtime.hasStartedFirstSpin=!0,this.simulationLastNow=0,this.simulationAccumulatorMs=0,this.button&&(this.button.disabled=!0),this.startLoop()}bindEvents(){window.addEventListener("resize",this.resize),this.button?.addEventListener("click",this.onSpinClick)}unbindEvents(){window.removeEventListener("resize",this.resize),this.button?.removeEventListener("click",this.onSpinClick)}onSpinClick=()=>{if(this.runtime.phase==="winFlash"&&(this.runtime.shouldHighlightCurrentSpin||!this.runtime.hasStartedFirstSpin)){this.finishSpinWithUi(!0),this.spinQueueController.hasPending()&&this.spin();return}this.runtime.isSpinning||this.spin()};getNextGrid(t){return t?D(t,this.spriteElementsCount):y(this.spriteElementsCount)}update(t){if(this.runtime.isSpinning){if(this.runtime.phase==="preSpin"){if(t-this.runtime.preSpinStartedAt<u.PRE_SPIN_MS)return;ot(this.runtime,{activeSpinState:this.runtime.activeSpinState,shouldHighlightCurrentSpin:this.runtime.shouldHighlightCurrentSpin,startedAt:t}),this.runtime.preSpinStartedAt=0;const s=this.runtime.activeSpinState?.finaleSequenceRows?this.runtime.activeSpinState.finaleSequenceRows.map(n=>G(n)):this.runtime.activeSpinState?.finaleSequence??[];this.scriptedCascadeQueue=s.map(n=>n.map(o=>[...o])),this.clearWinningCells();const i=this.runtime.activeSpinState?.stopRows?G(this.runtime.activeSpinState.stopRows):this.runtime.activeSpinState?.stopGrid,r=this.getNextGrid(i);this.startOutroTransition(r,t)}if(this.runtime.phase!=="outro"&&this.runtime.phase==="winFlash"){!this.runtime.shouldHighlightCurrentSpin&&t-this.runtime.winFlashStartedAt>=k&&this.finishSpinWithUi();return}}}stepScriptedOutro(t){if(!this.scriptedOutgoingGrid||!this.scriptedPendingGrid){this.finishSpinWithUi();return}this.outroMotionPlan||(this.outroMotionPlan=W({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile})),this.scriptedOutroElapsedMs+=t;const{allOutgoingDone:s,allIncomingDone:i}=B({elapsedMs:this.scriptedOutroElapsedMs,scriptedOutgoingOffsets:this.scriptedOutgoingOffsets,scriptedIncomingOffsets:this.scriptedIncomingOffsets,scriptedIncomingAlpha:this.scriptedIncomingAlpha,scriptedIncomingVisibility:this.scriptedIncomingVisibility,motionPlan:this.outroMotionPlan});if(!(!s||!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))){if(!this.runtime.shouldHighlightCurrentSpin){this.finishSpinWithUi();return}this.setWinningCells(U(this.grid)),q(this.runtime,this.scriptedOutroStartedAt+this.scriptedOutroElapsedMs),this.runtime.activeSpinState?.callback?.(),this.button&&this.runtime.shouldHighlightCurrentSpin&&this.spinQueueController.hasPending()&&(this.button.disabled=!1)}}tryStartScriptedCascade(t){if(this.scriptedCascadeQueue.length===0)return!1;const s=this.scriptedCascadeQueue.shift();return s?(this.startOutroTransition(D(s,this.spriteElementsCount),t),!0):!1}startOutroTransition(t,s){this.scriptedOutgoingGrid=this.grid.map(i=>[...i]),this.scriptedPendingGrid=t.map(i=>[...i]),this.outroMotionPlan=W({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile}),this.resetOutroBuffers(0,"hidden"),this.clearWinningCells(),this.runtime.phase="outro",this.scriptedOutroStartedAt=s,this.scriptedOutroElapsedMs=0,this.outroInterpolationAlpha=1}finishSpinWithUi(t=!1){const s=this.runtime.activeSpinState,i=t?void 0:s?.callback,r=this.spinQueueController.hasPending();lt(this.runtime,r,performance.now()),this.button&&(this.button.disabled=this.runtime.queueFinished),i?.()}applyInitialHighlightIfNeeded(){this.highlightInitialWinningCells&&(this.setWinningCells(U(this.grid)),this.initialHighlightRequestedAt=performance.now())}warmUpOutroPipeline(){if(this.isOutroPipelineWarmedUp)return;const t=W({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile}),s=p(),i=p(),r=p(),n=u.createVisibilityGrid("hidden"),o=Math.max(...t.rowStartDelays),l=2*t.columnStaggerMs,h=[0,this.motionProfile.fixedStepMs,t.incomingStartShift+this.motionProfile.fixedStepMs,t.fallMs+o+l+this.motionProfile.fixedStepMs];for(const c of h)B({elapsedMs:c,scriptedOutgoingOffsets:s,scriptedIncomingOffsets:i,scriptedIncomingAlpha:r,scriptedIncomingVisibility:n,motionPlan:t});this.isOutroPipelineWarmedUp=!0}warmUpGpuPipeline(){if(this.isGpuPipelineWarmedUp)return;const t=this.webglRenderer;if(!t)return;const s=Math.max(8,this.cellW*.2),i=Math.max(8,this.cellH*.2),r=this.boardX+2,n=this.boardY+2;t.beginFrame(),t.drawSprite(0,r,n,s,i,1),t.drawSolidRect(r+s+2,n,s,i,[1,1,1,.35]),t.beginAdditiveBlend(),t.drawSoftCircle(r+s*.5,n+i*.5,Math.max(2,s*.25),[1,.9,.4,.4]),t.endAdditiveBlend(),this.isGpuPipelineWarmedUp=!0}render(t){if(!this.webglRenderer)return;this.initialHighlightRequestedAt>0&&t-this.initialHighlightRequestedAt>=K&&(q(this.runtime,this.initialHighlightRequestedAt),this.runtime.winEffectsEnvelope=1,this.initialHighlightRequestedAt=0,this.button&&(this.button.disabled=!1));const s=this.runtime.phase==="preSpin"?0:this.runtime.phase==="winFlash"?1:0;if(this.lastRafTime>0){const l=Math.min(t-this.lastRafTime,50),h=1-Math.exp(-l/u.WIN_EFFECTS_ENVELOPE_TAU_MS);this.runtime.winEffectsEnvelope+=(s-this.runtime.winEffectsEnvelope)*h}this.lastRafTime=t,this.webglRenderer.beginFrame();const i=this.runtime.phase==="winFlash"||this.runtime.phase==="preSpin"||this.initialHighlightRequestedAt>0&&this.winningCells.length>0;this.runtime.phase==="outro"&&this.scriptedOutgoingGrid&&this.scriptedPendingGrid?(this.drawGridInterpolated(this.scriptedOutgoingGrid,this.scriptedOutgoingOffsetsPrev,this.scriptedOutgoingOffsets,this.outroInterpolationAlpha,i),this.drawGridInterpolated(this.scriptedPendingGrid,this.scriptedIncomingOffsetsPrev,this.scriptedIncomingOffsets,this.outroInterpolationAlpha,i,this.scriptedIncomingAlphaPrev,this.scriptedIncomingAlpha,this.scriptedIncomingVisibility)):this.drawGrid(this.grid,null,i);const r=this.initialHighlightRequestedAt>0?"winFlash":this.runtime.phase,n=this.initialHighlightRequestedAt>0?this.initialHighlightRequestedAt:this.runtime.winFlashStartedAt,o=this.initialHighlightRequestedAt>0?1:this.runtime.winEffectsEnvelope;this.drawWinningEffects({now:t,phase:r,winFlashStartedAt:n,winEffectsEnvelope:o})}isWinningCell=(t,s)=>this.winningCellKeys.has(`${t}:${s}`);getRowCompactOffset(t){return(Y[t]??0)*this.cellH}applyPixelSnapY(t){return this.pixelSnapY==="integer"?Math.round(t):this.pixelSnapY==="half"?Math.round(t*2)/2:t}drawGrid(t,s,i){this.drawGridWithSampler({grid:t,skipWinningCells:i,sampleOffsetY:(r,n)=>s?s[r][n]:0,sampleAlpha:()=>1,isVisible:()=>!0})}drawGridInterpolated(t,s,i,r,n,o,l,h){this.drawGridWithSampler({grid:t,skipWinningCells:n,sampleOffsetY:(c,a)=>s[c][a]+(i[c][a]-s[c][a])*r,sampleAlpha:(c,a)=>o&&l?o[c][a]+(l[c][a]-o[c][a])*r:1,isVisible:(c,a)=>!h||h[c][a]!=="hidden"})}drawGridWithSampler(t){const s=this.webglRenderer;if(s)for(let i=0;i<3;i+=1){const r=this.boardX+i*this.cellW;for(let n=0;n<3;n+=1){if(t.skipWinningCells&&this.isWinningCell(i,n)||!t.isVisible(i,n))continue;const o=t.sampleOffsetY(i,n),l=this.applyPixelSnapY(this.boardY+n*this.cellH+o+this.getRowCompactOffset(n));if(l>this.height||l+this.cellH<0)continue;const h=t.sampleAlpha(i,n);h<=0||s.drawSprite(t.grid[i][n],r,l,this.cellW,this.cellH,h)}}}drawWinningEffects(t){const s=this.webglRenderer;if(!s||this.winningCells.length===0||t.phase!=="winFlash"&&t.phase!=="preSpin")return;const i=Math.max(0,Math.min(1,t.winEffectsEnvelope)),r=Math.max(0,t.now-t.winFlashStartedAt),n=r%F/F,o=1+Math.sin(n*Math.PI*2)*z*i,l=Math.max(1,this.cellW*u.WIN_BORDER_INSET_RATIO),h=Math.max(1,this.cellW*.03),c=this.runtime.phase==="winFlash"&&this.runtime.shouldHighlightCurrentSpin&&this.runtime.hasStartedFirstSpin;for(const a of this.winningCells){const d=this.boardX+a.col*this.cellW,f=this.boardY+a.row*this.cellH+this.getRowCompactOffset(a.row),m=this.grid[a.col][a.row],S=u.WIN_BORDER_ALPHA*i,g=this.particleColorMode==="rainbow"?u.hslToRgb01((r*.2+a.col*36+a.row*22)%360,.96,.64):[this.particleColorRgb[0]/255,this.particleColorRgb[1]/255,this.particleColorRgb[2]/255],P=this.cellW*o,w=this.cellH*o,E=(this.cellW-P)*.5,dt=(this.cellH-w)*.5;s.drawSprite(m,d+E,f+dt,P,w,1);const C=d+l,b=f+l,v=this.cellW-l*2,L=this.cellH-l*2;v<=h*2||L<=h*2||(s.drawSolidRect(C,b,v,h,[g[0],g[1],g[2],S]),s.drawSolidRect(C,b+L-h,v,h,[g[0],g[1],g[2],S]),s.drawSolidRect(C,b,h,L,[g[0],g[1],g[2],S]),s.drawSolidRect(C+v-h,b,h,L,[g[0],g[1],g[2],S]),c&&this.drawCellParticleBurst({renderer:s,cell:a,centerX:d+this.cellW*.5,centerY:f+this.cellH*.5,elapsed:r,envelope:i}))}}drawCellParticleBurst(t){const s=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=[this.particleColorRgb[0]/255,this.particleColorRgb[1]/255,this.particleColorRgb[2]/255];t.renderer.beginAdditiveBlend();for(let o=0;o<this.particlesPerCell;o+=1){const l=r[o],h=l.phaseOffset*T,c=t.elapsed-h;if(c<0)continue;const a=c%T/T,d=l.seedA*Math.PI*2,f=s*a*(.35+l.seedB*.65),m=t.centerX+Math.cos(d)*f,S=t.centerY+Math.sin(d)*f,g=.7+.9*Math.max(0,Math.sin((t.elapsed*.012+l.twinkleSeed*2)*Math.PI*2)),P=Math.max(1,i*(.55+l.seedC*.6)*(1-a*.5)),w=Math.max(0,Math.min(1,(.9+g*.2)*u.PARTICLE_GLOBAL_ALPHA*t.envelope));if(w<=0)continue;const E=this.particleColorMode==="rainbow"?u.getRainbowParticleColor(t.elapsed,t.cell.col,t.cell.row,l.seedA):n;t.renderer.drawSoftCircle(m,S,P,[E[0],E[1],E[2],w])}t.renderer.endAdditiveBlend()}static hslToRgb01(t,s,i){const r=(t%360+360)%360,n=Math.max(0,Math.min(1,s)),o=Math.max(0,Math.min(1,i)),l=(1-Math.abs(2*o-1))*n,h=r/60,c=l*(1-Math.abs(h%2-1));let a=0,d=0,f=0;h>=0&&h<1?(a=l,d=c):h<2?(a=c,d=l):h<3?(d=l,f=c):h<4?(d=c,f=l):h<5?(a=c,f=l):(a=l,f=c);const m=o-l*.5;return[a+m,d+m,f+m]}static getRainbowParticleColor(t,s,i,r){const n=(r*360+t*.24+s*38+i*22)%360,o=360/u.RAINBOW_HUE_BUCKETS,l=Math.floor(n/o)*o;return u.hslToRgb01(l,.98,.64)}static hash01(t,s,i,r){const n=Math.sin(t*127.1+s*311.7+i*74.7+r*19.3)*43758.5453;return n-Math.floor(n)}static getParticleSeeds(t,s){const i=`${t},${s}`,r=u.particleSeedsCache.get(i);if(r)return r;const n=[];for(let o=0;o<H;o+=1)n.push({seedA:u.hash01(t,s,o,1),seedB:u.hash01(t,s,o,2),seedC:u.hash01(t,s,o,3),phaseOffset:u.hash01(t,s,o,4),twinkleSeed:u.hash01(t,s,o,5)});return u.particleSeedsCache.set(i,n),n}clearWinningCells(){this.winningCells=[],this.winningCellKeys.clear()}setWinningCells(t){this.winningCells=t,this.winningCellKeys.clear();for(const s of t)this.winningCellKeys.add(`${s.col}:${s.row}`)}resize=()=>{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));this.width=n,this.height=n;const o=Math.floor(Math.min(this.width/3,this.height/3));this.cellW=o,this.cellH=o,this.boardX=Math.floor((this.width-this.cellW*3)/2),this.boardY=Math.floor((this.height-this.cellH*3)/2),this.canvas.width=this.width,this.canvas.height=this.height,this.webglRenderer?.resize(this.width,this.height)};async loadSpriteIfProvided(){if(!this.spriteUrl)return;const t=new Image;t.decoding="async",t.src=this.spriteUrl;try{await t.decode(),this.spriteImage=t}catch{this.spriteImage=null}}advanceSimulation(t){if(this.simulationLastNow<=0){this.simulationLastNow=t,this.update(t);return}const s=Math.max(0,Math.min(t-this.simulationLastNow,u.MAX_FRAME_DELTA_MS));if(this.simulationLastNow=t,this.update(t),this.runtime.phase!=="outro"){this.outroInterpolationAlpha=1;return}this.snapshotOutroState(),this.simulationAccumulatorMs+=s;const i=this.motionProfile.fixedStepMs;let r=0;for(;this.simulationAccumulatorMs>=i&&r<this.motionProfile.maxCatchUpStepsPerFrame&&this.runtime.phase==="outro";)this.stepScriptedOutro(i),this.simulationAccumulatorMs-=i,r+=1;if(this.runtime.phase!=="outro"){this.outroInterpolationAlpha=1;return}this.outroInterpolationAlpha=Math.max(0,Math.min(1,this.simulationAccumulatorMs/i))}snapshotOutroState(){this.copyOffsets(this.scriptedOutgoingOffsetsPrev,this.scriptedOutgoingOffsets),this.copyOffsets(this.scriptedIncomingOffsetsPrev,this.scriptedIncomingOffsets),this.copyOffsets(this.scriptedIncomingAlphaPrev,this.scriptedIncomingAlpha),this.copyVisibility(this.scriptedIncomingVisibilityPrev,this.scriptedIncomingVisibility)}copyOffsets(t,s){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=s[i][r]}copyVisibility(t,s){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=s[i][r]}resetOutroBuffers(t,s){A(this.scriptedOutgoingOffsets,0),A(this.scriptedIncomingOffsets,0),A(this.scriptedOutgoingOffsetsPrev,0),A(this.scriptedIncomingOffsetsPrev,0),A(this.scriptedIncomingAlpha,t),A(this.scriptedIncomingAlphaPrev,t),this.fillVisibilityGrid(this.scriptedIncomingVisibility,s),this.fillVisibilityGrid(this.scriptedIncomingVisibilityPrev,s)}static createVisibilityGrid(t){return Array.from({length:3},()=>Array.from({length:3},()=>t))}fillVisibilityGrid(t,s){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=s}startLoop(){this.rafLoop.isRunning()||this.rafLoop.start(t=>(this.advanceSimulation(t),this.render(t),this.shouldKeepAnimating()))}shouldKeepAnimating(){return this.runtime.isSpinning||this.initialHighlightRequestedAt>0?!0:this.runtime.winEffectsEnvelope>.001}}R.CascadingReel=u,Object.defineProperty(R,Symbol.toStringTag,{value:"Module"})}));
53
+ `;class ut{canvas;spriteImage;spriteElementsCount;gl;program;uniforms;quadBuffer;texture;viewportW=1;viewportH=1;spriteWidth;spriteHeight;spriteSegmentHeight;constructor(t){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;const e=this.canvas.getContext("webgl2",{alpha:!0,antialias:!1})??this.canvas.getContext("webgl",{alpha:!0,antialias:!1});if(!e)throw new Error("WebGL context is not available");this.gl=e;const i=this.createShader(this.gl.VERTEX_SHADER,at),r=this.createShader(this.gl.FRAGMENT_SHADER,ct);this.program=this.createProgram(i,r),this.gl.deleteShader(i),this.gl.deleteShader(r);const n=this.gl.createBuffer();if(!n)throw new Error("Failed to create WebGL quad buffer");this.quadBuffer=n,this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.quadBuffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),this.gl.STATIC_DRAW);const o=this.gl.createTexture();if(!o)throw new Error("Failed to create WebGL texture");this.texture=o,this.gl.bindTexture(this.gl.TEXTURE_2D,this.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,0),this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,1),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.spriteImage),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);const h=this.gl.getAttribLocation(this.program,"a_pos");this.gl.enableVertexAttribArray(h),this.gl.vertexAttribPointer(h,2,this.gl.FLOAT,!1,8,0),this.uniforms={resolution:this.gl.getUniformLocation(this.program,"u_resolution"),destRect:this.gl.getUniformLocation(this.program,"u_destRect"),srcRect:this.gl.getUniformLocation(this.program,"u_srcRect"),color:this.gl.getUniformLocation(this.program,"u_color"),useTexture:this.gl.getUniformLocation(this.program,"u_useTexture"),shapeMode:this.gl.getUniformLocation(this.program,"u_shapeMode"),texture:this.gl.getUniformLocation(this.program,"u_texture")},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)}resize(t,e){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)}beginFrame(){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)}drawSprite(t,e,i,r,n,o=1){const l=_(t,this.spriteElementsCount)*this.spriteSegmentHeight,c=l+this.spriteSegmentHeight,a=.5,d=a/this.spriteWidth,f=1-a/this.spriteWidth,m=1-(c-a)/this.spriteHeight,S=1-(l+a)/this.spriteHeight;this.gl.uniform4f(this.uniforms.destRect,e,i,r,n),this.gl.uniform4f(this.uniforms.srcRect,d,m,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)}drawSolidRect(t,e,i,r,n){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)}drawSoftCircle(t,e,i,r){const n=i*2;this.gl.uniform4f(this.uniforms.destRect,t-i,e-i,n,n),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)}beginAdditiveBlend(){this.gl.blendFunc(this.gl.SRC_ALPHA,this.gl.ONE)}endAdditiveBlend(){this.gl.blendFunc(this.gl.ONE,this.gl.ONE_MINUS_SRC_ALPHA)}dispose(){this.gl.deleteTexture(this.texture),this.gl.deleteBuffer(this.quadBuffer),this.gl.deleteProgram(this.program)}createShader(t,e){const i=this.gl.createShader(t);if(!i)throw new Error("Failed to create WebGL shader");if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS)){const r=this.gl.getShaderInfoLog(i)??"unknown error";throw this.gl.deleteShader(i),new Error(`WebGL shader compile failed: ${r}`)}return i}createProgram(t,e){const i=this.gl.createProgram();if(!i)throw new Error("Failed to create WebGL program");if(this.gl.attachShader(i,t),this.gl.attachShader(i,e),this.gl.linkProgram(i),!this.gl.getProgramParameter(i,this.gl.LINK_STATUS)){const r=this.gl.getProgramInfoLog(i)??"unknown error";throw this.gl.deleteProgram(i),new Error(`WebGL program link failed: ${r}`)}return i}}class u{static RAINBOW_HUE_BUCKETS=24;static PARTICLE_GLOBAL_ALPHA=.9;static PARTICLE_MAX_DISTANCE=.72;static PARTICLE_BASE_RADIUS=.028;canvas;container;button;spinQueueController;spriteUrl;spriteElementsCount;highlightInitialWinningCells;particleColorRgb;particleColorMode;motionProfile;pixelSnapY;debugPerf;spriteImage=null;webglRenderer=null;rafLoop=new j;runtime=rt();width=0;height=0;cellW=0;cellH=0;boardX=0;boardY=0;scriptedCascadeQueue=[];scriptedOutgoingGrid=null;scriptedPendingGrid=null;scriptedOutroStartedAt=0;scriptedOutroElapsedMs=0;outroMotionPlan=null;scriptedOutgoingOffsets=g();scriptedOutgoingOffsetsPrev=g();scriptedIncomingOffsets=g();scriptedIncomingOffsetsPrev=g();scriptedIncomingAlpha=g();scriptedIncomingAlphaPrev=g();scriptedIncomingVisibility=u.createVisibilityGrid("hidden");scriptedIncomingVisibilityPrev=u.createVisibilityGrid("hidden");winningCells=[];winningCellKeys=new Set;grid;particlesPerCell=y;lastRafTime=0;initialHighlightRequestedAt=0;simulationLastNow=0;simulationAccumulatorMs=0;outroInterpolationAlpha=1;isOutroPipelineWarmedUp=!1;isGpuPipelineWarmedUp=!1;perfWindowStartedAt=0;perfFrameCount=0;perfDtSum=0;perfOver20MsCount=0;perfDtSamples=[];perfLogLines=[];static PERF_WINDOW_MS=1500;static PERF_LOG_LIMIT=60;static PRE_SPIN_MS=150;static WIN_EFFECTS_ENVELOPE_TAU_MS=120;static MAX_FRAME_DELTA_MS=250;static WIN_BORDER_ALPHA=.72;static WIN_BORDER_INSET_RATIO=.06;static particleSeedsCache=new Map;constructor(t){this.canvas=t.canvas,this.container=t.container,this.button=t.button,this.spriteUrl=t.sprite,this.spriteElementsCount=Math.max(1,t.spriteElementsCount??6),this.highlightInitialWinningCells=t.highlightInitialWinningCells!==!1,this.spinQueueController=new nt(t.queuedSpinStates),this.particleColorRgb=tt(t.particleColorRgb),this.particleColorMode=it(t.particleColorMode),this.motionProfile=X(t.motionProfile??V),this.pixelSnapY=t.pixelSnapY??this.motionProfile.pixelSnapY,this.debugPerf=t.debugPerf===!0,this.grid=t.initialSegments?et(t.initialSegments,this.spriteElementsCount):H(this.spriteElementsCount)}async init(){if(this.bindEvents(),this.resize(),await this.loadSpriteIfProvided(),!this.spriteImage)throw new Error("sprite is required for WebGL renderer");this.webglRenderer=new ut({canvas:this.canvas,spriteImage:this.spriteImage,spriteElementsCount:this.spriteElementsCount}),this.webglRenderer.resize(this.width,this.height),this.warmUpOutroPipeline(),this.warmUpGpuPipeline(),this.applyInitialHighlightIfNeeded(),requestAnimationFrame(t=>{this.render(t),this.startLoop()})}destroy(){this.unbindEvents(),this.rafLoop.stop(),this.simulationLastNow=0,this.simulationAccumulatorMs=0,lt(this.runtime),this.webglRenderer?.dispose(),this.webglRenderer=null,this.clearWinningCells()}getPerfLogs(){return[...this.perfLogLines]}clearPerfLogs(){this.perfLogLines.length=0}async copyPerfLogsToClipboard(){if(this.perfLogLines.length===0)return!1;const t=this.perfLogLines.join(`
54
+ `),e=navigator.clipboard;if(e&&typeof e.writeText=="function")return await e.writeText(t),!0;const i=document.createElement("textarea");i.value=t,i.setAttribute("readonly",""),i.style.position="fixed",i.style.left="-9999px",document.body.appendChild(i),i.select();const r=document.execCommand("copy");return document.body.removeChild(i),r}spin(){if(this.runtime.isSpinning||this.runtime.queueFinished)return;if(!this.spinQueueController.hasPending()){this.runtime.queueFinished=!0,this.button&&(this.button.disabled=!0);return}const t=this.spinQueueController.consume(),e=t?.highlightWin===!0;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()}bindEvents(){window.addEventListener("resize",this.resize),this.button?.addEventListener("click",this.onSpinClick)}unbindEvents(){window.removeEventListener("resize",this.resize),this.button?.removeEventListener("click",this.onSpinClick)}onSpinClick=()=>{if(this.runtime.phase==="winFlash"&&(this.runtime.shouldHighlightCurrentSpin||!this.runtime.hasStartedFirstSpin)){this.finishSpinWithUi(!0),this.spinQueueController.hasPending()&&this.spin();return}this.runtime.isSpinning||this.spin()};getNextGrid(t){return t?D(t,this.spriteElementsCount):H(this.spriteElementsCount)}update(t){if(this.runtime.isSpinning){if(this.runtime.phase==="preSpin"){if(t-this.runtime.preSpinStartedAt<u.PRE_SPIN_MS)return;ot(this.runtime,{activeSpinState:this.runtime.activeSpinState,shouldHighlightCurrentSpin:this.runtime.shouldHighlightCurrentSpin,startedAt:t}),this.runtime.preSpinStartedAt=0;const e=this.runtime.activeSpinState?.finaleSequenceRows?this.runtime.activeSpinState.finaleSequenceRows.map(n=>G(n)):this.runtime.activeSpinState?.finaleSequence??[];this.scriptedCascadeQueue=e.map(n=>n.map(o=>[...o])),this.clearWinningCells();const i=this.runtime.activeSpinState?.stopRows?G(this.runtime.activeSpinState.stopRows):this.runtime.activeSpinState?.stopGrid,r=this.getNextGrid(i);this.startOutroTransition(r,t)}if(this.runtime.phase!=="outro"&&this.runtime.phase==="winFlash"){!this.runtime.shouldHighlightCurrentSpin&&t-this.runtime.winFlashStartedAt>=k&&this.finishSpinWithUi();return}}}stepScriptedOutro(t){if(!this.scriptedOutgoingGrid||!this.scriptedPendingGrid){this.finishSpinWithUi();return}this.outroMotionPlan||(this.outroMotionPlan=T({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile})),this.scriptedOutroElapsedMs+=t;const{allOutgoingDone:e,allIncomingDone:i}=B({elapsedMs:this.scriptedOutroElapsedMs,scriptedOutgoingOffsets:this.scriptedOutgoingOffsets,scriptedIncomingOffsets:this.scriptedIncomingOffsets,scriptedIncomingAlpha:this.scriptedIncomingAlpha,scriptedIncomingVisibility:this.scriptedIncomingVisibility,motionPlan:this.outroMotionPlan});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))){if(!this.runtime.shouldHighlightCurrentSpin){this.finishSpinWithUi();return}this.setWinningCells(U(this.grid)),q(this.runtime,this.scriptedOutroStartedAt+this.scriptedOutroElapsedMs),this.runtime.activeSpinState?.callback?.(),this.button&&this.runtime.shouldHighlightCurrentSpin&&this.spinQueueController.hasPending()&&(this.button.disabled=!1)}}tryStartScriptedCascade(t){if(this.scriptedCascadeQueue.length===0)return!1;const e=this.scriptedCascadeQueue.shift();return e?(this.startOutroTransition(D(e,this.spriteElementsCount),t),!0):!1}startOutroTransition(t,e){this.scriptedOutgoingGrid=this.grid.map(i=>[...i]),this.scriptedPendingGrid=t.map(i=>[...i]),this.outroMotionPlan=T({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile}),this.resetOutroBuffers(0,"hidden"),this.clearWinningCells(),this.runtime.phase="outro",this.scriptedOutroStartedAt=e,this.scriptedOutroElapsedMs=0,this.outroInterpolationAlpha=1}finishSpinWithUi(t=!1){const e=this.runtime.activeSpinState,i=t?void 0:e?.callback,r=this.spinQueueController.hasPending();ht(this.runtime,r,performance.now()),this.button&&(this.button.disabled=this.runtime.queueFinished),i?.()}applyInitialHighlightIfNeeded(){this.highlightInitialWinningCells&&(this.setWinningCells(U(this.grid)),this.initialHighlightRequestedAt=performance.now())}warmUpOutroPipeline(){if(this.isOutroPipelineWarmedUp)return;const t=T({height:this.height,boardY:this.boardY,cellH:this.cellH,motionProfile:this.motionProfile}),e=g(),i=g(),r=g(),n=u.createVisibilityGrid("hidden"),o=Math.max(...t.rowStartDelays),h=2*t.columnStaggerMs,l=[0,this.motionProfile.fixedStepMs,t.incomingStartShift+this.motionProfile.fixedStepMs,t.fallMs+o+h+this.motionProfile.fixedStepMs];for(const c of l)B({elapsedMs:c,scriptedOutgoingOffsets:e,scriptedIncomingOffsets:i,scriptedIncomingAlpha:r,scriptedIncomingVisibility:n,motionPlan:t});this.isOutroPipelineWarmedUp=!0}warmUpGpuPipeline(){if(this.isGpuPipelineWarmedUp)return;const t=this.webglRenderer;if(!t)return;const e=Math.max(8,this.cellW*.2),i=Math.max(8,this.cellH*.2),r=this.boardX+2,n=this.boardY+2;t.beginFrame(),t.drawSprite(0,r,n,e,i,1),t.drawSolidRect(r+e+2,n,e,i,[1,1,1,.35]),t.beginAdditiveBlend(),t.drawSoftCircle(r+e*.5,n+i*.5,Math.max(2,e*.25),[1,.9,.4,.4]),t.endAdditiveBlend(),this.isGpuPipelineWarmedUp=!0}trackOutroPerf(t,e){if(this.debugPerf){if(this.runtime.phase!=="outro"){this.resetPerfWindow();return}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)}}resetPerfWindow(){this.perfWindowStartedAt=0,this.perfFrameCount=0,this.perfDtSum=0,this.perfOver20MsCount=0,this.perfDtSamples.length=0}flushPerfWindow(){if(this.perfFrameCount===0)return;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*.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}`;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}render(t){if(!this.webglRenderer)return;this.initialHighlightRequestedAt>0&&t-this.initialHighlightRequestedAt>=K&&(q(this.runtime,this.initialHighlightRequestedAt),this.runtime.winEffectsEnvelope=1,this.initialHighlightRequestedAt=0,this.button&&(this.button.disabled=!1));const e=this.runtime.phase==="preSpin"?0:this.runtime.phase==="winFlash"?1:0;if(this.lastRafTime>0){const h=Math.min(t-this.lastRafTime,50);this.trackOutroPerf(h,t);const l=1-Math.exp(-h/u.WIN_EFFECTS_ENVELOPE_TAU_MS);this.runtime.winEffectsEnvelope+=(e-this.runtime.winEffectsEnvelope)*l}else this.resetPerfWindow();this.lastRafTime=t,this.webglRenderer.beginFrame();const i=this.runtime.phase==="winFlash"||this.runtime.phase==="preSpin"||this.initialHighlightRequestedAt>0&&this.winningCells.length>0;this.runtime.phase==="outro"&&this.scriptedOutgoingGrid&&this.scriptedPendingGrid?(this.drawGridInterpolated(this.scriptedOutgoingGrid,this.scriptedOutgoingOffsetsPrev,this.scriptedOutgoingOffsets,this.outroInterpolationAlpha,i),this.drawGridInterpolated(this.scriptedPendingGrid,this.scriptedIncomingOffsetsPrev,this.scriptedIncomingOffsets,this.outroInterpolationAlpha,i,this.scriptedIncomingAlphaPrev,this.scriptedIncomingAlpha,this.scriptedIncomingVisibility)):this.drawGrid(this.grid,null,i);const r=this.initialHighlightRequestedAt>0?"winFlash":this.runtime.phase,n=this.initialHighlightRequestedAt>0?this.initialHighlightRequestedAt:this.runtime.winFlashStartedAt,o=this.initialHighlightRequestedAt>0?1:this.runtime.winEffectsEnvelope;this.drawWinningEffects({now:t,phase:r,winFlashStartedAt:n,winEffectsEnvelope:o})}isWinningCell=(t,e)=>this.winningCellKeys.has(`${t}:${e}`);getRowCompactOffset(t){return(Y[t]??0)*this.cellH}applyPixelSnapY(t){return this.pixelSnapY==="integer"?Math.round(t):this.pixelSnapY==="half"?Math.round(t*2)/2:t}drawGrid(t,e,i){this.drawGridWithSampler({grid:t,skipWinningCells:i,sampleOffsetY:(r,n)=>e?e[r][n]:0,sampleAlpha:()=>1,isVisible:()=>!0})}drawGridInterpolated(t,e,i,r,n,o,h,l){this.drawGridWithSampler({grid:t,skipWinningCells:n,sampleOffsetY:(c,a)=>e[c][a]+(i[c][a]-e[c][a])*r,sampleAlpha:(c,a)=>o&&h?o[c][a]+(h[c][a]-o[c][a])*r:1,isVisible:(c,a)=>!l||l[c][a]!=="hidden"})}drawGridWithSampler(t){const e=this.webglRenderer;if(e)for(let i=0;i<3;i+=1){const r=this.boardX+i*this.cellW;for(let n=0;n<3;n+=1){if(t.skipWinningCells&&this.isWinningCell(i,n)||!t.isVisible(i,n))continue;const o=t.sampleOffsetY(i,n),h=this.applyPixelSnapY(this.boardY+n*this.cellH+o+this.getRowCompactOffset(n));if(h>this.height||h+this.cellH<0)continue;const l=t.sampleAlpha(i,n);l<=0||e.drawSprite(t.grid[i][n],r,h,this.cellW,this.cellH,l)}}}drawWinningEffects(t){const e=this.webglRenderer;if(!e||this.winningCells.length===0||t.phase!=="winFlash"&&t.phase!=="preSpin")return;const i=Math.max(0,Math.min(1,t.winEffectsEnvelope)),r=Math.max(0,t.now-t.winFlashStartedAt),n=r%F/F,o=1+Math.sin(n*Math.PI*2)*z*i,h=Math.max(1,this.cellW*u.WIN_BORDER_INSET_RATIO),l=Math.max(1,this.cellW*.03),c=this.runtime.phase==="winFlash"&&this.runtime.shouldHighlightCurrentSpin&&this.runtime.hasStartedFirstSpin;for(const a of this.winningCells){const d=this.boardX+a.col*this.cellW,f=this.boardY+a.row*this.cellH+this.getRowCompactOffset(a.row),m=this.grid[a.col][a.row],S=u.WIN_BORDER_ALPHA*i,p=this.particleColorMode==="rainbow"?u.hslToRgb01((r*.2+a.col*36+a.row*22)%360,.96,.64):[this.particleColorRgb[0]/255,this.particleColorRgb[1]/255,this.particleColorRgb[2]/255],P=this.cellW*o,M=this.cellH*o,A=(this.cellW-P)*.5,dt=(this.cellH-M)*.5;e.drawSprite(m,d+A,f+dt,P,M,1);const C=d+h,b=f+h,L=this.cellW-h*2,v=this.cellH-h*2;L<=l*2||v<=l*2||(e.drawSolidRect(C,b,L,l,[p[0],p[1],p[2],S]),e.drawSolidRect(C,b+v-l,L,l,[p[0],p[1],p[2],S]),e.drawSolidRect(C,b,l,v,[p[0],p[1],p[2],S]),e.drawSolidRect(C+L-l,b,l,v,[p[0],p[1],p[2],S]),c&&this.drawCellParticleBurst({renderer:e,cell:a,centerX:d+this.cellW*.5,centerY:f+this.cellH*.5,elapsed:r,envelope:i}))}}drawCellParticleBurst(t){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=[this.particleColorRgb[0]/255,this.particleColorRgb[1]/255,this.particleColorRgb[2]/255];t.renderer.beginAdditiveBlend();for(let o=0;o<this.particlesPerCell;o+=1){const h=r[o],l=h.phaseOffset*x,c=t.elapsed-l;if(c<0)continue;const a=c%x/x,d=h.seedA*Math.PI*2,f=e*a*(.35+h.seedB*.65),m=t.centerX+Math.cos(d)*f,S=t.centerY+Math.sin(d)*f,p=.7+.9*Math.max(0,Math.sin((t.elapsed*.012+h.twinkleSeed*2)*Math.PI*2)),P=Math.max(1,i*(.55+h.seedC*.6)*(1-a*.5)),M=Math.max(0,Math.min(1,(.9+p*.2)*u.PARTICLE_GLOBAL_ALPHA*t.envelope));if(M<=0)continue;const A=this.particleColorMode==="rainbow"?u.getRainbowParticleColor(t.elapsed,t.cell.col,t.cell.row,h.seedA):n;t.renderer.drawSoftCircle(m,S,P,[A[0],A[1],A[2],M])}t.renderer.endAdditiveBlend()}static hslToRgb01(t,e,i){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));let a=0,d=0,f=0;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);const m=o-h*.5;return[a+m,d+m,f+m]}static getRainbowParticleColor(t,e,i,r){const n=(r*360+t*.24+e*38+i*22)%360,o=360/u.RAINBOW_HUE_BUCKETS,h=Math.floor(n/o)*o;return u.hslToRgb01(h,.98,.64)}static hash01(t,e,i,r){const n=Math.sin(t*127.1+e*311.7+i*74.7+r*19.3)*43758.5453;return n-Math.floor(n)}static getParticleSeeds(t,e){const i=`${t},${e}`,r=u.particleSeedsCache.get(i);if(r)return r;const n=[];for(let o=0;o<y;o+=1)n.push({seedA:u.hash01(t,e,o,1),seedB:u.hash01(t,e,o,2),seedC:u.hash01(t,e,o,3),phaseOffset:u.hash01(t,e,o,4),twinkleSeed:u.hash01(t,e,o,5)});return u.particleSeedsCache.set(i,n),n}clearWinningCells(){this.winningCells=[],this.winningCellKeys.clear()}setWinningCells(t){this.winningCells=t,this.winningCellKeys.clear();for(const e of t)this.winningCellKeys.add(`${e.col}:${e.row}`)}resize=()=>{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));this.width=n,this.height=n;const o=Math.floor(Math.min(this.width/3,this.height/3));this.cellW=o,this.cellH=o,this.boardX=Math.floor((this.width-this.cellW*3)/2),this.boardY=Math.floor((this.height-this.cellH*3)/2),this.canvas.width=this.width,this.canvas.height=this.height,this.webglRenderer?.resize(this.width,this.height)};async loadSpriteIfProvided(){if(!this.spriteUrl)return;const t=new Image;t.decoding="async",t.src=this.spriteUrl;try{await t.decode(),this.spriteImage=t}catch{this.spriteImage=null}}advanceSimulation(t){if(this.simulationLastNow<=0){this.simulationLastNow=t,this.update(t);return}const e=Math.max(0,Math.min(t-this.simulationLastNow,u.MAX_FRAME_DELTA_MS));if(this.simulationLastNow=t,this.update(t),this.runtime.phase!=="outro"){this.outroInterpolationAlpha=1;return}this.snapshotOutroState(),this.simulationAccumulatorMs+=e;const i=this.motionProfile.fixedStepMs;let r=0;for(;this.simulationAccumulatorMs>=i&&r<this.motionProfile.maxCatchUpStepsPerFrame&&this.runtime.phase==="outro";)this.stepScriptedOutro(i),this.simulationAccumulatorMs-=i,r+=1;if(this.runtime.phase!=="outro"){this.outroInterpolationAlpha=1;return}this.outroInterpolationAlpha=Math.max(0,Math.min(1,this.simulationAccumulatorMs/i))}snapshotOutroState(){this.copyOffsets(this.scriptedOutgoingOffsetsPrev,this.scriptedOutgoingOffsets),this.copyOffsets(this.scriptedIncomingOffsetsPrev,this.scriptedIncomingOffsets),this.copyOffsets(this.scriptedIncomingAlphaPrev,this.scriptedIncomingAlpha),this.copyVisibility(this.scriptedIncomingVisibilityPrev,this.scriptedIncomingVisibility)}copyOffsets(t,e){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=e[i][r]}copyVisibility(t,e){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=e[i][r]}resetOutroBuffers(t,e){w(this.scriptedOutgoingOffsets,0),w(this.scriptedIncomingOffsets,0),w(this.scriptedOutgoingOffsetsPrev,0),w(this.scriptedIncomingOffsetsPrev,0),w(this.scriptedIncomingAlpha,t),w(this.scriptedIncomingAlphaPrev,t),this.fillVisibilityGrid(this.scriptedIncomingVisibility,e),this.fillVisibilityGrid(this.scriptedIncomingVisibilityPrev,e)}static createVisibilityGrid(t){return Array.from({length:3},()=>Array.from({length:3},()=>t))}fillVisibilityGrid(t,e){for(let i=0;i<3;i+=1)for(let r=0;r<3;r+=1)t[i][r]=e}startLoop(){this.rafLoop.isRunning()||this.rafLoop.start(t=>(this.advanceSimulation(t),this.render(t),this.shouldKeepAnimating()))}shouldKeepAnimating(){return this.runtime.isSpinning||this.initialHighlightRequestedAt>0?!0:this.runtime.winEffectsEnvelope>.001}}R.CascadingReel=u,Object.defineProperty(R,Symbol.toStringTag,{value:"Module"})}));
54
55
  //# sourceMappingURL=index.umd.js.map