asciify-engine 1.0.11 → 1.0.12

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
@@ -253,32 +253,55 @@ declare function renderWaveBackground(ctx: CanvasRenderingContext2D, width: numb
253
253
  }, options?: WaveBackgroundOptions): void;
254
254
  /**
255
255
  * Drop-in helper that mounts an interactive ASCII wave background onto any
256
- * element. Creates and injects a `<canvas>`, wires mouse tracking, DPR
257
- * resize, and the RAF loop — all internally.
256
+ * element. Injects a canvas, wires DPR resize, mouse tracking, and the RAF
257
+ * loop — all internally. Auto-detects light/dark mode and stays in sync if
258
+ * the system theme changes.
258
259
  *
259
260
  * Returns a `destroy()` function to clean everything up.
260
261
  *
261
262
  * @example
262
263
  * ```ts
263
- * // 1 line that's it:
264
- * import { mountWaveBackground } from 'asciify-engine';
265
- * const { destroy } = mountWaveBackground('#hero', { opacity: 0.2 });
264
+ * import { asciiBackground } from 'asciify-engine';
266
265
  *
267
- * // React:
268
- * useEffect(() => mountWaveBackground(ref.current).destroy, []);
266
+ * // 1 line:
267
+ * const { destroy } = asciiBackground('#hero', { opacity: 0.2 });
268
+ *
269
+ * // Custom color:
270
+ * asciiBackground('#hero', { color: '#6b8700', accentColor: '#d4ff00' });
271
+ *
272
+ * // React — return destroy as cleanup:
273
+ * useEffect(() => asciiBackground(ref.current).destroy, []);
269
274
  * ```
270
275
  */
271
- interface MountWaveOptions extends WaveBackgroundOptions {
276
+ interface AsciiBackgroundOptions extends WaveBackgroundOptions {
272
277
  /** CSS opacity applied to the canvas element (default: 0.2) */
273
278
  opacity?: number;
274
279
  /** Extra CSS class names added to the injected canvas */
275
280
  className?: string;
276
281
  /** z-index of the canvas (default: 0) */
277
282
  zIndex?: number;
283
+ /**
284
+ * Colour scheme handling (default: 'auto').
285
+ * - 'auto' — follows the system prefers-color-scheme and updates live
286
+ * - 'dark' — always render dark-on-dark (bright chars on dark bg)
287
+ * - 'light' — always render dark chars on light background
288
+ */
289
+ colorScheme?: 'auto' | 'light' | 'dark';
290
+ /**
291
+ * Custom character colour. Accepts any CSS colour string: hex, rgb(), hsl().
292
+ * When set, overrides the default white/black colour for the ASCII chars.
293
+ * The accent colour remains separate — use `accentColor` to change it.
294
+ * @example '#6b8700'
295
+ */
296
+ color?: string;
278
297
  }
279
- declare function mountWaveBackground(target: string | HTMLElement, options?: MountWaveOptions): {
298
+ declare function asciiBackground(target: string | HTMLElement | null, options?: AsciiBackgroundOptions): {
280
299
  destroy: () => void;
281
300
  };
301
+ /** @deprecated Use `asciiBackground` instead. */
302
+ declare const mountWaveBackground: typeof asciiBackground;
303
+ /** @deprecated Use `AsciiBackgroundOptions` instead. */
304
+ type MountWaveOptions = AsciiBackgroundOptions;
282
305
 
283
306
  interface WebGLRenderer {
284
307
  render(frame: AsciiFrame, options: AsciiOptions, displayW: number, displayH: number, time: number, hoverPos?: {
@@ -297,4 +320,4 @@ interface WebGLRenderer {
297
320
  */
298
321
  declare function tryCreateWebGLRenderer(canvas: HTMLCanvasElement): WebGLRenderer | null;
299
322
 
300
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, 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 RenderMode, type SourceType, type WaveBackgroundOptions, type WebGLRenderer, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
323
+ 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 RenderMode, type SourceType, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
package/dist/index.d.ts CHANGED
@@ -253,32 +253,55 @@ declare function renderWaveBackground(ctx: CanvasRenderingContext2D, width: numb
253
253
  }, options?: WaveBackgroundOptions): void;
254
254
  /**
255
255
  * Drop-in helper that mounts an interactive ASCII wave background onto any
256
- * element. Creates and injects a `<canvas>`, wires mouse tracking, DPR
257
- * resize, and the RAF loop — all internally.
256
+ * element. Injects a canvas, wires DPR resize, mouse tracking, and the RAF
257
+ * loop — all internally. Auto-detects light/dark mode and stays in sync if
258
+ * the system theme changes.
258
259
  *
259
260
  * Returns a `destroy()` function to clean everything up.
260
261
  *
261
262
  * @example
262
263
  * ```ts
263
- * // 1 line that's it:
264
- * import { mountWaveBackground } from 'asciify-engine';
265
- * const { destroy } = mountWaveBackground('#hero', { opacity: 0.2 });
264
+ * import { asciiBackground } from 'asciify-engine';
266
265
  *
267
- * // React:
268
- * useEffect(() => mountWaveBackground(ref.current).destroy, []);
266
+ * // 1 line:
267
+ * const { destroy } = asciiBackground('#hero', { opacity: 0.2 });
268
+ *
269
+ * // Custom color:
270
+ * asciiBackground('#hero', { color: '#6b8700', accentColor: '#d4ff00' });
271
+ *
272
+ * // React — return destroy as cleanup:
273
+ * useEffect(() => asciiBackground(ref.current).destroy, []);
269
274
  * ```
270
275
  */
271
- interface MountWaveOptions extends WaveBackgroundOptions {
276
+ interface AsciiBackgroundOptions extends WaveBackgroundOptions {
272
277
  /** CSS opacity applied to the canvas element (default: 0.2) */
273
278
  opacity?: number;
274
279
  /** Extra CSS class names added to the injected canvas */
275
280
  className?: string;
276
281
  /** z-index of the canvas (default: 0) */
277
282
  zIndex?: number;
283
+ /**
284
+ * Colour scheme handling (default: 'auto').
285
+ * - 'auto' — follows the system prefers-color-scheme and updates live
286
+ * - 'dark' — always render dark-on-dark (bright chars on dark bg)
287
+ * - 'light' — always render dark chars on light background
288
+ */
289
+ colorScheme?: 'auto' | 'light' | 'dark';
290
+ /**
291
+ * Custom character colour. Accepts any CSS colour string: hex, rgb(), hsl().
292
+ * When set, overrides the default white/black colour for the ASCII chars.
293
+ * The accent colour remains separate — use `accentColor` to change it.
294
+ * @example '#6b8700'
295
+ */
296
+ color?: string;
278
297
  }
279
- declare function mountWaveBackground(target: string | HTMLElement, options?: MountWaveOptions): {
298
+ declare function asciiBackground(target: string | HTMLElement | null, options?: AsciiBackgroundOptions): {
280
299
  destroy: () => void;
281
300
  };
301
+ /** @deprecated Use `asciiBackground` instead. */
302
+ declare const mountWaveBackground: typeof asciiBackground;
303
+ /** @deprecated Use `AsciiBackgroundOptions` instead. */
304
+ type MountWaveOptions = AsciiBackgroundOptions;
282
305
 
283
306
  interface WebGLRenderer {
284
307
  render(frame: AsciiFrame, options: AsciiOptions, displayW: number, displayH: number, time: number, hoverPos?: {
@@ -297,4 +320,4 @@ interface WebGLRenderer {
297
320
  */
298
321
  declare function tryCreateWebGLRenderer(canvas: HTMLCanvasElement): WebGLRenderer | null;
299
322
 
300
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, 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 RenderMode, type SourceType, type WaveBackgroundOptions, type WebGLRenderer, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
323
+ 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 RenderMode, type SourceType, type WaveBackgroundOptions, type WebGLRenderer, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
package/dist/index.js CHANGED
@@ -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.11";
833
+ var EMBED_CDN_VERSION = "1.0.12";
834
834
  function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
835
835
  const o = {
836
836
  r: rows,
@@ -997,11 +997,28 @@ function renderWaveBackground(ctx, width, height, time, mousePos = { x: 0.5, y:
997
997
  }
998
998
  }
999
999
  }
1000
- function mountWaveBackground(target, options = {}) {
1001
- const { opacity = 0.2, className, zIndex = 0, ...renderOpts } = options;
1000
+ function _parseColor(c) {
1001
+ const hex = c.match(/^#([0-9a-f]{3,8})$/i)?.[1];
1002
+ if (hex) {
1003
+ const h = hex.length <= 4 ? hex.split("").map((x) => parseInt(x + x, 16)) : [parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16)];
1004
+ return { r: h[0], g: h[1], b: h[2] };
1005
+ }
1006
+ const rgb = c.match(/rgba?\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)/i);
1007
+ if (rgb) return { r: +rgb[1], g: +rgb[2], b: +rgb[3] };
1008
+ return null;
1009
+ }
1010
+ function asciiBackground(target, options = {}) {
1011
+ const {
1012
+ opacity = 0.2,
1013
+ className,
1014
+ zIndex = 0,
1015
+ colorScheme = "auto",
1016
+ color,
1017
+ ...renderOpts
1018
+ } = options;
1002
1019
  const container = typeof target === "string" ? document.querySelector(target) : target;
1003
1020
  if (!container) {
1004
- console.warn("[asciify] mountWaveBackground: target not found", target);
1021
+ console.warn("[asciify] asciiBackground: target not found", target);
1005
1022
  return { destroy: () => {
1006
1023
  } };
1007
1024
  }
@@ -1025,6 +1042,24 @@ function mountWaveBackground(target, options = {}) {
1025
1042
  const dpr = window.devicePixelRatio || 1;
1026
1043
  const mouse = { x: 0.5, y: 0.5 };
1027
1044
  const smoothMouse = { x: 0.5, y: 0.5 };
1045
+ const mq = window.matchMedia("(prefers-color-scheme: light)");
1046
+ const isLight = () => {
1047
+ if (colorScheme === "light") return true;
1048
+ if (colorScheme === "dark") return false;
1049
+ return mq.matches;
1050
+ };
1051
+ let parsedColor = null;
1052
+ if (color) parsedColor = _parseColor(color);
1053
+ const buildOpts = () => ({
1054
+ ...renderOpts,
1055
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1056
+ baseColor: parsedColor ? `rgba(${parsedColor.r},${parsedColor.g},${parsedColor.b},{a})` : renderOpts.baseColor
1057
+ });
1058
+ const optsRef = { current: buildOpts() };
1059
+ const onSchemeChange = () => {
1060
+ optsRef.current = buildOpts();
1061
+ };
1062
+ if (colorScheme === "auto") mq.addEventListener("change", onSchemeChange);
1028
1063
  const resize = () => {
1029
1064
  const r = container.getBoundingClientRect();
1030
1065
  canvas.width = r.width * dpr;
@@ -1046,7 +1081,7 @@ function mountWaveBackground(target, options = {}) {
1046
1081
  smoothMouse.x += (mouse.x - smoothMouse.x) * 0.07;
1047
1082
  smoothMouse.y += (mouse.y - smoothMouse.y) * 0.07;
1048
1083
  const r = container.getBoundingClientRect();
1049
- renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, renderOpts);
1084
+ renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1050
1085
  time += 0.016;
1051
1086
  raf = requestAnimationFrame(tick);
1052
1087
  };
@@ -1055,12 +1090,14 @@ function mountWaveBackground(target, options = {}) {
1055
1090
  destroy: () => {
1056
1091
  cancelAnimationFrame(raf);
1057
1092
  ro.disconnect();
1093
+ if (colorScheme === "auto") mq.removeEventListener("change", onSchemeChange);
1058
1094
  window.removeEventListener("mousemove", onMouseMove);
1059
1095
  canvas.remove();
1060
1096
  container.style.position = prevPosition;
1061
1097
  }
1062
1098
  };
1063
1099
  }
1100
+ var mountWaveBackground = asciiBackground;
1064
1101
 
1065
1102
  // src/webgl-engine.ts
1066
1103
  var VERT_SRC = (
@@ -1510,6 +1547,6 @@ function tryCreateWebGLRenderer(canvas) {
1510
1547
  }
1511
1548
  }
1512
1549
 
1513
- export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
1550
+ export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciiBackground, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
1514
1551
  //# sourceMappingURL=index.js.map
1515
1552
  //# sourceMappingURL=index.js.map