asciify-engine 1.0.4 → 1.0.6

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.js CHANGED
@@ -274,6 +274,8 @@ function getAnimationMultiplier(x, y, cols, rows, time, style, speed) {
274
274
  }
275
275
  return 0.7 + 0.3 * Math.sin(sdist * 10 - t * 2);
276
276
  }
277
+ case "waveField":
278
+ return 1;
277
279
  default:
278
280
  return 1;
279
281
  }
@@ -466,6 +468,24 @@ function computeHoverEffect(nx, ny, hoverX, hoverY, hoverIntensity, strength, ce
466
468
  return _hoverResult;
467
469
  }
468
470
  function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, time = 0, hoverPos) {
471
+ if (options.animationStyle === "waveField") {
472
+ const mouseNorm = hoverPos ? { x: hoverPos.x, y: hoverPos.y } : { x: 0.5, y: 0.5 };
473
+ const acHexWF = (options.accentColor || "#d4ff00").replace("#", "");
474
+ parseInt(acHexWF.substring(0, 2), 16) || 212;
475
+ parseInt(acHexWF.substring(2, 4), 16) || 255;
476
+ parseInt(acHexWF.substring(4, 6), 16) || 0;
477
+ renderWaveBackground(ctx, canvasWidth, canvasHeight, time, mouseNorm, {
478
+ accentColor: `#${acHexWF}`,
479
+ accentThreshold: 0.52,
480
+ mouseInfluence: options.hoverStrength > 0 ? Math.min(1, 0.3 + options.hoverStrength * 0.5) : 0.55,
481
+ mouseFalloff: 2.8,
482
+ speed: options.animationSpeed,
483
+ vortex: options.hoverStrength > 0,
484
+ sparkles: true,
485
+ breathe: true
486
+ });
487
+ return;
488
+ }
469
489
  const rows = frame.length;
470
490
  if (rows === 0) return;
471
491
  const cols = frame[0].length;
@@ -698,36 +718,27 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
698
718
  ctx.globalAlpha = 1;
699
719
  }
700
720
  function serializeFrame(frame, includeChars) {
701
- return frame.map((row) => row.map((cell) => {
702
- const obj = { r: cell.r, g: cell.g, b: cell.b, a: cell.a };
703
- if (includeChars) obj.c = cell.char.charCodeAt(0);
704
- else obj.l = Math.round(0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b);
705
- return obj;
706
- }));
707
- }
708
- function buildAnimFnJS(style, speed) {
709
- if (style === "none") return "function(){return 1}";
710
- return `function(x,y,cols,rows,t){
711
- var s=${speed},T=t*s;
712
- ${style === "wave" ? `var w=Math.sin(x/cols*Math.PI*4+T*3)*.5+.5,w2=Math.sin(y/rows*Math.PI*3+T*2)*.5+.5;return .3+.7*(w*.6+w2*.4);` : ""}${style === "pulse" ? `var cx=cols/2,cy=rows/2,d=Math.sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy)),m=Math.sqrt(cx*cx+cy*cy);return .2+.8*(Math.sin(d/m*Math.PI*6-T*4)*.5+.5);` : ""}${style === "rain" ? `return .1+.9*(Math.sin(y/rows*Math.PI*8-T*5+x*.3)*.5+.5)*(Math.sin(x/cols*Math.PI*2+T)*.3+.7);` : ""}${style === "breathe" ? `return Math.max(.1,Math.min(1,Math.sin(T*2)*.3+.7+Math.sin((x+y)*.1+T)*.1));` : ""}${style === "sparkle" ? `var h=Math.sin(x*127.1+y*311.7+Math.floor(T*8)*43758.5453)*43758.5453;var sp=h-Math.floor(h);return sp>.7?1:.15+sp*.4;` : ""}${style === "glitch" ? `var b=Math.floor(y/(rows*.05)),gh=Math.sin(b*43.23+Math.floor(T*6)*17.89)*43758.5453,gv=gh-Math.floor(gh);if(gv>.85){var fl=Math.sin(T*30+b)*.5+.5;return fl<.3?0:fl}return 1;` : ""}${style === "spiral" ? `var cx=cols/2,cy=rows/2,dx=x-cx,dy=y-cy,a=Math.atan2(dy,dx),d=Math.sqrt(dx*dx+dy*dy),m=Math.sqrt(cx*cx+cy*cy);return .15+.85*(Math.sin(a*3+d/m*Math.PI*8-T*3)*.5+.5);` : ""}${style === "typewriter" ? `var tc=cols*rows,ci=y*cols+x,p=(T*.5)%1,rp=p*tc*1.3,dd=ci-rp;if(dd>0)return 0;return Math.min(1,Math.max(0,1+dd/(tc*.15)));` : ""}${style === "scatter" ? `var cx=cols/2,cy=rows/2,dx=x-cx,dy=y-cy,sd=Math.sqrt(dx*dx+dy*dy)/Math.sqrt(cx*cx+cy*cy),ph=Math.sin(T*1.5)*.5+.5;if(sd>ph)return Math.max(0,1-(sd-ph)*3);return .7+.3*Math.sin(sd*10-T*2);` : ""}
713
- }`;
714
- }
715
- function buildColorFnJS(options) {
716
- switch (options.colorMode) {
717
- case "fullcolor":
718
- return `function(c){return 'rgb('+c.r+','+c.g+','+c.b+')'}`;
719
- case "matrix":
720
- return `function(c){var b=Math.floor(.299*c.r+.587*c.g+.114*c.b);return 'rgb(0,'+b+',0)'}`;
721
- case "accent": {
722
- const hex = options.accentColor.replace("#", "");
723
- const ar = parseInt(hex.substring(0, 2), 16);
724
- const ag = parseInt(hex.substring(2, 4), 16);
725
- const ab = parseInt(hex.substring(4, 6), 16);
726
- return `function(c){var b=(.299*c.r+.587*c.g+.114*c.b)/255;return 'rgb('+Math.floor(${ar}*b)+','+Math.floor(${ag}*b)+','+Math.floor(${ab}*b)+')'}`;
721
+ const rows = frame.length;
722
+ const cols = rows > 0 ? frame[0].length : 0;
723
+ const buf = new Uint8Array(rows * cols * 5);
724
+ let i = 0;
725
+ for (let y = 0; y < rows; y++) {
726
+ for (let x = 0; x < cols; x++) {
727
+ const cell = frame[y][x];
728
+ buf[i++] = cell.r;
729
+ buf[i++] = cell.g;
730
+ buf[i++] = cell.b;
731
+ buf[i++] = cell.a;
732
+ if (includeChars) {
733
+ buf[i++] = cell.char.charCodeAt(0) & 255;
734
+ } else {
735
+ buf[i++] = Math.round(0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b);
736
+ }
727
737
  }
728
- default:
729
- return `function(c){var g=Math.floor(.299*c.r+.587*c.g+.114*c.b);return 'rgb('+g+','+g+','+g+')'}`;
730
738
  }
739
+ let binary = "";
740
+ for (let j = 0; j < buf.length; j++) binary += String.fromCharCode(buf[j]);
741
+ return btoa(binary);
731
742
  }
732
743
  async function asciify(source, canvas, { fontSize = 10, style = "classic", options = {} } = {}) {
733
744
  let el;
@@ -819,188 +830,171 @@ async function asciifyVideo(source, canvas, { fontSize = 10, style = "classic",
819
830
  cancelAnimationFrame(animId);
820
831
  };
821
832
  }
833
+ var EMBED_CDN_VERSION = "1.0.5";
834
+ function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
835
+ const o = {
836
+ r: rows,
837
+ c: cols,
838
+ w: width,
839
+ h: height,
840
+ cs: options.charset,
841
+ cm: options.colorMode,
842
+ as: options.animationStyle,
843
+ sp: options.animationSpeed,
844
+ inv: options.invert,
845
+ hs: options.hoverStrength,
846
+ hr: options.hoverRadius,
847
+ he: options.hoverEffect,
848
+ hc: options.hoverColor,
849
+ dr: options.dotSizeRatio,
850
+ dots: options.renderMode === "dots"
851
+ };
852
+ if (options.colorMode === "accent") o.ac = options.accentColor;
853
+ if (fps !== void 0) o.fps = fps;
854
+ if (animated) o.anim = true;
855
+ return JSON.stringify(o);
856
+ }
822
857
  function generateEmbedCode(frame, options, width, height) {
823
858
  const rows = frame.length;
824
859
  if (rows === 0) return "";
825
860
  const cols = frame[0].length;
826
861
  const isDots = options.renderMode === "dots";
827
862
  const data = serializeFrame(frame, !isDots);
828
- const hasAnim = options.animationStyle !== "none";
829
- const hasHover = options.hoverStrength > 0;
830
- const charset = isDots ? "" : options.charset;
831
- const hc = options.hoverColor || "#ffffff";
832
- const hcR = parseInt(hc.slice(1, 3), 16) || 255;
833
- const hcG = parseInt(hc.slice(3, 5), 16) || 255;
834
- const hcB = parseInt(hc.slice(5, 7), 16) || 255;
835
- const hasTransparency = frame.some((row) => row.some((cell) => cell.a < 200));
863
+ const id = `ar-${Math.random().toString(36).slice(2, 9)}`;
864
+ const opts = buildEmbedOpts(options, rows, cols, width, height);
836
865
  return `<!-- Asciify Embed -->
837
- <canvas id="ar-embed" width="${width}" height="${height}" style="${hasTransparency ? "" : "background:#0a0a0a;"}display:block;"></canvas>
838
- <script>
839
- (function(){
840
- var D=${JSON.stringify(data)};
841
- var R=${rows},C=${cols},W=${width},H=${height};
842
- var cW=W/C,cH=H/R;
843
- var isDots=${isDots};
844
- var invert=${options.invert};
845
- var dotR=${options.dotSizeRatio};
846
- var hStr=${options.hoverStrength},hRad=${options.hoverRadius};
847
- var hcR=${hcR},hcG=${hcG},hcB=${hcB};
848
- var hEff='${options.hoverEffect}';
849
- var charset=${JSON.stringify(charset)};
850
- var hasTr=${hasTransparency};
851
- var cv=document.getElementById('ar-embed'),ctx=cv.getContext('2d');
852
- var mx=-1,my=-1,mIn=0;
853
- var getColor=${buildColorFnJS(options)};
854
- var getAnim=${buildAnimFnJS(options.animationStyle, options.animationSpeed)};
855
- ${hasHover ? `
856
- cv.addEventListener('mousemove',function(e){var r=cv.getBoundingClientRect();mx=(e.clientX-r.left)/r.width;my=(e.clientY-r.top)/r.height});
857
- cv.addEventListener('mouseleave',function(){mx=-1;my=-1});
858
- function ss(t){return t*t*(3-2*t)}
859
- ` : ""}
860
- var smX=.5,smY=.5;
861
- function draw(t){
862
- var time=t/1000;
863
- ctx.clearRect(0,0,W,H);
864
- if(!hasTr){ctx.fillStyle='#0a0a0a';ctx.fillRect(0,0,W,H)};
865
- ${hasHover ? `
866
- if(mx>=0){smX+=(mx-smX)*.1;smY+=(my-smY)*.1;mIn+=(1-mIn)*.12}
867
- else{mIn*=.96;if(mIn<.003)mIn=0}
868
- ` : ""}
869
- for(var y=0;y<R;y++)for(var x=0;x<C;x++){
870
- var p=D[y][x];if(p.a<10)continue;
871
- var am=getAnim(x,y,C,R,time);if(am<.05)continue;
872
- var sc=1,ox=0,oy=0,gl=0,cb=0;
873
- ${hasHover ? `
874
- if(mIn>.003&&hStr>0){
875
- var nx=x/C,ny=y/R,dx=nx-smX,dy=ny-smY,dd=Math.sqrt(dx*dx+dy*dy);
876
- var rad=(.08+hRad*.35)+hStr*.04;
877
- if(dd<rad){
878
- var tt=1-dd/rad,e=ss(tt)*mIn,ang=Math.atan2(dy,dx);
879
- if(hEff==='spotlight'){sc=1+e*hStr*1.8;var pf=e*e*hStr*.6;ox=Math.cos(ang)*pf*cW;oy=Math.sin(ang)*pf*cH;gl=e*hStr*.4;cb=e*e*hStr*.25}
880
- else if(hEff==='magnify'){sc=1+e*hStr*2.5;gl=e*hStr*.15}
881
- else if(hEff==='repel'){sc=1+e*hStr*.3;var pf=e*e*hStr*1.2;ox=Math.cos(ang)*pf*cW;oy=Math.sin(ang)*pf*cH}
882
- else if(hEff==='glow'){gl=e*hStr*.8;cb=e*hStr*.4}
883
- else if(hEff==='colorShift'){sc=1+e*hStr*.4;gl=e*hStr*.2;cb=e*hStr*.7}
884
- }
885
- }
886
- ` : ""}
887
- var px=x*cW+cW/2+ox,py=y*cH+cH/2+oy;
888
- var col=getColor(p);
889
- if(cb>0){var m=col.match(/rgb\\((\\d+),(\\d+),(\\d+)\\)/);if(m){var rr=+m[1],gg=+m[2],bb=+m[3];col='rgb('+Math.min(255,Math.round(rr+(hcR-rr)*cb))+','+Math.min(255,Math.round(gg+(hcG-gg)*cb))+','+Math.min(255,Math.round(bb+(hcB-bb)*cb))+')'}}
890
- if(isDots){
891
- var lum=p.l/255;var int=invert?1-lum:lum;if(int<.02)continue;
892
- var rad=Math.min(cW,cH)*.5*dotR*int*am*sc;if(rad<.3)continue;
893
- ctx.globalAlpha=Math.min(1,(p.a/255)*am*(1+gl));
894
- ctx.fillStyle=col;ctx.beginPath();ctx.arc(px,py,rad,0,Math.PI*2);ctx.fill()
895
- }else{
896
- var lum=(.299*p.r+.587*p.g+.114*p.b)/255;if(invert)lum=1-lum;
897
- var ci=Math.floor(lum*(charset.length-1));
898
- var ch=charset[Math.max(0,Math.min(charset.length-1,ci))];
899
- if(ch===' ')continue;
900
- ctx.globalAlpha=Math.min(1,(p.a/255)*am*(1+gl));
901
- ctx.fillStyle=col;
902
- var fs=Math.min(cW/.55,cH)*.9*sc;
903
- ctx.font=fs+'px "JetBrains Mono",monospace';ctx.textAlign='center';ctx.textBaseline='middle';
904
- ctx.fillText(ch,px,py)
905
- }
906
- }
907
- ctx.globalAlpha=1;
908
- ${hasAnim || hasHover ? "requestAnimationFrame(draw)" : ""};
909
- }
910
- ${hasAnim || hasHover ? "requestAnimationFrame(draw)" : "draw(0)"};
911
- })();
912
- </script>
866
+ <canvas id="${id}" width="${width}" height="${height}" style="display:block"></canvas>
867
+ <script src="https://cdn.jsdelivr.net/npm/asciify-engine@${EMBED_CDN_VERSION}/dist/embed.js"></script>
868
+ <script>Asciify('${id}','${data}',${opts})</script>
913
869
  <!-- /Asciify Embed -->`;
914
870
  }
915
871
  function generateAnimatedEmbedCode(frames, options, fps, width, height) {
872
+ if (frames.length === 0) return "";
916
873
  const rows = frames[0].length;
917
874
  const cols = frames[0][0].length;
918
875
  const isDots = options.renderMode === "dots";
919
876
  const allData = frames.map((f) => serializeFrame(f, !isDots));
920
- const hasHover = options.hoverStrength > 0;
921
- const hc = options.hoverColor || "#ffffff";
922
- const hcR = parseInt(hc.slice(1, 3), 16) || 255;
923
- const hcG = parseInt(hc.slice(3, 5), 16) || 255;
924
- const hcB = parseInt(hc.slice(5, 7), 16) || 255;
925
- const charset = isDots ? "" : options.charset;
926
- const hasTransparency = frames.some((f) => f.some((row) => row.some((cell) => cell.a < 200)));
877
+ const id = `ar-${Math.random().toString(36).slice(2, 9)}`;
878
+ const opts = buildEmbedOpts(options, rows, cols, width, height, fps, true);
927
879
  return `<!-- Asciify Animated Embed -->
928
- <canvas id="ar-anim" width="${width}" height="${height}" style="${hasTransparency ? "" : "background:#0a0a0a;"}display:block;"></canvas>
929
- <script>
930
- (function(){
931
- var F=${JSON.stringify(allData)};
932
- var R=${rows},C=${cols},W=${width},H=${height},FPS=${fps};
933
- var cW=W/C,cH=H/R;
934
- var isDots=${isDots};
935
- var invert=${options.invert};
936
- var dotR=${options.dotSizeRatio};
937
- var hStr=${options.hoverStrength},hRad=${options.hoverRadius};
938
- var hcR=${hcR},hcG=${hcG},hcB=${hcB};
939
- var hEff='${options.hoverEffect}';
940
- var charset=${JSON.stringify(charset)};
941
- var hasTr=${hasTransparency};
942
- var cv=document.getElementById('ar-anim'),ctx=cv.getContext('2d');
943
- var mx=-1,my=-1,mIn=0,smX=.5,smY=.5;
944
- var fi=0,lastT=0;
945
- var getColor=${buildColorFnJS(options)};
946
- ${hasHover ? `
947
- cv.addEventListener('mousemove',function(e){var r=cv.getBoundingClientRect();mx=(e.clientX-r.left)/r.width;my=(e.clientY-r.top)/r.height});
948
- cv.addEventListener('mouseleave',function(){mx=-1;my=-1});
949
- function ss(t){return t*t*(3-2*t)}
950
- ` : ""}
951
- function draw(t){
952
- var time=t/1000;
953
- if(t-lastT>=1000/FPS){fi=(fi+1)%F.length;lastT=t}
954
- var D=F[fi];
955
- ctx.clearRect(0,0,W,H);if(!hasTr){ctx.fillStyle='#0a0a0a';ctx.fillRect(0,0,W,H)};
956
- ${hasHover ? `
957
- if(mx>=0){smX+=(mx-smX)*.1;smY+=(my-smY)*.1;mIn+=(1-mIn)*.12}
958
- else{mIn*=.96;if(mIn<.003)mIn=0}
959
- ` : ""}
960
- for(var y=0;y<R;y++)for(var x=0;x<C;x++){
961
- var p=D[y][x];if(p.a<10)continue;
962
- var sc=1,ox=0,oy=0,gl=0,cb=0;
963
- ${hasHover ? `
964
- if(mIn>.003&&hStr>0){
965
- var nx=x/C,ny=y/R,dx=nx-smX,dy=ny-smY,dd=Math.sqrt(dx*dx+dy*dy);
966
- var rad=(.08+hRad*.35)+hStr*.04;
967
- if(dd<rad){
968
- var tt=1-dd/rad,e=ss(tt)*mIn,ang=Math.atan2(dy,dx);
969
- if(hEff==='spotlight'){sc=1+e*hStr*1.8;var pf=e*e*hStr*.6;ox=Math.cos(ang)*pf*cW;oy=Math.sin(ang)*pf*cH;gl=e*hStr*.4;cb=e*e*hStr*.25}
970
- else if(hEff==='magnify'){sc=1+e*hStr*2.5;gl=e*hStr*.15}
971
- else if(hEff==='repel'){sc=1+e*hStr*.3;var pf=e*e*hStr*1.2;ox=Math.cos(ang)*pf*cW;oy=Math.sin(ang)*pf*cH}
972
- else if(hEff==='glow'){gl=e*hStr*.8;cb=e*hStr*.4}
973
- else if(hEff==='colorShift'){sc=1+e*hStr*.4;gl=e*hStr*.2;cb=e*hStr*.7}
880
+ <canvas id="${id}" width="${width}" height="${height}" style="display:block"></canvas>
881
+ <script src="https://cdn.jsdelivr.net/npm/asciify-engine@${EMBED_CDN_VERSION}/dist/embed.js"></script>
882
+ <script>Asciify('${id}',${JSON.stringify(allData)},${opts})</script>
883
+ <!-- /Asciify Animated Embed -->`;
884
+ }
885
+ function _fade(t) {
886
+ return t * t * t * (t * (t * 6 - 15) + 10);
887
+ }
888
+ function _lerp(a, b, t) {
889
+ return a + (b - a) * t;
890
+ }
891
+ function _hash2(ix, iy) {
892
+ let n = ix * 127 + iy * 311;
893
+ n = n >> 13 ^ n;
894
+ return (n * (n * n * 15731 + 789221) + 1376312589 & 2147483647) / 1073741823 - 1;
895
+ }
896
+ function _vnoise(x, y) {
897
+ const ix = Math.floor(x), iy = Math.floor(y);
898
+ const fx = x - ix, fy = y - iy;
899
+ const ux = _fade(fx), uy = _fade(fy);
900
+ const v00 = _hash2(ix, iy);
901
+ const v10 = _hash2(ix + 1, iy);
902
+ const v01 = _hash2(ix, iy + 1);
903
+ const v11 = _hash2(ix + 1, iy + 1);
904
+ return _lerp(_lerp(v00, v10, ux), _lerp(v01, v11, ux), uy);
905
+ }
906
+ function _fbm(x, y) {
907
+ return (_vnoise(x, y) * 0.5 + _vnoise(x * 2.1, y * 2.1) * 0.25 + _vnoise(x * 4.3, y * 4.3) * 0.125) / 0.875;
908
+ }
909
+ function renderWaveBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
910
+ const {
911
+ fontSize = 13,
912
+ charAspect = 0.62,
913
+ lineHeightRatio = 1.4,
914
+ chars = " .:-=+*#%@",
915
+ baseColor = null,
916
+ accentColor = "#d4ff00",
917
+ accentThreshold = 0.52,
918
+ mouseInfluence = 0.55,
919
+ mouseFalloff = 2.8,
920
+ speed = 1,
921
+ vortex = true,
922
+ sparkles = true,
923
+ breathe = true,
924
+ lightMode = false
925
+ } = options;
926
+ const charW = fontSize * charAspect;
927
+ const lineH = fontSize * lineHeightRatio;
928
+ const cols = Math.ceil(width / charW);
929
+ const rows = Math.ceil(height / lineH);
930
+ const mx = mousePos.x;
931
+ const my = mousePos.y;
932
+ let acR = 212, acG = 255, acB = 0;
933
+ if (accentColor) {
934
+ const hex = accentColor.replace("#", "");
935
+ if (hex.length === 6) {
936
+ acR = parseInt(hex.slice(0, 2), 16);
937
+ acG = parseInt(hex.slice(2, 4), 16);
938
+ acB = parseInt(hex.slice(4, 6), 16);
939
+ }
940
+ }
941
+ ctx.clearRect(0, 0, width, height);
942
+ ctx.font = `${fontSize}px "JetBrains Mono", monospace`;
943
+ ctx.textBaseline = "top";
944
+ const t = time * speed;
945
+ const breatheAmp = breathe ? (Math.sin(t * 0.22) * 0.5 + 0.5) * 0.12 : 0;
946
+ for (let row = 0; row < rows; row++) {
947
+ for (let col = 0; col < cols; col++) {
948
+ const nx = col / cols;
949
+ const ny = row / rows;
950
+ const w1 = Math.sin(col * 0.08 + row * 0.05 + t * 0.6) * 0.5 + 0.5;
951
+ const w2 = Math.sin(col * 0.03 - row * 0.07 + t * 0.4) * 0.5 + 0.5;
952
+ const w3 = Math.sin(col * 0.05 + row * 0.03 + t * 0.8) * 0.5 + 0.5;
953
+ const sinePart = (w1 + w2 + w3) / 3;
954
+ const noiseScale = 0.045;
955
+ const noiseShift = t * 0.08;
956
+ const noisePart = _fbm(col * noiseScale + noiseShift, row * noiseScale * 1.4 - noiseShift * 0.7) * 0.5 + 0.5;
957
+ const driftFreq = 0.06;
958
+ const driftPart = Math.sin((col + row * 0.65) * driftFreq + t * 1.1) * 0.5 + 0.5;
959
+ const wavePart = sinePart * 0.45 + noisePart * 0.35 + driftPart * 0.2 + breatheAmp;
960
+ const dxRaw = nx - mx;
961
+ const dyRaw = ny - my;
962
+ const distRaw = Math.sqrt(dxRaw * dxRaw + dyRaw * dyRaw);
963
+ let vortexBump = 0;
964
+ if (vortex && distRaw < 0.35) {
965
+ const angle = Math.atan2(dyRaw, dxRaw);
966
+ const swirl = Math.sin(angle * 4 + t * 2.2 - distRaw * 14);
967
+ const falloff = Math.max(0, 1 - distRaw / 0.35);
968
+ vortexBump = swirl * falloff * falloff * 0.22;
969
+ }
970
+ const proximity = Math.max(0, 1 - distRaw * mouseFalloff);
971
+ const intensity = wavePart * (1 - mouseInfluence) + (proximity + vortexBump * 0.5) * mouseInfluence + vortexBump * 0.15;
972
+ const clamped = Math.min(1, Math.max(0, intensity));
973
+ let finalIntensity = clamped;
974
+ if (sparkles && clamped > 0.72) {
975
+ const bucket = Math.floor(t * 8);
976
+ const sparkleSeed = _hash2(col * 7 + bucket * 3, row * 11 + bucket);
977
+ if (sparkleSeed > 0.88) {
978
+ finalIntensity = Math.min(1, clamped + (sparkleSeed - 0.88) * 4);
974
979
  }
975
980
  }
976
- ` : ""}
977
- var px=x*cW+cW/2+ox,py=y*cH+cH/2+oy;
978
- var col=getColor(p);
979
- if(cb>0){var m=col.match(/rgb\\((\\d+),(\\d+),(\\d+)\\)/);if(m){var rr=+m[1],gg=+m[2],bb=+m[3];col='rgb('+Math.min(255,Math.round(rr+(hcR-rr)*cb))+','+Math.min(255,Math.round(gg+(hcG-gg)*cb))+','+Math.min(255,Math.round(bb+(hcB-bb)*cb))+')'}}
980
- if(isDots){
981
- var lum=p.l/255;var int=invert?1-lum:lum;if(int<.02)continue;
982
- var rad=Math.min(cW,cH)*.5*dotR*int*sc;if(rad<.3)continue;
983
- ctx.globalAlpha=Math.min(1,(p.a/255)*(1+gl));
984
- ctx.fillStyle=col;ctx.beginPath();ctx.arc(px,py,rad,0,Math.PI*2);ctx.fill()
985
- }else{
986
- var lum=(.299*p.r+.587*p.g+.114*p.b)/255;if(invert)lum=1-lum;
987
- var ci=Math.floor(lum*(charset.length-1));
988
- var ch=charset[Math.max(0,Math.min(charset.length-1,ci))];
989
- if(ch===' ')continue;
990
- ctx.globalAlpha=Math.min(1,(p.a/255)*(1+gl));
991
- ctx.fillStyle=col;
992
- var fs=Math.min(cW/.55,cH)*.9*sc;
993
- ctx.font=fs+'px "JetBrains Mono",monospace';ctx.textAlign='center';ctx.textBaseline='middle';
994
- ctx.fillText(ch,px,py)
981
+ const charIdx = Math.floor(finalIntensity * (chars.length - 1));
982
+ if (chars[charIdx] === " ") continue;
983
+ const alpha = 0.015 + finalIntensity * 0.07;
984
+ const isAccent = finalIntensity > accentThreshold;
985
+ if (isAccent) {
986
+ const accentAlpha = Math.min(lightMode ? 0.4 : 0.28, alpha * (lightMode ? 4 : 2.8));
987
+ ctx.fillStyle = `rgba(${acR},${acG},${acB},${accentAlpha})`;
988
+ } else if (baseColor) {
989
+ ctx.fillStyle = baseColor.replace("{a}", String(alpha));
990
+ } else if (lightMode) {
991
+ ctx.fillStyle = `rgba(0,0,0,${alpha * 1.3})`;
992
+ } else {
993
+ ctx.fillStyle = `rgba(255,255,255,${alpha})`;
995
994
  }
995
+ ctx.fillText(chars[charIdx], col * charW, row * lineH);
996
996
  }
997
- ctx.globalAlpha=1;
998
- requestAnimationFrame(draw);
999
997
  }
1000
- requestAnimationFrame(draw);
1001
- })();
1002
- </script>
1003
- <!-- /Asciify Animated Embed -->`;
1004
998
  }
1005
999
 
1006
1000
  // src/webgl-engine.ts
@@ -1265,7 +1259,7 @@ function makeTexture(gl, filter = gl.NEAREST) {
1265
1259
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1266
1260
  return t;
1267
1261
  }
1268
- var ANIM_STYLES = ["none", "wave", "pulse", "rain", "breathe", "sparkle", "glitch", "spiral", "typewriter", "scatter"];
1262
+ var ANIM_STYLES = ["none", "wave", "pulse", "rain", "breathe", "sparkle", "glitch", "spiral", "typewriter", "scatter", "waveField"];
1269
1263
  var HOVER_EFFECTS = ["spotlight", "magnify", "repel", "glow", "colorShift"];
1270
1264
  var COLOR_MODES = ["grayscale", "fullcolor", "matrix", "accent"];
1271
1265
  function tryCreateWebGLRenderer(canvas) {
@@ -1451,6 +1445,6 @@ function tryCreateWebGLRenderer(canvas) {
1451
1445
  }
1452
1446
  }
1453
1447
 
1454
- export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, renderFrameToCanvas, tryCreateWebGLRenderer, videoToAsciiFrames };
1448
+ export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
1455
1449
  //# sourceMappingURL=index.js.map
1456
1450
  //# sourceMappingURL=index.js.map