asciify-engine 1.0.49 → 1.0.51

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.cjs CHANGED
@@ -615,6 +615,10 @@ function renderWaveBackground(ctx, width, height, time, mousePos = { x: 0.5, y:
615
615
  }
616
616
 
617
617
  // src/core/renderer.ts
618
+ function resolveInvert(invert) {
619
+ if (invert !== "auto") return invert;
620
+ return typeof window !== "undefined" && !window.matchMedia("(prefers-color-scheme: dark)").matches;
621
+ }
618
622
  function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
619
623
  const srcWidth = source instanceof HTMLVideoElement ? source.videoWidth : source.width;
620
624
  const srcHeight = source instanceof HTMLVideoElement ? source.videoHeight : source.height;
@@ -648,6 +652,7 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
648
652
  normRange = hi > lo ? hi - lo : 255;
649
653
  }
650
654
  const frame = [];
655
+ const invertVal = resolveInvert(options.invert);
651
656
  const ck = options.chromaKey;
652
657
  const ckEnabled = ck != null && ck !== false;
653
658
  const ckHeuristicGreen = ck === true;
@@ -687,22 +692,22 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
687
692
  const lum = options.normalize ? (rawLum - normMin) / normRange * 255 : rawLum;
688
693
  const adjustedLum = adjustLuminance(lum, options.brightness, options.contrast);
689
694
  const ditheredLum = applyDither(adjustedLum, x, y, options.ditherStrength);
690
- const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, options.invert) : luminanceToChar(ditheredLum, options.charset, options.invert);
695
+ const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, invertVal) : luminanceToChar(ditheredLum, options.charset, invertVal);
691
696
  row.push({ char, r, g, b, a });
692
697
  }
693
698
  frame.push(row);
694
699
  }
695
700
  return { frame, cols, rows };
696
701
  }
697
- async function videoToAsciiFrames(video, options, targetWidth, targetHeight, targetFps = 12, maxDuration = 10, onProgress) {
698
- const duration = Math.min(video.duration, maxDuration);
702
+ async function videoToAsciiFrames(video, options, targetWidth, targetHeight, targetFps = 12, maxDuration = 10, onProgress, startTime = 0) {
703
+ const duration = Math.min(video.duration - startTime, maxDuration);
699
704
  const totalFrames = Math.ceil(duration * targetFps);
700
705
  const frames = [];
701
706
  let cols = 0;
702
707
  let rows = 0;
703
708
  for (let i = 0; i < totalFrames; i++) {
704
- const time = i / targetFps;
705
- if (time > duration) break;
709
+ const time = startTime + i / targetFps;
710
+ if (time > startTime + duration) break;
706
711
  video.currentTime = time;
707
712
  await new Promise((resolve) => {
708
713
  const handler = () => {
@@ -846,7 +851,7 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
846
851
  const hoverStrength = options.hoverStrength;
847
852
  const hoverEffect = options.hoverEffect;
848
853
  const hoverRadiusFactor = effectiveHoverRadius;
849
- const isInverted = options.invert;
854
+ const isInverted = resolveInvert(options.invert);
850
855
  const colorMode = options.colorMode;
851
856
  const TWO_PI = Math.PI * 2;
852
857
  const invCols = 1 / cols;
@@ -1089,7 +1094,9 @@ async function asciifyGif(source, canvas, { fontSize = 10, artStyle = "classic",
1089
1094
  cancelAnimationFrame(animId);
1090
1095
  };
1091
1096
  }
1092
- async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic", options = {}, fitTo, preExtract = false, onReady, onFrame } = {}) {
1097
+ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic", options = {}, fitTo, preExtract = false, trim, onReady, onFrame } = {}) {
1098
+ const trimStart = trim?.start ?? 0;
1099
+ const trimEnd = trim?.end;
1093
1100
  const merged = { ...DEFAULT_OPTIONS, ...ART_STYLE_PRESETS[artStyle], ...options, fontSize };
1094
1101
  const ctx = canvas.getContext("2d");
1095
1102
  if (!ctx) throw new Error("asciifyVideo: could not get 2d context from canvas.");
@@ -1110,8 +1117,8 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
1110
1117
  video2 = source;
1111
1118
  }
1112
1119
  if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight);
1113
- onReady?.(video2);
1114
- const { frames, fps } = await videoToAsciiFrames(video2, merged, canvas.width, canvas.height);
1120
+ const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
1121
+ const { frames, fps } = await videoToAsciiFrames(video2, merged, canvas.width, canvas.height, void 0, maxDur, void 0, trimStart);
1115
1122
  let cancelled2 = false, animId2, i = 0, last = performance.now();
1116
1123
  let firstFrame2 = true;
1117
1124
  const interval = 1e3 / fps;
@@ -1167,6 +1174,23 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
1167
1174
  if (video.paused) await video.play().catch(() => {
1168
1175
  });
1169
1176
  }
1177
+ if (trimStart > 0) {
1178
+ video.currentTime = trimStart;
1179
+ await new Promise((resolve) => {
1180
+ const h = () => {
1181
+ video.removeEventListener("seeked", h);
1182
+ resolve();
1183
+ };
1184
+ video.addEventListener("seeked", h);
1185
+ });
1186
+ }
1187
+ let timeupdateHandler = null;
1188
+ if (trimEnd !== void 0) {
1189
+ timeupdateHandler = () => {
1190
+ if (video.currentTime >= trimEnd) video.currentTime = trimStart;
1191
+ };
1192
+ video.addEventListener("timeupdate", timeupdateHandler);
1193
+ }
1170
1194
  let ro = null;
1171
1195
  if (container) {
1172
1196
  const aspect = video.videoWidth / video.videoHeight;
@@ -1196,6 +1220,7 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
1196
1220
  cancelled = true;
1197
1221
  cancelAnimationFrame(animId);
1198
1222
  ro?.disconnect();
1223
+ if (timeupdateHandler) video.removeEventListener("timeupdate", timeupdateHandler);
1199
1224
  if (ownedVideo) {
1200
1225
  video.pause();
1201
1226
  video.src = "";