asciify-engine 1.0.54 → 1.0.56

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
@@ -126,12 +126,12 @@ All conversion and render functions accept an `AsciiOptions` object. Spread `DEF
126
126
  | `charset` | `string` | Standard ramp | Characters ordered from dense to sparse, representing brightness levels. |
127
127
  | `brightness` | `number` | `0` | Brightness adjustment from `-1` (darker) to `1` (lighter). |
128
128
  | `contrast` | `number` | `1` | Contrast multiplier applied before character mapping. |
129
- | `invert` | `boolean` | `false` | Inverts the luminance mapping — light areas become dense, dark areas sparse. |
129
+ | `invert` | `boolean \| 'auto'` | `false` | Inverts the luminance mapping — light areas become dense, dark areas sparse. Set to `'auto'` to auto-detect from OS color scheme (light mode → invert, dark mode → normal). |
130
130
  | `renderMode` | `'ascii' \| 'dots'` | `'ascii'` | Render as text characters or circular dot particles. |
131
131
  | `hoverEffect` | `string` | `'none'` | Interactive effect driven by cursor position. See hover effects below. |
132
132
  | `hoverStrength` | `number` | `0` | Effect intensity (0–1). `0` = hover disabled. |
133
133
  | `hoverRadius` | `number` | `0.2` | Effect radius relative to canvas size (0–1). |
134
- | `chromaKey` | `{r,g,b} \| string \| null` | `null` | Remove a background colour (green/blue screen). Keyed pixels become transparent spaces. Accepts `{r,g,b}`, any CSS colour string, or `null` to disable. |
134
+ | `chromaKey` | `true \| 'blue-screen' \| {r,g,b} \| string \| null` | `null` | Remove a background colour. `true` = heuristic green screen (any shade). `'blue-screen'` = heuristic blue screen. Custom: `{r,g,b}` or any CSS hex string keyed by Euclidean distance. `null` to disable. |
135
135
  | `chromaKeyTolerance` | `number` | `60` | Euclidean RGB distance threshold for chroma-key detection. `0` = exact match, higher = more pixels removed (max useful ~100). |
136
136
 
137
137
  ### Chroma Key (Green/Blue Screen)
@@ -148,7 +148,7 @@ asciify(img, canvas, {
148
148
 
149
149
  // Blue screen
150
150
  asciify(img, canvas, {
151
- options: { ...DEFAULT_OPTIONS, chromaKey: 'blue', chromaKeyTolerance: 70 },
151
+ options: { ...DEFAULT_OPTIONS, chromaKey: 'blue-screen', chromaKeyTolerance: 70 },
152
152
  });
153
153
 
154
154
  // Custom RGB key
@@ -238,7 +238,7 @@ stop();
238
238
  | `fontSize` | `number` | `13` | Character size in pixels. |
239
239
  | `speed` | `number` | `1` | Global animation speed multiplier. |
240
240
  | `density` | `number` | `0.55` | Fraction of grid cells that are active (0–1). |
241
- | `accentColor` | `string` | varies | Highlight or leading-character color (any CSS color string). |
241
+ | `accentColor` | `string \| 'auto'` | varies | Highlight or leading-character color (any CSS hex string). Set to `'auto'` to auto-detect: probes `--accent-color`, `--color-accent`, `--accent`, `--primary` CSS variables on `:root`, then falls back to OS color scheme (dark ink in light mode, light ink in dark mode). |
242
242
  | `color` | `string` | — | Override the body character color. |
243
243
 
244
244
  ---
@@ -304,7 +304,7 @@ const animatedHtml = generateAnimatedEmbedCode(frames, options, fps);
304
304
  | `generateEmbedCode` | `(frame, options)` | `string` |
305
305
  | `generateAnimatedEmbedCode` | `(frames, options, fps)` | `string` |
306
306
 
307
- `asciifyVideo` options: `fitTo` (HTMLElement/selector — fits canvas to container + ResizeObserver), `preExtract` (pre-decode all frames, default false), `onReady(video)`, `onFrame()`
307
+ `asciifyVideo` options: `fitTo` (HTMLElement/selector — fits canvas to container + ResizeObserver), `preExtract` (pre-decode all frames, default false), `trim: { start?: number; end?: number }` (loop a time slice in seconds, accepts floats), `onReady(video)`, `onFrame()`
308
308
 
309
309
  ---
310
310
 
package/dist/index.cjs CHANGED
@@ -26,7 +26,32 @@ var CHARSETS = {
26
26
  katakana: " \uFF66\uFF67\uFF68\uFF69\uFF6A\uFF6B\uFF6C\uFF6D\uFF6E\uFF6F\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF83\uFF84\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E\uFF8F\uFF90\uFF91\uFF92\uFF93\uFF94\uFF95\uFF96\uFF97\uFF98\uFF99\uFF9A\uFF9B\uFF9C\uFF9D",
27
27
  musical: " \u2669\u266A\u266B\u266C\u266D\u266E\u266F",
28
28
  emoji: " \u2B1B\u{1F7EB}\u{1F7E5}\u{1F7E7}\u{1F7E8}\u{1F7E9}\u{1F7E6}\u{1F7EA}\u2B1C",
29
- circles: " .\xB7:\u2218\u25CB\u25E6\xB0\u2022\u2219"
29
+ circles: " .\xB7:\u2218\u25CB\u25E6\xB0\u2022\u2219",
30
+ shadows: " \xB7\u2218\u25E6\u25CB\u25CE\u2299\u25CF\u25C9",
31
+ starfield: " \u02D9\xB7\u2218\u2217\u2726\u2727\u2605\u25C6\u25CF",
32
+ geometric: " \xB7\u25B3\u25B7\u25C7\u25C8\u25C6\u25A3\u25A0\u2588",
33
+ pipes: " \u2576\u2500\u2510\u2514\u251C\u2524\u252C\u2534\u253C\u256C\u2592\u2593\u2588",
34
+ waves: " \u02DC\u223C\u2248\u3030\u224B\u223F\u223E\u222D\u222B",
35
+ shards: " \u2571\u2572\u2573\u25E4\u25E5\u25E3\u25E2\u25B3\u25B2\u25C6\u25FC\u2588",
36
+ smoke: " \xB7\u02D9\u205A\u2056\u2236\u2237\u22EE\u22F0\u22F1\u2234\u2235"
37
+ };
38
+ var CHARSET_SEQUENCES = {
39
+ /** Stars → softcircles → orbs — dreamy space feel */
40
+ cosmic: [CHARSETS.starfield, CHARSETS.circles, CHARSETS.shadows],
41
+ /** Katakana → braille dots → binary — hacker rain */
42
+ rain: [CHARSETS.katakana, CHARSETS.braille, CHARSETS.binary],
43
+ /** Box pipes → Claude glyphs → classic — terminal morph */
44
+ terminal: [CHARSETS.pipes, CHARSETS.claudeCode, CHARSETS.standard],
45
+ /** Shards → blocks → squares — shattering crystal */
46
+ crystal: [CHARSETS.shards, CHARSETS.geometric, CHARSETS.blocks],
47
+ /** Wave glyphs → smoke dots → circles — fluid / organic */
48
+ fluid: [CHARSETS.waves, CHARSETS.smoke, CHARSETS.circles],
49
+ /** Dense classic → art → blocks — maximum detail pulse */
50
+ pulse: [CHARSETS.dense, CHARSETS.standard, CHARSETS.blocks],
51
+ /** Braille → shadows → smoke — ethereal / dream-like */
52
+ dream: [CHARSETS.braille, CHARSETS.shadows, CHARSETS.smoke],
53
+ /** Geometric shapes → shards → starfield — sci-fi angular */
54
+ angular: [CHARSETS.geometric, CHARSETS.shards, CHARSETS.starfield]
30
55
  };
31
56
  var ART_STYLE_PRESETS = {
32
57
  classic: {
@@ -96,6 +121,44 @@ var ART_STYLE_PRESETS = {
96
121
  charset: CHARSETS.circles,
97
122
  colorMode: "accent",
98
123
  accentColor: "#d4ff00"
124
+ },
125
+ shadows: {
126
+ renderMode: "ascii",
127
+ charset: CHARSETS.shadows,
128
+ colorMode: "accent",
129
+ accentColor: "#50a0ff"
130
+ },
131
+ starfield: {
132
+ renderMode: "ascii",
133
+ charset: CHARSETS.starfield,
134
+ colorMode: "fullcolor"
135
+ },
136
+ geometric: {
137
+ renderMode: "ascii",
138
+ charset: CHARSETS.geometric,
139
+ colorMode: "grayscale"
140
+ },
141
+ pipes: {
142
+ renderMode: "ascii",
143
+ charset: CHARSETS.pipes,
144
+ colorMode: "accent",
145
+ accentColor: "#00ff88"
146
+ },
147
+ waves: {
148
+ renderMode: "ascii",
149
+ charset: CHARSETS.waves,
150
+ colorMode: "fullcolor"
151
+ },
152
+ shards: {
153
+ renderMode: "ascii",
154
+ charset: CHARSETS.shards,
155
+ colorMode: "grayscale"
156
+ },
157
+ smoke: {
158
+ renderMode: "ascii",
159
+ charset: CHARSETS.smoke,
160
+ colorMode: "accent",
161
+ accentColor: "#c850ff"
99
162
  }
100
163
  };
101
164
  var DEFAULT_OPTIONS = {
@@ -724,7 +787,7 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
724
787
  const adjustedLum = adjustLuminance(lum, options.brightness, options.contrast);
725
788
  const ditheredLum = applyDither(adjustedLum, x, y, options.ditherStrength);
726
789
  const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, invertVal) : luminanceToChar(ditheredLum, options.charset, invertVal);
727
- row.push({ char, r, g, b, a });
790
+ row.push({ char, r, g, b, a, lum: ditheredLum });
728
791
  }
729
792
  frame.push(row);
730
793
  }
@@ -968,9 +1031,12 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
968
1031
  ctx.textBaseline = "middle";
969
1032
  }
970
1033
  let charWeights = null;
1034
+ const dynFrms = options.charsetFrames;
1035
+ const hasDyn = !!dynFrms?.length;
1036
+ const dynCharset = hasDyn ? dynFrms[Math.floor(Math.max(0, time) * (options.charsetFps ?? 2)) % dynFrms.length] : options.charset;
971
1037
  if (useFastRect) {
972
1038
  charWeights = {};
973
- const csChars = [...options.charset];
1039
+ const csChars = [...dynCharset];
974
1040
  const csLen = csChars.length;
975
1041
  for (let i = 0; i < csLen; i++) {
976
1042
  charWeights[csChars[i]] = Math.max(0.1, (i + 0.3) / csLen);
@@ -981,7 +1047,9 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
981
1047
  const rowData = frame[y];
982
1048
  for (let x = 0; x < cols; x++) {
983
1049
  const cell = rowData[x];
984
- if (cell.char === " " || cell.a < 10) continue;
1050
+ if (cell.a < 10) continue;
1051
+ const drawChar = hasDyn && cell.lum != null ? luminanceToChar(cell.lum, dynCharset, isInverted) : cell.char;
1052
+ if (drawChar === " ") continue;
985
1053
  const animMul = noAnimation ? 1 : getAnimationMultiplier(x, y, cols, rows, time, animStyle, animSpeed);
986
1054
  if (animMul < 0.05) continue;
987
1055
  let hoverScale = 1;
@@ -1021,7 +1089,7 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
1021
1089
  color = getCellColorStr(cell, colorMode, acR, acG, acB, isInverted);
1022
1090
  }
1023
1091
  if (useFastRect) {
1024
- const weight = charWeights[cell.char] ?? 0.5;
1092
+ const weight = charWeights[drawChar] ?? 0.5;
1025
1093
  const effAlpha = Math.min(1, cell.a * 0.00392156863 * animMul * (1 + hoverGlow)) * weight;
1026
1094
  if (effAlpha < 0.02) continue;
1027
1095
  if (effAlpha !== lastAlpha) {
@@ -1048,10 +1116,10 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
1048
1116
  if (hoverScale !== 1) {
1049
1117
  ctx.translate(px, py);
1050
1118
  ctx.scale(hoverScale, hoverScale);
1051
- ctx.fillText(cell.char, 0, 0);
1119
+ ctx.fillText(drawChar, 0, 0);
1052
1120
  ctx.setTransform(baseTransform);
1053
1121
  } else {
1054
- ctx.fillText(cell.char, px, py);
1122
+ ctx.fillText(drawChar, px, py);
1055
1123
  }
1056
1124
  }
1057
1125
  }
@@ -2645,6 +2713,7 @@ async function asciifyWebcam(canvas, {
2645
2713
  exports.ART_STYLE_PRESETS = ART_STYLE_PRESETS;
2646
2714
  exports.BACKGROUND_TYPES = BACKGROUND_TYPES;
2647
2715
  exports.CHARSETS = CHARSETS;
2716
+ exports.CHARSET_SEQUENCES = CHARSET_SEQUENCES;
2648
2717
  exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
2649
2718
  exports.HOVER_PRESETS = HOVER_PRESETS;
2650
2719
  exports.PALETTE_THEMES = PALETTE_THEMES;