@diabolic/borealis 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,24 +5,15 @@ An interactive, animated canvas background with noise-based patterns and visual
5
5
  [![npm version](https://badge.fury.io/js/@diabolic%2Fborealis.svg)](https://www.npmjs.com/package/@diabolic/borealis)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- https://github.com/user-attachments/assets/897d9ca9-2ac9-4b55-adaa-158a704aa220
9
-
10
8
  > 🎎 [Live Demo](https://bugrakaan.github.io/borealis/)
11
9
 
12
10
  ## Features
13
11
 
14
- - 🌟 **Noise-based patterns** - Beautiful river-like patterns using Simplex noise with domain warping
15
- - ðŸ”ĩ **Solid dot pattern** - Clean grid of uniform dots (alternative to noise)
16
- - âœĻ **Wave effect** - Diagonal sparkling wave that sweeps across the screen
17
- - ðŸ’Ŧ **Twinkle effect** - Grouped star twinkling with customizable dead zone
18
- - 🌈 **Aurora colors** - Optional cyan-green to violet color gradient
19
- - ðŸŽŊ **Radial collapse/expand** - Smooth show/hide animations from center
20
- - 🎎 **WebM Recording** - Export animations as high-quality video (VP9 codec)
21
- - 🎭 **Alpha Mask Export** - Generate separate luma matte video for compositing
22
- - ðŸ’ū **URL State Persistence** - Share configurations via URL parameters
23
- - 📋 **Copy Code Button** - Generate initialization code from current settings
12
+ - âœĻ **Multiple effects** - Wave, twinkle, and noise-based patterns with domain warping
13
+ - 🌈 **Aurora colors** - Customizable gradient color schemes
14
+ - ðŸŽŊ **Animations** - Smooth radial collapse/expand show/hide transitions
24
15
  - ⚡ **Highly customizable** - 40+ configurable options
25
- - ðŸ“ą **Responsive** - Automatically adapts to window size
16
+ - ðŸ“ą **Responsive** - Automatically adapts to container or window size
26
17
  - ðŸŠķ **Lightweight** - No dependencies, pure JavaScript
27
18
  - ðŸ“Ķ **TypeScript support** - Full type definitions included
28
19
 
@@ -257,6 +248,11 @@ borealis.destroy();
257
248
  | Option | Type | Default | Description |
258
249
  |--------|------|---------|-------------|
259
250
  | `container` | `HTMLElement` | `document.body` | Parent element for the canvas |
251
+ | `width` | `number \| null` | `null` | Canvas width (null = auto from container/window) |
252
+ | `height` | `number \| null` | `null` | Canvas height (null = auto from container/window) |
253
+ | `fullscreen` | `boolean` | `true` | Use fixed positioning to cover viewport |
254
+ | `zIndex` | `number` | `0` | Canvas z-index |
255
+ | `initiallyHidden` | `boolean` | `false` | Start collapsed/hidden |
260
256
 
261
257
  ### Grid Options
262
258
 
@@ -50,6 +50,10 @@ declare module '@diabolic/borealis' {
50
50
  height?: number | null;
51
51
  /** If true, uses fixed positioning to cover viewport (default: true) */
52
52
  fullscreen?: boolean;
53
+ /** Canvas z-index (default: 0) */
54
+ zIndex?: number;
55
+ /** If true, starts collapsed/hidden (default: false) */
56
+ initiallyHidden?: boolean;
53
57
 
54
58
  // Grid settings
55
59
  /** Grid density (10-100) */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.1
3
+ * @version 1.0.3
4
4
  * @license MIT
5
5
  */
6
6
  /**
@@ -93,6 +93,8 @@ class Borealis {
93
93
  width: null, // Canvas width (null = auto from container/window)
94
94
  height: null, // Canvas height (null = auto from container/window)
95
95
  fullscreen: true, // If true, uses fixed positioning to cover viewport
96
+ zIndex: 0, // Canvas z-index (can be any integer)
97
+ initiallyHidden: false, // If true, starts collapsed/hidden
96
98
 
97
99
  // Grid settings
98
100
  density: 50, // Grid density (10-100)
@@ -182,6 +184,7 @@ class Borealis {
182
184
  this.canvas = document.createElement('canvas');
183
185
 
184
186
  // Set canvas styles based on mode
187
+ const zIndex = this.options.zIndex;
185
188
  if (this.options.fullscreen) {
186
189
  this.canvas.style.cssText = `
187
190
  position: fixed;
@@ -190,7 +193,7 @@ class Borealis {
190
193
  width: 100%;
191
194
  height: 100%;
192
195
  pointer-events: none;
193
- z-index: 0;
196
+ z-index: ${zIndex};
194
197
  `;
195
198
  } else {
196
199
  this.canvas.style.cssText = `
@@ -200,6 +203,7 @@ class Borealis {
200
203
  width: 100%;
201
204
  height: 100%;
202
205
  pointer-events: none;
206
+ z-index: ${zIndex};
203
207
  `;
204
208
  }
205
209
 
@@ -231,8 +235,8 @@ class Borealis {
231
235
  this._sparkleWaiting = false;
232
236
  this._sparkleWaitUntil = 0;
233
237
  this._diagPos = 0;
234
- this._isCollapsing = false;
235
- this._collapseProgress = 0;
238
+ this._isCollapsing = this.options.initiallyHidden; // Stay collapsed until manual show() call
239
+ this._collapseProgress = this.options.initiallyHidden ? 1 + this.options.collapseWaveWidth : 0; // Start fully hidden if initiallyHidden is true
236
240
  this._isRunning = false;
237
241
  this._animationId = null;
238
242
 
package/dist/borealis.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.1
3
+ * @version 1.0.3
4
4
  * @license MIT
5
5
  */
6
6
  (function (global, factory) {
@@ -99,6 +99,8 @@
99
99
  width: null, // Canvas width (null = auto from container/window)
100
100
  height: null, // Canvas height (null = auto from container/window)
101
101
  fullscreen: true, // If true, uses fixed positioning to cover viewport
102
+ zIndex: 0, // Canvas z-index (can be any integer)
103
+ initiallyHidden: false, // If true, starts collapsed/hidden
102
104
 
103
105
  // Grid settings
104
106
  density: 50, // Grid density (10-100)
@@ -188,6 +190,7 @@
188
190
  this.canvas = document.createElement('canvas');
189
191
 
190
192
  // Set canvas styles based on mode
193
+ const zIndex = this.options.zIndex;
191
194
  if (this.options.fullscreen) {
192
195
  this.canvas.style.cssText = `
193
196
  position: fixed;
@@ -196,7 +199,7 @@
196
199
  width: 100%;
197
200
  height: 100%;
198
201
  pointer-events: none;
199
- z-index: 0;
202
+ z-index: ${zIndex};
200
203
  `;
201
204
  } else {
202
205
  this.canvas.style.cssText = `
@@ -206,6 +209,7 @@
206
209
  width: 100%;
207
210
  height: 100%;
208
211
  pointer-events: none;
212
+ z-index: ${zIndex};
209
213
  `;
210
214
  }
211
215
 
@@ -237,8 +241,8 @@
237
241
  this._sparkleWaiting = false;
238
242
  this._sparkleWaitUntil = 0;
239
243
  this._diagPos = 0;
240
- this._isCollapsing = false;
241
- this._collapseProgress = 0;
244
+ this._isCollapsing = this.options.initiallyHidden; // Stay collapsed until manual show() call
245
+ this._collapseProgress = this.options.initiallyHidden ? 1 + this.options.collapseWaveWidth : 0; // Start fully hidden if initiallyHidden is true
242
246
  this._isRunning = false;
243
247
  this._animationId = null;
244
248
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.1
3
+ * @version 1.0.3
4
4
  * @license MIT
5
5
  */
6
- !function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).Borealis=i()}(this,function(){"use strict";class t{constructor(t=Math.random()){this.p=new Uint8Array(256);for(let t=0;t<256;t++)this.p[t]=t;for(let i=255;i>0;i--){const e=(t=16807*t%2147483647)%(i+1);[this.p[i],this.p[e]]=[this.p[e],this.p[i]]}this.perm=new Uint8Array(512);for(let t=0;t<512;t++)this.perm[t]=this.p[255&t]}noise2D(t,i){const e=.5*(Math.sqrt(3)-1),s=(3-Math.sqrt(3))/6,a=(t+i)*e,o=Math.floor(t+a),n=Math.floor(i+a),r=(o+n)*s,h=t-(o-r),l=i-(n-r),c=h>l?1:0,p=h>l?0:1,d=h-c+s,f=l-p+s,u=h-1+2*s,_=l-1+2*s,g=255&o,M=255&n,m=(t,i,e)=>{const s=7&t,a=s<4?i:e,o=s<4?e:i;return(1&s?-a:a)+(2&s?-2*o:2*o)};let w=0,C=0,S=0,y=.5-h*h-l*l;y>=0&&(y*=y,w=y*y*m(this.perm[g+this.perm[M]],h,l));let v=.5-d*d-f*f;v>=0&&(v*=v,C=v*v*m(this.perm[g+c+this.perm[M+p]],d,f));let z=.5-u*u-_*_;return z>=0&&(z*=z,S=z*z*m(this.perm[g+1+this.perm[M+1]],u,_)),70*(w+C+S)}}class i{static get defaultOptions(){return{container:document.body,width:null,height:null,fullscreen:!0,density:50,dotSize:5,solidPattern:!1,densityMinCell:2,densityMaxCell:8,densityMinGap:1,densityMaxGap:4,patternScale:.001,patternAurora:!1,warpScale:.5,warpAmount:20,animationSpeed:2e-5,ridgePower:2,minOpacity:0,maxOpacity:1,waveFrequency:3,waveAmplitude:.5,effect:{type:"wave",aurora:!1,deadzone:20,speed:8e-4,width:120,chance:.08,intensity:1,delayMin:1e3,delayMax:3e3,combineSparkle:!1,sparkleBaseOpacity:0,mode:"sparkle",combined:!1,baseOpacity:30,twinkleSpeed:50,size:50,density:50},auroraColor1:[0,255,128],auroraColor2:[148,0,211],colorScale:.003,collapseSpeed:.1,collapseWaveWidth:.4,autoStart:!0,onShow:null,onHide:null}}constructor(t={}){const e=i.defaultOptions.effect,s=t.effect||{};this.options={...i.defaultOptions,...t,effect:{...e,...s}},this._init()}_init(){this.canvas=document.createElement("canvas"),this.options.fullscreen?this.canvas.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 0;\n ":this.canvas.style.cssText="\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n ";const i=this.options.container;if(i===document.body&&this.options.fullscreen)document.body.insertBefore(this.canvas,document.body.firstChild);else{"static"===window.getComputedStyle(i).position&&(i.style.position="relative"),i.appendChild(this.canvas)}this.ctx=this.canvas.getContext("2d"),this.noise=new t(1e4*Math.random()),this.randomOffset=1e3*Math.random(),this._cellSize=4,this._gap=2,this._gridSize=6,this._sparkleMap={},this._animTime=0,this._twinkleTime=0,this._lastFrameTime=0,this._sparkleWaiting=!1,this._sparkleWaitUntil=0,this._diagPos=0,this._isCollapsing=!1,this._collapseProgress=0,this._isRunning=!1,this._animationId=null,this._twinkleThreshold=.8,this._twinkleSpeedValue=3,this._twinkleScaleValue=.01,this._deadzoneValue=.2,this._updateDensity(this.options.density),this._updateTwinkleSettings(),this._updateDeadzone(),this._draw=this._draw.bind(this),this._resize=this._resize.bind(this),window.addEventListener("resize",this._resize),this._resize(),this.options.autoStart&&this.start()}_updateDensity(t){const i=(100-t)/90,e=this.options.densityMinCell+i*(this.options.densityMaxCell-this.options.densityMinCell),s=.3+this.options.dotSize/10*1.7;this._cellSize=e*s,this._gap=this.options.densityMinGap+i*(this.options.densityMaxGap-this.options.densityMinGap),this._gridSize=this._cellSize+this._gap}_updateTwinkleSettings(){const t=this.options.effect;this._twinkleSpeedValue=1+(t.twinkleSpeed-10)/90*5,this._twinkleScaleValue=.5-(t.size-10)/90*.499,this._twinkleThreshold=1-t.density/100*.9}_updateDeadzone(){this._deadzoneValue=this.options.effect.deadzone/100}_generateSparkles(t,i){this._sparkleMap={};for(let e=0;e<i;e++)for(let i=0;i<t;i++)Math.random()<this.options.effect.chance&&(this._sparkleMap[`${i},${e}`]=Math.random())}_resize(){let t,i;if(null!==this.options.width&&null!==this.options.height)t=this.options.width,i=this.options.height;else if(this.options.fullscreen)t=window.innerWidth,i=window.innerHeight;else{const e=this.options.container;t=null!==this.options.width?this.options.width:e.clientWidth,i=null!==this.options.height?this.options.height:e.clientHeight}this.canvas.width=t,this.canvas.height=i;const e=Math.ceil(this.canvas.width/this._gridSize),s=Math.ceil(this.canvas.height/this._gridSize);this._generateSparkles(e,s),this._offscreenCanvas=null,this._offscreenCtx=null}_draw(t){if(!this._isRunning)return;const i=t-this._lastFrameTime;this._animTime+=i*this.options.animationSpeed,this._twinkleTime+=.001*i;const e=this.options.effect;if(this._sparkleWaiting)t>=this._sparkleWaitUntil&&(this._sparkleWaiting=!1,this._diagPos=-e.width);else{this._diagPos+=i*e.speed*100;const s=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize),o=s+a;if(this._diagPos>o+e.width){this._sparkleWaiting=!0;const i=e.delayMin+Math.random()*(e.delayMax-e.delayMin);this._sparkleWaitUntil=t+i,this._generateSparkles(s,a)}}this._lastFrameTime=t,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);const s=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===s&&this._offscreenCanvas.height===a||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=s,this._offscreenCanvas.height=a,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(s,a),e=i.data;for(let t=0;t<a;t++)for(let i=0;i<s;i++){const o=this._calculateCellData(i,t,s,a),n=4*(t*s+i);e[n]=o.r,e[n+1]=o.g,e[n+2]=o.b,e[n+3]=Math.round(255*o.opacity)}if(t.putImageData(i,0,0),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.ctx.drawImage(this._offscreenCanvas,0,0,this.canvas.width,this.canvas.height),"none"!==this.options.effect.type)for(let t=0;t<a;t++)for(let i=0;i<s;i++)this._drawEffect(i,t,s,a)}else for(let t=0;t<a;t++)for(let i=0;i<s;i++)this._drawCell(i,t,s,a);this._updateCollapse(),this._animationId=requestAnimationFrame(this._draw)}_calculateCellData(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r}=this,h=Math.sin(r*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,l=Math.cos(r*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,c=o.noise2D(t*a.patternScale*a.warpScale+h+n,i*a.patternScale*a.warpScale+r+n)*a.warpAmount,p=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+r+l+n)*a.warpAmount,d=o.noise2D((t+c)*a.patternScale+.5*l+n,(i+p)*a.patternScale+.5*h+n),f=1-Math.abs(d),u=Math.pow(f,a.ridgePower);let _,g,M,m=a.minOpacity+u*(a.maxOpacity-a.minOpacity);if(a.patternAurora){const e=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*r+.5*n)+1)/2;_=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),g=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),M=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)}else _=g=M=255;if(this._collapseProgress>0){m=this._applyCollapse(t,i,e,s,m,0).opacity}return{r:_,g:g,b:M,opacity:m}}_drawEffect(t,i,e,s){const a=this.options.effect;let o=[255,255,255],n=0;if("wave"===a.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,e,s);o=a.color,n=a.opacity}if("twinkle"===a.type){const a=this._calculateTwinkleEffect(t,i,e,s);o=a.color,n=a.opacity}if(this._collapseProgress>0){n=this._applyCollapse(t,i,e,s,0,n).effectOpacity}n>0&&(this.ctx.fillStyle=`rgba(${o[0]}, ${o[1]}, ${o[2]}, ${n})`,this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill())}_drawCell(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r,_twinkleTime:h}=this,l=Math.sin(r*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,c=Math.cos(r*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,p=o.noise2D(t*a.patternScale*a.warpScale+l+n,i*a.patternScale*a.warpScale+r+n)*a.warpAmount,d=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+r+c+n)*a.warpAmount,f=o.noise2D((t+p)*a.patternScale+.5*c+n,(i+d)*a.patternScale+.5*l+n),u=1-Math.abs(f),_=Math.pow(u,a.ridgePower);let g,M,m,w=a.minOpacity+_*(a.maxOpacity-a.minOpacity),C=[255,255,255],S=0;if("wave"===a.effect.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,e,s);C=a.color,S=a.opacity}if("twinkle"===a.effect.type){const a=this._calculateTwinkleEffect(t,i,e,s);C=a.color,S=a.opacity}if(a.patternAurora){const e=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*r+.5*n)+1)/2;g=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),M=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),m=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)}else g=M=m=255;if(this._collapseProgress>0){const a=this._applyCollapse(t,i,e,s,w,S);w=a.opacity,S=a.effectOpacity}if(!(w<=0&&S<=0)){if(this.ctx.fillStyle=`rgba(${g}, ${M}, ${m}, ${w})`,this.options.solidPattern){const e=Math.floor(t*this._gridSize),s=Math.floor(i*this._gridSize);this.ctx.fillRect(e,s,Math.ceil(this._gridSize)+1,Math.ceil(this._gridSize)+1)}else this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill();S>0&&(this.ctx.fillStyle=`rgba(${C[0]}, ${C[1]}, ${C[2]}, ${S})`,this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill())}}_calculateWaveEffect(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r,_twinkleTime:h}=this,l=a.effect;let c=[255,255,255],p=0;const d=e/2,f=s/2,u=Math.sqrt((t-d)**2+(i-f)**2),_=Math.sqrt(d**2+f**2)*this._deadzoneValue,g=.3*_;let M=1;if(u<_)M=0;else if(u<_+g){const t=(u-_)/g;M=t*t*(3-2*t)}if(l.combineSparkle&&M>0){const e=t+i,s=Math.abs(e-this._diagPos),o=Math.max(0,1-s/l.width),r=Math.pow(o,.5),d=43758.5453*Math.sin(12.9898*t+78.233*i+n),f=d-Math.floor(d),u=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),_=u-Math.floor(u);if(f>1-l.density/100*.9){const e=_*Math.PI*2,s=.1+l.twinkleSpeed/100*.4,o=Math.sin(h*s+e),d=Math.max(0,o),f=l.sparkleBaseOpacity/100;if(p=d*(f+(1-f)*r)*M,l.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);c=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}return{color:c,opacity:p}}const m=t+i,w=Math.abs(m-this._diagPos);if(w<l.width&&void 0!==this._sparkleMap[`${t},${i}`]){const h=w/l.width,d=Math.cos(h*Math.PI*.5)*l.intensity,f=Math.min(e,s),u=Math.max(0,Math.floor(this._diagPos)-(s-1)),_=Math.min(e-1,Math.floor(this._diagPos)),g=Math.max(1,_-u+1);let m=1;if(g>=f&&g>1){const i=(t-u)/(g-1),e=Math.max(0,Math.min(1,i));m=.3+.7*Math.sin(e*Math.PI)}else if(g>1){const i=g/f,e=(t-u)/(g-1),s=Math.max(0,Math.min(1,e)),a=Math.sin(s*Math.PI);m=Math.max(.3,1-(1-a)*i*.7)}if(p=d*this._sparkleMap[`${t},${i}`]*Math.max(0,m)*M,l.aurora){const e=(o.noise2D(t*a.colorScale*2+n,i*a.colorScale*2+r+n)+1)/2;c=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)]}}return{color:c,opacity:p}}_calculateTwinkleEffect(t,i,e,s){const{options:a,noise:o,randomOffset:n,_twinkleTime:r}=this,h=a.effect;let l=[255,255,255],c=0;const p=e/2,d=s/2,f=Math.sqrt((t-p)**2+(i-d)**2),u=Math.sqrt(p**2+d**2)*this._deadzoneValue,_=.3*u;let g=1;if(f<u)g=0;else if(f<u+_){const t=(f-u)/_;g=t*t*(3-2*t)}if(g>0)if(h.combined){const e=5e-4+.003*(1-this._twinkleScaleValue),s=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*e+r*s,i*e+r*s*.5+n)+.3*o.noise2D(t*e*.5+r*s*.3+50,i*e*.7-r*s*.2+n+50)+.2*o.noise2D((t+.5*i)*e*.8+r*s*.4,(i-.3*t)*e*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,f=Math.pow(d,.5),u=43758.5453*Math.sin(12.9898*t+78.233*i+n),_=u-Math.floor(u),M=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),m=M-Math.floor(M);if(_>this._twinkleThreshold){const e=m*Math.PI*2,s=Math.sin(r*this._twinkleSpeedValue*2+e),o=Math.max(0,s),p=h.baseOpacity/100;if(c=o*(p+(1-p)*f)*h.intensity*g,h.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}}else if("wave"===h.mode){const e=5e-4+.003*(1-this._twinkleScaleValue),s=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*e+r*s,i*e+r*s*.5+n)+.3*o.noise2D(t*e*.5+r*s*.3+50,i*e*.7-r*s*.2+n+50)+.2*o.noise2D((t+.5*i)*e*.8+r*s*.4,(i-.3*t)*e*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,f=.3+.7*this._twinkleThreshold;if(c=Math.pow(d,1/f)*h.intensity*g,h.aurora&&c>0){const h=(o.noise2D(t*e*.3+r*s*.1+n,i*e*.3+n)+1)/2;l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*h),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*h),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*h)]}}else{const e=43758.5453*Math.sin(12.9898*t+78.233*i+n),s=e-Math.floor(e),p=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),d=p-Math.floor(p);if(s>this._twinkleThreshold){const e=d*Math.PI*2,s=Math.sin(r*this._twinkleSpeedValue+e);if(c=Math.max(0,s)*(.2+(o.noise2D(t*this._twinkleScaleValue+.2*r+n,i*this._twinkleScaleValue+n)+1)/2*.8)*h.intensity*g,h.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}}return{color:l,opacity:c}}_applyCollapse(t,i,e,s,a,o){const n=e/2,r=s/2,h=Math.sqrt(n*n+r*r),l=1-Math.sqrt((t-n)**2+(i-r)**2)/h;if(this._collapseProgress>l+this.options.collapseWaveWidth)a=0,o=0;else if(this._collapseProgress>l){const t=1-(this._collapseProgress-l)/this.options.collapseWaveWidth,i=t*t*(3-2*t);a*=i,o*=i}return{opacity:a,effectOpacity:o}}_updateCollapse(){const t=1+this.options.collapseWaveWidth;this._isCollapsing&&this._collapseProgress<t?(this._collapseProgress+=this.options.collapseSpeed,this._collapseProgress>=t&&(this._collapseProgress=t,this.options.onHide&&this.options.onHide())):!this._isCollapsing&&this._collapseProgress>0&&(this._collapseProgress-=this.options.collapseSpeed,this._collapseProgress<=0&&(this._collapseProgress=0,this.options.onShow&&this.options.onShow()))}start(){return this._isRunning||(this._isRunning=!0,this._lastFrameTime=performance.now(),this._animationId=requestAnimationFrame(this._draw)),this}stop(){return this._isRunning=!1,this._animationId&&(cancelAnimationFrame(this._animationId),this._animationId=null),this}resize(t,i){return void 0!==t&&(this.options.width=t),void 0!==i&&(this.options.height=i),this._resize(),this}redraw(){const t=performance.now(),i=this._isRunning;this._isRunning=!0,this._lastFrameTime=t-16;this._animTime+=16*this.options.animationSpeed,this._twinkleTime+=.016,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);const e=Math.ceil(this.canvas.width/this._gridSize),s=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===e&&this._offscreenCanvas.height===s||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=e,this._offscreenCanvas.height=s,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(e,s),a=i.data;for(let t=0;t<s;t++)for(let i=0;i<e;i++){const o=this._calculateCellData(i,t,e,s),n=4*(t*e+i);a[n]=o.r,a[n+1]=o.g,a[n+2]=o.b,a[n+3]=Math.round(255*o.opacity)}if(t.putImageData(i,0,0),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.ctx.drawImage(this._offscreenCanvas,0,0,this.canvas.width,this.canvas.height),"none"!==this.options.effect.type)for(let t=0;t<s;t++)for(let i=0;i<e;i++)this._drawEffect(i,t,e,s)}else for(let t=0;t<s;t++)for(let i=0;i<e;i++)this._drawCell(i,t,e,s);return this._isRunning=i,this}show(t){if(this._isCollapsing=!1,t){const i=this.options.onShow;this.options.onShow=()=>{t(),this.options.onShow=i}}return this}hide(t){if(this._isCollapsing=!0,t){const i=this.options.onHide;this.options.onHide=()=>{t(),this.options.onHide=i}}return this}toggle(t){return this._isCollapsing?this.show(t):this.hide(t)}isVisible(){return!this._isCollapsing&&0===this._collapseProgress}isHidden(){return this._isCollapsing&&this._collapseProgress>=1+this.options.collapseWaveWidth}setOption(t,i){if("effect"===t)return"object"==typeof i?this.setEffect(i.type,i):this;this.options[t]=i;return["density","dotSize","solidPattern","patternAurora","maxOpacity","minOpacity"].includes(t)&&(this._updateDensity(this.options.density),this._resize()),this}setEffect(t,i={}){return t&&(this.options.effect.type=t),Object.keys(i).forEach(t=>{"type"!==t&&(this.options.effect[t]=i[t])}),this._updateTwinkleSettings(),this._updateDeadzone(),this._resize(),this}getEffect(){return{...this.options.effect}}setOptions(t){return Object.keys(t).forEach(i=>{this.setOption(i,t[i])}),this}getOptions(){return{...this.options}}getOption(t){return this.options[t]}destroy(){this.stop(),window.removeEventListener("resize",this._resize),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas),this.canvas=null,this.ctx=null,this.noise=null}}return i});
6
+ !function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).Borealis=i()}(this,function(){"use strict";class t{constructor(t=Math.random()){this.p=new Uint8Array(256);for(let t=0;t<256;t++)this.p[t]=t;for(let i=255;i>0;i--){const e=(t=16807*t%2147483647)%(i+1);[this.p[i],this.p[e]]=[this.p[e],this.p[i]]}this.perm=new Uint8Array(512);for(let t=0;t<512;t++)this.perm[t]=this.p[255&t]}noise2D(t,i){const e=.5*(Math.sqrt(3)-1),s=(3-Math.sqrt(3))/6,a=(t+i)*e,o=Math.floor(t+a),n=Math.floor(i+a),r=(o+n)*s,h=t-(o-r),l=i-(n-r),c=h>l?1:0,p=h>l?0:1,d=h-c+s,f=l-p+s,u=h-1+2*s,_=l-1+2*s,g=255&o,M=255&n,m=(t,i,e)=>{const s=7&t,a=s<4?i:e,o=s<4?e:i;return(1&s?-a:a)+(2&s?-2*o:2*o)};let w=0,C=0,S=0,y=.5-h*h-l*l;y>=0&&(y*=y,w=y*y*m(this.perm[g+this.perm[M]],h,l));let v=.5-d*d-f*f;v>=0&&(v*=v,C=v*v*m(this.perm[g+c+this.perm[M+p]],d,f));let z=.5-u*u-_*_;return z>=0&&(z*=z,S=z*z*m(this.perm[g+1+this.perm[M+1]],u,_)),70*(w+C+S)}}class i{static get defaultOptions(){return{container:document.body,width:null,height:null,fullscreen:!0,zIndex:0,initiallyHidden:!1,density:50,dotSize:5,solidPattern:!1,densityMinCell:2,densityMaxCell:8,densityMinGap:1,densityMaxGap:4,patternScale:.001,patternAurora:!1,warpScale:.5,warpAmount:20,animationSpeed:2e-5,ridgePower:2,minOpacity:0,maxOpacity:1,waveFrequency:3,waveAmplitude:.5,effect:{type:"wave",aurora:!1,deadzone:20,speed:8e-4,width:120,chance:.08,intensity:1,delayMin:1e3,delayMax:3e3,combineSparkle:!1,sparkleBaseOpacity:0,mode:"sparkle",combined:!1,baseOpacity:30,twinkleSpeed:50,size:50,density:50},auroraColor1:[0,255,128],auroraColor2:[148,0,211],colorScale:.003,collapseSpeed:.1,collapseWaveWidth:.4,autoStart:!0,onShow:null,onHide:null}}constructor(t={}){const e=i.defaultOptions.effect,s=t.effect||{};this.options={...i.defaultOptions,...t,effect:{...e,...s}},this._init()}_init(){this.canvas=document.createElement("canvas");const i=this.options.zIndex;this.options.fullscreen?this.canvas.style.cssText=`\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: ${i};\n `:this.canvas.style.cssText=`\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: ${i};\n `;const e=this.options.container;if(e===document.body&&this.options.fullscreen)document.body.insertBefore(this.canvas,document.body.firstChild);else{"static"===window.getComputedStyle(e).position&&(e.style.position="relative"),e.appendChild(this.canvas)}this.ctx=this.canvas.getContext("2d"),this.noise=new t(1e4*Math.random()),this.randomOffset=1e3*Math.random(),this._cellSize=4,this._gap=2,this._gridSize=6,this._sparkleMap={},this._animTime=0,this._twinkleTime=0,this._lastFrameTime=0,this._sparkleWaiting=!1,this._sparkleWaitUntil=0,this._diagPos=0,this._isCollapsing=this.options.initiallyHidden,this._collapseProgress=this.options.initiallyHidden?1+this.options.collapseWaveWidth:0,this._isRunning=!1,this._animationId=null,this._twinkleThreshold=.8,this._twinkleSpeedValue=3,this._twinkleScaleValue=.01,this._deadzoneValue=.2,this._updateDensity(this.options.density),this._updateTwinkleSettings(),this._updateDeadzone(),this._draw=this._draw.bind(this),this._resize=this._resize.bind(this),window.addEventListener("resize",this._resize),this._resize(),this.options.autoStart&&this.start()}_updateDensity(t){const i=(100-t)/90,e=this.options.densityMinCell+i*(this.options.densityMaxCell-this.options.densityMinCell),s=.3+this.options.dotSize/10*1.7;this._cellSize=e*s,this._gap=this.options.densityMinGap+i*(this.options.densityMaxGap-this.options.densityMinGap),this._gridSize=this._cellSize+this._gap}_updateTwinkleSettings(){const t=this.options.effect;this._twinkleSpeedValue=1+(t.twinkleSpeed-10)/90*5,this._twinkleScaleValue=.5-(t.size-10)/90*.499,this._twinkleThreshold=1-t.density/100*.9}_updateDeadzone(){this._deadzoneValue=this.options.effect.deadzone/100}_generateSparkles(t,i){this._sparkleMap={};for(let e=0;e<i;e++)for(let i=0;i<t;i++)Math.random()<this.options.effect.chance&&(this._sparkleMap[`${i},${e}`]=Math.random())}_resize(){let t,i;if(null!==this.options.width&&null!==this.options.height)t=this.options.width,i=this.options.height;else if(this.options.fullscreen)t=window.innerWidth,i=window.innerHeight;else{const e=this.options.container;t=null!==this.options.width?this.options.width:e.clientWidth,i=null!==this.options.height?this.options.height:e.clientHeight}this.canvas.width=t,this.canvas.height=i;const e=Math.ceil(this.canvas.width/this._gridSize),s=Math.ceil(this.canvas.height/this._gridSize);this._generateSparkles(e,s),this._offscreenCanvas=null,this._offscreenCtx=null}_draw(t){if(!this._isRunning)return;const i=t-this._lastFrameTime;this._animTime+=i*this.options.animationSpeed,this._twinkleTime+=.001*i;const e=this.options.effect;if(this._sparkleWaiting)t>=this._sparkleWaitUntil&&(this._sparkleWaiting=!1,this._diagPos=-e.width);else{this._diagPos+=i*e.speed*100;const s=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize),o=s+a;if(this._diagPos>o+e.width){this._sparkleWaiting=!0;const i=e.delayMin+Math.random()*(e.delayMax-e.delayMin);this._sparkleWaitUntil=t+i,this._generateSparkles(s,a)}}this._lastFrameTime=t,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);const s=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===s&&this._offscreenCanvas.height===a||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=s,this._offscreenCanvas.height=a,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(s,a),e=i.data;for(let t=0;t<a;t++)for(let i=0;i<s;i++){const o=this._calculateCellData(i,t,s,a),n=4*(t*s+i);e[n]=o.r,e[n+1]=o.g,e[n+2]=o.b,e[n+3]=Math.round(255*o.opacity)}if(t.putImageData(i,0,0),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.ctx.drawImage(this._offscreenCanvas,0,0,this.canvas.width,this.canvas.height),"none"!==this.options.effect.type)for(let t=0;t<a;t++)for(let i=0;i<s;i++)this._drawEffect(i,t,s,a)}else for(let t=0;t<a;t++)for(let i=0;i<s;i++)this._drawCell(i,t,s,a);this._updateCollapse(),this._animationId=requestAnimationFrame(this._draw)}_calculateCellData(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r}=this,h=Math.sin(r*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,l=Math.cos(r*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,c=o.noise2D(t*a.patternScale*a.warpScale+h+n,i*a.patternScale*a.warpScale+r+n)*a.warpAmount,p=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+r+l+n)*a.warpAmount,d=o.noise2D((t+c)*a.patternScale+.5*l+n,(i+p)*a.patternScale+.5*h+n),f=1-Math.abs(d),u=Math.pow(f,a.ridgePower);let _,g,M,m=a.minOpacity+u*(a.maxOpacity-a.minOpacity);if(a.patternAurora){const e=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*r+.5*n)+1)/2;_=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),g=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),M=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)}else _=g=M=255;if(this._collapseProgress>0){m=this._applyCollapse(t,i,e,s,m,0).opacity}return{r:_,g:g,b:M,opacity:m}}_drawEffect(t,i,e,s){const a=this.options.effect;let o=[255,255,255],n=0;if("wave"===a.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,e,s);o=a.color,n=a.opacity}if("twinkle"===a.type){const a=this._calculateTwinkleEffect(t,i,e,s);o=a.color,n=a.opacity}if(this._collapseProgress>0){n=this._applyCollapse(t,i,e,s,0,n).effectOpacity}n>0&&(this.ctx.fillStyle=`rgba(${o[0]}, ${o[1]}, ${o[2]}, ${n})`,this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill())}_drawCell(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r,_twinkleTime:h}=this,l=Math.sin(r*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,c=Math.cos(r*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,p=o.noise2D(t*a.patternScale*a.warpScale+l+n,i*a.patternScale*a.warpScale+r+n)*a.warpAmount,d=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+r+c+n)*a.warpAmount,f=o.noise2D((t+p)*a.patternScale+.5*c+n,(i+d)*a.patternScale+.5*l+n),u=1-Math.abs(f),_=Math.pow(u,a.ridgePower);let g,M,m,w=a.minOpacity+_*(a.maxOpacity-a.minOpacity),C=[255,255,255],S=0;if("wave"===a.effect.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,e,s);C=a.color,S=a.opacity}if("twinkle"===a.effect.type){const a=this._calculateTwinkleEffect(t,i,e,s);C=a.color,S=a.opacity}if(a.patternAurora){const e=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*r+.5*n)+1)/2;g=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),M=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),m=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)}else g=M=m=255;if(this._collapseProgress>0){const a=this._applyCollapse(t,i,e,s,w,S);w=a.opacity,S=a.effectOpacity}if(!(w<=0&&S<=0)){if(this.ctx.fillStyle=`rgba(${g}, ${M}, ${m}, ${w})`,this.options.solidPattern){const e=Math.floor(t*this._gridSize),s=Math.floor(i*this._gridSize);this.ctx.fillRect(e,s,Math.ceil(this._gridSize)+1,Math.ceil(this._gridSize)+1)}else this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill();S>0&&(this.ctx.fillStyle=`rgba(${C[0]}, ${C[1]}, ${C[2]}, ${S})`,this.ctx.beginPath(),this.ctx.arc(t*this._gridSize+this._cellSize/2,i*this._gridSize+this._cellSize/2,this._cellSize/2,0,2*Math.PI),this.ctx.fill())}}_calculateWaveEffect(t,i,e,s){const{options:a,noise:o,randomOffset:n,_animTime:r,_twinkleTime:h}=this,l=a.effect;let c=[255,255,255],p=0;const d=e/2,f=s/2,u=Math.sqrt((t-d)**2+(i-f)**2),_=Math.sqrt(d**2+f**2)*this._deadzoneValue,g=.3*_;let M=1;if(u<_)M=0;else if(u<_+g){const t=(u-_)/g;M=t*t*(3-2*t)}if(l.combineSparkle&&M>0){const e=t+i,s=Math.abs(e-this._diagPos),o=Math.max(0,1-s/l.width),r=Math.pow(o,.5),d=43758.5453*Math.sin(12.9898*t+78.233*i+n),f=d-Math.floor(d),u=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),_=u-Math.floor(u);if(f>1-l.density/100*.9){const e=_*Math.PI*2,s=.1+l.twinkleSpeed/100*.4,o=Math.sin(h*s+e),d=Math.max(0,o),f=l.sparkleBaseOpacity/100;if(p=d*(f+(1-f)*r)*M,l.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);c=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}return{color:c,opacity:p}}const m=t+i,w=Math.abs(m-this._diagPos);if(w<l.width&&void 0!==this._sparkleMap[`${t},${i}`]){const h=w/l.width,d=Math.cos(h*Math.PI*.5)*l.intensity,f=Math.min(e,s),u=Math.max(0,Math.floor(this._diagPos)-(s-1)),_=Math.min(e-1,Math.floor(this._diagPos)),g=Math.max(1,_-u+1);let m=1;if(g>=f&&g>1){const i=(t-u)/(g-1),e=Math.max(0,Math.min(1,i));m=.3+.7*Math.sin(e*Math.PI)}else if(g>1){const i=g/f,e=(t-u)/(g-1),s=Math.max(0,Math.min(1,e)),a=Math.sin(s*Math.PI);m=Math.max(.3,1-(1-a)*i*.7)}if(p=d*this._sparkleMap[`${t},${i}`]*Math.max(0,m)*M,l.aurora){const e=(o.noise2D(t*a.colorScale*2+n,i*a.colorScale*2+r+n)+1)/2;c=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*e),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*e),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*e)]}}return{color:c,opacity:p}}_calculateTwinkleEffect(t,i,e,s){const{options:a,noise:o,randomOffset:n,_twinkleTime:r}=this,h=a.effect;let l=[255,255,255],c=0;const p=e/2,d=s/2,f=Math.sqrt((t-p)**2+(i-d)**2),u=Math.sqrt(p**2+d**2)*this._deadzoneValue,_=.3*u;let g=1;if(f<u)g=0;else if(f<u+_){const t=(f-u)/_;g=t*t*(3-2*t)}if(g>0)if(h.combined){const e=5e-4+.003*(1-this._twinkleScaleValue),s=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*e+r*s,i*e+r*s*.5+n)+.3*o.noise2D(t*e*.5+r*s*.3+50,i*e*.7-r*s*.2+n+50)+.2*o.noise2D((t+.5*i)*e*.8+r*s*.4,(i-.3*t)*e*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,f=Math.pow(d,.5),u=43758.5453*Math.sin(12.9898*t+78.233*i+n),_=u-Math.floor(u),M=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),m=M-Math.floor(M);if(_>this._twinkleThreshold){const e=m*Math.PI*2,s=Math.sin(r*this._twinkleSpeedValue*2+e),o=Math.max(0,s),p=h.baseOpacity/100;if(c=o*(p+(1-p)*f)*h.intensity*g,h.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}}else if("wave"===h.mode){const e=5e-4+.003*(1-this._twinkleScaleValue),s=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*e+r*s,i*e+r*s*.5+n)+.3*o.noise2D(t*e*.5+r*s*.3+50,i*e*.7-r*s*.2+n+50)+.2*o.noise2D((t+.5*i)*e*.8+r*s*.4,(i-.3*t)*e*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,f=.3+.7*this._twinkleThreshold;if(c=Math.pow(d,1/f)*h.intensity*g,h.aurora&&c>0){const h=(o.noise2D(t*e*.3+r*s*.1+n,i*e*.3+n)+1)/2;l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*h),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*h),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*h)]}}else{const e=43758.5453*Math.sin(12.9898*t+78.233*i+n),s=e-Math.floor(e),p=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),d=p-Math.floor(p);if(s>this._twinkleThreshold){const e=d*Math.PI*2,s=Math.sin(r*this._twinkleSpeedValue+e);if(c=Math.max(0,s)*(.2+(o.noise2D(t*this._twinkleScaleValue+.2*r+n,i*this._twinkleScaleValue+n)+1)/2*.8)*h.intensity*g,h.aurora){const e=12345.6789*Math.sin(45.123*t+89.456*i+n),s=e-Math.floor(e);l=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)]}}}return{color:l,opacity:c}}_applyCollapse(t,i,e,s,a,o){const n=e/2,r=s/2,h=Math.sqrt(n*n+r*r),l=1-Math.sqrt((t-n)**2+(i-r)**2)/h;if(this._collapseProgress>l+this.options.collapseWaveWidth)a=0,o=0;else if(this._collapseProgress>l){const t=1-(this._collapseProgress-l)/this.options.collapseWaveWidth,i=t*t*(3-2*t);a*=i,o*=i}return{opacity:a,effectOpacity:o}}_updateCollapse(){const t=1+this.options.collapseWaveWidth;this._isCollapsing&&this._collapseProgress<t?(this._collapseProgress+=this.options.collapseSpeed,this._collapseProgress>=t&&(this._collapseProgress=t,this.options.onHide&&this.options.onHide())):!this._isCollapsing&&this._collapseProgress>0&&(this._collapseProgress-=this.options.collapseSpeed,this._collapseProgress<=0&&(this._collapseProgress=0,this.options.onShow&&this.options.onShow()))}start(){return this._isRunning||(this._isRunning=!0,this._lastFrameTime=performance.now(),this._animationId=requestAnimationFrame(this._draw)),this}stop(){return this._isRunning=!1,this._animationId&&(cancelAnimationFrame(this._animationId),this._animationId=null),this}resize(t,i){return void 0!==t&&(this.options.width=t),void 0!==i&&(this.options.height=i),this._resize(),this}redraw(){const t=performance.now(),i=this._isRunning;this._isRunning=!0,this._lastFrameTime=t-16;this._animTime+=16*this.options.animationSpeed,this._twinkleTime+=.016,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);const e=Math.ceil(this.canvas.width/this._gridSize),s=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===e&&this._offscreenCanvas.height===s||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=e,this._offscreenCanvas.height=s,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(e,s),a=i.data;for(let t=0;t<s;t++)for(let i=0;i<e;i++){const o=this._calculateCellData(i,t,e,s),n=4*(t*e+i);a[n]=o.r,a[n+1]=o.g,a[n+2]=o.b,a[n+3]=Math.round(255*o.opacity)}if(t.putImageData(i,0,0),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.ctx.drawImage(this._offscreenCanvas,0,0,this.canvas.width,this.canvas.height),"none"!==this.options.effect.type)for(let t=0;t<s;t++)for(let i=0;i<e;i++)this._drawEffect(i,t,e,s)}else for(let t=0;t<s;t++)for(let i=0;i<e;i++)this._drawCell(i,t,e,s);return this._isRunning=i,this}show(t){if(this._isCollapsing=!1,t){const i=this.options.onShow;this.options.onShow=()=>{t(),this.options.onShow=i}}return this}hide(t){if(this._isCollapsing=!0,t){const i=this.options.onHide;this.options.onHide=()=>{t(),this.options.onHide=i}}return this}toggle(t){return this._isCollapsing?this.show(t):this.hide(t)}isVisible(){return!this._isCollapsing&&0===this._collapseProgress}isHidden(){return this._isCollapsing&&this._collapseProgress>=1+this.options.collapseWaveWidth}setOption(t,i){if("effect"===t)return"object"==typeof i?this.setEffect(i.type,i):this;this.options[t]=i;return["density","dotSize","solidPattern","patternAurora","maxOpacity","minOpacity"].includes(t)&&(this._updateDensity(this.options.density),this._resize()),this}setEffect(t,i={}){return t&&(this.options.effect.type=t),Object.keys(i).forEach(t=>{"type"!==t&&(this.options.effect[t]=i[t])}),this._updateTwinkleSettings(),this._updateDeadzone(),this._resize(),this}getEffect(){return{...this.options.effect}}setOptions(t){return Object.keys(t).forEach(i=>{this.setOption(i,t[i])}),this}getOptions(){return{...this.options}}getOption(t){return this.options[t]}destroy(){this.stop(),window.removeEventListener("resize",this._resize),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas),this.canvas=null,this.ctx=null,this.noise=null}}return i});
7
7
  //# sourceMappingURL=borealis.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"borealis.min.js","sources":["../src/borealis.js"],"sourcesContent":["/**\n * Borealis - Interactive Animated Background\n * A canvas-based particle animation system with noise patterns and effects\n * \n * @author Borealis\n * @version 1.0.0\n */\n\nclass SimplexNoise {\n constructor(seed = Math.random()) {\n this.p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) this.p[i] = i;\n \n for (let i = 255; i > 0; i--) {\n seed = (seed * 16807) % 2147483647;\n const j = seed % (i + 1);\n [this.p[i], this.p[j]] = [this.p[j], this.p[i]];\n }\n \n this.perm = new Uint8Array(512);\n for (let i = 0; i < 512; i++) this.perm[i] = this.p[i & 255];\n }\n\n noise2D(x, y) {\n const F2 = 0.5 * (Math.sqrt(3) - 1);\n const G2 = (3 - Math.sqrt(3)) / 6;\n \n const s = (x + y) * F2;\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n \n const t = (i + j) * G2;\n const X0 = i - t;\n const Y0 = j - t;\n const x0 = x - X0;\n const y0 = y - Y0;\n \n const i1 = x0 > y0 ? 1 : 0;\n const j1 = x0 > y0 ? 0 : 1;\n \n const x1 = x0 - i1 + G2;\n const y1 = y0 - j1 + G2;\n const x2 = x0 - 1 + 2 * G2;\n const y2 = y0 - 1 + 2 * G2;\n \n const ii = i & 255;\n const jj = j & 255;\n \n const grad = (hash, x, y) => {\n const h = hash & 7;\n const u = h < 4 ? x : y;\n const v = h < 4 ? y : x;\n return ((h & 1) ? -u : u) + ((h & 2) ? -2 * v : 2 * v);\n };\n \n let n0 = 0, n1 = 0, n2 = 0;\n \n let t0 = 0.5 - x0 * x0 - y0 * y0;\n if (t0 >= 0) {\n t0 *= t0;\n n0 = t0 * t0 * grad(this.perm[ii + this.perm[jj]], x0, y0);\n }\n \n let t1 = 0.5 - x1 * x1 - y1 * y1;\n if (t1 >= 0) {\n t1 *= t1;\n n1 = t1 * t1 * grad(this.perm[ii + i1 + this.perm[jj + j1]], x1, y1);\n }\n \n let t2 = 0.5 - x2 * x2 - y2 * y2;\n if (t2 >= 0) {\n t2 *= t2;\n n2 = t2 * t2 * grad(this.perm[ii + 1 + this.perm[jj + 1]], x2, y2);\n }\n \n return 70 * (n0 + n1 + n2);\n }\n}\n\nclass Borealis {\n /**\n * Default options for Borealis\n */\n static get defaultOptions() {\n return {\n // Container & Size\n container: document.body,\n width: null, // Canvas width (null = auto from container/window)\n height: null, // Canvas height (null = auto from container/window)\n fullscreen: true, // If true, uses fixed positioning to cover viewport\n \n // Grid settings\n density: 50, // Grid density (10-100)\n dotSize: 5, // Dot size (0-10, 0=smallest)\n solidPattern: false, // Solid pattern without gaps/circles\n densityMinCell: 2, // Cell size at max density\n densityMaxCell: 8, // Cell size at min density\n densityMinGap: 1, // Gap at max density\n densityMaxGap: 4, // Gap at min density\n \n // Pattern settings\n patternScale: 0.001, // Noise scale (smaller = larger patterns)\n patternAurora: false, // Use aurora colors for pattern\n warpScale: 0.5, // Domain warp frequency multiplier\n warpAmount: 20, // Domain warp intensity\n animationSpeed: 0.00002, // Animation speed multiplier\n ridgePower: 2, // Ridge sharpness (higher = sharper lines)\n minOpacity: 0, // Minimum opacity (0-1)\n maxOpacity: 1, // Maximum opacity (0-1)\n waveFrequency: 3, // Wave oscillation frequency\n waveAmplitude: 0.5, // Wave intensity (0-1)\n \n // Effect settings (unified structure)\n effect: {\n type: 'wave', // 'none', 'wave', 'twinkle'\n aurora: false, // Use aurora colors for effect\n deadzone: 20, // Center dead zone size (0-100)\n // Wave-specific options\n speed: 0.0008, // Diagonal line speed\n width: 120, // Width of the wave band\n chance: 0.08, // Chance of a cell sparkling (0-1)\n intensity: 1, // Max brightness\n delayMin: 1000, // Min delay between sweeps (ms)\n delayMax: 3000, // Max delay between sweeps (ms)\n combineSparkle: false, // Add sparkles that get boosted by wave\n sparkleBaseOpacity: 0, // Sparkle base opacity when wave not passing (0-100)\n // Twinkle-specific options\n mode: 'sparkle', // 'sparkle' (random) or 'wave' (flowing waves)\n combined: false, // Combine sparkle with wave (sparkles boosted by wave)\n baseOpacity: 30, // Base opacity when wave is not passing (0-100)\n twinkleSpeed: 50, // Twinkle animation speed (10-100)\n size: 50, // Pattern size (10-100)\n density: 50, // Star density (0-100)\n },\n \n // Aurora colors\n auroraColor1: [0, 255, 128], // Cyan-green\n auroraColor2: [148, 0, 211], // Violet\n colorScale: 0.003, // Color variation scale\n \n // Collapse settings\n collapseSpeed: 0.1, // Collapse animation speed\n collapseWaveWidth: 0.4, // Width of the collapse transition\n \n // Animation\n autoStart: true, // Start animation automatically\n \n // Callbacks\n onShow: null, // Called when show animation completes\n onHide: null, // Called when hide animation completes\n };\n }\n\n /**\n * Create a new Borealis instance\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n // Deep merge for effect object\n const defaultEffect = Borealis.defaultOptions.effect;\n const userEffect = options.effect || {};\n \n this.options = { \n ...Borealis.defaultOptions, \n ...options,\n effect: { ...defaultEffect, ...userEffect }\n };\n this._init();\n }\n\n /**\n * Initialize the Borealis instance\n * @private\n */\n _init() {\n // Create canvas\n this.canvas = document.createElement('canvas');\n \n // Set canvas styles based on mode\n if (this.options.fullscreen) {\n this.canvas.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 0;\n `;\n } else {\n this.canvas.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n `;\n }\n \n // Add to container\n const container = this.options.container;\n if (container === document.body && this.options.fullscreen) {\n document.body.insertBefore(this.canvas, document.body.firstChild);\n } else {\n // Ensure container has position for absolute positioning\n const containerStyle = window.getComputedStyle(container);\n if (containerStyle.position === 'static') {\n container.style.position = 'relative';\n }\n container.appendChild(this.canvas);\n }\n \n this.ctx = this.canvas.getContext('2d');\n this.noise = new SimplexNoise(Math.random() * 10000);\n this.randomOffset = Math.random() * 1000;\n \n // Internal state\n this._cellSize = 4;\n this._gap = 2;\n this._gridSize = 6;\n this._sparkleMap = {};\n this._animTime = 0;\n this._twinkleTime = 0;\n this._lastFrameTime = 0;\n this._sparkleWaiting = false;\n this._sparkleWaitUntil = 0;\n this._diagPos = 0;\n this._isCollapsing = false;\n this._collapseProgress = 0;\n this._isRunning = false;\n this._animationId = null;\n \n // Computed twinkle values\n this._twinkleThreshold = 0.8;\n this._twinkleSpeedValue = 3;\n this._twinkleScaleValue = 0.01;\n this._deadzoneValue = 0.2;\n \n // Apply initial options\n this._updateDensity(this.options.density);\n this._updateTwinkleSettings();\n this._updateDeadzone();\n \n // Bind methods\n this._draw = this._draw.bind(this);\n this._resize = this._resize.bind(this);\n \n // Setup event listeners\n window.addEventListener('resize', this._resize);\n \n // Initial resize\n this._resize();\n \n // Auto start\n if (this.options.autoStart) {\n this.start();\n }\n }\n\n /**\n * Update density settings\n * @private\n */\n _updateDensity(value) {\n const t = (100 - value) / 90;\n const baseCell = this.options.densityMinCell + t * (this.options.densityMaxCell - this.options.densityMinCell);\n // Apply dotSize multiplier (0 = 0.3x, 5 = 1x, 10 = 2x)\n const sizeMultiplier = 0.3 + (this.options.dotSize / 10) * 1.7;\n this._cellSize = baseCell * sizeMultiplier;\n this._gap = this.options.densityMinGap + t * (this.options.densityMaxGap - this.options.densityMinGap);\n this._gridSize = this._cellSize + this._gap;\n }\n\n /**\n * Update twinkle settings from options\n * @private\n */\n _updateTwinkleSettings() {\n const effect = this.options.effect;\n // Speed: 10-100 maps to 1-6\n this._twinkleSpeedValue = 1 + (effect.twinkleSpeed - 10) / 90 * 5;\n // Size: 10-100 maps to 0.5-0.001 (inverted, much wider range)\n this._twinkleScaleValue = 0.5 - (effect.size - 10) / 90 * 0.499;\n // Density: 0-100 maps to threshold 1.0-0.1\n this._twinkleThreshold = 1 - effect.density / 100 * 0.9;\n }\n\n /**\n * Update deadzone setting (applies to all effects)\n * @private\n */\n _updateDeadzone() {\n // Deadzone: 0-100 maps to 0-1 (percentage of diagonal distance from center to corner)\n this._deadzoneValue = this.options.effect.deadzone / 100;\n }\n\n /**\n * Generate sparkle map\n * @private\n */\n _generateSparkles(cols, rows) {\n this._sparkleMap = {};\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n if (Math.random() < this.options.effect.chance) {\n this._sparkleMap[`${x},${y}`] = Math.random();\n }\n }\n }\n }\n\n /**\n * Resize handler\n * @private\n */\n _resize() {\n // Determine dimensions\n let width, height;\n \n if (this.options.width !== null && this.options.height !== null) {\n // Use explicit dimensions\n width = this.options.width;\n height = this.options.height;\n } else if (this.options.fullscreen) {\n // Use window dimensions\n width = window.innerWidth;\n height = window.innerHeight;\n } else {\n // Use container dimensions\n const container = this.options.container;\n width = this.options.width !== null ? this.options.width : container.clientWidth;\n height = this.options.height !== null ? this.options.height : container.clientHeight;\n }\n \n this.canvas.width = width;\n this.canvas.height = height;\n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n this._generateSparkles(cols, rows);\n // Clear offscreen canvas cache on resize\n this._offscreenCanvas = null;\n this._offscreenCtx = null;\n }\n\n /**\n * Main draw loop\n * @private\n */\n _draw(time) {\n if (!this._isRunning) return;\n \n const delta = time - this._lastFrameTime;\n \n this._animTime += delta * this.options.animationSpeed;\n this._twinkleTime += delta * 0.001;\n \n // Handle wave timing\n const effect = this.options.effect;\n if (!this._sparkleWaiting) {\n this._diagPos += delta * effect.speed * 100;\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n const maxDiag = cols + rows;\n \n if (this._diagPos > maxDiag + effect.width) {\n this._sparkleWaiting = true;\n const delay = effect.delayMin + Math.random() * (effect.delayMax - effect.delayMin);\n this._sparkleWaitUntil = time + delay;\n this._generateSparkles(cols, rows);\n }\n } else {\n if (time >= this._sparkleWaitUntil) {\n this._sparkleWaiting = false;\n this._diagPos = -effect.width;\n }\n }\n \n this._lastFrameTime = time;\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n \n // For solid pattern, use offscreen canvas for pixel-perfect base pattern\n if (this.options.solidPattern) {\n // Create or reuse offscreen canvas at grid resolution\n if (!this._offscreenCanvas || this._offscreenCanvas.width !== cols || this._offscreenCanvas.height !== rows) {\n this._offscreenCanvas = document.createElement('canvas');\n this._offscreenCanvas.width = cols;\n this._offscreenCanvas.height = rows;\n this._offscreenCtx = this._offscreenCanvas.getContext('2d');\n }\n \n const offCtx = this._offscreenCtx;\n const imageData = offCtx.createImageData(cols, rows);\n const data = imageData.data;\n \n // Draw only base pattern to ImageData (no effects)\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n const cellData = this._calculateCellData(x, y, cols, rows);\n \n const idx = (y * cols + x) * 4;\n data[idx] = cellData.r;\n data[idx + 1] = cellData.g;\n data[idx + 2] = cellData.b;\n data[idx + 3] = Math.round(cellData.opacity * 255);\n }\n }\n \n offCtx.putImageData(imageData, 0, 0);\n \n // Scale up to full canvas size with smooth interpolation\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n this.ctx.drawImage(this._offscreenCanvas, 0, 0, this.canvas.width, this.canvas.height);\n \n // Draw effects on top using regular canvas API (crisp circles)\n if (this.options.effect.type !== 'none') {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawEffect(x, y, cols, rows);\n }\n }\n }\n } else {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawCell(x, y, cols, rows);\n }\n }\n }\n \n // Update collapse\n this._updateCollapse();\n \n this._animationId = requestAnimationFrame(this._draw);\n }\n\n /**\n * Calculate cell data for solid pattern (used for ImageData rendering)\n * @private\n */\n _calculateCellData(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime } = this;\n \n // Oscillating wave effect\n const wave1 = Math.sin(_animTime * options.waveFrequency + x * options.patternScale * 10) * options.waveAmplitude;\n const wave2 = Math.cos(_animTime * options.waveFrequency * 0.7 + y * options.patternScale * 10) * options.waveAmplitude;\n \n // Domain warping\n const warpX = noise.noise2D(x * options.patternScale * options.warpScale + wave1 + randomOffset, y * options.patternScale * options.warpScale + _animTime + randomOffset) * options.warpAmount;\n const warpY = noise.noise2D(x * options.patternScale * options.warpScale + 100 + randomOffset, y * options.patternScale * options.warpScale + _animTime + wave2 + randomOffset) * options.warpAmount;\n \n const noiseVal = noise.noise2D(\n (x + warpX) * options.patternScale + wave2 * 0.5 + randomOffset,\n (y + warpY) * options.patternScale + wave1 * 0.5 + randomOffset\n );\n \n // Ridge noise\n const ridge = 1 - Math.abs(noiseVal);\n const rawOpacity = Math.pow(ridge, options.ridgePower);\n let opacity = options.minOpacity + rawOpacity * (options.maxOpacity - options.minOpacity);\n \n // Pattern color (no effects in solid pattern base - effects drawn separately)\n let r, g, b;\n if (options.patternAurora) {\n const colorNoise = noise.noise2D(x * options.colorScale + randomOffset * 0.5, y * options.colorScale + _animTime * 0.5 + randomOffset * 0.5);\n const colorBlend = (colorNoise + 1) / 2;\n r = Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend);\n g = Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend);\n b = Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend);\n } else {\n r = g = b = 255;\n }\n \n // Apply collapse (only base pattern, no effect)\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, opacity, 0);\n opacity = collapseResult.opacity;\n }\n \n return { r, g, b, opacity };\n }\n\n /**\n * Draw only effect for a cell (used in solid pattern mode)\n * @private\n */\n _drawEffect(x, y, cols, rows) {\n const effect = this.options.effect;\n \n let effectColor = [255, 255, 255];\n let effectOpacity = 0;\n \n // Wave effect\n if (effect.type === 'wave' && !this._sparkleWaiting) {\n const result = this._calculateWaveEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Twinkle effect\n if (effect.type === 'twinkle') {\n const result = this._calculateTwinkleEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Apply collapse\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, 0, effectOpacity);\n effectOpacity = collapseResult.effectOpacity;\n }\n \n // Draw effect circle if visible\n if (effectOpacity > 0) {\n this.ctx.fillStyle = `rgba(${effectColor[0]}, ${effectColor[1]}, ${effectColor[2]}, ${effectOpacity})`;\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n }\n\n /**\n * Draw a single cell\n * @private\n */\n _drawCell(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime, _twinkleTime } = this;\n \n // Oscillating wave effect\n const wave1 = Math.sin(_animTime * options.waveFrequency + x * options.patternScale * 10) * options.waveAmplitude;\n const wave2 = Math.cos(_animTime * options.waveFrequency * 0.7 + y * options.patternScale * 10) * options.waveAmplitude;\n \n // Domain warping\n const warpX = noise.noise2D(x * options.patternScale * options.warpScale + wave1 + randomOffset, y * options.patternScale * options.warpScale + _animTime + randomOffset) * options.warpAmount;\n const warpY = noise.noise2D(x * options.patternScale * options.warpScale + 100 + randomOffset, y * options.patternScale * options.warpScale + _animTime + wave2 + randomOffset) * options.warpAmount;\n \n const noiseVal = noise.noise2D(\n (x + warpX) * options.patternScale + wave2 * 0.5 + randomOffset,\n (y + warpY) * options.patternScale + wave1 * 0.5 + randomOffset\n );\n \n // Ridge noise\n const ridge = 1 - Math.abs(noiseVal);\n const rawOpacity = Math.pow(ridge, options.ridgePower);\n let opacity = options.minOpacity + rawOpacity * (options.maxOpacity - options.minOpacity);\n \n // Effect variables\n let effectColor = [255, 255, 255];\n let effectOpacity = 0;\n \n // Wave effect\n if (options.effect.type === 'wave' && !this._sparkleWaiting) {\n const result = this._calculateWaveEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Twinkle effect\n if (options.effect.type === 'twinkle') {\n const result = this._calculateTwinkleEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Pattern color\n let r, g, b;\n if (options.patternAurora) {\n const colorNoise = noise.noise2D(x * options.colorScale + randomOffset * 0.5, y * options.colorScale + _animTime * 0.5 + randomOffset * 0.5);\n const colorBlend = (colorNoise + 1) / 2;\n r = Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend);\n g = Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend);\n b = Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend);\n } else {\n r = g = b = 255;\n }\n \n // Apply collapse\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, opacity, effectOpacity);\n opacity = collapseResult.opacity;\n effectOpacity = collapseResult.effectOpacity;\n }\n \n // Skip rendering if both opacities are 0 (performance optimization)\n if (opacity <= 0 && effectOpacity <= 0) {\n return;\n }\n \n // Draw base pattern\n this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${opacity})`;\n if (this.options.solidPattern) {\n // Solid mode: fill entire cell without gaps (add 0.5px overlap to prevent gaps)\n const px = Math.floor(x * this._gridSize);\n const py = Math.floor(y * this._gridSize);\n this.ctx.fillRect(px, py, Math.ceil(this._gridSize) + 1, Math.ceil(this._gridSize) + 1);\n } else {\n // Circle mode\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n \n // Draw effect on top (always circles)\n if (effectOpacity > 0) {\n this.ctx.fillStyle = `rgba(${effectColor[0]}, ${effectColor[1]}, ${effectColor[2]}, ${effectOpacity})`;\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n }\n\n /**\n * Calculate wave effect\n * @private\n */\n _calculateWaveEffect(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime, _twinkleTime } = this;\n const effect = options.effect;\n let color = [255, 255, 255];\n let opacity = 0;\n \n // Dead zone calculation (using diagonal distance to corner)\n const centerX = cols / 2;\n const centerY = rows / 2;\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const maxDist = Math.sqrt(centerX ** 2 + centerY ** 2); // Distance from center to corner\n const maxRadius = maxDist * this._deadzoneValue;\n const fadeZone = maxRadius * 0.3;\n \n let centerFade = 1;\n if (distFromCenter < maxRadius) {\n centerFade = 0;\n } else if (distFromCenter < maxRadius + fadeZone) {\n const t = (distFromCenter - maxRadius) / fadeZone;\n centerFade = t * t * (3 - 2 * t);\n }\n \n // Combined sparkle mode - sparkles that get boosted by wave\n if (effect.combineSparkle && centerFade > 0) {\n // Calculate wave proximity (0-1, 1 = wave is here)\n const cellDiag = x + y;\n const distFromLine = Math.abs(cellDiag - this._diagPos);\n // Narrower wave effect zone for more dramatic boost\n const waveProximity = Math.max(0, 1 - distFromLine / effect.width);\n // Sharper falloff - wave effect drops quickly\n const smoothWaveProximity = Math.pow(waveProximity, 0.5);\n \n // Calculate sparkle\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n // Use twinkle density for sparkle distribution\n const sparkleThreshold = 1 - effect.density / 100 * 0.9;\n \n if (rand1 > sparkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const sparkleSpeed = 0.1 + (effect.twinkleSpeed / 100) * 0.4;\n const twinkleWave = Math.sin(_twinkleTime * sparkleSpeed + phase);\n const sparkle = Math.max(0, twinkleWave);\n \n // Base opacity is limited, wave boosts it to full\n const baseOpacity = effect.sparkleBaseOpacity / 100;\n const maxBoost = 1 - baseOpacity;\n const finalOpacity = baseOpacity + (maxBoost * smoothWaveProximity);\n \n opacity = sparkle * finalOpacity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n \n return { color, opacity };\n }\n \n const cellDiag = x + y;\n const distFromLine = Math.abs(cellDiag - this._diagPos);\n \n if (distFromLine < effect.width && this._sparkleMap[`${x},${y}`] !== undefined) {\n const normalizedDist = distFromLine / effect.width;\n const sparkle = Math.cos(normalizedDist * Math.PI * 0.5) * effect.intensity;\n \n // Cylinder effect\n const fullDiagonalLength = Math.min(cols, rows);\n const diagStartX = Math.max(0, Math.floor(this._diagPos) - (rows - 1));\n const diagEndX = Math.min(cols - 1, Math.floor(this._diagPos));\n const currentLineLength = Math.max(1, diagEndX - diagStartX + 1);\n \n let cylinderFade = 1;\n if (currentLineLength >= fullDiagonalLength && currentLineLength > 1) {\n const posAlongLine = (x - diagStartX) / (currentLineLength - 1);\n const clampedPos = Math.max(0, Math.min(1, posAlongLine));\n cylinderFade = 0.3 + 0.7 * Math.sin(clampedPos * Math.PI);\n } else if (currentLineLength > 1) {\n const completeness = currentLineLength / fullDiagonalLength;\n const posAlongLine = (x - diagStartX) / (currentLineLength - 1);\n const clampedPos = Math.max(0, Math.min(1, posAlongLine));\n const baseFade = Math.sin(clampedPos * Math.PI);\n cylinderFade = Math.max(0.3, 1 - (1 - baseFade) * completeness * 0.7);\n }\n \n opacity = sparkle * this._sparkleMap[`${x},${y}`] * Math.max(0, cylinderFade) * centerFade;\n \n // Color\n if (effect.aurora) {\n const colorNoise = noise.noise2D(x * options.colorScale * 2 + randomOffset, y * options.colorScale * 2 + _animTime + randomOffset);\n const colorBlend = (colorNoise + 1) / 2;\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n \n return { color, opacity };\n }\n\n /**\n * Calculate twinkle effect\n * @private\n */\n _calculateTwinkleEffect(x, y, cols, rows) {\n const { options, noise, randomOffset, _twinkleTime } = this;\n const effect = options.effect;\n let color = [255, 255, 255];\n let opacity = 0;\n \n // Dead zone calculation (using diagonal distance to corner)\n const centerX = cols / 2;\n const centerY = rows / 2;\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const maxDist = Math.sqrt(centerX ** 2 + centerY ** 2); // Distance from center to corner\n const maxRadius = maxDist * this._deadzoneValue;\n const fadeZone = maxRadius * 0.3;\n \n let centerFade = 1;\n if (distFromCenter < maxRadius) {\n centerFade = 0;\n } else if (distFromCenter < maxRadius + fadeZone) {\n const t = (distFromCenter - maxRadius) / fadeZone;\n centerFade = t * t * (3 - 2 * t);\n }\n \n if (centerFade > 0) {\n // Combined mode - sparkles that get boosted by passing waves\n if (effect.combined) {\n // Calculate wave intensity first\n const baseScale = 0.0005 + (1 - this._twinkleScaleValue) * 0.003;\n const waveSpeed = this._twinkleSpeedValue * 0.15;\n \n const wave1 = noise.noise2D(\n x * baseScale + _twinkleTime * waveSpeed,\n y * baseScale + _twinkleTime * waveSpeed * 0.5 + randomOffset\n );\n const wave2 = noise.noise2D(\n x * baseScale * 0.5 + _twinkleTime * waveSpeed * 0.3 + 50,\n y * baseScale * 0.7 - _twinkleTime * waveSpeed * 0.2 + randomOffset + 50\n );\n const wave3 = noise.noise2D(\n (x + y * 0.5) * baseScale * 0.8 + _twinkleTime * waveSpeed * 0.4,\n (y - x * 0.3) * baseScale * 0.8 + randomOffset + 100\n );\n \n const combined = (wave1 * 0.5 + wave2 * 0.3 + wave3 * 0.2);\n const smoothWave = (Math.sin(combined * Math.PI * 2) + 1) / 2;\n const waveIntensity = Math.pow(smoothWave, 0.5); // Smoother wave\n \n // Calculate sparkle\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n if (rand1 > this._twinkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const twinkleWave = Math.sin(_twinkleTime * this._twinkleSpeedValue * 2 + phase);\n const sparkle = Math.max(0, twinkleWave);\n \n // Base opacity is limited, wave boosts it to full\n const baseOpacity = effect.baseOpacity / 100;\n const maxBoost = 1 - baseOpacity;\n const finalOpacity = baseOpacity + (maxBoost * waveIntensity);\n \n opacity = sparkle * finalOpacity * effect.intensity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n }\n // Wave mode - flowing waves that boost opacity to 100%\n else if (effect.mode === 'wave') {\n // Create smooth, wide flowing light bands\n // Size controls the width of the bands\n const baseScale = 0.0005 + (1 - this._twinkleScaleValue) * 0.003;\n const waveSpeed = this._twinkleSpeedValue * 0.15;\n \n // Slow, smooth primary wave - creates wide bands\n const wave1 = noise.noise2D(\n x * baseScale + _twinkleTime * waveSpeed,\n y * baseScale + _twinkleTime * waveSpeed * 0.5 + randomOffset\n );\n \n // Very slow secondary wave for organic variation\n const wave2 = noise.noise2D(\n x * baseScale * 0.5 + _twinkleTime * waveSpeed * 0.3 + 50,\n y * baseScale * 0.7 - _twinkleTime * waveSpeed * 0.2 + randomOffset + 50\n );\n \n // Third wave for extra organic feel\n const wave3 = noise.noise2D(\n (x + y * 0.5) * baseScale * 0.8 + _twinkleTime * waveSpeed * 0.4,\n (y - x * 0.3) * baseScale * 0.8 + randomOffset + 100\n );\n \n // Combine waves smoothly\n const combined = (wave1 * 0.5 + wave2 * 0.3 + wave3 * 0.2);\n \n // Smooth sine-based intensity (no harsh ridges)\n const smoothWave = (Math.sin(combined * Math.PI * 2) + 1) / 2;\n \n // Apply density as band width control\n const densityFactor = 0.3 + this._twinkleThreshold * 0.7;\n const intensity = Math.pow(smoothWave, 1 / densityFactor);\n \n // Smooth the final output\n opacity = intensity * effect.intensity * centerFade;\n \n // Aurora colors for wave mode\n if (effect.aurora && opacity > 0) {\n const colorWave = noise.noise2D(\n x * baseScale * 0.3 + _twinkleTime * waveSpeed * 0.1 + randomOffset,\n y * baseScale * 0.3 + randomOffset\n );\n const colorBlend = (colorWave + 1) / 2;\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n } else {\n // Sparkle mode - original random twinkling\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n \n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n if (rand1 > this._twinkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const twinkleWave = Math.sin(_twinkleTime * this._twinkleSpeedValue + phase);\n const baseBrightness = Math.max(0, twinkleWave);\n \n const groupWave = noise.noise2D(\n x * this._twinkleScaleValue + _twinkleTime * 0.2 + randomOffset,\n y * this._twinkleScaleValue + randomOffset\n );\n const maxOpacity = 0.2 + (groupWave + 1) / 2 * 0.8;\n \n opacity = baseBrightness * maxOpacity * effect.intensity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n }\n }\n \n return { color, opacity };\n }\n\n /**\n * Apply collapse effect\n * @private\n */\n _applyCollapse(x, y, cols, rows, opacity, effectOpacity) {\n const centerX = cols / 2;\n const centerY = rows / 2;\n const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const normalizedDist = distFromCenter / maxRadius;\n \n const collapseAt = 1 - normalizedDist;\n \n if (this._collapseProgress > collapseAt + this.options.collapseWaveWidth) {\n opacity = 0;\n effectOpacity = 0;\n } else if (this._collapseProgress > collapseAt) {\n const t = 1 - (this._collapseProgress - collapseAt) / this.options.collapseWaveWidth;\n const smoothFade = t * t * (3 - 2 * t);\n opacity *= smoothFade;\n effectOpacity *= smoothFade;\n }\n \n return { opacity, effectOpacity };\n }\n\n /**\n * Update collapse animation\n * @private\n */\n _updateCollapse() {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n \n if (this._isCollapsing && this._collapseProgress < collapseEnd) {\n this._collapseProgress += this.options.collapseSpeed;\n if (this._collapseProgress >= collapseEnd) {\n this._collapseProgress = collapseEnd;\n if (this.options.onHide) {\n this.options.onHide();\n }\n }\n } else if (!this._isCollapsing && this._collapseProgress > 0) {\n this._collapseProgress -= this.options.collapseSpeed;\n if (this._collapseProgress <= 0) {\n this._collapseProgress = 0;\n if (this.options.onShow) {\n this.options.onShow();\n }\n }\n }\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Start the animation\n * @returns {Borealis} this instance for chaining\n */\n start() {\n if (!this._isRunning) {\n this._isRunning = true;\n this._lastFrameTime = performance.now();\n this._animationId = requestAnimationFrame(this._draw);\n }\n return this;\n }\n\n /**\n * Stop the animation\n * @returns {Borealis} this instance for chaining\n */\n stop() {\n this._isRunning = false;\n if (this._animationId) {\n cancelAnimationFrame(this._animationId);\n this._animationId = null;\n }\n return this;\n }\n\n /**\n * Manually trigger a resize (useful when container size changes)\n * @param {number} [width] - Optional new width\n * @param {number} [height] - Optional new height\n * @returns {Borealis} this instance for chaining\n */\n resize(width, height) {\n if (width !== undefined) {\n this.options.width = width;\n }\n if (height !== undefined) {\n this.options.height = height;\n }\n this._resize();\n return this;\n }\n\n /**\n * Force a single frame redraw (useful when animation is stopped)\n * @returns {Borealis} this instance for chaining\n */\n redraw() {\n const time = performance.now();\n const wasRunning = this._isRunning;\n this._isRunning = true;\n this._lastFrameTime = time - 16; // Simulate ~60fps frame\n \n // Draw single frame without requesting next\n const delta = 16;\n this._animTime += delta * this.options.animationSpeed;\n this._twinkleTime += delta * 0.001;\n \n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n \n if (this.options.solidPattern) {\n if (!this._offscreenCanvas || this._offscreenCanvas.width !== cols || this._offscreenCanvas.height !== rows) {\n this._offscreenCanvas = document.createElement('canvas');\n this._offscreenCanvas.width = cols;\n this._offscreenCanvas.height = rows;\n this._offscreenCtx = this._offscreenCanvas.getContext('2d');\n }\n \n const offCtx = this._offscreenCtx;\n const imageData = offCtx.createImageData(cols, rows);\n const data = imageData.data;\n \n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n const cellData = this._calculateCellData(x, y, cols, rows);\n const idx = (y * cols + x) * 4;\n data[idx] = cellData.r;\n data[idx + 1] = cellData.g;\n data[idx + 2] = cellData.b;\n data[idx + 3] = Math.round(cellData.opacity * 255);\n }\n }\n \n offCtx.putImageData(imageData, 0, 0);\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n this.ctx.drawImage(this._offscreenCanvas, 0, 0, this.canvas.width, this.canvas.height);\n \n if (this.options.effect.type !== 'none') {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawEffect(x, y, cols, rows);\n }\n }\n }\n } else {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawCell(x, y, cols, rows);\n }\n }\n }\n \n this._isRunning = wasRunning;\n return this;\n }\n\n /**\n * Show the pattern (expand from center)\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n show(callback) {\n this._isCollapsing = false;\n if (callback) {\n const originalCallback = this.options.onShow;\n this.options.onShow = () => {\n callback();\n this.options.onShow = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Hide the pattern (collapse to center)\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n hide(callback) {\n this._isCollapsing = true;\n if (callback) {\n const originalCallback = this.options.onHide;\n this.options.onHide = () => {\n callback();\n this.options.onHide = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Toggle between show and hide\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n toggle(callback) {\n if (this._isCollapsing) {\n return this.show(callback);\n } else {\n return this.hide(callback);\n }\n }\n\n /**\n * Check if currently visible (not collapsed)\n * @returns {boolean}\n */\n isVisible() {\n return !this._isCollapsing && this._collapseProgress === 0;\n }\n\n /**\n * Check if currently hidden (fully collapsed)\n * @returns {boolean}\n */\n isHidden() {\n return this._isCollapsing && this._collapseProgress >= 1 + this.options.collapseWaveWidth;\n }\n\n /**\n * Set a single option\n * @param {string} key - Option key\n * @param {*} value - Option value\n * @returns {Borealis} this instance for chaining\n */\n setOption(key, value) {\n // Handle effect as special case (use setEffect instead)\n if (key === 'effect') {\n if (typeof value === 'object') {\n return this.setEffect(value.type, value);\n }\n return this;\n }\n \n this.options[key] = value;\n \n // Handle special cases that need resize/recalculation\n const needsResize = [\n 'density', 'dotSize', 'solidPattern', 'patternAurora', \n 'maxOpacity', 'minOpacity'\n ];\n \n if (needsResize.includes(key)) {\n this._updateDensity(this.options.density);\n this._resize();\n }\n \n return this;\n }\n\n /**\n * Set effect type and options\n * @param {string} type - Effect type: 'none', 'wave', or 'twinkle'\n * @param {Object} [effectOptions] - Effect-specific options\n * @returns {Borealis} this instance for chaining\n */\n setEffect(type, effectOptions = {}) {\n // Update effect type\n if (type) {\n this.options.effect.type = type;\n }\n \n // Merge effect options\n Object.keys(effectOptions).forEach(key => {\n if (key !== 'type') {\n this.options.effect[key] = effectOptions[key];\n }\n });\n \n // Update internal computed values\n this._updateTwinkleSettings();\n this._updateDeadzone();\n this._resize();\n \n return this;\n }\n\n /**\n * Get current effect configuration\n * @returns {Object} Effect configuration with type and options\n */\n getEffect() {\n return { ...this.options.effect };\n }\n\n /**\n * Set multiple options at once\n * @param {Object} options - Options object\n * @returns {Borealis} this instance for chaining\n */\n setOptions(options) {\n Object.keys(options).forEach(key => {\n this.setOption(key, options[key]);\n });\n return this;\n }\n\n /**\n * Get current options\n * @returns {Object} Current options\n */\n getOptions() {\n return { ...this.options };\n }\n\n /**\n * Get a specific option value\n * @param {string} key - Option key\n * @returns {*} Option value\n */\n getOption(key) {\n return this.options[key];\n }\n\n /**\n * Destroy the instance and clean up\n */\n destroy() {\n this.stop();\n window.removeEventListener('resize', this._resize);\n \n if (this.canvas && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n \n this.canvas = null;\n this.ctx = null;\n this.noise = null;\n }\n}\n\nexport default Borealis;\n"],"names":["SimplexNoise","constructor","seed","Math","random","this","p","Uint8Array","i","j","perm","noise2D","x","y","F2","sqrt","G2","s","floor","t","x0","y0","i1","j1","x1","y1","x2","y2","ii","jj","grad","hash","h","u","v","n0","n1","n2","t0","t1","t2","Borealis","defaultOptions","container","document","body","width","height","fullscreen","density","dotSize","solidPattern","densityMinCell","densityMaxCell","densityMinGap","densityMaxGap","patternScale","patternAurora","warpScale","warpAmount","animationSpeed","ridgePower","minOpacity","maxOpacity","waveFrequency","waveAmplitude","effect","type","aurora","deadzone","speed","chance","intensity","delayMin","delayMax","combineSparkle","sparkleBaseOpacity","mode","combined","baseOpacity","twinkleSpeed","size","auroraColor1","auroraColor2","colorScale","collapseSpeed","collapseWaveWidth","autoStart","onShow","onHide","options","defaultEffect","userEffect","_init","canvas","createElement","style","cssText","insertBefore","firstChild","window","getComputedStyle","position","appendChild","ctx","getContext","noise","randomOffset","_cellSize","_gap","_gridSize","_sparkleMap","_animTime","_twinkleTime","_lastFrameTime","_sparkleWaiting","_sparkleWaitUntil","_diagPos","_isCollapsing","_collapseProgress","_isRunning","_animationId","_twinkleThreshold","_twinkleSpeedValue","_twinkleScaleValue","_deadzoneValue","_updateDensity","_updateTwinkleSettings","_updateDeadzone","_draw","bind","_resize","addEventListener","start","value","baseCell","sizeMultiplier","_generateSparkles","cols","rows","innerWidth","innerHeight","clientWidth","clientHeight","ceil","_offscreenCanvas","_offscreenCtx","time","delta","maxDiag","delay","clearRect","offCtx","imageData","createImageData","data","cellData","_calculateCellData","idx","r","g","b","round","opacity","putImageData","imageSmoothingEnabled","imageSmoothingQuality","drawImage","_drawEffect","_drawCell","_updateCollapse","requestAnimationFrame","wave1","sin","wave2","cos","warpX","warpY","noiseVal","ridge","abs","rawOpacity","pow","colorBlend","_applyCollapse","effectColor","effectOpacity","result","_calculateWaveEffect","color","_calculateTwinkleEffect","fillStyle","beginPath","arc","PI","fill","collapseResult","px","py","fillRect","centerX","centerY","distFromCenter","maxRadius","fadeZone","centerFade","cellDiag","distFromLine","waveProximity","max","smoothWaveProximity","hash1","rand1","hash2","rand2","phase","sparkleSpeed","twinkleWave","sparkle","colorRand","undefined","normalizedDist","fullDiagonalLength","min","diagStartX","diagEndX","currentLineLength","cylinderFade","posAlongLine","clampedPos","completeness","baseFade","baseScale","waveSpeed","smoothWave","waveIntensity","densityFactor","collapseAt","smoothFade","collapseEnd","performance","now","stop","cancelAnimationFrame","resize","redraw","wasRunning","show","callback","originalCallback","hide","toggle","isVisible","isHidden","setOption","key","setEffect","includes","effectOptions","Object","keys","forEach","getEffect","setOptions","getOptions","getOption","destroy","removeEventListener","parentNode","removeChild"],"mappings":"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"}
1
+ {"version":3,"file":"borealis.min.js","sources":["../src/borealis.js"],"sourcesContent":["/**\n * Borealis - Interactive Animated Background\n * A canvas-based particle animation system with noise patterns and effects\n * \n * @author Borealis\n * @version 1.0.0\n */\n\nclass SimplexNoise {\n constructor(seed = Math.random()) {\n this.p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) this.p[i] = i;\n \n for (let i = 255; i > 0; i--) {\n seed = (seed * 16807) % 2147483647;\n const j = seed % (i + 1);\n [this.p[i], this.p[j]] = [this.p[j], this.p[i]];\n }\n \n this.perm = new Uint8Array(512);\n for (let i = 0; i < 512; i++) this.perm[i] = this.p[i & 255];\n }\n\n noise2D(x, y) {\n const F2 = 0.5 * (Math.sqrt(3) - 1);\n const G2 = (3 - Math.sqrt(3)) / 6;\n \n const s = (x + y) * F2;\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n \n const t = (i + j) * G2;\n const X0 = i - t;\n const Y0 = j - t;\n const x0 = x - X0;\n const y0 = y - Y0;\n \n const i1 = x0 > y0 ? 1 : 0;\n const j1 = x0 > y0 ? 0 : 1;\n \n const x1 = x0 - i1 + G2;\n const y1 = y0 - j1 + G2;\n const x2 = x0 - 1 + 2 * G2;\n const y2 = y0 - 1 + 2 * G2;\n \n const ii = i & 255;\n const jj = j & 255;\n \n const grad = (hash, x, y) => {\n const h = hash & 7;\n const u = h < 4 ? x : y;\n const v = h < 4 ? y : x;\n return ((h & 1) ? -u : u) + ((h & 2) ? -2 * v : 2 * v);\n };\n \n let n0 = 0, n1 = 0, n2 = 0;\n \n let t0 = 0.5 - x0 * x0 - y0 * y0;\n if (t0 >= 0) {\n t0 *= t0;\n n0 = t0 * t0 * grad(this.perm[ii + this.perm[jj]], x0, y0);\n }\n \n let t1 = 0.5 - x1 * x1 - y1 * y1;\n if (t1 >= 0) {\n t1 *= t1;\n n1 = t1 * t1 * grad(this.perm[ii + i1 + this.perm[jj + j1]], x1, y1);\n }\n \n let t2 = 0.5 - x2 * x2 - y2 * y2;\n if (t2 >= 0) {\n t2 *= t2;\n n2 = t2 * t2 * grad(this.perm[ii + 1 + this.perm[jj + 1]], x2, y2);\n }\n \n return 70 * (n0 + n1 + n2);\n }\n}\n\nclass Borealis {\n /**\n * Default options for Borealis\n */\n static get defaultOptions() {\n return {\n // Container & Size\n container: document.body,\n width: null, // Canvas width (null = auto from container/window)\n height: null, // Canvas height (null = auto from container/window)\n fullscreen: true, // If true, uses fixed positioning to cover viewport\n zIndex: 0, // Canvas z-index (can be any integer)\n initiallyHidden: false, // If true, starts collapsed/hidden\n \n // Grid settings\n density: 50, // Grid density (10-100)\n dotSize: 5, // Dot size (0-10, 0=smallest)\n solidPattern: false, // Solid pattern without gaps/circles\n densityMinCell: 2, // Cell size at max density\n densityMaxCell: 8, // Cell size at min density\n densityMinGap: 1, // Gap at max density\n densityMaxGap: 4, // Gap at min density\n \n // Pattern settings\n patternScale: 0.001, // Noise scale (smaller = larger patterns)\n patternAurora: false, // Use aurora colors for pattern\n warpScale: 0.5, // Domain warp frequency multiplier\n warpAmount: 20, // Domain warp intensity\n animationSpeed: 0.00002, // Animation speed multiplier\n ridgePower: 2, // Ridge sharpness (higher = sharper lines)\n minOpacity: 0, // Minimum opacity (0-1)\n maxOpacity: 1, // Maximum opacity (0-1)\n waveFrequency: 3, // Wave oscillation frequency\n waveAmplitude: 0.5, // Wave intensity (0-1)\n \n // Effect settings (unified structure)\n effect: {\n type: 'wave', // 'none', 'wave', 'twinkle'\n aurora: false, // Use aurora colors for effect\n deadzone: 20, // Center dead zone size (0-100)\n // Wave-specific options\n speed: 0.0008, // Diagonal line speed\n width: 120, // Width of the wave band\n chance: 0.08, // Chance of a cell sparkling (0-1)\n intensity: 1, // Max brightness\n delayMin: 1000, // Min delay between sweeps (ms)\n delayMax: 3000, // Max delay between sweeps (ms)\n combineSparkle: false, // Add sparkles that get boosted by wave\n sparkleBaseOpacity: 0, // Sparkle base opacity when wave not passing (0-100)\n // Twinkle-specific options\n mode: 'sparkle', // 'sparkle' (random) or 'wave' (flowing waves)\n combined: false, // Combine sparkle with wave (sparkles boosted by wave)\n baseOpacity: 30, // Base opacity when wave is not passing (0-100)\n twinkleSpeed: 50, // Twinkle animation speed (10-100)\n size: 50, // Pattern size (10-100)\n density: 50, // Star density (0-100)\n },\n \n // Aurora colors\n auroraColor1: [0, 255, 128], // Cyan-green\n auroraColor2: [148, 0, 211], // Violet\n colorScale: 0.003, // Color variation scale\n \n // Collapse settings\n collapseSpeed: 0.1, // Collapse animation speed\n collapseWaveWidth: 0.4, // Width of the collapse transition\n \n // Animation\n autoStart: true, // Start animation automatically\n \n // Callbacks\n onShow: null, // Called when show animation completes\n onHide: null, // Called when hide animation completes\n };\n }\n\n /**\n * Create a new Borealis instance\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n // Deep merge for effect object\n const defaultEffect = Borealis.defaultOptions.effect;\n const userEffect = options.effect || {};\n \n this.options = { \n ...Borealis.defaultOptions, \n ...options,\n effect: { ...defaultEffect, ...userEffect }\n };\n this._init();\n }\n\n /**\n * Initialize the Borealis instance\n * @private\n */\n _init() {\n // Create canvas\n this.canvas = document.createElement('canvas');\n \n // Set canvas styles based on mode\n const zIndex = this.options.zIndex;\n if (this.options.fullscreen) {\n this.canvas.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: ${zIndex};\n `;\n } else {\n this.canvas.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: ${zIndex};\n `;\n }\n \n // Add to container\n const container = this.options.container;\n if (container === document.body && this.options.fullscreen) {\n document.body.insertBefore(this.canvas, document.body.firstChild);\n } else {\n // Ensure container has position for absolute positioning\n const containerStyle = window.getComputedStyle(container);\n if (containerStyle.position === 'static') {\n container.style.position = 'relative';\n }\n container.appendChild(this.canvas);\n }\n \n this.ctx = this.canvas.getContext('2d');\n this.noise = new SimplexNoise(Math.random() * 10000);\n this.randomOffset = Math.random() * 1000;\n \n // Internal state\n this._cellSize = 4;\n this._gap = 2;\n this._gridSize = 6;\n this._sparkleMap = {};\n this._animTime = 0;\n this._twinkleTime = 0;\n this._lastFrameTime = 0;\n this._sparkleWaiting = false;\n this._sparkleWaitUntil = 0;\n this._diagPos = 0;\n this._isCollapsing = this.options.initiallyHidden; // Stay collapsed until manual show() call\n this._collapseProgress = this.options.initiallyHidden ? 1 + this.options.collapseWaveWidth : 0; // Start fully hidden if initiallyHidden is true\n this._isRunning = false;\n this._animationId = null;\n \n // Computed twinkle values\n this._twinkleThreshold = 0.8;\n this._twinkleSpeedValue = 3;\n this._twinkleScaleValue = 0.01;\n this._deadzoneValue = 0.2;\n \n // Apply initial options\n this._updateDensity(this.options.density);\n this._updateTwinkleSettings();\n this._updateDeadzone();\n \n // Bind methods\n this._draw = this._draw.bind(this);\n this._resize = this._resize.bind(this);\n \n // Setup event listeners\n window.addEventListener('resize', this._resize);\n \n // Initial resize\n this._resize();\n \n // Auto start\n if (this.options.autoStart) {\n this.start();\n }\n }\n\n /**\n * Update density settings\n * @private\n */\n _updateDensity(value) {\n const t = (100 - value) / 90;\n const baseCell = this.options.densityMinCell + t * (this.options.densityMaxCell - this.options.densityMinCell);\n // Apply dotSize multiplier (0 = 0.3x, 5 = 1x, 10 = 2x)\n const sizeMultiplier = 0.3 + (this.options.dotSize / 10) * 1.7;\n this._cellSize = baseCell * sizeMultiplier;\n this._gap = this.options.densityMinGap + t * (this.options.densityMaxGap - this.options.densityMinGap);\n this._gridSize = this._cellSize + this._gap;\n }\n\n /**\n * Update twinkle settings from options\n * @private\n */\n _updateTwinkleSettings() {\n const effect = this.options.effect;\n // Speed: 10-100 maps to 1-6\n this._twinkleSpeedValue = 1 + (effect.twinkleSpeed - 10) / 90 * 5;\n // Size: 10-100 maps to 0.5-0.001 (inverted, much wider range)\n this._twinkleScaleValue = 0.5 - (effect.size - 10) / 90 * 0.499;\n // Density: 0-100 maps to threshold 1.0-0.1\n this._twinkleThreshold = 1 - effect.density / 100 * 0.9;\n }\n\n /**\n * Update deadzone setting (applies to all effects)\n * @private\n */\n _updateDeadzone() {\n // Deadzone: 0-100 maps to 0-1 (percentage of diagonal distance from center to corner)\n this._deadzoneValue = this.options.effect.deadzone / 100;\n }\n\n /**\n * Generate sparkle map\n * @private\n */\n _generateSparkles(cols, rows) {\n this._sparkleMap = {};\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n if (Math.random() < this.options.effect.chance) {\n this._sparkleMap[`${x},${y}`] = Math.random();\n }\n }\n }\n }\n\n /**\n * Resize handler\n * @private\n */\n _resize() {\n // Determine dimensions\n let width, height;\n \n if (this.options.width !== null && this.options.height !== null) {\n // Use explicit dimensions\n width = this.options.width;\n height = this.options.height;\n } else if (this.options.fullscreen) {\n // Use window dimensions\n width = window.innerWidth;\n height = window.innerHeight;\n } else {\n // Use container dimensions\n const container = this.options.container;\n width = this.options.width !== null ? this.options.width : container.clientWidth;\n height = this.options.height !== null ? this.options.height : container.clientHeight;\n }\n \n this.canvas.width = width;\n this.canvas.height = height;\n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n this._generateSparkles(cols, rows);\n // Clear offscreen canvas cache on resize\n this._offscreenCanvas = null;\n this._offscreenCtx = null;\n }\n\n /**\n * Main draw loop\n * @private\n */\n _draw(time) {\n if (!this._isRunning) return;\n \n const delta = time - this._lastFrameTime;\n \n this._animTime += delta * this.options.animationSpeed;\n this._twinkleTime += delta * 0.001;\n \n // Handle wave timing\n const effect = this.options.effect;\n if (!this._sparkleWaiting) {\n this._diagPos += delta * effect.speed * 100;\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n const maxDiag = cols + rows;\n \n if (this._diagPos > maxDiag + effect.width) {\n this._sparkleWaiting = true;\n const delay = effect.delayMin + Math.random() * (effect.delayMax - effect.delayMin);\n this._sparkleWaitUntil = time + delay;\n this._generateSparkles(cols, rows);\n }\n } else {\n if (time >= this._sparkleWaitUntil) {\n this._sparkleWaiting = false;\n this._diagPos = -effect.width;\n }\n }\n \n this._lastFrameTime = time;\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n \n // For solid pattern, use offscreen canvas for pixel-perfect base pattern\n if (this.options.solidPattern) {\n // Create or reuse offscreen canvas at grid resolution\n if (!this._offscreenCanvas || this._offscreenCanvas.width !== cols || this._offscreenCanvas.height !== rows) {\n this._offscreenCanvas = document.createElement('canvas');\n this._offscreenCanvas.width = cols;\n this._offscreenCanvas.height = rows;\n this._offscreenCtx = this._offscreenCanvas.getContext('2d');\n }\n \n const offCtx = this._offscreenCtx;\n const imageData = offCtx.createImageData(cols, rows);\n const data = imageData.data;\n \n // Draw only base pattern to ImageData (no effects)\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n const cellData = this._calculateCellData(x, y, cols, rows);\n \n const idx = (y * cols + x) * 4;\n data[idx] = cellData.r;\n data[idx + 1] = cellData.g;\n data[idx + 2] = cellData.b;\n data[idx + 3] = Math.round(cellData.opacity * 255);\n }\n }\n \n offCtx.putImageData(imageData, 0, 0);\n \n // Scale up to full canvas size with smooth interpolation\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n this.ctx.drawImage(this._offscreenCanvas, 0, 0, this.canvas.width, this.canvas.height);\n \n // Draw effects on top using regular canvas API (crisp circles)\n if (this.options.effect.type !== 'none') {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawEffect(x, y, cols, rows);\n }\n }\n }\n } else {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawCell(x, y, cols, rows);\n }\n }\n }\n \n // Update collapse\n this._updateCollapse();\n \n this._animationId = requestAnimationFrame(this._draw);\n }\n\n /**\n * Calculate cell data for solid pattern (used for ImageData rendering)\n * @private\n */\n _calculateCellData(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime } = this;\n \n // Oscillating wave effect\n const wave1 = Math.sin(_animTime * options.waveFrequency + x * options.patternScale * 10) * options.waveAmplitude;\n const wave2 = Math.cos(_animTime * options.waveFrequency * 0.7 + y * options.patternScale * 10) * options.waveAmplitude;\n \n // Domain warping\n const warpX = noise.noise2D(x * options.patternScale * options.warpScale + wave1 + randomOffset, y * options.patternScale * options.warpScale + _animTime + randomOffset) * options.warpAmount;\n const warpY = noise.noise2D(x * options.patternScale * options.warpScale + 100 + randomOffset, y * options.patternScale * options.warpScale + _animTime + wave2 + randomOffset) * options.warpAmount;\n \n const noiseVal = noise.noise2D(\n (x + warpX) * options.patternScale + wave2 * 0.5 + randomOffset,\n (y + warpY) * options.patternScale + wave1 * 0.5 + randomOffset\n );\n \n // Ridge noise\n const ridge = 1 - Math.abs(noiseVal);\n const rawOpacity = Math.pow(ridge, options.ridgePower);\n let opacity = options.minOpacity + rawOpacity * (options.maxOpacity - options.minOpacity);\n \n // Pattern color (no effects in solid pattern base - effects drawn separately)\n let r, g, b;\n if (options.patternAurora) {\n const colorNoise = noise.noise2D(x * options.colorScale + randomOffset * 0.5, y * options.colorScale + _animTime * 0.5 + randomOffset * 0.5);\n const colorBlend = (colorNoise + 1) / 2;\n r = Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend);\n g = Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend);\n b = Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend);\n } else {\n r = g = b = 255;\n }\n \n // Apply collapse (only base pattern, no effect)\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, opacity, 0);\n opacity = collapseResult.opacity;\n }\n \n return { r, g, b, opacity };\n }\n\n /**\n * Draw only effect for a cell (used in solid pattern mode)\n * @private\n */\n _drawEffect(x, y, cols, rows) {\n const effect = this.options.effect;\n \n let effectColor = [255, 255, 255];\n let effectOpacity = 0;\n \n // Wave effect\n if (effect.type === 'wave' && !this._sparkleWaiting) {\n const result = this._calculateWaveEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Twinkle effect\n if (effect.type === 'twinkle') {\n const result = this._calculateTwinkleEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Apply collapse\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, 0, effectOpacity);\n effectOpacity = collapseResult.effectOpacity;\n }\n \n // Draw effect circle if visible\n if (effectOpacity > 0) {\n this.ctx.fillStyle = `rgba(${effectColor[0]}, ${effectColor[1]}, ${effectColor[2]}, ${effectOpacity})`;\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n }\n\n /**\n * Draw a single cell\n * @private\n */\n _drawCell(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime, _twinkleTime } = this;\n \n // Oscillating wave effect\n const wave1 = Math.sin(_animTime * options.waveFrequency + x * options.patternScale * 10) * options.waveAmplitude;\n const wave2 = Math.cos(_animTime * options.waveFrequency * 0.7 + y * options.patternScale * 10) * options.waveAmplitude;\n \n // Domain warping\n const warpX = noise.noise2D(x * options.patternScale * options.warpScale + wave1 + randomOffset, y * options.patternScale * options.warpScale + _animTime + randomOffset) * options.warpAmount;\n const warpY = noise.noise2D(x * options.patternScale * options.warpScale + 100 + randomOffset, y * options.patternScale * options.warpScale + _animTime + wave2 + randomOffset) * options.warpAmount;\n \n const noiseVal = noise.noise2D(\n (x + warpX) * options.patternScale + wave2 * 0.5 + randomOffset,\n (y + warpY) * options.patternScale + wave1 * 0.5 + randomOffset\n );\n \n // Ridge noise\n const ridge = 1 - Math.abs(noiseVal);\n const rawOpacity = Math.pow(ridge, options.ridgePower);\n let opacity = options.minOpacity + rawOpacity * (options.maxOpacity - options.minOpacity);\n \n // Effect variables\n let effectColor = [255, 255, 255];\n let effectOpacity = 0;\n \n // Wave effect\n if (options.effect.type === 'wave' && !this._sparkleWaiting) {\n const result = this._calculateWaveEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Twinkle effect\n if (options.effect.type === 'twinkle') {\n const result = this._calculateTwinkleEffect(x, y, cols, rows);\n effectColor = result.color;\n effectOpacity = result.opacity;\n }\n \n // Pattern color\n let r, g, b;\n if (options.patternAurora) {\n const colorNoise = noise.noise2D(x * options.colorScale + randomOffset * 0.5, y * options.colorScale + _animTime * 0.5 + randomOffset * 0.5);\n const colorBlend = (colorNoise + 1) / 2;\n r = Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend);\n g = Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend);\n b = Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend);\n } else {\n r = g = b = 255;\n }\n \n // Apply collapse\n if (this._collapseProgress > 0) {\n const collapseResult = this._applyCollapse(x, y, cols, rows, opacity, effectOpacity);\n opacity = collapseResult.opacity;\n effectOpacity = collapseResult.effectOpacity;\n }\n \n // Skip rendering if both opacities are 0 (performance optimization)\n if (opacity <= 0 && effectOpacity <= 0) {\n return;\n }\n \n // Draw base pattern\n this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${opacity})`;\n if (this.options.solidPattern) {\n // Solid mode: fill entire cell without gaps (add 0.5px overlap to prevent gaps)\n const px = Math.floor(x * this._gridSize);\n const py = Math.floor(y * this._gridSize);\n this.ctx.fillRect(px, py, Math.ceil(this._gridSize) + 1, Math.ceil(this._gridSize) + 1);\n } else {\n // Circle mode\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n \n // Draw effect on top (always circles)\n if (effectOpacity > 0) {\n this.ctx.fillStyle = `rgba(${effectColor[0]}, ${effectColor[1]}, ${effectColor[2]}, ${effectOpacity})`;\n this.ctx.beginPath();\n this.ctx.arc(x * this._gridSize + this._cellSize / 2, y * this._gridSize + this._cellSize / 2, this._cellSize / 2, 0, Math.PI * 2);\n this.ctx.fill();\n }\n }\n\n /**\n * Calculate wave effect\n * @private\n */\n _calculateWaveEffect(x, y, cols, rows) {\n const { options, noise, randomOffset, _animTime, _twinkleTime } = this;\n const effect = options.effect;\n let color = [255, 255, 255];\n let opacity = 0;\n \n // Dead zone calculation (using diagonal distance to corner)\n const centerX = cols / 2;\n const centerY = rows / 2;\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const maxDist = Math.sqrt(centerX ** 2 + centerY ** 2); // Distance from center to corner\n const maxRadius = maxDist * this._deadzoneValue;\n const fadeZone = maxRadius * 0.3;\n \n let centerFade = 1;\n if (distFromCenter < maxRadius) {\n centerFade = 0;\n } else if (distFromCenter < maxRadius + fadeZone) {\n const t = (distFromCenter - maxRadius) / fadeZone;\n centerFade = t * t * (3 - 2 * t);\n }\n \n // Combined sparkle mode - sparkles that get boosted by wave\n if (effect.combineSparkle && centerFade > 0) {\n // Calculate wave proximity (0-1, 1 = wave is here)\n const cellDiag = x + y;\n const distFromLine = Math.abs(cellDiag - this._diagPos);\n // Narrower wave effect zone for more dramatic boost\n const waveProximity = Math.max(0, 1 - distFromLine / effect.width);\n // Sharper falloff - wave effect drops quickly\n const smoothWaveProximity = Math.pow(waveProximity, 0.5);\n \n // Calculate sparkle\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n // Use twinkle density for sparkle distribution\n const sparkleThreshold = 1 - effect.density / 100 * 0.9;\n \n if (rand1 > sparkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const sparkleSpeed = 0.1 + (effect.twinkleSpeed / 100) * 0.4;\n const twinkleWave = Math.sin(_twinkleTime * sparkleSpeed + phase);\n const sparkle = Math.max(0, twinkleWave);\n \n // Base opacity is limited, wave boosts it to full\n const baseOpacity = effect.sparkleBaseOpacity / 100;\n const maxBoost = 1 - baseOpacity;\n const finalOpacity = baseOpacity + (maxBoost * smoothWaveProximity);\n \n opacity = sparkle * finalOpacity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n \n return { color, opacity };\n }\n \n const cellDiag = x + y;\n const distFromLine = Math.abs(cellDiag - this._diagPos);\n \n if (distFromLine < effect.width && this._sparkleMap[`${x},${y}`] !== undefined) {\n const normalizedDist = distFromLine / effect.width;\n const sparkle = Math.cos(normalizedDist * Math.PI * 0.5) * effect.intensity;\n \n // Cylinder effect\n const fullDiagonalLength = Math.min(cols, rows);\n const diagStartX = Math.max(0, Math.floor(this._diagPos) - (rows - 1));\n const diagEndX = Math.min(cols - 1, Math.floor(this._diagPos));\n const currentLineLength = Math.max(1, diagEndX - diagStartX + 1);\n \n let cylinderFade = 1;\n if (currentLineLength >= fullDiagonalLength && currentLineLength > 1) {\n const posAlongLine = (x - diagStartX) / (currentLineLength - 1);\n const clampedPos = Math.max(0, Math.min(1, posAlongLine));\n cylinderFade = 0.3 + 0.7 * Math.sin(clampedPos * Math.PI);\n } else if (currentLineLength > 1) {\n const completeness = currentLineLength / fullDiagonalLength;\n const posAlongLine = (x - diagStartX) / (currentLineLength - 1);\n const clampedPos = Math.max(0, Math.min(1, posAlongLine));\n const baseFade = Math.sin(clampedPos * Math.PI);\n cylinderFade = Math.max(0.3, 1 - (1 - baseFade) * completeness * 0.7);\n }\n \n opacity = sparkle * this._sparkleMap[`${x},${y}`] * Math.max(0, cylinderFade) * centerFade;\n \n // Color\n if (effect.aurora) {\n const colorNoise = noise.noise2D(x * options.colorScale * 2 + randomOffset, y * options.colorScale * 2 + _animTime + randomOffset);\n const colorBlend = (colorNoise + 1) / 2;\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n \n return { color, opacity };\n }\n\n /**\n * Calculate twinkle effect\n * @private\n */\n _calculateTwinkleEffect(x, y, cols, rows) {\n const { options, noise, randomOffset, _twinkleTime } = this;\n const effect = options.effect;\n let color = [255, 255, 255];\n let opacity = 0;\n \n // Dead zone calculation (using diagonal distance to corner)\n const centerX = cols / 2;\n const centerY = rows / 2;\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const maxDist = Math.sqrt(centerX ** 2 + centerY ** 2); // Distance from center to corner\n const maxRadius = maxDist * this._deadzoneValue;\n const fadeZone = maxRadius * 0.3;\n \n let centerFade = 1;\n if (distFromCenter < maxRadius) {\n centerFade = 0;\n } else if (distFromCenter < maxRadius + fadeZone) {\n const t = (distFromCenter - maxRadius) / fadeZone;\n centerFade = t * t * (3 - 2 * t);\n }\n \n if (centerFade > 0) {\n // Combined mode - sparkles that get boosted by passing waves\n if (effect.combined) {\n // Calculate wave intensity first\n const baseScale = 0.0005 + (1 - this._twinkleScaleValue) * 0.003;\n const waveSpeed = this._twinkleSpeedValue * 0.15;\n \n const wave1 = noise.noise2D(\n x * baseScale + _twinkleTime * waveSpeed,\n y * baseScale + _twinkleTime * waveSpeed * 0.5 + randomOffset\n );\n const wave2 = noise.noise2D(\n x * baseScale * 0.5 + _twinkleTime * waveSpeed * 0.3 + 50,\n y * baseScale * 0.7 - _twinkleTime * waveSpeed * 0.2 + randomOffset + 50\n );\n const wave3 = noise.noise2D(\n (x + y * 0.5) * baseScale * 0.8 + _twinkleTime * waveSpeed * 0.4,\n (y - x * 0.3) * baseScale * 0.8 + randomOffset + 100\n );\n \n const combined = (wave1 * 0.5 + wave2 * 0.3 + wave3 * 0.2);\n const smoothWave = (Math.sin(combined * Math.PI * 2) + 1) / 2;\n const waveIntensity = Math.pow(smoothWave, 0.5); // Smoother wave\n \n // Calculate sparkle\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n if (rand1 > this._twinkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const twinkleWave = Math.sin(_twinkleTime * this._twinkleSpeedValue * 2 + phase);\n const sparkle = Math.max(0, twinkleWave);\n \n // Base opacity is limited, wave boosts it to full\n const baseOpacity = effect.baseOpacity / 100;\n const maxBoost = 1 - baseOpacity;\n const finalOpacity = baseOpacity + (maxBoost * waveIntensity);\n \n opacity = sparkle * finalOpacity * effect.intensity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n }\n // Wave mode - flowing waves that boost opacity to 100%\n else if (effect.mode === 'wave') {\n // Create smooth, wide flowing light bands\n // Size controls the width of the bands\n const baseScale = 0.0005 + (1 - this._twinkleScaleValue) * 0.003;\n const waveSpeed = this._twinkleSpeedValue * 0.15;\n \n // Slow, smooth primary wave - creates wide bands\n const wave1 = noise.noise2D(\n x * baseScale + _twinkleTime * waveSpeed,\n y * baseScale + _twinkleTime * waveSpeed * 0.5 + randomOffset\n );\n \n // Very slow secondary wave for organic variation\n const wave2 = noise.noise2D(\n x * baseScale * 0.5 + _twinkleTime * waveSpeed * 0.3 + 50,\n y * baseScale * 0.7 - _twinkleTime * waveSpeed * 0.2 + randomOffset + 50\n );\n \n // Third wave for extra organic feel\n const wave3 = noise.noise2D(\n (x + y * 0.5) * baseScale * 0.8 + _twinkleTime * waveSpeed * 0.4,\n (y - x * 0.3) * baseScale * 0.8 + randomOffset + 100\n );\n \n // Combine waves smoothly\n const combined = (wave1 * 0.5 + wave2 * 0.3 + wave3 * 0.2);\n \n // Smooth sine-based intensity (no harsh ridges)\n const smoothWave = (Math.sin(combined * Math.PI * 2) + 1) / 2;\n \n // Apply density as band width control\n const densityFactor = 0.3 + this._twinkleThreshold * 0.7;\n const intensity = Math.pow(smoothWave, 1 / densityFactor);\n \n // Smooth the final output\n opacity = intensity * effect.intensity * centerFade;\n \n // Aurora colors for wave mode\n if (effect.aurora && opacity > 0) {\n const colorWave = noise.noise2D(\n x * baseScale * 0.3 + _twinkleTime * waveSpeed * 0.1 + randomOffset,\n y * baseScale * 0.3 + randomOffset\n );\n const colorBlend = (colorWave + 1) / 2;\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n } else {\n // Sparkle mode - original random twinkling\n const hash1 = Math.sin(x * 12.9898 + y * 78.233 + randomOffset) * 43758.5453;\n const rand1 = hash1 - Math.floor(hash1);\n \n const hash2 = Math.sin(x * 93.9898 + y * 67.345 + randomOffset * 2) * 23421.6312;\n const rand2 = hash2 - Math.floor(hash2);\n \n if (rand1 > this._twinkleThreshold) {\n const phase = rand2 * Math.PI * 2;\n const twinkleWave = Math.sin(_twinkleTime * this._twinkleSpeedValue + phase);\n const baseBrightness = Math.max(0, twinkleWave);\n \n const groupWave = noise.noise2D(\n x * this._twinkleScaleValue + _twinkleTime * 0.2 + randomOffset,\n y * this._twinkleScaleValue + randomOffset\n );\n const maxOpacity = 0.2 + (groupWave + 1) / 2 * 0.8;\n \n opacity = baseBrightness * maxOpacity * effect.intensity * centerFade;\n \n if (effect.aurora) {\n const colorRand = Math.sin(x * 45.123 + y * 89.456 + randomOffset) * 12345.6789;\n const colorBlend = colorRand - Math.floor(colorRand);\n color = [\n Math.round(options.auroraColor1[0] + (options.auroraColor2[0] - options.auroraColor1[0]) * colorBlend),\n Math.round(options.auroraColor1[1] + (options.auroraColor2[1] - options.auroraColor1[1]) * colorBlend),\n Math.round(options.auroraColor1[2] + (options.auroraColor2[2] - options.auroraColor1[2]) * colorBlend)\n ];\n }\n }\n }\n }\n \n return { color, opacity };\n }\n\n /**\n * Apply collapse effect\n * @private\n */\n _applyCollapse(x, y, cols, rows, opacity, effectOpacity) {\n const centerX = cols / 2;\n const centerY = rows / 2;\n const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);\n const distFromCenter = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n const normalizedDist = distFromCenter / maxRadius;\n \n const collapseAt = 1 - normalizedDist;\n \n if (this._collapseProgress > collapseAt + this.options.collapseWaveWidth) {\n opacity = 0;\n effectOpacity = 0;\n } else if (this._collapseProgress > collapseAt) {\n const t = 1 - (this._collapseProgress - collapseAt) / this.options.collapseWaveWidth;\n const smoothFade = t * t * (3 - 2 * t);\n opacity *= smoothFade;\n effectOpacity *= smoothFade;\n }\n \n return { opacity, effectOpacity };\n }\n\n /**\n * Update collapse animation\n * @private\n */\n _updateCollapse() {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n \n if (this._isCollapsing && this._collapseProgress < collapseEnd) {\n this._collapseProgress += this.options.collapseSpeed;\n if (this._collapseProgress >= collapseEnd) {\n this._collapseProgress = collapseEnd;\n if (this.options.onHide) {\n this.options.onHide();\n }\n }\n } else if (!this._isCollapsing && this._collapseProgress > 0) {\n this._collapseProgress -= this.options.collapseSpeed;\n if (this._collapseProgress <= 0) {\n this._collapseProgress = 0;\n if (this.options.onShow) {\n this.options.onShow();\n }\n }\n }\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Start the animation\n * @returns {Borealis} this instance for chaining\n */\n start() {\n if (!this._isRunning) {\n this._isRunning = true;\n this._lastFrameTime = performance.now();\n this._animationId = requestAnimationFrame(this._draw);\n }\n return this;\n }\n\n /**\n * Stop the animation\n * @returns {Borealis} this instance for chaining\n */\n stop() {\n this._isRunning = false;\n if (this._animationId) {\n cancelAnimationFrame(this._animationId);\n this._animationId = null;\n }\n return this;\n }\n\n /**\n * Manually trigger a resize (useful when container size changes)\n * @param {number} [width] - Optional new width\n * @param {number} [height] - Optional new height\n * @returns {Borealis} this instance for chaining\n */\n resize(width, height) {\n if (width !== undefined) {\n this.options.width = width;\n }\n if (height !== undefined) {\n this.options.height = height;\n }\n this._resize();\n return this;\n }\n\n /**\n * Force a single frame redraw (useful when animation is stopped)\n * @returns {Borealis} this instance for chaining\n */\n redraw() {\n const time = performance.now();\n const wasRunning = this._isRunning;\n this._isRunning = true;\n this._lastFrameTime = time - 16; // Simulate ~60fps frame\n \n // Draw single frame without requesting next\n const delta = 16;\n this._animTime += delta * this.options.animationSpeed;\n this._twinkleTime += delta * 0.001;\n \n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n const cols = Math.ceil(this.canvas.width / this._gridSize);\n const rows = Math.ceil(this.canvas.height / this._gridSize);\n \n if (this.options.solidPattern) {\n if (!this._offscreenCanvas || this._offscreenCanvas.width !== cols || this._offscreenCanvas.height !== rows) {\n this._offscreenCanvas = document.createElement('canvas');\n this._offscreenCanvas.width = cols;\n this._offscreenCanvas.height = rows;\n this._offscreenCtx = this._offscreenCanvas.getContext('2d');\n }\n \n const offCtx = this._offscreenCtx;\n const imageData = offCtx.createImageData(cols, rows);\n const data = imageData.data;\n \n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n const cellData = this._calculateCellData(x, y, cols, rows);\n const idx = (y * cols + x) * 4;\n data[idx] = cellData.r;\n data[idx + 1] = cellData.g;\n data[idx + 2] = cellData.b;\n data[idx + 3] = Math.round(cellData.opacity * 255);\n }\n }\n \n offCtx.putImageData(imageData, 0, 0);\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n this.ctx.drawImage(this._offscreenCanvas, 0, 0, this.canvas.width, this.canvas.height);\n \n if (this.options.effect.type !== 'none') {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawEffect(x, y, cols, rows);\n }\n }\n }\n } else {\n for (let y = 0; y < rows; y++) {\n for (let x = 0; x < cols; x++) {\n this._drawCell(x, y, cols, rows);\n }\n }\n }\n \n this._isRunning = wasRunning;\n return this;\n }\n\n /**\n * Show the pattern (expand from center)\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n show(callback) {\n this._isCollapsing = false;\n if (callback) {\n const originalCallback = this.options.onShow;\n this.options.onShow = () => {\n callback();\n this.options.onShow = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Hide the pattern (collapse to center)\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n hide(callback) {\n this._isCollapsing = true;\n if (callback) {\n const originalCallback = this.options.onHide;\n this.options.onHide = () => {\n callback();\n this.options.onHide = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Toggle between show and hide\n * @param {Function} [callback] - Called when animation completes\n * @returns {Borealis} this instance for chaining\n */\n toggle(callback) {\n if (this._isCollapsing) {\n return this.show(callback);\n } else {\n return this.hide(callback);\n }\n }\n\n /**\n * Check if currently visible (not collapsed)\n * @returns {boolean}\n */\n isVisible() {\n return !this._isCollapsing && this._collapseProgress === 0;\n }\n\n /**\n * Check if currently hidden (fully collapsed)\n * @returns {boolean}\n */\n isHidden() {\n return this._isCollapsing && this._collapseProgress >= 1 + this.options.collapseWaveWidth;\n }\n\n /**\n * Set a single option\n * @param {string} key - Option key\n * @param {*} value - Option value\n * @returns {Borealis} this instance for chaining\n */\n setOption(key, value) {\n // Handle effect as special case (use setEffect instead)\n if (key === 'effect') {\n if (typeof value === 'object') {\n return this.setEffect(value.type, value);\n }\n return this;\n }\n \n this.options[key] = value;\n \n // Handle special cases that need resize/recalculation\n const needsResize = [\n 'density', 'dotSize', 'solidPattern', 'patternAurora', \n 'maxOpacity', 'minOpacity'\n ];\n \n if (needsResize.includes(key)) {\n this._updateDensity(this.options.density);\n this._resize();\n }\n \n return this;\n }\n\n /**\n * Set effect type and options\n * @param {string} type - Effect type: 'none', 'wave', or 'twinkle'\n * @param {Object} [effectOptions] - Effect-specific options\n * @returns {Borealis} this instance for chaining\n */\n setEffect(type, effectOptions = {}) {\n // Update effect type\n if (type) {\n this.options.effect.type = type;\n }\n \n // Merge effect options\n Object.keys(effectOptions).forEach(key => {\n if (key !== 'type') {\n this.options.effect[key] = effectOptions[key];\n }\n });\n \n // Update internal computed values\n this._updateTwinkleSettings();\n this._updateDeadzone();\n this._resize();\n \n return this;\n }\n\n /**\n * Get current effect configuration\n * @returns {Object} Effect configuration with type and options\n */\n getEffect() {\n return { ...this.options.effect };\n }\n\n /**\n * Set multiple options at once\n * @param {Object} options - Options object\n * @returns {Borealis} this instance for chaining\n */\n setOptions(options) {\n Object.keys(options).forEach(key => {\n this.setOption(key, options[key]);\n });\n return this;\n }\n\n /**\n * Get current options\n * @returns {Object} Current options\n */\n getOptions() {\n return { ...this.options };\n }\n\n /**\n * Get a specific option value\n * @param {string} key - Option key\n * @returns {*} Option value\n */\n getOption(key) {\n return this.options[key];\n }\n\n /**\n * Destroy the instance and clean up\n */\n destroy() {\n this.stop();\n window.removeEventListener('resize', this._resize);\n \n if (this.canvas && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n \n this.canvas = null;\n this.ctx = null;\n this.noise = null;\n }\n}\n\nexport default Borealis;\n"],"names":["SimplexNoise","constructor","seed","Math","random","this","p","Uint8Array","i","j","perm","noise2D","x","y","F2","sqrt","G2","s","floor","t","x0","y0","i1","j1","x1","y1","x2","y2","ii","jj","grad","hash","h","u","v","n0","n1","n2","t0","t1","t2","Borealis","defaultOptions","container","document","body","width","height","fullscreen","zIndex","initiallyHidden","density","dotSize","solidPattern","densityMinCell","densityMaxCell","densityMinGap","densityMaxGap","patternScale","patternAurora","warpScale","warpAmount","animationSpeed","ridgePower","minOpacity","maxOpacity","waveFrequency","waveAmplitude","effect","type","aurora","deadzone","speed","chance","intensity","delayMin","delayMax","combineSparkle","sparkleBaseOpacity","mode","combined","baseOpacity","twinkleSpeed","size","auroraColor1","auroraColor2","colorScale","collapseSpeed","collapseWaveWidth","autoStart","onShow","onHide","options","defaultEffect","userEffect","_init","canvas","createElement","style","cssText","insertBefore","firstChild","window","getComputedStyle","position","appendChild","ctx","getContext","noise","randomOffset","_cellSize","_gap","_gridSize","_sparkleMap","_animTime","_twinkleTime","_lastFrameTime","_sparkleWaiting","_sparkleWaitUntil","_diagPos","_isCollapsing","_collapseProgress","_isRunning","_animationId","_twinkleThreshold","_twinkleSpeedValue","_twinkleScaleValue","_deadzoneValue","_updateDensity","_updateTwinkleSettings","_updateDeadzone","_draw","bind","_resize","addEventListener","start","value","baseCell","sizeMultiplier","_generateSparkles","cols","rows","innerWidth","innerHeight","clientWidth","clientHeight","ceil","_offscreenCanvas","_offscreenCtx","time","delta","maxDiag","delay","clearRect","offCtx","imageData","createImageData","data","cellData","_calculateCellData","idx","r","g","b","round","opacity","putImageData","imageSmoothingEnabled","imageSmoothingQuality","drawImage","_drawEffect","_drawCell","_updateCollapse","requestAnimationFrame","wave1","sin","wave2","cos","warpX","warpY","noiseVal","ridge","abs","rawOpacity","pow","colorBlend","_applyCollapse","effectColor","effectOpacity","result","_calculateWaveEffect","color","_calculateTwinkleEffect","fillStyle","beginPath","arc","PI","fill","collapseResult","px","py","fillRect","centerX","centerY","distFromCenter","maxRadius","fadeZone","centerFade","cellDiag","distFromLine","waveProximity","max","smoothWaveProximity","hash1","rand1","hash2","rand2","phase","sparkleSpeed","twinkleWave","sparkle","colorRand","undefined","normalizedDist","fullDiagonalLength","min","diagStartX","diagEndX","currentLineLength","cylinderFade","posAlongLine","clampedPos","completeness","baseFade","baseScale","waveSpeed","smoothWave","waveIntensity","densityFactor","collapseAt","smoothFade","collapseEnd","performance","now","stop","cancelAnimationFrame","resize","redraw","wasRunning","show","callback","originalCallback","hide","toggle","isVisible","isHidden","setOption","key","setEffect","includes","effectOptions","Object","keys","forEach","getEffect","setOptions","getOptions","getOption","destroy","removeEventListener","parentNode","removeChild"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diabolic/borealis",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Interactive animated canvas background with noise patterns, wave effects, and aurora colors",
5
5
  "type": "module",
6
6
  "main": "dist/borealis.js",
@@ -25,8 +25,9 @@
25
25
  "access": "public"
26
26
  },
27
27
  "scripts": {
28
- "build": "rollup -c && cp src/borealis.d.ts dist/",
28
+ "build": "rollup -c && cp src/borealis.d.ts dist/ && cp dist/borealis.js docs/",
29
29
  "build:watch": "rollup -c -w",
30
+ "dev": "concurrently -k \"npm run build:watch\" \"npx live-server docs --port=8080 --wait=1000\" \"npx chokidar 'dist/borealis.js' -c 'cp dist/borealis.js docs/'\"",
30
31
  "prepublishOnly": "npm run build"
31
32
  },
32
33
  "repository": {
@@ -55,6 +56,8 @@
55
56
  "homepage": "https://bugrakaan.github.io/borealis/",
56
57
  "devDependencies": {
57
58
  "@rollup/plugin-terser": "^0.4.4",
59
+ "chokidar-cli": "^3.0.0",
60
+ "concurrently": "^9.2.1",
58
61
  "rollup": "^4.9.1"
59
62
  }
60
63
  }