asciify-engine 1.0.45 → 1.0.46

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
@@ -131,6 +131,47 @@ All conversion and render functions accept an `AsciiOptions` object. Spread `DEF
131
131
  | `hoverEffect` | `string` | `'none'` | Interactive effect driven by cursor position. See hover effects below. |
132
132
  | `hoverStrength` | `number` | `0.8` | Effect intensity (0–1). |
133
133
  | `hoverRadius` | `number` | `0.3` | 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. |
135
+ | `chromaKeyTolerance` | `number` | `60` | Euclidean RGB distance threshold for chroma-key detection. `0` = exact match, higher = more pixels removed (max useful ~100). |
136
+
137
+ ### Chroma Key (Green/Blue Screen)
138
+
139
+ Remove a solid background colour from any source — images, GIFs, or video — so the canvas background shows through keyed pixels.
140
+
141
+ ```ts
142
+ import { asciify, DEFAULT_OPTIONS } from 'asciify-engine';
143
+
144
+ // Green screen
145
+ asciify(img, canvas, {
146
+ options: {
147
+ ...DEFAULT_OPTIONS,
148
+ chromaKey: '#00ff00', // CSS colour string — hex, rgb(), named all work
149
+ chromaKeyTolerance: 60, // tune to your footage (0 = exact, ~80 = loose)
150
+ colorMode: 'fullcolor',
151
+ },
152
+ });
153
+
154
+ // Blue screen
155
+ asciify(img, canvas, {
156
+ options: { ...DEFAULT_OPTIONS, chromaKey: 'blue', chromaKeyTolerance: 70 },
157
+ });
158
+
159
+ // Custom RGB key
160
+ asciify(img, canvas, {
161
+ options: { ...DEFAULT_OPTIONS, chromaKey: { r: 0, g: 180, b: 90 }, chromaKeyTolerance: 50 },
162
+ });
163
+
164
+ // Live video with green screen
165
+ asciifyVideo('/footage.mp4', canvas, {
166
+ fitTo: '#container',
167
+ options: { ...DEFAULT_OPTIONS, chromaKey: '#00b140', chromaKeyTolerance: 65, colorMode: 'fullcolor' },
168
+ });
169
+ ```
170
+
171
+ **Tolerance guide:**
172
+ - `40–60` — tight key, natural green screen under good lighting
173
+ - `60–80` — broader key, wrinkled fabric or uneven lighting
174
+ - `80–120` — aggressive; expect some spill into the subject
134
175
 
135
176
  ### Color Modes
136
177
 
package/dist/index.cjs CHANGED
@@ -119,7 +119,9 @@ var DEFAULT_OPTIONS = {
119
119
  hoverEffect: "spotlight",
120
120
  hoverColor: "#ffffff",
121
121
  artStyle: "classic",
122
- customText: ""
122
+ customText: "",
123
+ chromaKey: null,
124
+ chromaKeyTolerance: 60
123
125
  };
124
126
  var HOVER_PRESETS = {
125
127
  none: {
@@ -258,6 +260,17 @@ function getCellColorRGB(cell, colorMode, acR, acG, acB) {
258
260
  }
259
261
  return _colorRGB;
260
262
  }
263
+ function parseChromaKeyColor(color) {
264
+ if (typeof color !== "string") return color;
265
+ const canvas = document.createElement("canvas");
266
+ canvas.width = 1;
267
+ canvas.height = 1;
268
+ const ctx = canvas.getContext("2d");
269
+ ctx.fillStyle = color;
270
+ ctx.fillRect(0, 0, 1, 1);
271
+ const d = ctx.getImageData(0, 0, 1, 1).data;
272
+ return { r: d[0], g: d[1], b: d[2] };
273
+ }
261
274
 
262
275
  // src/core/animation.ts
263
276
  function smoothstep(t) {
@@ -635,6 +648,12 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
635
648
  normRange = hi > lo ? hi - lo : 255;
636
649
  }
637
650
  const frame = [];
651
+ let ckRGB = null;
652
+ let ckTolSq = 0;
653
+ if (options.chromaKey != null) {
654
+ ckRGB = parseChromaKeyColor(options.chromaKey);
655
+ ckTolSq = (options.chromaKeyTolerance ?? 60) ** 2;
656
+ }
638
657
  for (let y = 0; y < rows; y++) {
639
658
  const row = [];
640
659
  for (let x = 0; x < cols; x++) {
@@ -643,6 +662,15 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
643
662
  const g = pixels[i + 1];
644
663
  const b = pixels[i + 2];
645
664
  const a = pixels[i + 3];
665
+ if (ckRGB !== null) {
666
+ const dr = r - ckRGB.r;
667
+ const dg = g - ckRGB.g;
668
+ const db = b - ckRGB.b;
669
+ if (dr * dr + dg * dg + db * db <= ckTolSq) {
670
+ row.push({ char: " ", r: 0, g: 0, b: 0, a: 0 });
671
+ continue;
672
+ }
673
+ }
646
674
  const rawLum = 0.299 * r + 0.587 * g + 0.114 * b;
647
675
  const lum = options.normalize ? (rawLum - normMin) / normRange * 255 : rawLum;
648
676
  const adjustedLum = adjustLuminance(lum, options.brightness, options.contrast);