asciify-engine 1.0.14 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -308,6 +308,129 @@ declare function renderStarsBackground(ctx: CanvasRenderingContext2D, width: num
308
308
  x: number;
309
309
  y: number;
310
310
  }, options?: StarsBackgroundOptions): void;
311
+ /**
312
+ * Concentric ASCII ripples that radiate from a vanishing point following
313
+ * the mouse — like a sonar / radar signal.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * asciiBackground('#hero', { type: 'pulse' });
318
+ * ```
319
+ */
320
+ interface PulseBackgroundOptions {
321
+ /** Font size in CSS pixels (default: 13). */
322
+ fontSize?: number;
323
+ /** Character ramp dark → bright (default: ' .:-=+*#%@'). */
324
+ chars?: string;
325
+ /** Accent colour on ring crests (default: '#d4ff00'). */
326
+ accentColor?: string;
327
+ /** Custom base character colour (any CSS colour string). */
328
+ color?: string;
329
+ /** Number of concentric rings (default: 6). */
330
+ rings?: number;
331
+ /** Ring travel speed (default: 1). */
332
+ speed?: number;
333
+ /** Ring width sharpness — higher = thinner rings (default: 4). */
334
+ sharpness?: number;
335
+ /** Light mode (default: false). */
336
+ lightMode?: boolean;
337
+ }
338
+ declare function renderPulseBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
339
+ x: number;
340
+ y: number;
341
+ }, options?: PulseBackgroundOptions): void;
342
+ /**
343
+ * Slow-drifting organic fractal noise field. No directional pattern —
344
+ * pure ambient texture. The mouse subtly warps the field around the cursor.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * asciiBackground('#hero', { type: 'noise' });
349
+ * ```
350
+ */
351
+ interface NoiseBackgroundOptions {
352
+ /** Font size in CSS pixels (default: 14). */
353
+ fontSize?: number;
354
+ /** Character ramp dark → bright (default: ' .·:;=+*#%@░▒▓'). */
355
+ chars?: string;
356
+ /** Accent colour on intensity peaks (default: '#d4ff00'). */
357
+ accentColor?: string;
358
+ /** Custom base character colour (any CSS colour string). */
359
+ color?: string;
360
+ /** Number of noise octaves for FBM detail (default: 4, max: 6). */
361
+ octaves?: number;
362
+ /** Drift / scroll speed (default: 1). */
363
+ speed?: number;
364
+ /** Noise scale — lower = larger blobs (default: 1). */
365
+ scale?: number;
366
+ /** Accent threshold 0-1 (default: 0.78). */
367
+ accentThreshold?: number;
368
+ /** Mouse warp radius 0-1 (default: 0.3). */
369
+ mouseWarp?: number;
370
+ /** Light mode (default: false). */
371
+ lightMode?: boolean;
372
+ }
373
+ declare function renderNoiseBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
374
+ x: number;
375
+ y: number;
376
+ }, options?: NoiseBackgroundOptions): void;
377
+ /**
378
+ * CRT-style horizontal scan-line sweep. Bright scan bands travel downward
379
+ * continuously; the cursor creates a local disruption / glitch zone.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * asciiBackground('#hero', { type: 'grid' });
384
+ * ```
385
+ */
386
+ interface GridBackgroundOptions {
387
+ /** Font size in CSS pixels (default: 12). */
388
+ fontSize?: number;
389
+ /** Character set (default: '·-=+|/'). */
390
+ chars?: string;
391
+ /** Accent / scan-band colour (default: '#d4ff00'). */
392
+ accentColor?: string;
393
+ /** Custom base character colour (any CSS colour string). */
394
+ color?: string;
395
+ /** Number of scan bands visible at once (default: 3). */
396
+ bands?: number;
397
+ /** Band travel speed (default: 1). */
398
+ speed?: number;
399
+ /** Band width as fraction of canvas height (default: 0.12). */
400
+ bandWidth?: number;
401
+ /** Enable cursor disruption glitch zone (default: true). */
402
+ glitch?: boolean;
403
+ /** Light mode (default: false). */
404
+ lightMode?: boolean;
405
+ }
406
+ declare function renderGridBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
407
+ x: number;
408
+ y: number;
409
+ }, options?: GridBackgroundOptions): void;
410
+ interface AuroraBackgroundOptions {
411
+ /** Character grid density. Default 14. */
412
+ fontSize?: number;
413
+ /** Character ramp from sparse to dense. Default fine gradient ramp. */
414
+ chars?: string;
415
+ /** Base character color. Default theme-aware white/black. */
416
+ color?: string;
417
+ /** Accent color for intensity peaks. Default '#d4ff00'. */
418
+ accentColor?: string;
419
+ /** Animation speed multiplier. Default 1. */
420
+ speed?: number;
421
+ /** Number of wave layers stacked. More = richer interference. Default 5. */
422
+ layers?: number;
423
+ /** Wave spread/softness — higher = broader, more diffuse bands. Default 1.2. */
424
+ softness?: number;
425
+ /** Mouse distortion radius (0–1). Elegant ripple that follows the cursor. Default 0.2. */
426
+ mouseRipple?: number;
427
+ /** Force light mode (dark chars on light bg). Default false. */
428
+ lightMode?: boolean;
429
+ }
430
+ declare function renderAuroraBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
431
+ x: number;
432
+ y: number;
433
+ }, options?: AuroraBackgroundOptions): void;
311
434
  /**
312
435
  * Drop-in helper that mounts an interactive ASCII wave background onto any
313
436
  * element. Injects a canvas, wires DPR resize, mouse tracking, and the RAF
@@ -330,14 +453,17 @@ declare function renderStarsBackground(ctx: CanvasRenderingContext2D, width: num
330
453
  * useEffect(() => asciiBackground(ref.current).destroy, []);
331
454
  * ```
332
455
  */
333
- interface AsciiBackgroundOptions extends WaveBackgroundOptions, RainBackgroundOptions, StarsBackgroundOptions {
456
+ interface AsciiBackgroundOptions extends WaveBackgroundOptions, RainBackgroundOptions, StarsBackgroundOptions, PulseBackgroundOptions, NoiseBackgroundOptions, GridBackgroundOptions, AuroraBackgroundOptions {
334
457
  /**
335
458
  * Which background to render (default: 'wave').
336
459
  * - 'wave' — interactive ASCII field with vortex, sparkles, breathe
337
460
  * - 'rain' — digital column rain (Matrix-style falling characters)
338
461
  * - 'stars' — 3D star-warp / hyperspace (chars fly toward the viewer)
462
+ * - 'pulse' — concentric ASCII ripples radiating from the mouse position
463
+ * - 'noise' — slow-drifting organic fractal noise field
464
+ * - 'grid' — CRT-style horizontal scan bands with cursor glitch zone
339
465
  */
340
- type?: 'wave' | 'rain' | 'stars';
466
+ type?: 'wave' | 'rain' | 'stars' | 'pulse' | 'noise' | 'grid' | 'aurora';
341
467
  /** CSS opacity applied to the canvas element (default: 0.2) */
342
468
  opacity?: number;
343
469
  /** Extra CSS class names added to the injected canvas */
@@ -383,4 +509,4 @@ interface WebGLRenderer {
383
509
  */
384
510
  declare function tryCreateWebGLRenderer(canvas: HTMLCanvasElement): WebGLRenderer | null;
385
511
 
386
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, CHARSETS, type CharsetKey, type ColorMode, DEFAULT_OPTIONS, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MountWaveOptions, type RainBackgroundOptions, type RenderMode, type SourceType, type StarsBackgroundOptions, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
512
+ export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type ColorMode, DEFAULT_OPTIONS, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MountWaveOptions, type NoiseBackgroundOptions, type PulseBackgroundOptions, type RainBackgroundOptions, type RenderMode, type SourceType, type StarsBackgroundOptions, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderAuroraBackground, renderFrameToCanvas, renderGridBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
package/dist/index.d.ts CHANGED
@@ -308,6 +308,129 @@ declare function renderStarsBackground(ctx: CanvasRenderingContext2D, width: num
308
308
  x: number;
309
309
  y: number;
310
310
  }, options?: StarsBackgroundOptions): void;
311
+ /**
312
+ * Concentric ASCII ripples that radiate from a vanishing point following
313
+ * the mouse — like a sonar / radar signal.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * asciiBackground('#hero', { type: 'pulse' });
318
+ * ```
319
+ */
320
+ interface PulseBackgroundOptions {
321
+ /** Font size in CSS pixels (default: 13). */
322
+ fontSize?: number;
323
+ /** Character ramp dark → bright (default: ' .:-=+*#%@'). */
324
+ chars?: string;
325
+ /** Accent colour on ring crests (default: '#d4ff00'). */
326
+ accentColor?: string;
327
+ /** Custom base character colour (any CSS colour string). */
328
+ color?: string;
329
+ /** Number of concentric rings (default: 6). */
330
+ rings?: number;
331
+ /** Ring travel speed (default: 1). */
332
+ speed?: number;
333
+ /** Ring width sharpness — higher = thinner rings (default: 4). */
334
+ sharpness?: number;
335
+ /** Light mode (default: false). */
336
+ lightMode?: boolean;
337
+ }
338
+ declare function renderPulseBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
339
+ x: number;
340
+ y: number;
341
+ }, options?: PulseBackgroundOptions): void;
342
+ /**
343
+ * Slow-drifting organic fractal noise field. No directional pattern —
344
+ * pure ambient texture. The mouse subtly warps the field around the cursor.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * asciiBackground('#hero', { type: 'noise' });
349
+ * ```
350
+ */
351
+ interface NoiseBackgroundOptions {
352
+ /** Font size in CSS pixels (default: 14). */
353
+ fontSize?: number;
354
+ /** Character ramp dark → bright (default: ' .·:;=+*#%@░▒▓'). */
355
+ chars?: string;
356
+ /** Accent colour on intensity peaks (default: '#d4ff00'). */
357
+ accentColor?: string;
358
+ /** Custom base character colour (any CSS colour string). */
359
+ color?: string;
360
+ /** Number of noise octaves for FBM detail (default: 4, max: 6). */
361
+ octaves?: number;
362
+ /** Drift / scroll speed (default: 1). */
363
+ speed?: number;
364
+ /** Noise scale — lower = larger blobs (default: 1). */
365
+ scale?: number;
366
+ /** Accent threshold 0-1 (default: 0.78). */
367
+ accentThreshold?: number;
368
+ /** Mouse warp radius 0-1 (default: 0.3). */
369
+ mouseWarp?: number;
370
+ /** Light mode (default: false). */
371
+ lightMode?: boolean;
372
+ }
373
+ declare function renderNoiseBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
374
+ x: number;
375
+ y: number;
376
+ }, options?: NoiseBackgroundOptions): void;
377
+ /**
378
+ * CRT-style horizontal scan-line sweep. Bright scan bands travel downward
379
+ * continuously; the cursor creates a local disruption / glitch zone.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * asciiBackground('#hero', { type: 'grid' });
384
+ * ```
385
+ */
386
+ interface GridBackgroundOptions {
387
+ /** Font size in CSS pixels (default: 12). */
388
+ fontSize?: number;
389
+ /** Character set (default: '·-=+|/'). */
390
+ chars?: string;
391
+ /** Accent / scan-band colour (default: '#d4ff00'). */
392
+ accentColor?: string;
393
+ /** Custom base character colour (any CSS colour string). */
394
+ color?: string;
395
+ /** Number of scan bands visible at once (default: 3). */
396
+ bands?: number;
397
+ /** Band travel speed (default: 1). */
398
+ speed?: number;
399
+ /** Band width as fraction of canvas height (default: 0.12). */
400
+ bandWidth?: number;
401
+ /** Enable cursor disruption glitch zone (default: true). */
402
+ glitch?: boolean;
403
+ /** Light mode (default: false). */
404
+ lightMode?: boolean;
405
+ }
406
+ declare function renderGridBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
407
+ x: number;
408
+ y: number;
409
+ }, options?: GridBackgroundOptions): void;
410
+ interface AuroraBackgroundOptions {
411
+ /** Character grid density. Default 14. */
412
+ fontSize?: number;
413
+ /** Character ramp from sparse to dense. Default fine gradient ramp. */
414
+ chars?: string;
415
+ /** Base character color. Default theme-aware white/black. */
416
+ color?: string;
417
+ /** Accent color for intensity peaks. Default '#d4ff00'. */
418
+ accentColor?: string;
419
+ /** Animation speed multiplier. Default 1. */
420
+ speed?: number;
421
+ /** Number of wave layers stacked. More = richer interference. Default 5. */
422
+ layers?: number;
423
+ /** Wave spread/softness — higher = broader, more diffuse bands. Default 1.2. */
424
+ softness?: number;
425
+ /** Mouse distortion radius (0–1). Elegant ripple that follows the cursor. Default 0.2. */
426
+ mouseRipple?: number;
427
+ /** Force light mode (dark chars on light bg). Default false. */
428
+ lightMode?: boolean;
429
+ }
430
+ declare function renderAuroraBackground(ctx: CanvasRenderingContext2D, width: number, height: number, time: number, mousePos?: {
431
+ x: number;
432
+ y: number;
433
+ }, options?: AuroraBackgroundOptions): void;
311
434
  /**
312
435
  * Drop-in helper that mounts an interactive ASCII wave background onto any
313
436
  * element. Injects a canvas, wires DPR resize, mouse tracking, and the RAF
@@ -330,14 +453,17 @@ declare function renderStarsBackground(ctx: CanvasRenderingContext2D, width: num
330
453
  * useEffect(() => asciiBackground(ref.current).destroy, []);
331
454
  * ```
332
455
  */
333
- interface AsciiBackgroundOptions extends WaveBackgroundOptions, RainBackgroundOptions, StarsBackgroundOptions {
456
+ interface AsciiBackgroundOptions extends WaveBackgroundOptions, RainBackgroundOptions, StarsBackgroundOptions, PulseBackgroundOptions, NoiseBackgroundOptions, GridBackgroundOptions, AuroraBackgroundOptions {
334
457
  /**
335
458
  * Which background to render (default: 'wave').
336
459
  * - 'wave' — interactive ASCII field with vortex, sparkles, breathe
337
460
  * - 'rain' — digital column rain (Matrix-style falling characters)
338
461
  * - 'stars' — 3D star-warp / hyperspace (chars fly toward the viewer)
462
+ * - 'pulse' — concentric ASCII ripples radiating from the mouse position
463
+ * - 'noise' — slow-drifting organic fractal noise field
464
+ * - 'grid' — CRT-style horizontal scan bands with cursor glitch zone
339
465
  */
340
- type?: 'wave' | 'rain' | 'stars';
466
+ type?: 'wave' | 'rain' | 'stars' | 'pulse' | 'noise' | 'grid' | 'aurora';
341
467
  /** CSS opacity applied to the canvas element (default: 0.2) */
342
468
  opacity?: number;
343
469
  /** Extra CSS class names added to the injected canvas */
@@ -383,4 +509,4 @@ interface WebGLRenderer {
383
509
  */
384
510
  declare function tryCreateWebGLRenderer(canvas: HTMLCanvasElement): WebGLRenderer | null;
385
511
 
386
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, CHARSETS, type CharsetKey, type ColorMode, DEFAULT_OPTIONS, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MountWaveOptions, type RainBackgroundOptions, type RenderMode, type SourceType, type StarsBackgroundOptions, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
512
+ export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type ColorMode, DEFAULT_OPTIONS, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MountWaveOptions, type NoiseBackgroundOptions, type PulseBackgroundOptions, type RainBackgroundOptions, type RenderMode, type SourceType, type StarsBackgroundOptions, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderAuroraBackground, renderFrameToCanvas, renderGridBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
package/dist/index.js CHANGED
@@ -379,7 +379,7 @@ async function gifToAsciiFrames(buffer, options, targetWidth, targetHeight, onPr
379
379
  prevCtx.clearRect(0, 0, logicalW, logicalH);
380
380
  prevCtx.drawImage(compCanvas, 0, 0);
381
381
  }
382
- const frameImageData = new ImageData(patch, dims.width, dims.height);
382
+ const frameImageData = new ImageData(new Uint8ClampedArray(patch.buffer), dims.width, dims.height);
383
383
  const tempCanvas = document.createElement("canvas");
384
384
  tempCanvas.width = dims.width;
385
385
  tempCanvas.height = dims.height;
@@ -830,7 +830,7 @@ async function asciifyVideo(source, canvas, { fontSize = 10, style = "classic",
830
830
  cancelAnimationFrame(animId);
831
831
  };
832
832
  }
833
- var EMBED_CDN_VERSION = "1.0.14";
833
+ var EMBED_CDN_VERSION = "1.0.16";
834
834
  function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
835
835
  const o = {
836
836
  r: rows,
@@ -1118,6 +1118,303 @@ function renderStarsBackground(ctx, width, height, time, mousePos = { x: 0.5, y:
1118
1118
  }
1119
1119
  ctx.textAlign = "left";
1120
1120
  }
1121
+ function renderPulseBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1122
+ const {
1123
+ fontSize = 13,
1124
+ chars = " .:-=+*#%@",
1125
+ accentColor = "#d4ff00",
1126
+ color,
1127
+ rings = 6,
1128
+ speed = 1,
1129
+ sharpness = 4,
1130
+ lightMode = false
1131
+ } = options;
1132
+ const charW = fontSize * 0.62;
1133
+ const lineH = fontSize * 1.4;
1134
+ const cols = Math.ceil(width / charW);
1135
+ const rows = Math.ceil(height / lineH);
1136
+ ctx.clearRect(0, 0, width, height);
1137
+ ctx.font = `${fontSize}px monospace`;
1138
+ ctx.textBaseline = "top";
1139
+ const maxR = Math.sqrt(width * width + height * height) * 0.5;
1140
+ const ox = mousePos.x * width;
1141
+ const oy = mousePos.y * height;
1142
+ let br = 255, bg2 = 255, bb = 255;
1143
+ if (lightMode) {
1144
+ br = 0;
1145
+ bg2 = 0;
1146
+ bb = 0;
1147
+ }
1148
+ if (color) {
1149
+ const p = _parseColor(color);
1150
+ if (p) {
1151
+ br = p.r;
1152
+ bg2 = p.g;
1153
+ bb = p.b;
1154
+ }
1155
+ }
1156
+ let acR = 212, acG = 255, acB = 0;
1157
+ const ap = _parseColor(accentColor);
1158
+ if (ap) {
1159
+ acR = ap.r;
1160
+ acG = ap.g;
1161
+ acB = ap.b;
1162
+ }
1163
+ const t = time * speed;
1164
+ for (let row = 0; row < rows; row++) {
1165
+ for (let col = 0; col < cols; col++) {
1166
+ const px = col * charW + charW * 0.5;
1167
+ const py = row * lineH + lineH * 0.5;
1168
+ const dist = Math.sqrt((px - ox) ** 2 + (py - oy) ** 2);
1169
+ const norm = dist / maxR;
1170
+ const phase = (norm * rings - t * 1.4) % 1;
1171
+ const wave = Math.pow(Math.max(0, Math.cos(phase * Math.PI * 2)), sharpness);
1172
+ if (wave < 0.02) continue;
1173
+ const charIdx = Math.floor(wave * (chars.length - 1));
1174
+ const ch = chars[charIdx];
1175
+ if (ch === " ") continue;
1176
+ const isAccent = wave > 0.75;
1177
+ const alpha = lightMode ? wave * 0.22 : wave * 0.14;
1178
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.5 : 0.35})` : `rgba(${br},${bg2},${bb},${alpha})`;
1179
+ ctx.fillText(ch, col * charW, row * lineH);
1180
+ }
1181
+ }
1182
+ }
1183
+ function renderNoiseBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1184
+ const {
1185
+ fontSize = 14,
1186
+ chars = " .\xB7:;=+*#%@\u2591\u2592\u2593",
1187
+ accentColor = "#d4ff00",
1188
+ color,
1189
+ octaves = 4,
1190
+ speed = 1,
1191
+ scale = 1,
1192
+ accentThreshold = 0.78,
1193
+ mouseWarp = 0.3,
1194
+ lightMode = false
1195
+ } = options;
1196
+ const charW = fontSize * 0.62;
1197
+ const lineH = fontSize * 1.4;
1198
+ const cols = Math.ceil(width / charW);
1199
+ const rows = Math.ceil(height / lineH);
1200
+ ctx.clearRect(0, 0, width, height);
1201
+ ctx.font = `${fontSize}px monospace`;
1202
+ ctx.textBaseline = "top";
1203
+ let br = 255, bgc = 255, bb = 255;
1204
+ if (lightMode) {
1205
+ br = 0;
1206
+ bgc = 0;
1207
+ bb = 0;
1208
+ }
1209
+ if (color) {
1210
+ const p = _parseColor(color);
1211
+ if (p) {
1212
+ br = p.r;
1213
+ bgc = p.g;
1214
+ bb = p.b;
1215
+ }
1216
+ }
1217
+ let acR = 212, acG = 255, acB = 0;
1218
+ const ap = _parseColor(accentColor);
1219
+ if (ap) {
1220
+ acR = ap.r;
1221
+ acG = ap.g;
1222
+ acB = ap.b;
1223
+ }
1224
+ const noiseScale = 0.035 * scale;
1225
+ const t = time * speed;
1226
+ const oct = Math.min(6, Math.max(1, octaves));
1227
+ const fbmN = (x, y) => {
1228
+ let v = 0, amp = 0.5, freq = 1, norm = 0;
1229
+ for (let o = 0; o < oct; o++) {
1230
+ v += _vnoise(x * freq, y * freq) * amp;
1231
+ norm += amp;
1232
+ amp *= 0.5;
1233
+ freq *= 2.1;
1234
+ }
1235
+ return v / norm;
1236
+ };
1237
+ for (let row = 0; row < rows; row++) {
1238
+ for (let col = 0; col < cols; col++) {
1239
+ const nx = col * noiseScale + t * 0.06;
1240
+ const ny = row * noiseScale * 1.3 - t * 0.04;
1241
+ const dx = col / cols - mousePos.x;
1242
+ const dy = row / rows - mousePos.y;
1243
+ const dist = Math.sqrt(dx * dx + dy * dy);
1244
+ const warp = mouseWarp > 0 ? Math.max(0, 1 - dist / mouseWarp) * 0.12 : 0;
1245
+ const wx = nx + warp * Math.sin(t * 1.3 + dy * 8);
1246
+ const wy = ny + warp * Math.cos(t * 0.9 + dx * 8);
1247
+ const raw = fbmN(wx, wy);
1248
+ const norm2 = raw * 0.5 + 0.5;
1249
+ if (norm2 < 0.12) continue;
1250
+ const charIdx = Math.floor(norm2 * (chars.length - 1));
1251
+ const ch = chars[charIdx];
1252
+ if (ch === " ") continue;
1253
+ const isAccent = norm2 > accentThreshold;
1254
+ const alpha = lightMode ? norm2 * 0.2 : norm2 * 0.13;
1255
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.42 : 0.28})` : `rgba(${br},${bgc},${bb},${alpha})`;
1256
+ ctx.fillText(ch, col * charW, row * lineH);
1257
+ }
1258
+ }
1259
+ }
1260
+ function renderGridBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1261
+ const {
1262
+ fontSize = 12,
1263
+ chars = "\xB7-=+|/",
1264
+ accentColor = "#d4ff00",
1265
+ color,
1266
+ bands = 3,
1267
+ speed = 1,
1268
+ bandWidth = 0.12,
1269
+ glitch = true,
1270
+ lightMode = false
1271
+ } = options;
1272
+ const charW = fontSize * 0.62;
1273
+ const lineH = fontSize * 1.4;
1274
+ const cols = Math.ceil(width / charW);
1275
+ const rows = Math.ceil(height / lineH);
1276
+ ctx.clearRect(0, 0, width, height);
1277
+ ctx.font = `${fontSize}px monospace`;
1278
+ ctx.textBaseline = "top";
1279
+ let br = 255, bgv = 255, bb = 255;
1280
+ if (lightMode) {
1281
+ br = 0;
1282
+ bgv = 0;
1283
+ bb = 0;
1284
+ }
1285
+ if (color) {
1286
+ const p = _parseColor(color);
1287
+ if (p) {
1288
+ br = p.r;
1289
+ bgv = p.g;
1290
+ bb = p.b;
1291
+ }
1292
+ }
1293
+ let acR = 212, acG = 255, acB = 0;
1294
+ const ap = _parseColor(accentColor);
1295
+ if (ap) {
1296
+ acR = ap.r;
1297
+ acG = ap.g;
1298
+ acB = ap.b;
1299
+ }
1300
+ const t = time * speed;
1301
+ for (let row = 0; row < rows; row++) {
1302
+ for (let col = 0; col < cols; col++) {
1303
+ const ny = row / rows;
1304
+ const scanPhase = ((ny * bands - t * 0.5) % 1 + 1) % 1;
1305
+ const bandIntensity = Math.max(0, 1 - scanPhase / bandWidth);
1306
+ const gridSeed = _hash2(col * 3, row * 7);
1307
+ const gridBase = (gridSeed * 0.5 + 0.5) * 0.35;
1308
+ let glitchBump = 0;
1309
+ if (glitch) {
1310
+ const dx = col / cols - mousePos.x;
1311
+ const dy = ny - mousePos.y;
1312
+ const d = Math.sqrt(dx * dx + dy * dy);
1313
+ if (d < 0.18) {
1314
+ const g = _hash2(col * 11 + Math.floor(t * 12), row * 5);
1315
+ glitchBump = Math.max(0, 1 - d / 0.18) * (g > 0.5 ? g - 0.3 : 0);
1316
+ }
1317
+ }
1318
+ const intensity = Math.min(1, gridBase + bandIntensity * 0.8 + glitchBump * 0.6);
1319
+ if (intensity < 0.04) continue;
1320
+ const charIdx = Math.floor(intensity * (chars.length - 1));
1321
+ const ch = chars[charIdx];
1322
+ const isAccent = bandIntensity > 0.55;
1323
+ const alpha = lightMode ? intensity * 0.2 : intensity * 0.12;
1324
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.46 : 0.28})` : `rgba(${br},${bgv},${bb},${alpha})`;
1325
+ ctx.fillText(ch, col * charW, row * lineH);
1326
+ }
1327
+ }
1328
+ }
1329
+ function renderAuroraBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1330
+ const {
1331
+ fontSize = 14,
1332
+ chars = " \xB7\u2219\u2022:;+=\u2261\u2263#@",
1333
+ color,
1334
+ accentColor = "#d4ff00",
1335
+ speed = 1,
1336
+ layers = 5,
1337
+ softness = 1.2,
1338
+ mouseRipple = 0.2,
1339
+ lightMode = false
1340
+ } = options;
1341
+ const charW = fontSize * 0.62;
1342
+ const lineH = fontSize * 1.4;
1343
+ const cols = Math.ceil(width / charW);
1344
+ const rows = Math.ceil(height / lineH);
1345
+ ctx.clearRect(0, 0, width, height);
1346
+ ctx.font = `${fontSize}px monospace`;
1347
+ ctx.textBaseline = "top";
1348
+ let cr = 255, cg = 255, cb = 255;
1349
+ if (lightMode) {
1350
+ cr = 0;
1351
+ cg = 0;
1352
+ cb = 0;
1353
+ }
1354
+ if (color) {
1355
+ const p = _parseColor(color);
1356
+ if (p) {
1357
+ cr = p.r;
1358
+ cg = p.g;
1359
+ cb = p.b;
1360
+ }
1361
+ }
1362
+ let acR = 212, acG = 255, acB = 0;
1363
+ const ap = _parseColor(accentColor);
1364
+ if (ap) {
1365
+ acR = ap.r;
1366
+ acG = ap.g;
1367
+ acB = ap.b;
1368
+ }
1369
+ const t = time * speed;
1370
+ const layerParams = [];
1371
+ for (let l = 0; l < layers; l++) {
1372
+ const seed = _hash2(l * 17, l * 31 + 7);
1373
+ const seed2 = _hash2(l * 23 + 5, l * 11);
1374
+ layerParams.push({
1375
+ fx: 0.8 + seed * 2.2,
1376
+ // x spatial frequency
1377
+ fy: 1.2 + seed2 * 1.8,
1378
+ // y spatial frequency
1379
+ phase: seed * Math.PI * 4,
1380
+ // phase offset
1381
+ dt: (0.3 + _hash2(l * 7, l * 13 + 3) * 0.5) * (l % 2 === 0 ? 1 : -1),
1382
+ // drift speed & direction
1383
+ amp: 0.55 + _hash2(l * 29, l * 3) * 0.45
1384
+ // amplitude weight
1385
+ });
1386
+ }
1387
+ for (let row = 0; row < rows; row++) {
1388
+ const ny = row / rows;
1389
+ for (let col = 0; col < cols; col++) {
1390
+ const nx = col / cols;
1391
+ const mdx = nx - mousePos.x;
1392
+ const mdy = ny - mousePos.y;
1393
+ const md = Math.sqrt(mdx * mdx + mdy * mdy);
1394
+ const warp = mouseRipple * Math.exp(-md * md / 0.06);
1395
+ const wx = nx + mdx * warp;
1396
+ const wy = ny + mdy * warp;
1397
+ let sum = 0;
1398
+ let totalAmp = 0;
1399
+ for (let l = 0; l < layers; l++) {
1400
+ const { fx, fy, phase, dt, amp } = layerParams[l];
1401
+ const wave = Math.sin(wx * fx * Math.PI * 2 + t * dt + phase) * Math.cos(wy * fy * Math.PI * 2 + t * dt * 0.7 + phase * 1.3);
1402
+ sum += wave * amp;
1403
+ totalAmp += amp;
1404
+ }
1405
+ const rawVal = sum / totalAmp;
1406
+ const curved = 0.5 + 0.5 * Math.tanh(rawVal * softness * 2.2);
1407
+ if (curved < 0.12) continue;
1408
+ const normalized = (curved - 0.12) / 0.88;
1409
+ const charIdx = Math.min(chars.length - 1, Math.floor(normalized * chars.length));
1410
+ const ch = chars[charIdx];
1411
+ const isAccent = curved > 0.82;
1412
+ const alpha = lightMode ? curved * 0.18 : curved * 0.14;
1413
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.5 : 0.32})` : `rgba(${cr},${cg},${cb},${alpha})`;
1414
+ ctx.fillText(ch, col * charW, row * lineH);
1415
+ }
1416
+ }
1417
+ }
1121
1418
  function _parseColor(c) {
1122
1419
  const hex = c.match(/^#([0-9a-f]{3,8})$/i)?.[1];
1123
1420
  if (hex) {
@@ -1186,10 +1483,34 @@ function asciiBackground(target, options = {}) {
1186
1483
  lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1187
1484
  color: color ?? renderOpts.color
1188
1485
  });
1486
+ const buildPulseOpts = () => ({
1487
+ ...renderOpts,
1488
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1489
+ color: color ?? renderOpts.color
1490
+ });
1491
+ const buildNoiseOpts = () => ({
1492
+ ...renderOpts,
1493
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1494
+ color: color ?? renderOpts.color
1495
+ });
1496
+ const buildGridOpts = () => ({
1497
+ ...renderOpts,
1498
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1499
+ color: color ?? renderOpts.color
1500
+ });
1501
+ const buildAuroraOpts = () => ({
1502
+ ...renderOpts,
1503
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1504
+ color: color ?? renderOpts.color
1505
+ });
1189
1506
  const optsRef = { current: buildWaveOpts() };
1190
1507
  const rebuildOpts = () => {
1191
1508
  if (type === "rain") optsRef.current = buildRainOpts();
1192
1509
  else if (type === "stars") optsRef.current = buildStarsOpts();
1510
+ else if (type === "pulse") optsRef.current = buildPulseOpts();
1511
+ else if (type === "noise") optsRef.current = buildNoiseOpts();
1512
+ else if (type === "grid") optsRef.current = buildGridOpts();
1513
+ else if (type === "aurora") optsRef.current = buildAuroraOpts();
1193
1514
  else optsRef.current = buildWaveOpts();
1194
1515
  };
1195
1516
  rebuildOpts();
@@ -1222,6 +1543,14 @@ function asciiBackground(target, options = {}) {
1222
1543
  renderRainBackground(ctx, r.width, r.height, time, optsRef.current);
1223
1544
  } else if (type === "stars") {
1224
1545
  renderStarsBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1546
+ } else if (type === "pulse") {
1547
+ renderPulseBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1548
+ } else if (type === "noise") {
1549
+ renderNoiseBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1550
+ } else if (type === "grid") {
1551
+ renderGridBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1552
+ } else if (type === "aurora") {
1553
+ renderAuroraBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1225
1554
  } else {
1226
1555
  renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1227
1556
  }
@@ -1690,6 +2019,6 @@ function tryCreateWebGLRenderer(canvas) {
1690
2019
  }
1691
2020
  }
1692
2021
 
1693
- export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
2022
+ export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderAuroraBackground, renderFrameToCanvas, renderGridBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderStarsBackground, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
1694
2023
  //# sourceMappingURL=index.js.map
1695
2024
  //# sourceMappingURL=index.js.map