@diabolic/borealis 1.0.3 → 1.0.5

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
@@ -253,6 +253,8 @@ borealis.destroy();
253
253
  | `fullscreen` | `boolean` | `true` | Use fixed positioning to cover viewport |
254
254
  | `zIndex` | `number` | `0` | Canvas z-index |
255
255
  | `initiallyHidden` | `boolean` | `false` | Start collapsed/hidden |
256
+ | `className` | `string \| null` | `null` | Custom class name for canvas |
257
+ | `background` | `string \| null` | `null` | Canvas background (color, gradient, etc.) |
256
258
 
257
259
  ### Grid Options
258
260
 
@@ -327,8 +329,15 @@ borealis.destroy();
327
329
 
328
330
  | Option | Type | Default | Description |
329
331
  |--------|------|---------|-------------|
330
- | `collapseSpeed` | `number` | `0.1` | Collapse/expand animation speed |
332
+ | `collapseSpeed` | `number` | `0.1` | Collapse/expand animation speed (used when duration not specified) |
331
333
  | `collapseWaveWidth` | `number` | `0.4` | Width of the collapse transition |
334
+ | `showDuration` | `number \| null` | `null` | Show animation duration in ms (null = use collapseSpeed) |
335
+ | `hideDuration` | `number \| null` | `null` | Hide animation duration in ms (null = use collapseSpeed) |
336
+ | `fadeOpacity` | `boolean` | `true` | Fade canvas opacity during show/hide animations |
337
+ | `revealingClass` | `string` | `'borealis-revealing'` | Class added during show animation |
338
+ | `visibleClass` | `string` | `'borealis-visible'` | Class added when fully visible |
339
+ | `hidingClass` | `string` | `'borealis-hiding'` | Class added during hide animation |
340
+ | `hiddenClass` | `string` | `'borealis-hidden'` | Class added when fully hidden |
332
341
 
333
342
  ### Animation Options
334
343
 
@@ -54,6 +54,10 @@ declare module '@diabolic/borealis' {
54
54
  zIndex?: number;
55
55
  /** If true, starts collapsed/hidden (default: false) */
56
56
  initiallyHidden?: boolean;
57
+ /** Custom class name for canvas */
58
+ className?: string | null;
59
+ /** Canvas background (color, gradient, etc.) */
60
+ background?: string | null;
57
61
 
58
62
  // Grid settings
59
63
  /** Grid density (10-100) */
@@ -106,10 +110,24 @@ declare module '@diabolic/borealis' {
106
110
  colorScale?: number;
107
111
 
108
112
  // Collapse settings
109
- /** Collapse animation speed */
113
+ /** Collapse animation speed (used when duration not specified) */
110
114
  collapseSpeed?: number;
111
115
  /** Width of the collapse transition */
112
116
  collapseWaveWidth?: number;
117
+ /** Show animation duration in ms (null = use collapseSpeed) */
118
+ showDuration?: number | null;
119
+ /** Hide animation duration in ms (null = use collapseSpeed) */
120
+ hideDuration?: number | null;
121
+ /** Fade canvas opacity during show/hide animations (default: true) */
122
+ fadeOpacity?: boolean;
123
+ /** Class added during show animation */
124
+ revealingClass?: string;
125
+ /** Class added when fully visible */
126
+ visibleClass?: string;
127
+ /** Class added during hide animation */
128
+ hidingClass?: string;
129
+ /** Class added when fully hidden */
130
+ hiddenClass?: string;
113
131
 
114
132
  // Animation
115
133
  /** Start animation automatically */
@@ -166,24 +184,27 @@ declare module '@diabolic/borealis' {
166
184
 
167
185
  /**
168
186
  * Show the pattern (expand from center)
169
- * @param callback - Called when animation completes
187
+ * @param durationOrCallback - Duration in ms or callback function
188
+ * @param callback - Called when animation completes (if first param is duration)
170
189
  * @returns this instance for chaining
171
190
  */
172
- show(callback?: () => void): this;
191
+ show(durationOrCallback?: number | (() => void), callback?: () => void): this;
173
192
 
174
193
  /**
175
194
  * Hide the pattern (collapse to center)
176
- * @param callback - Called when animation completes
195
+ * @param durationOrCallback - Duration in ms or callback function
196
+ * @param callback - Called when animation completes (if first param is duration)
177
197
  * @returns this instance for chaining
178
198
  */
179
- hide(callback?: () => void): this;
199
+ hide(durationOrCallback?: number | (() => void), callback?: () => void): this;
180
200
 
181
201
  /**
182
202
  * Toggle between show and hide
183
- * @param callback - Called when animation completes
203
+ * @param durationOrCallback - Duration in ms or callback function
204
+ * @param callback - Called when animation completes (if first param is duration)
184
205
  * @returns this instance for chaining
185
206
  */
186
- toggle(callback?: () => void): this;
207
+ toggle(durationOrCallback?: number | (() => void), callback?: () => void): this;
187
208
 
188
209
  /**
189
210
  * Check if currently visible (not collapsed)
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.3
3
+ * @version 1.0.5
4
4
  * @license MIT
5
5
  */
6
6
  /**
@@ -95,6 +95,8 @@ class Borealis {
95
95
  fullscreen: true, // If true, uses fixed positioning to cover viewport
96
96
  zIndex: 0, // Canvas z-index (can be any integer)
97
97
  initiallyHidden: false, // If true, starts collapsed/hidden
98
+ className: null, // Custom class name for canvas
99
+ background: null, // Canvas background (color, gradient, etc.)
98
100
 
99
101
  // Grid settings
100
102
  density: 50, // Grid density (10-100)
@@ -146,8 +148,15 @@ class Borealis {
146
148
  colorScale: 0.003, // Color variation scale
147
149
 
148
150
  // Collapse settings
149
- collapseSpeed: 0.1, // Collapse animation speed
151
+ collapseSpeed: 0.1, // Collapse animation speed (used when duration not specified)
150
152
  collapseWaveWidth: 0.4, // Width of the collapse transition
153
+ showDuration: null, // Show animation duration in ms (null = use collapseSpeed)
154
+ hideDuration: null, // Hide animation duration in ms (null = use collapseSpeed)
155
+ fadeOpacity: true, // Fade canvas opacity during show/hide animations
156
+ revealingClass: 'borealis-revealing', // Class added during show animation
157
+ visibleClass: 'borealis-visible', // Class added when fully visible
158
+ hidingClass: 'borealis-hiding', // Class added during hide animation
159
+ hiddenClass: 'borealis-hidden', // Class added when fully hidden
151
160
 
152
161
  // Animation
153
162
  autoStart: true, // Start animation automatically
@@ -183,8 +192,14 @@ class Borealis {
183
192
  // Create canvas
184
193
  this.canvas = document.createElement('canvas');
185
194
 
195
+ // Set custom class name if provided
196
+ if (this.options.className) {
197
+ this.canvas.className = this.options.className;
198
+ }
199
+
186
200
  // Set canvas styles based on mode
187
201
  const zIndex = this.options.zIndex;
202
+ const background = this.options.background ? `background: ${this.options.background};` : '';
188
203
  if (this.options.fullscreen) {
189
204
  this.canvas.style.cssText = `
190
205
  position: fixed;
@@ -194,6 +209,7 @@ class Borealis {
194
209
  height: 100%;
195
210
  pointer-events: none;
196
211
  z-index: ${zIndex};
212
+ ${background}
197
213
  `;
198
214
  } else {
199
215
  this.canvas.style.cssText = `
@@ -204,6 +220,7 @@ class Borealis {
204
220
  height: 100%;
205
221
  pointer-events: none;
206
222
  z-index: ${zIndex};
223
+ ${background}
207
224
  `;
208
225
  }
209
226
 
@@ -239,6 +256,17 @@ class Borealis {
239
256
  this._collapseProgress = this.options.initiallyHidden ? 1 + this.options.collapseWaveWidth : 0; // Start fully hidden if initiallyHidden is true
240
257
  this._isRunning = false;
241
258
  this._animationId = null;
259
+ this._showSpeed = null;
260
+ this._hideSpeed = null;
261
+
262
+ // Set initial CSS class and opacity based on initiallyHidden
263
+ if (this.options.initiallyHidden) {
264
+ if (this.options.hiddenClass) this.canvas.classList.add(this.options.hiddenClass);
265
+ if (this.options.fadeOpacity) this.canvas.style.opacity = 0;
266
+ } else {
267
+ if (this.options.visibleClass) this.canvas.classList.add(this.options.visibleClass);
268
+ if (this.options.fadeOpacity) this.canvas.style.opacity = 1;
269
+ }
242
270
 
243
271
  // Computed twinkle values
244
272
  this._twinkleThreshold = 0.8;
@@ -937,21 +965,74 @@ class Borealis {
937
965
  */
938
966
  _updateCollapse() {
939
967
  const collapseEnd = 1 + this.options.collapseWaveWidth;
968
+ const opts = this.options;
940
969
 
941
970
  if (this._isCollapsing && this._collapseProgress < collapseEnd) {
942
- this._collapseProgress += this.options.collapseSpeed;
971
+ // Use duration-based speed if hideDuration is set
972
+ const speed = this._hideSpeed || opts.collapseSpeed;
973
+ this._collapseProgress += speed;
974
+
975
+ // Update canvas opacity if fadeOpacity is enabled
976
+ if (opts.fadeOpacity) {
977
+ const progress = Math.min(this._collapseProgress / collapseEnd, 1);
978
+ this.canvas.style.opacity = 1 - progress;
979
+ }
980
+
981
+ // Update CSS classes
982
+ if (opts.hidingClass && !this.canvas.classList.contains(opts.hidingClass)) {
983
+ this.canvas.classList.remove(opts.revealingClass, opts.visibleClass);
984
+ this.canvas.classList.add(opts.hidingClass);
985
+ }
986
+
943
987
  if (this._collapseProgress >= collapseEnd) {
944
988
  this._collapseProgress = collapseEnd;
945
- if (this.options.onHide) {
946
- this.options.onHide();
989
+ this._hideSpeed = null;
990
+
991
+ // Set final opacity
992
+ if (opts.fadeOpacity) {
993
+ this.canvas.style.opacity = 0;
994
+ }
995
+
996
+ // Update CSS classes
997
+ if (opts.hidingClass) this.canvas.classList.remove(opts.hidingClass);
998
+ if (opts.hiddenClass) this.canvas.classList.add(opts.hiddenClass);
999
+
1000
+ if (opts.onHide) {
1001
+ opts.onHide();
947
1002
  }
948
1003
  }
949
1004
  } else if (!this._isCollapsing && this._collapseProgress > 0) {
950
- this._collapseProgress -= this.options.collapseSpeed;
1005
+ // Use duration-based speed if showDuration is set
1006
+ const speed = this._showSpeed || opts.collapseSpeed;
1007
+ this._collapseProgress -= speed;
1008
+
1009
+ // Update canvas opacity if fadeOpacity is enabled
1010
+ if (opts.fadeOpacity) {
1011
+ const progress = Math.max(this._collapseProgress / collapseEnd, 0);
1012
+ this.canvas.style.opacity = 1 - progress;
1013
+ }
1014
+
1015
+ // Update CSS classes
1016
+ if (opts.revealingClass && !this.canvas.classList.contains(opts.revealingClass)) {
1017
+ this.canvas.classList.remove(opts.hidingClass, opts.hiddenClass);
1018
+ this.canvas.classList.add(opts.revealingClass);
1019
+ }
1020
+
951
1021
  if (this._collapseProgress <= 0) {
952
1022
  this._collapseProgress = 0;
953
- if (this.options.onShow) {
954
- this.options.onShow();
1023
+ this._showSpeed = null;
1024
+
1025
+ // Set final opacity
1026
+ if (opts.fadeOpacity) {
1027
+ this.canvas.style.opacity = 1;
1028
+ }
1029
+
1030
+ // Update CSS classes
1031
+ if (opts.revealingClass) this.canvas.classList.remove(opts.revealingClass);
1032
+ if (opts.visibleClass) this.canvas.classList.add(opts.visibleClass);
1033
+
1034
+ if (opts.onShow) {
1035
+ opts.onShow();
955
1036
  }
956
1037
  }
957
1038
  }
@@ -1071,15 +1152,37 @@ class Borealis {
1071
1152
 
1072
1153
  /**
1073
1154
  * Show the pattern (expand from center)
1074
- * @param {Function} [callback] - Called when animation completes
1155
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1156
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1075
1157
  * @returns {Borealis} this instance for chaining
1076
1158
  */
1077
- show(callback) {
1159
+ show(durationOrCallback, callback) {
1160
+ let duration = null;
1161
+ let cb = null;
1162
+
1163
+ if (typeof durationOrCallback === 'function') {
1164
+ cb = durationOrCallback;
1165
+ } else if (typeof durationOrCallback === 'number') {
1166
+ duration = durationOrCallback;
1167
+ cb = callback;
1168
+ }
1169
+
1170
+ // Calculate speed from duration
1171
+ if (duration !== null) {
1172
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1173
+ const framesNeeded = duration / 16.67; // ~60fps
1174
+ this._showSpeed = collapseEnd / framesNeeded;
1175
+ } else if (this.options.showDuration) {
1176
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1177
+ const framesNeeded = this.options.showDuration / 16.67;
1178
+ this._showSpeed = collapseEnd / framesNeeded;
1179
+ }
1180
+
1078
1181
  this._isCollapsing = false;
1079
- if (callback) {
1182
+ if (cb) {
1080
1183
  const originalCallback = this.options.onShow;
1081
1184
  this.options.onShow = () => {
1082
- callback();
1185
+ cb();
1083
1186
  this.options.onShow = originalCallback;
1084
1187
  };
1085
1188
  }
@@ -1088,15 +1191,37 @@ class Borealis {
1088
1191
 
1089
1192
  /**
1090
1193
  * Hide the pattern (collapse to center)
1091
- * @param {Function} [callback] - Called when animation completes
1194
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1195
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1092
1196
  * @returns {Borealis} this instance for chaining
1093
1197
  */
1094
- hide(callback) {
1198
+ hide(durationOrCallback, callback) {
1199
+ let duration = null;
1200
+ let cb = null;
1201
+
1202
+ if (typeof durationOrCallback === 'function') {
1203
+ cb = durationOrCallback;
1204
+ } else if (typeof durationOrCallback === 'number') {
1205
+ duration = durationOrCallback;
1206
+ cb = callback;
1207
+ }
1208
+
1209
+ // Calculate speed from duration
1210
+ if (duration !== null) {
1211
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1212
+ const framesNeeded = duration / 16.67; // ~60fps
1213
+ this._hideSpeed = collapseEnd / framesNeeded;
1214
+ } else if (this.options.hideDuration) {
1215
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1216
+ const framesNeeded = this.options.hideDuration / 16.67;
1217
+ this._hideSpeed = collapseEnd / framesNeeded;
1218
+ }
1219
+
1095
1220
  this._isCollapsing = true;
1096
- if (callback) {
1221
+ if (cb) {
1097
1222
  const originalCallback = this.options.onHide;
1098
1223
  this.options.onHide = () => {
1099
- callback();
1224
+ cb();
1100
1225
  this.options.onHide = originalCallback;
1101
1226
  };
1102
1227
  }
@@ -1105,14 +1230,15 @@ class Borealis {
1105
1230
 
1106
1231
  /**
1107
1232
  * Toggle between show and hide
1108
- * @param {Function} [callback] - Called when animation completes
1233
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1234
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1109
1235
  * @returns {Borealis} this instance for chaining
1110
1236
  */
1111
- toggle(callback) {
1237
+ toggle(durationOrCallback, callback) {
1112
1238
  if (this._isCollapsing) {
1113
- return this.show(callback);
1239
+ return this.show(durationOrCallback, callback);
1114
1240
  } else {
1115
- return this.hide(callback);
1241
+ return this.hide(durationOrCallback, callback);
1116
1242
  }
1117
1243
  }
1118
1244
 
package/dist/borealis.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.3
3
+ * @version 1.0.5
4
4
  * @license MIT
5
5
  */
6
6
  (function (global, factory) {
@@ -101,6 +101,8 @@
101
101
  fullscreen: true, // If true, uses fixed positioning to cover viewport
102
102
  zIndex: 0, // Canvas z-index (can be any integer)
103
103
  initiallyHidden: false, // If true, starts collapsed/hidden
104
+ className: null, // Custom class name for canvas
105
+ background: null, // Canvas background (color, gradient, etc.)
104
106
 
105
107
  // Grid settings
106
108
  density: 50, // Grid density (10-100)
@@ -152,8 +154,15 @@
152
154
  colorScale: 0.003, // Color variation scale
153
155
 
154
156
  // Collapse settings
155
- collapseSpeed: 0.1, // Collapse animation speed
157
+ collapseSpeed: 0.1, // Collapse animation speed (used when duration not specified)
156
158
  collapseWaveWidth: 0.4, // Width of the collapse transition
159
+ showDuration: null, // Show animation duration in ms (null = use collapseSpeed)
160
+ hideDuration: null, // Hide animation duration in ms (null = use collapseSpeed)
161
+ fadeOpacity: true, // Fade canvas opacity during show/hide animations
162
+ revealingClass: 'borealis-revealing', // Class added during show animation
163
+ visibleClass: 'borealis-visible', // Class added when fully visible
164
+ hidingClass: 'borealis-hiding', // Class added during hide animation
165
+ hiddenClass: 'borealis-hidden', // Class added when fully hidden
157
166
 
158
167
  // Animation
159
168
  autoStart: true, // Start animation automatically
@@ -189,8 +198,14 @@
189
198
  // Create canvas
190
199
  this.canvas = document.createElement('canvas');
191
200
 
201
+ // Set custom class name if provided
202
+ if (this.options.className) {
203
+ this.canvas.className = this.options.className;
204
+ }
205
+
192
206
  // Set canvas styles based on mode
193
207
  const zIndex = this.options.zIndex;
208
+ const background = this.options.background ? `background: ${this.options.background};` : '';
194
209
  if (this.options.fullscreen) {
195
210
  this.canvas.style.cssText = `
196
211
  position: fixed;
@@ -200,6 +215,7 @@
200
215
  height: 100%;
201
216
  pointer-events: none;
202
217
  z-index: ${zIndex};
218
+ ${background}
203
219
  `;
204
220
  } else {
205
221
  this.canvas.style.cssText = `
@@ -210,6 +226,7 @@
210
226
  height: 100%;
211
227
  pointer-events: none;
212
228
  z-index: ${zIndex};
229
+ ${background}
213
230
  `;
214
231
  }
215
232
 
@@ -245,6 +262,17 @@
245
262
  this._collapseProgress = this.options.initiallyHidden ? 1 + this.options.collapseWaveWidth : 0; // Start fully hidden if initiallyHidden is true
246
263
  this._isRunning = false;
247
264
  this._animationId = null;
265
+ this._showSpeed = null;
266
+ this._hideSpeed = null;
267
+
268
+ // Set initial CSS class and opacity based on initiallyHidden
269
+ if (this.options.initiallyHidden) {
270
+ if (this.options.hiddenClass) this.canvas.classList.add(this.options.hiddenClass);
271
+ if (this.options.fadeOpacity) this.canvas.style.opacity = 0;
272
+ } else {
273
+ if (this.options.visibleClass) this.canvas.classList.add(this.options.visibleClass);
274
+ if (this.options.fadeOpacity) this.canvas.style.opacity = 1;
275
+ }
248
276
 
249
277
  // Computed twinkle values
250
278
  this._twinkleThreshold = 0.8;
@@ -943,21 +971,74 @@
943
971
  */
944
972
  _updateCollapse() {
945
973
  const collapseEnd = 1 + this.options.collapseWaveWidth;
974
+ const opts = this.options;
946
975
 
947
976
  if (this._isCollapsing && this._collapseProgress < collapseEnd) {
948
- this._collapseProgress += this.options.collapseSpeed;
977
+ // Use duration-based speed if hideDuration is set
978
+ const speed = this._hideSpeed || opts.collapseSpeed;
979
+ this._collapseProgress += speed;
980
+
981
+ // Update canvas opacity if fadeOpacity is enabled
982
+ if (opts.fadeOpacity) {
983
+ const progress = Math.min(this._collapseProgress / collapseEnd, 1);
984
+ this.canvas.style.opacity = 1 - progress;
985
+ }
986
+
987
+ // Update CSS classes
988
+ if (opts.hidingClass && !this.canvas.classList.contains(opts.hidingClass)) {
989
+ this.canvas.classList.remove(opts.revealingClass, opts.visibleClass);
990
+ this.canvas.classList.add(opts.hidingClass);
991
+ }
992
+
949
993
  if (this._collapseProgress >= collapseEnd) {
950
994
  this._collapseProgress = collapseEnd;
951
- if (this.options.onHide) {
952
- this.options.onHide();
995
+ this._hideSpeed = null;
996
+
997
+ // Set final opacity
998
+ if (opts.fadeOpacity) {
999
+ this.canvas.style.opacity = 0;
1000
+ }
1001
+
1002
+ // Update CSS classes
1003
+ if (opts.hidingClass) this.canvas.classList.remove(opts.hidingClass);
1004
+ if (opts.hiddenClass) this.canvas.classList.add(opts.hiddenClass);
1005
+
1006
+ if (opts.onHide) {
1007
+ opts.onHide();
953
1008
  }
954
1009
  }
955
1010
  } else if (!this._isCollapsing && this._collapseProgress > 0) {
956
- this._collapseProgress -= this.options.collapseSpeed;
1011
+ // Use duration-based speed if showDuration is set
1012
+ const speed = this._showSpeed || opts.collapseSpeed;
1013
+ this._collapseProgress -= speed;
1014
+
1015
+ // Update canvas opacity if fadeOpacity is enabled
1016
+ if (opts.fadeOpacity) {
1017
+ const progress = Math.max(this._collapseProgress / collapseEnd, 0);
1018
+ this.canvas.style.opacity = 1 - progress;
1019
+ }
1020
+
1021
+ // Update CSS classes
1022
+ if (opts.revealingClass && !this.canvas.classList.contains(opts.revealingClass)) {
1023
+ this.canvas.classList.remove(opts.hidingClass, opts.hiddenClass);
1024
+ this.canvas.classList.add(opts.revealingClass);
1025
+ }
1026
+
957
1027
  if (this._collapseProgress <= 0) {
958
1028
  this._collapseProgress = 0;
959
- if (this.options.onShow) {
960
- this.options.onShow();
1029
+ this._showSpeed = null;
1030
+
1031
+ // Set final opacity
1032
+ if (opts.fadeOpacity) {
1033
+ this.canvas.style.opacity = 1;
1034
+ }
1035
+
1036
+ // Update CSS classes
1037
+ if (opts.revealingClass) this.canvas.classList.remove(opts.revealingClass);
1038
+ if (opts.visibleClass) this.canvas.classList.add(opts.visibleClass);
1039
+
1040
+ if (opts.onShow) {
1041
+ opts.onShow();
961
1042
  }
962
1043
  }
963
1044
  }
@@ -1077,15 +1158,37 @@
1077
1158
 
1078
1159
  /**
1079
1160
  * Show the pattern (expand from center)
1080
- * @param {Function} [callback] - Called when animation completes
1161
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1162
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1081
1163
  * @returns {Borealis} this instance for chaining
1082
1164
  */
1083
- show(callback) {
1165
+ show(durationOrCallback, callback) {
1166
+ let duration = null;
1167
+ let cb = null;
1168
+
1169
+ if (typeof durationOrCallback === 'function') {
1170
+ cb = durationOrCallback;
1171
+ } else if (typeof durationOrCallback === 'number') {
1172
+ duration = durationOrCallback;
1173
+ cb = callback;
1174
+ }
1175
+
1176
+ // Calculate speed from duration
1177
+ if (duration !== null) {
1178
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1179
+ const framesNeeded = duration / 16.67; // ~60fps
1180
+ this._showSpeed = collapseEnd / framesNeeded;
1181
+ } else if (this.options.showDuration) {
1182
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1183
+ const framesNeeded = this.options.showDuration / 16.67;
1184
+ this._showSpeed = collapseEnd / framesNeeded;
1185
+ }
1186
+
1084
1187
  this._isCollapsing = false;
1085
- if (callback) {
1188
+ if (cb) {
1086
1189
  const originalCallback = this.options.onShow;
1087
1190
  this.options.onShow = () => {
1088
- callback();
1191
+ cb();
1089
1192
  this.options.onShow = originalCallback;
1090
1193
  };
1091
1194
  }
@@ -1094,15 +1197,37 @@
1094
1197
 
1095
1198
  /**
1096
1199
  * Hide the pattern (collapse to center)
1097
- * @param {Function} [callback] - Called when animation completes
1200
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1201
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1098
1202
  * @returns {Borealis} this instance for chaining
1099
1203
  */
1100
- hide(callback) {
1204
+ hide(durationOrCallback, callback) {
1205
+ let duration = null;
1206
+ let cb = null;
1207
+
1208
+ if (typeof durationOrCallback === 'function') {
1209
+ cb = durationOrCallback;
1210
+ } else if (typeof durationOrCallback === 'number') {
1211
+ duration = durationOrCallback;
1212
+ cb = callback;
1213
+ }
1214
+
1215
+ // Calculate speed from duration
1216
+ if (duration !== null) {
1217
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1218
+ const framesNeeded = duration / 16.67; // ~60fps
1219
+ this._hideSpeed = collapseEnd / framesNeeded;
1220
+ } else if (this.options.hideDuration) {
1221
+ const collapseEnd = 1 + this.options.collapseWaveWidth;
1222
+ const framesNeeded = this.options.hideDuration / 16.67;
1223
+ this._hideSpeed = collapseEnd / framesNeeded;
1224
+ }
1225
+
1101
1226
  this._isCollapsing = true;
1102
- if (callback) {
1227
+ if (cb) {
1103
1228
  const originalCallback = this.options.onHide;
1104
1229
  this.options.onHide = () => {
1105
- callback();
1230
+ cb();
1106
1231
  this.options.onHide = originalCallback;
1107
1232
  };
1108
1233
  }
@@ -1111,14 +1236,15 @@
1111
1236
 
1112
1237
  /**
1113
1238
  * Toggle between show and hide
1114
- * @param {Function} [callback] - Called when animation completes
1239
+ * @param {number|Function} [durationOrCallback] - Duration in ms or callback function
1240
+ * @param {Function} [callback] - Called when animation completes (if first param is duration)
1115
1241
  * @returns {Borealis} this instance for chaining
1116
1242
  */
1117
- toggle(callback) {
1243
+ toggle(durationOrCallback, callback) {
1118
1244
  if (this._isCollapsing) {
1119
- return this.show(callback);
1245
+ return this.show(durationOrCallback, callback);
1120
1246
  } else {
1121
- return this.hide(callback);
1247
+ return this.hide(durationOrCallback, callback);
1122
1248
  }
1123
1249
  }
1124
1250
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Borealis - Interactive Animated Background
3
- * @version 1.0.3
3
+ * @version 1.0.5
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,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});
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 s=(t=16807*t%2147483647)%(i+1);[this.p[i],this.p[s]]=[this.p[s],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 s=.5*(Math.sqrt(3)-1),e=(3-Math.sqrt(3))/6,a=(t+i)*s,o=Math.floor(t+a),n=Math.floor(i+a),h=(o+n)*e,l=t-(o-h),r=i-(n-h),c=l>r?1:0,p=l>r?0:1,d=l-c+e,u=r-p+e,f=l-1+2*e,_=r-1+2*e,g=255&o,m=255&n,C=(t,i,s)=>{const e=7&t,a=e<4?i:s,o=e<4?s:i;return(1&e?-a:a)+(2&e?-2*o:2*o)};let w=0,M=0,y=0,v=.5-l*l-r*r;v>=0&&(v*=v,w=v*v*C(this.perm[g+this.perm[m]],l,r));let S=.5-d*d-u*u;S>=0&&(S*=S,M=S*S*C(this.perm[g+c+this.perm[m+p]],d,u));let k=.5-f*f-_*_;return k>=0&&(k*=k,y=k*k*C(this.perm[g+1+this.perm[m+1]],f,_)),70*(w+M+y)}}class i{static get defaultOptions(){return{container:document.body,width:null,height:null,fullscreen:!0,zIndex:0,initiallyHidden:!1,className:null,background:null,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,showDuration:null,hideDuration:null,fadeOpacity:!0,revealingClass:"borealis-revealing",visibleClass:"borealis-visible",hidingClass:"borealis-hiding",hiddenClass:"borealis-hidden",autoStart:!0,onShow:null,onHide:null}}constructor(t={}){const s=i.defaultOptions.effect,e=t.effect||{};this.options={...i.defaultOptions,...t,effect:{...s,...e}},this._init()}_init(){this.canvas=document.createElement("canvas"),this.options.className&&(this.canvas.className=this.options.className);const i=this.options.zIndex,s=this.options.background?`background: ${this.options.background};`:"";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 ${s}\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 ${s}\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._showSpeed=null,this._hideSpeed=null,this.options.initiallyHidden?(this.options.hiddenClass&&this.canvas.classList.add(this.options.hiddenClass),this.options.fadeOpacity&&(this.canvas.style.opacity=0)):(this.options.visibleClass&&this.canvas.classList.add(this.options.visibleClass),this.options.fadeOpacity&&(this.canvas.style.opacity=1)),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,s=this.options.densityMinCell+i*(this.options.densityMaxCell-this.options.densityMinCell),e=.3+this.options.dotSize/10*1.7;this._cellSize=s*e,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 s=0;s<i;s++)for(let i=0;i<t;i++)Math.random()<this.options.effect.chance&&(this._sparkleMap[`${i},${s}`]=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 s=this.options.container;t=null!==this.options.width?this.options.width:s.clientWidth,i=null!==this.options.height?this.options.height:s.clientHeight}this.canvas.width=t,this.canvas.height=i;const s=Math.ceil(this.canvas.width/this._gridSize),e=Math.ceil(this.canvas.height/this._gridSize);this._generateSparkles(s,e),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 s=this.options.effect;if(this._sparkleWaiting)t>=this._sparkleWaitUntil&&(this._sparkleWaiting=!1,this._diagPos=-s.width);else{this._diagPos+=i*s.speed*100;const e=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize),o=e+a;if(this._diagPos>o+s.width){this._sparkleWaiting=!0;const i=s.delayMin+Math.random()*(s.delayMax-s.delayMin);this._sparkleWaitUntil=t+i,this._generateSparkles(e,a)}}this._lastFrameTime=t,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);const e=Math.ceil(this.canvas.width/this._gridSize),a=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===e&&this._offscreenCanvas.height===a||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=e,this._offscreenCanvas.height=a,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(e,a),s=i.data;for(let t=0;t<a;t++)for(let i=0;i<e;i++){const o=this._calculateCellData(i,t,e,a),n=4*(t*e+i);s[n]=o.r,s[n+1]=o.g,s[n+2]=o.b,s[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<e;i++)this._drawEffect(i,t,e,a)}else for(let t=0;t<a;t++)for(let i=0;i<e;i++)this._drawCell(i,t,e,a);this._updateCollapse(),this._animationId=requestAnimationFrame(this._draw)}_calculateCellData(t,i,s,e){const{options:a,noise:o,randomOffset:n,_animTime:h}=this,l=Math.sin(h*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,r=Math.cos(h*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,c=o.noise2D(t*a.patternScale*a.warpScale+l+n,i*a.patternScale*a.warpScale+h+n)*a.warpAmount,p=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+h+r+n)*a.warpAmount,d=o.noise2D((t+c)*a.patternScale+.5*r+n,(i+p)*a.patternScale+.5*l+n),u=1-Math.abs(d),f=Math.pow(u,a.ridgePower);let _,g,m,C=a.minOpacity+f*(a.maxOpacity-a.minOpacity);if(a.patternAurora){const s=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*h+.5*n)+1)/2;_=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),g=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),m=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)}else _=g=m=255;if(this._collapseProgress>0){C=this._applyCollapse(t,i,s,e,C,0).opacity}return{r:_,g:g,b:m,opacity:C}}_drawEffect(t,i,s,e){const a=this.options.effect;let o=[255,255,255],n=0;if("wave"===a.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,s,e);o=a.color,n=a.opacity}if("twinkle"===a.type){const a=this._calculateTwinkleEffect(t,i,s,e);o=a.color,n=a.opacity}if(this._collapseProgress>0){n=this._applyCollapse(t,i,s,e,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,s,e){const{options:a,noise:o,randomOffset:n,_animTime:h,_twinkleTime:l}=this,r=Math.sin(h*a.waveFrequency+t*a.patternScale*10)*a.waveAmplitude,c=Math.cos(h*a.waveFrequency*.7+i*a.patternScale*10)*a.waveAmplitude,p=o.noise2D(t*a.patternScale*a.warpScale+r+n,i*a.patternScale*a.warpScale+h+n)*a.warpAmount,d=o.noise2D(t*a.patternScale*a.warpScale+100+n,i*a.patternScale*a.warpScale+h+c+n)*a.warpAmount,u=o.noise2D((t+p)*a.patternScale+.5*c+n,(i+d)*a.patternScale+.5*r+n),f=1-Math.abs(u),_=Math.pow(f,a.ridgePower);let g,m,C,w=a.minOpacity+_*(a.maxOpacity-a.minOpacity),M=[255,255,255],y=0;if("wave"===a.effect.type&&!this._sparkleWaiting){const a=this._calculateWaveEffect(t,i,s,e);M=a.color,y=a.opacity}if("twinkle"===a.effect.type){const a=this._calculateTwinkleEffect(t,i,s,e);M=a.color,y=a.opacity}if(a.patternAurora){const s=(o.noise2D(t*a.colorScale+.5*n,i*a.colorScale+.5*h+.5*n)+1)/2;g=Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*s),m=Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*s),C=Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*s)}else g=m=C=255;if(this._collapseProgress>0){const a=this._applyCollapse(t,i,s,e,w,y);w=a.opacity,y=a.effectOpacity}if(!(w<=0&&y<=0)){if(this.ctx.fillStyle=`rgba(${g}, ${m}, ${C}, ${w})`,this.options.solidPattern){const s=Math.floor(t*this._gridSize),e=Math.floor(i*this._gridSize);this.ctx.fillRect(s,e,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();y>0&&(this.ctx.fillStyle=`rgba(${M[0]}, ${M[1]}, ${M[2]}, ${y})`,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,s,e){const{options:a,noise:o,randomOffset:n,_animTime:h,_twinkleTime:l}=this,r=a.effect;let c=[255,255,255],p=0;const d=s/2,u=e/2,f=Math.sqrt((t-d)**2+(i-u)**2),_=Math.sqrt(d**2+u**2)*this._deadzoneValue,g=.3*_;let m=1;if(f<_)m=0;else if(f<_+g){const t=(f-_)/g;m=t*t*(3-2*t)}if(r.combineSparkle&&m>0){const s=t+i,e=Math.abs(s-this._diagPos),o=Math.max(0,1-e/r.width),h=Math.pow(o,.5),d=43758.5453*Math.sin(12.9898*t+78.233*i+n),u=d-Math.floor(d),f=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),_=f-Math.floor(f);if(u>1-r.density/100*.9){const s=_*Math.PI*2,e=.1+r.twinkleSpeed/100*.4,o=Math.sin(l*e+s),d=Math.max(0,o),u=r.sparkleBaseOpacity/100;if(p=d*(u+(1-u)*h)*m,r.aurora){const s=12345.6789*Math.sin(45.123*t+89.456*i+n),e=s-Math.floor(s);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}}const C=t+i,w=Math.abs(C-this._diagPos);if(w<r.width&&void 0!==this._sparkleMap[`${t},${i}`]){const l=w/r.width,d=Math.cos(l*Math.PI*.5)*r.intensity,u=Math.min(s,e),f=Math.max(0,Math.floor(this._diagPos)-(e-1)),_=Math.min(s-1,Math.floor(this._diagPos)),g=Math.max(1,_-f+1);let C=1;if(g>=u&&g>1){const i=(t-f)/(g-1),s=Math.max(0,Math.min(1,i));C=.3+.7*Math.sin(s*Math.PI)}else if(g>1){const i=g/u,s=(t-f)/(g-1),e=Math.max(0,Math.min(1,s)),a=Math.sin(e*Math.PI);C=Math.max(.3,1-(1-a)*i*.7)}if(p=d*this._sparkleMap[`${t},${i}`]*Math.max(0,C)*m,r.aurora){const s=(o.noise2D(t*a.colorScale*2+n,i*a.colorScale*2+h+n)+1)/2;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}}_calculateTwinkleEffect(t,i,s,e){const{options:a,noise:o,randomOffset:n,_twinkleTime:h}=this,l=a.effect;let r=[255,255,255],c=0;const p=s/2,d=e/2,u=Math.sqrt((t-p)**2+(i-d)**2),f=Math.sqrt(p**2+d**2)*this._deadzoneValue,_=.3*f;let g=1;if(u<f)g=0;else if(u<f+_){const t=(u-f)/_;g=t*t*(3-2*t)}if(g>0)if(l.combined){const s=5e-4+.003*(1-this._twinkleScaleValue),e=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*s+h*e,i*s+h*e*.5+n)+.3*o.noise2D(t*s*.5+h*e*.3+50,i*s*.7-h*e*.2+n+50)+.2*o.noise2D((t+.5*i)*s*.8+h*e*.4,(i-.3*t)*s*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,u=Math.pow(d,.5),f=43758.5453*Math.sin(12.9898*t+78.233*i+n),_=f-Math.floor(f),m=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),C=m-Math.floor(m);if(_>this._twinkleThreshold){const s=C*Math.PI*2,e=Math.sin(h*this._twinkleSpeedValue*2+s),o=Math.max(0,e),p=l.baseOpacity/100;if(c=o*(p+(1-p)*u)*l.intensity*g,l.aurora){const s=12345.6789*Math.sin(45.123*t+89.456*i+n),e=s-Math.floor(s);r=[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)]}}}else if("wave"===l.mode){const s=5e-4+.003*(1-this._twinkleScaleValue),e=.15*this._twinkleSpeedValue,p=.5*o.noise2D(t*s+h*e,i*s+h*e*.5+n)+.3*o.noise2D(t*s*.5+h*e*.3+50,i*s*.7-h*e*.2+n+50)+.2*o.noise2D((t+.5*i)*s*.8+h*e*.4,(i-.3*t)*s*.8+n+100),d=(Math.sin(p*Math.PI*2)+1)/2,u=.3+.7*this._twinkleThreshold;if(c=Math.pow(d,1/u)*l.intensity*g,l.aurora&&c>0){const l=(o.noise2D(t*s*.3+h*e*.1+n,i*s*.3+n)+1)/2;r=[Math.round(a.auroraColor1[0]+(a.auroraColor2[0]-a.auroraColor1[0])*l),Math.round(a.auroraColor1[1]+(a.auroraColor2[1]-a.auroraColor1[1])*l),Math.round(a.auroraColor1[2]+(a.auroraColor2[2]-a.auroraColor1[2])*l)]}}else{const s=43758.5453*Math.sin(12.9898*t+78.233*i+n),e=s-Math.floor(s),p=23421.6312*Math.sin(93.9898*t+67.345*i+2*n),d=p-Math.floor(p);if(e>this._twinkleThreshold){const s=d*Math.PI*2,e=Math.sin(h*this._twinkleSpeedValue+s);if(c=Math.max(0,e)*(.2+(o.noise2D(t*this._twinkleScaleValue+.2*h+n,i*this._twinkleScaleValue+n)+1)/2*.8)*l.intensity*g,l.aurora){const s=12345.6789*Math.sin(45.123*t+89.456*i+n),e=s-Math.floor(s);r=[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:r,opacity:c}}_applyCollapse(t,i,s,e,a,o){const n=s/2,h=e/2,l=Math.sqrt(n*n+h*h),r=1-Math.sqrt((t-n)**2+(i-h)**2)/l;if(this._collapseProgress>r+this.options.collapseWaveWidth)a=0,o=0;else if(this._collapseProgress>r){const t=1-(this._collapseProgress-r)/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,i=this.options;if(this._isCollapsing&&this._collapseProgress<t){const s=this._hideSpeed||i.collapseSpeed;if(this._collapseProgress+=s,i.fadeOpacity){const i=Math.min(this._collapseProgress/t,1);this.canvas.style.opacity=1-i}i.hidingClass&&!this.canvas.classList.contains(i.hidingClass)&&(this.canvas.classList.remove(i.revealingClass,i.visibleClass),this.canvas.classList.add(i.hidingClass)),this._collapseProgress>=t&&(this._collapseProgress=t,this._hideSpeed=null,i.fadeOpacity&&(this.canvas.style.opacity=0),i.hidingClass&&this.canvas.classList.remove(i.hidingClass),i.hiddenClass&&this.canvas.classList.add(i.hiddenClass),i.onHide&&i.onHide())}else if(!this._isCollapsing&&this._collapseProgress>0){const s=this._showSpeed||i.collapseSpeed;if(this._collapseProgress-=s,i.fadeOpacity){const i=Math.max(this._collapseProgress/t,0);this.canvas.style.opacity=1-i}i.revealingClass&&!this.canvas.classList.contains(i.revealingClass)&&(this.canvas.classList.remove(i.hidingClass,i.hiddenClass),this.canvas.classList.add(i.revealingClass)),this._collapseProgress<=0&&(this._collapseProgress=0,this._showSpeed=null,i.fadeOpacity&&(this.canvas.style.opacity=1),i.revealingClass&&this.canvas.classList.remove(i.revealingClass),i.visibleClass&&this.canvas.classList.add(i.visibleClass),i.onShow&&i.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 s=Math.ceil(this.canvas.width/this._gridSize),e=Math.ceil(this.canvas.height/this._gridSize);if(this.options.solidPattern){this._offscreenCanvas&&this._offscreenCanvas.width===s&&this._offscreenCanvas.height===e||(this._offscreenCanvas=document.createElement("canvas"),this._offscreenCanvas.width=s,this._offscreenCanvas.height=e,this._offscreenCtx=this._offscreenCanvas.getContext("2d"));const t=this._offscreenCtx,i=t.createImageData(s,e),a=i.data;for(let t=0;t<e;t++)for(let i=0;i<s;i++){const o=this._calculateCellData(i,t,s,e),n=4*(t*s+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<e;t++)for(let i=0;i<s;i++)this._drawEffect(i,t,s,e)}else for(let t=0;t<e;t++)for(let i=0;i<s;i++)this._drawCell(i,t,s,e);return this._isRunning=i,this}show(t,i){let s=null,e=null;if("function"==typeof t?e=t:"number"==typeof t&&(s=t,e=i),null!==s){const t=1+this.options.collapseWaveWidth,i=s/16.67;this._showSpeed=t/i}else if(this.options.showDuration){const t=1+this.options.collapseWaveWidth,i=this.options.showDuration/16.67;this._showSpeed=t/i}if(this._isCollapsing=!1,e){const t=this.options.onShow;this.options.onShow=()=>{e(),this.options.onShow=t}}return this}hide(t,i){let s=null,e=null;if("function"==typeof t?e=t:"number"==typeof t&&(s=t,e=i),null!==s){const t=1+this.options.collapseWaveWidth,i=s/16.67;this._hideSpeed=t/i}else if(this.options.hideDuration){const t=1+this.options.collapseWaveWidth,i=this.options.hideDuration/16.67;this._hideSpeed=t/i}if(this._isCollapsing=!0,e){const t=this.options.onHide;this.options.onHide=()=>{e(),this.options.onHide=t}}return this}toggle(t,i){return this._isCollapsing?this.show(t,i):this.hide(t,i)}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 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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"}
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 className: null, // Custom class name for canvas\n background: null, // Canvas background (color, gradient, etc.)\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 (used when duration not specified)\n collapseWaveWidth: 0.4, // Width of the collapse transition\n showDuration: null, // Show animation duration in ms (null = use collapseSpeed)\n hideDuration: null, // Hide animation duration in ms (null = use collapseSpeed)\n fadeOpacity: true, // Fade canvas opacity during show/hide animations\n revealingClass: 'borealis-revealing', // Class added during show animation\n visibleClass: 'borealis-visible', // Class added when fully visible\n hidingClass: 'borealis-hiding', // Class added during hide animation\n hiddenClass: 'borealis-hidden', // Class added when fully hidden\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 custom class name if provided\n if (this.options.className) {\n this.canvas.className = this.options.className;\n }\n \n // Set canvas styles based on mode\n const zIndex = this.options.zIndex;\n const background = this.options.background ? `background: ${this.options.background};` : '';\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 ${background}\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 ${background}\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 this._showSpeed = null;\n this._hideSpeed = null;\n \n // Set initial CSS class and opacity based on initiallyHidden\n if (this.options.initiallyHidden) {\n if (this.options.hiddenClass) this.canvas.classList.add(this.options.hiddenClass);\n if (this.options.fadeOpacity) this.canvas.style.opacity = 0;\n } else {\n if (this.options.visibleClass) this.canvas.classList.add(this.options.visibleClass);\n if (this.options.fadeOpacity) this.canvas.style.opacity = 1;\n }\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 const opts = this.options;\n \n if (this._isCollapsing && this._collapseProgress < collapseEnd) {\n // Use duration-based speed if hideDuration is set\n const speed = this._hideSpeed || opts.collapseSpeed;\n this._collapseProgress += speed;\n \n // Update canvas opacity if fadeOpacity is enabled\n if (opts.fadeOpacity) {\n const progress = Math.min(this._collapseProgress / collapseEnd, 1);\n this.canvas.style.opacity = 1 - progress;\n }\n \n // Update CSS classes\n if (opts.hidingClass && !this.canvas.classList.contains(opts.hidingClass)) {\n this.canvas.classList.remove(opts.revealingClass, opts.visibleClass);\n this.canvas.classList.add(opts.hidingClass);\n }\n \n if (this._collapseProgress >= collapseEnd) {\n this._collapseProgress = collapseEnd;\n this._hideSpeed = null;\n \n // Set final opacity\n if (opts.fadeOpacity) {\n this.canvas.style.opacity = 0;\n }\n \n // Update CSS classes\n if (opts.hidingClass) this.canvas.classList.remove(opts.hidingClass);\n if (opts.hiddenClass) this.canvas.classList.add(opts.hiddenClass);\n \n if (opts.onHide) {\n opts.onHide();\n }\n }\n } else if (!this._isCollapsing && this._collapseProgress > 0) {\n // Use duration-based speed if showDuration is set\n const speed = this._showSpeed || opts.collapseSpeed;\n this._collapseProgress -= speed;\n \n // Update canvas opacity if fadeOpacity is enabled\n if (opts.fadeOpacity) {\n const progress = Math.max(this._collapseProgress / collapseEnd, 0);\n this.canvas.style.opacity = 1 - progress;\n }\n \n // Update CSS classes\n if (opts.revealingClass && !this.canvas.classList.contains(opts.revealingClass)) {\n this.canvas.classList.remove(opts.hidingClass, opts.hiddenClass);\n this.canvas.classList.add(opts.revealingClass);\n }\n \n if (this._collapseProgress <= 0) {\n this._collapseProgress = 0;\n this._showSpeed = null;\n \n // Set final opacity\n if (opts.fadeOpacity) {\n this.canvas.style.opacity = 1;\n }\n \n // Update CSS classes\n if (opts.revealingClass) this.canvas.classList.remove(opts.revealingClass);\n if (opts.visibleClass) this.canvas.classList.add(opts.visibleClass);\n \n if (opts.onShow) {\n opts.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 {number|Function} [durationOrCallback] - Duration in ms or callback function\n * @param {Function} [callback] - Called when animation completes (if first param is duration)\n * @returns {Borealis} this instance for chaining\n */\n show(durationOrCallback, callback) {\n let duration = null;\n let cb = null;\n \n if (typeof durationOrCallback === 'function') {\n cb = durationOrCallback;\n } else if (typeof durationOrCallback === 'number') {\n duration = durationOrCallback;\n cb = callback;\n }\n \n // Calculate speed from duration\n if (duration !== null) {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n const framesNeeded = duration / 16.67; // ~60fps\n this._showSpeed = collapseEnd / framesNeeded;\n } else if (this.options.showDuration) {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n const framesNeeded = this.options.showDuration / 16.67;\n this._showSpeed = collapseEnd / framesNeeded;\n }\n \n this._isCollapsing = false;\n if (cb) {\n const originalCallback = this.options.onShow;\n this.options.onShow = () => {\n cb();\n this.options.onShow = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Hide the pattern (collapse to center)\n * @param {number|Function} [durationOrCallback] - Duration in ms or callback function\n * @param {Function} [callback] - Called when animation completes (if first param is duration)\n * @returns {Borealis} this instance for chaining\n */\n hide(durationOrCallback, callback) {\n let duration = null;\n let cb = null;\n \n if (typeof durationOrCallback === 'function') {\n cb = durationOrCallback;\n } else if (typeof durationOrCallback === 'number') {\n duration = durationOrCallback;\n cb = callback;\n }\n \n // Calculate speed from duration\n if (duration !== null) {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n const framesNeeded = duration / 16.67; // ~60fps\n this._hideSpeed = collapseEnd / framesNeeded;\n } else if (this.options.hideDuration) {\n const collapseEnd = 1 + this.options.collapseWaveWidth;\n const framesNeeded = this.options.hideDuration / 16.67;\n this._hideSpeed = collapseEnd / framesNeeded;\n }\n \n this._isCollapsing = true;\n if (cb) {\n const originalCallback = this.options.onHide;\n this.options.onHide = () => {\n cb();\n this.options.onHide = originalCallback;\n };\n }\n return this;\n }\n\n /**\n * Toggle between show and hide\n * @param {number|Function} [durationOrCallback] - Duration in ms or callback function\n * @param {Function} [callback] - Called when animation completes (if first param is duration)\n * @returns {Borealis} this instance for chaining\n */\n toggle(durationOrCallback, callback) {\n if (this._isCollapsing) {\n return this.show(durationOrCallback, callback);\n } else {\n return this.hide(durationOrCallback, 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","className","background","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","showDuration","hideDuration","fadeOpacity","revealingClass","visibleClass","hidingClass","hiddenClass","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","_showSpeed","_hideSpeed","classList","add","opacity","_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","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","opts","progress","contains","remove","performance","now","stop","cancelAnimationFrame","resize","redraw","wasRunning","show","durationOrCallback","callback","duration","cb","framesNeeded","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.3",
3
+ "version": "1.0.5",
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",