asciify-engine 1.0.5 → 1.0.7

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;
@@ -697,37 +717,30 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
697
717
  }
698
718
  ctx.globalAlpha = 1;
699
719
  }
700
- 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)+')'}`;
720
+ function serializeFrame(frame, fullColor) {
721
+ const rows = frame.length;
722
+ const cols = rows > 0 ? frame[0].length : 0;
723
+ const stride = fullColor ? 4 : 2;
724
+ const buf = new Uint8Array(1 + rows * cols * stride);
725
+ buf[0] = stride;
726
+ let i = 1;
727
+ for (let y = 0; y < rows; y++) {
728
+ for (let x = 0; x < cols; x++) {
729
+ const cell = frame[y][x];
730
+ if (fullColor) {
731
+ buf[i++] = cell.r;
732
+ buf[i++] = cell.g;
733
+ buf[i++] = cell.b;
734
+ buf[i++] = cell.a;
735
+ } else {
736
+ buf[i++] = Math.round(0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b);
737
+ buf[i++] = cell.a;
738
+ }
727
739
  }
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
740
  }
741
+ let binary = "";
742
+ for (let j = 0; j < buf.length; j++) binary += String.fromCharCode(buf[j]);
743
+ return btoa(binary);
731
744
  }
732
745
  async function asciify(source, canvas, { fontSize = 10, style = "classic", options = {} } = {}) {
733
746
  let el;
@@ -819,188 +832,171 @@ async function asciifyVideo(source, canvas, { fontSize = 10, style = "classic",
819
832
  cancelAnimationFrame(animId);
820
833
  };
821
834
  }
835
+ var EMBED_CDN_VERSION = "1.0.7";
836
+ function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
837
+ const o = {
838
+ r: rows,
839
+ c: cols,
840
+ w: width,
841
+ h: height,
842
+ cs: options.charset,
843
+ cm: options.colorMode,
844
+ as: options.animationStyle,
845
+ sp: options.animationSpeed,
846
+ inv: options.invert,
847
+ hs: options.hoverStrength,
848
+ hr: options.hoverRadius,
849
+ he: options.hoverEffect,
850
+ hc: options.hoverColor,
851
+ dr: options.dotSizeRatio,
852
+ dots: options.renderMode === "dots"
853
+ };
854
+ if (options.colorMode === "accent") o.ac = options.accentColor;
855
+ if (fps !== void 0) o.fps = fps;
856
+ if (animated) o.anim = true;
857
+ return JSON.stringify(o);
858
+ }
822
859
  function generateEmbedCode(frame, options, width, height) {
823
860
  const rows = frame.length;
824
861
  if (rows === 0) return "";
825
862
  const cols = frame[0].length;
826
863
  const isDots = options.renderMode === "dots";
827
864
  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));
865
+ const id = `ar-${Math.random().toString(36).slice(2, 9)}`;
866
+ const opts = buildEmbedOpts(options, rows, cols, width, height);
836
867
  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>
868
+ <canvas id="${id}" width="${width}" height="${height}" style="display:block"></canvas>
869
+ <script src="https://cdn.jsdelivr.net/npm/asciify-engine@${EMBED_CDN_VERSION}/dist/embed.js"></script>
870
+ <script>Asciify('${id}','${data}',${opts})</script>
913
871
  <!-- /Asciify Embed -->`;
914
872
  }
915
873
  function generateAnimatedEmbedCode(frames, options, fps, width, height) {
874
+ if (frames.length === 0) return "";
916
875
  const rows = frames[0].length;
917
876
  const cols = frames[0][0].length;
918
877
  const isDots = options.renderMode === "dots";
919
878
  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)));
879
+ const id = `ar-${Math.random().toString(36).slice(2, 9)}`;
880
+ const opts = buildEmbedOpts(options, rows, cols, width, height, fps, true);
927
881
  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}
882
+ <canvas id="${id}" width="${width}" height="${height}" style="display:block"></canvas>
883
+ <script src="https://cdn.jsdelivr.net/npm/asciify-engine@${EMBED_CDN_VERSION}/dist/embed.js"></script>
884
+ <script>Asciify('${id}',${JSON.stringify(allData)},${opts})</script>
885
+ <!-- /Asciify Animated Embed -->`;
886
+ }
887
+ function _fade(t) {
888
+ return t * t * t * (t * (t * 6 - 15) + 10);
889
+ }
890
+ function _lerp(a, b, t) {
891
+ return a + (b - a) * t;
892
+ }
893
+ function _hash2(ix, iy) {
894
+ let n = ix * 127 + iy * 311;
895
+ n = n >> 13 ^ n;
896
+ return (n * (n * n * 15731 + 789221) + 1376312589 & 2147483647) / 1073741823 - 1;
897
+ }
898
+ function _vnoise(x, y) {
899
+ const ix = Math.floor(x), iy = Math.floor(y);
900
+ const fx = x - ix, fy = y - iy;
901
+ const ux = _fade(fx), uy = _fade(fy);
902
+ const v00 = _hash2(ix, iy);
903
+ const v10 = _hash2(ix + 1, iy);
904
+ const v01 = _hash2(ix, iy + 1);
905
+ const v11 = _hash2(ix + 1, iy + 1);
906
+ return _lerp(_lerp(v00, v10, ux), _lerp(v01, v11, ux), uy);
907
+ }
908
+ function _fbm(x, y) {
909
+ 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;
910
+ }
911
+ function renderWaveBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
912
+ const {
913
+ fontSize = 13,
914
+ charAspect = 0.62,
915
+ lineHeightRatio = 1.4,
916
+ chars = " .:-=+*#%@",
917
+ baseColor = null,
918
+ accentColor = "#d4ff00",
919
+ accentThreshold = 0.52,
920
+ mouseInfluence = 0.55,
921
+ mouseFalloff = 2.8,
922
+ speed = 1,
923
+ vortex = true,
924
+ sparkles = true,
925
+ breathe = true,
926
+ lightMode = false
927
+ } = options;
928
+ const charW = fontSize * charAspect;
929
+ const lineH = fontSize * lineHeightRatio;
930
+ const cols = Math.ceil(width / charW);
931
+ const rows = Math.ceil(height / lineH);
932
+ const mx = mousePos.x;
933
+ const my = mousePos.y;
934
+ let acR = 212, acG = 255, acB = 0;
935
+ if (accentColor) {
936
+ const hex = accentColor.replace("#", "");
937
+ if (hex.length === 6) {
938
+ acR = parseInt(hex.slice(0, 2), 16);
939
+ acG = parseInt(hex.slice(2, 4), 16);
940
+ acB = parseInt(hex.slice(4, 6), 16);
941
+ }
942
+ }
943
+ ctx.clearRect(0, 0, width, height);
944
+ ctx.font = `${fontSize}px "JetBrains Mono", monospace`;
945
+ ctx.textBaseline = "top";
946
+ const t = time * speed;
947
+ const breatheAmp = breathe ? (Math.sin(t * 0.22) * 0.5 + 0.5) * 0.12 : 0;
948
+ for (let row = 0; row < rows; row++) {
949
+ for (let col = 0; col < cols; col++) {
950
+ const nx = col / cols;
951
+ const ny = row / rows;
952
+ const w1 = Math.sin(col * 0.08 + row * 0.05 + t * 0.6) * 0.5 + 0.5;
953
+ const w2 = Math.sin(col * 0.03 - row * 0.07 + t * 0.4) * 0.5 + 0.5;
954
+ const w3 = Math.sin(col * 0.05 + row * 0.03 + t * 0.8) * 0.5 + 0.5;
955
+ const sinePart = (w1 + w2 + w3) / 3;
956
+ const noiseScale = 0.045;
957
+ const noiseShift = t * 0.08;
958
+ const noisePart = _fbm(col * noiseScale + noiseShift, row * noiseScale * 1.4 - noiseShift * 0.7) * 0.5 + 0.5;
959
+ const driftFreq = 0.06;
960
+ const driftPart = Math.sin((col + row * 0.65) * driftFreq + t * 1.1) * 0.5 + 0.5;
961
+ const wavePart = sinePart * 0.45 + noisePart * 0.35 + driftPart * 0.2 + breatheAmp;
962
+ const dxRaw = nx - mx;
963
+ const dyRaw = ny - my;
964
+ const distRaw = Math.sqrt(dxRaw * dxRaw + dyRaw * dyRaw);
965
+ let vortexBump = 0;
966
+ if (vortex && distRaw < 0.35) {
967
+ const angle = Math.atan2(dyRaw, dxRaw);
968
+ const swirl = Math.sin(angle * 4 + t * 2.2 - distRaw * 14);
969
+ const falloff = Math.max(0, 1 - distRaw / 0.35);
970
+ vortexBump = swirl * falloff * falloff * 0.22;
971
+ }
972
+ const proximity = Math.max(0, 1 - distRaw * mouseFalloff);
973
+ const intensity = wavePart * (1 - mouseInfluence) + (proximity + vortexBump * 0.5) * mouseInfluence + vortexBump * 0.15;
974
+ const clamped = Math.min(1, Math.max(0, intensity));
975
+ let finalIntensity = clamped;
976
+ if (sparkles && clamped > 0.72) {
977
+ const bucket = Math.floor(t * 8);
978
+ const sparkleSeed = _hash2(col * 7 + bucket * 3, row * 11 + bucket);
979
+ if (sparkleSeed > 0.88) {
980
+ finalIntensity = Math.min(1, clamped + (sparkleSeed - 0.88) * 4);
974
981
  }
975
982
  }
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)
983
+ const charIdx = Math.floor(finalIntensity * (chars.length - 1));
984
+ if (chars[charIdx] === " ") continue;
985
+ const alpha = 0.015 + finalIntensity * 0.07;
986
+ const isAccent = finalIntensity > accentThreshold;
987
+ if (isAccent) {
988
+ const accentAlpha = Math.min(lightMode ? 0.4 : 0.28, alpha * (lightMode ? 4 : 2.8));
989
+ ctx.fillStyle = `rgba(${acR},${acG},${acB},${accentAlpha})`;
990
+ } else if (baseColor) {
991
+ ctx.fillStyle = baseColor.replace("{a}", String(alpha));
992
+ } else if (lightMode) {
993
+ ctx.fillStyle = `rgba(0,0,0,${alpha * 1.3})`;
994
+ } else {
995
+ ctx.fillStyle = `rgba(255,255,255,${alpha})`;
995
996
  }
997
+ ctx.fillText(chars[charIdx], col * charW, row * lineH);
996
998
  }
997
- ctx.globalAlpha=1;
998
- requestAnimationFrame(draw);
999
999
  }
1000
- requestAnimationFrame(draw);
1001
- })();
1002
- </script>
1003
- <!-- /Asciify Animated Embed -->`;
1004
1000
  }
1005
1001
 
1006
1002
  // src/webgl-engine.ts
@@ -1265,7 +1261,7 @@ function makeTexture(gl, filter = gl.NEAREST) {
1265
1261
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1266
1262
  return t;
1267
1263
  }
1268
- var ANIM_STYLES = ["none", "wave", "pulse", "rain", "breathe", "sparkle", "glitch", "spiral", "typewriter", "scatter"];
1264
+ var ANIM_STYLES = ["none", "wave", "pulse", "rain", "breathe", "sparkle", "glitch", "spiral", "typewriter", "scatter", "waveField"];
1269
1265
  var HOVER_EFFECTS = ["spotlight", "magnify", "repel", "glow", "colorShift"];
1270
1266
  var COLOR_MODES = ["grayscale", "fullcolor", "matrix", "accent"];
1271
1267
  function tryCreateWebGLRenderer(canvas) {
@@ -1451,6 +1447,6 @@ function tryCreateWebGLRenderer(canvas) {
1451
1447
  }
1452
1448
  }
1453
1449
 
1454
- export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, renderFrameToCanvas, tryCreateWebGLRenderer, videoToAsciiFrames };
1450
+ export { ART_STYLE_PRESETS, CHARSETS, DEFAULT_OPTIONS, HOVER_PRESETS, asciify, asciifyGif, asciifyVideo, generateAnimatedEmbedCode, generateEmbedCode, gifToAsciiFrames, imageToAsciiFrame, renderFrameToCanvas, renderWaveBackground, tryCreateWebGLRenderer, videoToAsciiFrames };
1455
1451
  //# sourceMappingURL=index.js.map
1456
1452
  //# sourceMappingURL=index.js.map