@liiift-studio/threadtext 0.0.1 → 0.1.0

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
@@ -15,7 +15,7 @@ Homepage: [threadtext.com](https://threadtext.com) · npm: `@liiift-studio/threa
15
15
 
16
16
  ## What it is
17
17
 
18
- Give it a word set in any loaded (variable) font and it renders it as **raised white satin floss on woven fabric** — threads that run *across* each stroke and fan around the curves, lifted into 3D, seated with a contact shadow, and sewn in one satin stitch at a time. It's photorealistic **by construction** (real thread geometry + lighting), not a raster filter and not an AI image.
18
+ Give it a word set in any loaded (variable) font and it renders it as **raised satin floss on a transparent ground** — threads that run *across* each stroke and fan around the curves, lifted into 3D, and sewn in one satin stitch at a time. Drop it over any background. It's photorealistic **by construction** (real thread geometry + lighting), not a raster filter and not an AI image.
19
19
 
20
20
  ## Why it's worth building (the niche is empty)
21
21
 
@@ -44,7 +44,7 @@ Type to embroider a new word · Backspace to unpick · Enter to replay the sew-i
44
44
 
45
45
  ## How it works (one paragraph)
46
46
 
47
- Rasterise the glyphs → compute a signed-distance field → derive a **flow field** (smoothed in double-angle orientation space so opposite edge-normals reinforce) so threads run across each stroke → lay thousands of discrete pre-shaded **thread sprites** oriented by the flow → lift to 3D with a dome-shade/normal map → seat on procedural woven fabric with a contact shadow → **sew it in** one BFS cross-row at a time (the needle follows the stroke) → a subtle cursor-driven sheen. Full walkthrough with line references in `HANDOFF.md`.
47
+ Rasterise the glyphs → compute a signed-distance field → derive a **flow field** (smoothed in double-angle orientation space so opposite edge-normals reinforce) so threads run across each stroke → lay thousands of discrete pre-shaded **thread sprites** oriented by the flow → lift to 3D with a dome-shade/normal map on a transparent ground → **sew it in** one BFS cross-row at a time (the needle follows the stroke) → a subtle cursor-driven sheen. Full walkthrough with line references in `HANDOFF.md`.
48
48
 
49
49
  ## Use it (extracted API)
50
50
 
@@ -72,9 +72,11 @@ import { ThreadText } from '@liiift-studio/threadtext'
72
72
  <ThreadText text="Thread" font='"Your Font", serif' weight={680} />
73
73
  ```
74
74
 
75
- Colours (`threadColor`, `fabricColor`), thread `pitch`, `sewRate`, `sheen`, `animate`, and
76
- `reducedMotion` are all options see `ThreadTextOptions`. `react`/`react-dom` are optional
77
- peers; the core is framework-free.
75
+ Thread colour, `fill` (size the word re-fits to the container width on load/resize),
76
+ `weight`, `font`, `sewRate`, `sheen`, `animate`, and `editable` (type straight on the
77
+ artwork) are all options — see `ThreadTextOptions`. Change any of them live with
78
+ `instance.update(...)` — it redraws instantly, never re-running the sew-in. `react`/`react-dom`
79
+ are optional peers; the core is framework-free.
78
80
 
79
81
  ## What's next
80
82
 
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Q=require("react"),le=require("react/jsx-runtime"),Dt={bg:"tt-bg",fx:"tt-fx"};function Z(x,r){let a=Math.imul(x|0,374761393)+Math.imul(r|0,668265263)|0;return a=Math.imul(a^a>>>13,1274126177),((a^a>>>16)>>>0)/4294967295}function Nt(x,r){const a=Math.floor(x),c=Math.floor(r),l=x-a,s=r-c,h=l*l*(3-2*l),T=s*s*(3-2*s),S=Z(a,c),I=Z(a+1,c),f=Z(a,c+1),u=Z(a+1,c+1);return S+(I-S)*h+(f-S)*T+(S-I-f+u)*h*T}const wt=1e20;function Qt(x,r,a,c,l){let s=0;c[0]=0,l[0]=-wt,l[1]=wt;for(let h=1;h<r;h++){let T=(x[h]+h*h-(x[c[s]]+c[s]*c[s]))/(2*h-2*c[s]);for(;T<=l[s];)s--,T=(x[h]+h*h-(x[c[s]]+c[s]*c[s]))/(2*h-2*c[s]);s++,c[s]=h,l[s]=T,l[s+1]=wt}s=0;for(let h=0;h<r;h++){for(;l[s+1]<h;)s++;a[h]=(h-c[s])*(h-c[s])+x[c[s]]}}function fe(x,r,a){const c=new Float64Array(r*a);for(let f=0;f<r*a;f++)c[f]=x[f]?wt:0;const l=Math.max(r,a),s=new Float64Array(l),h=new Float64Array(l),T=new Int32Array(l),S=new Float64Array(l+1);for(let f=0;f<r;f++){for(let u=0;u<a;u++)s[u]=c[u*r+f];Qt(s,a,h,T,S);for(let u=0;u<a;u++)c[u*r+f]=h[u]}for(let f=0;f<a;f++){for(let u=0;u<r;u++)s[u]=c[f*r+u];Qt(s,r,h,T,S);for(let u=0;u<r;u++)c[f*r+u]=h[u]}const I=new Float32Array(r*a);for(let f=0;f<r*a;f++)I[f]=Math.sqrt(c[f]);return I}function Zt(x,r,a,c,l){let s=Float32Array.from(x);const h=new Float32Array(r*a),T=1/(2*c+1),S=(I,f)=>I<0?0:I>f?f:I;for(let I=0;I<l;I++){for(let f=0;f<a;f++){const u=f*r;let R=0;for(let P=-c;P<=c;P++)R+=s[u+S(P,r-1)];for(let P=0;P<r;P++)h[u+P]=R*T,R+=s[u+S(P+c+1,r-1)]-s[u+S(P-c,r-1)]}for(let f=0;f<r;f++){let u=0;for(let R=-c;R<=c;R++)u+=h[S(R,a-1)*r+f];for(let R=0;R<a;R++)s[R*r+f]=u*T,u+=h[S(R+c+1,a-1)*r+f]-h[S(R-c,a-1)*r+f]}}return s}function Ht(x,r){if(!x)return r;const a=x.trim();if(a[0]==="#"){let l=a.slice(1);if(l.length===3&&(l=l[0]+l[0]+l[1]+l[1]+l[2]+l[2]),l.length>=6){const s=parseInt(l.slice(0,2),16),h=parseInt(l.slice(2,4),16),T=parseInt(l.slice(4,6),16);if(!Number.isNaN(s)&&!Number.isNaN(h)&&!Number.isNaN(T))return[s,h,T]}return r}const c=a.match(/rgba?\(([^)]+)\)/i);if(c){const l=c[1].split(",").map(s=>parseFloat(s));if(l.length>=3&&l.slice(0,3).every(s=>!Number.isNaN(s)))return[Math.round(l[0]),Math.round(l[1]),Math.round(l[2])]}return r}function D(x){return x<0?0:x>255?255:Math.round(x)}function Wt(x,r){if(typeof window>"u"||typeof document>"u"||!x)return{setText(){},replay(){},resize(){},destroy(){},get text(){return r.text??""}};let a=r.text??"";const c=r.font??"Georgia, serif",l=r.weight??680,s=r.aspect??.46,h=r.sewRate??110,T=r.sheen??!0,S=r.animate??!0,I=(c.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,""),f=r.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),u=Ht(r.threadColor??"#fffbf3",[255,251,243]),R=[u[0]*.585,u[1]*.585,u[2]*.585],P=[u[0]*.47,u[1]*.47,u[2]*.47],H=Ht(r.fabricColor??"#08080a",[8,8,10]),pt=[D(H[0]+14),D(H[1]+13),D(H[2]+15)],j=t=>`rgb(${D(t[0])},${D(t[1])},${D(t[2])})`,W=[];let L,O;x instanceof HTMLCanvasElement?(L=x,O=x.parentElement??x):(O=x,L=document.createElement("canvas"),W.push(L),O.appendChild(L)),L.classList.add(Dt.bg);const N=document.createElement("canvas");W.push(N),N.classList.add(Dt.fx),O.appendChild(N),getComputedStyle(O).position==="static"&&(O.style.position="relative"),L.style.display="block",L.style.width="100%",Object.assign(N.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let e=0,i=0,G=0,Mt=0,et=4,nt=[],ot=0,rt=0,Ct=new Uint8Array(0),St=new Float32Array(0),ft=new Float32Array(0),dt=new Float32Array(0),k=null,U=null,V=null,at=null,ut=null,X=[],ht=3;const A={rows:[],idx:0,acc:0,rate:0,on:!1},K={x:0,y:0,set:!1};let Y=!0,Tt=0,Ot=!1,mt=0,J=!1,At=!1;function qt(){const t=O.getBoundingClientRect(),n=Math.round(t.width||Math.min(window.innerWidth*.95,1240)),o=Math.round(n*s);let d=Math.min(window.devicePixelRatio||1,1.7);for(;n*d*o*d>9e5&&d>.55;)d-=.1;e=Math.max(1,Math.round(n*d)),i=Math.max(1,Math.round(o*d));for(const m of[L,N])m.width=e,m.height=i,m.style.height=o+"px";O.style.height=o+"px"}function zt(){const t=Math.max(7,et*2.5),n=Math.max(3.2,et*1.3);ot=Math.ceil(t)+2,rt=Math.ceil(n)+2,nt=[];for(let o=0;o<20;o++){const d=.34+o/19*.82,m=document.createElement("canvas");m.width=ot,m.height=rt;const M=m.getContext("2d");if(!M){nt.push(m);continue}const C=ot/2,F=rt/2,v=M.createLinearGradient(0,F-n/2,0,F+n/2),p=($,q)=>`rgba(${D($[0]*d)},${D($[1]*d)},${D($[2]*d)},${q})`;v.addColorStop(0,p(P,0)),v.addColorStop(.16,p(R,1)),v.addColorStop(.5,p(u,1)),v.addColorStop(.84,p(R,1)),v.addColorStop(1,p(P,0)),M.fillStyle=v,M.beginPath();const w=n/2;M.moveTo(C-t/2+w,F-w),M.lineTo(C+t/2-w,F-w),M.arc(C+t/2-w,F,w,-Math.PI/2,Math.PI/2),M.lineTo(C-t/2+w,F+w),M.arc(C-t/2+w,F,w,Math.PI/2,-Math.PI/2),M.closePath(),M.fill(),M.globalCompositeOperation="destination-in";const E=M.createLinearGradient(C-t/2,0,C+t/2,0);E.addColorStop(0,"rgba(0,0,0,0)"),E.addColorStop(.22,"rgba(0,0,0,1)"),E.addColorStop(.78,"rgba(0,0,0,1)"),E.addColorStop(1,"rgba(0,0,0,0)"),M.fillStyle=E,M.fillRect(0,0,ot,rt),nt.push(m)}}function bt(){if(!ut)return;const t=ut;t.clearRect(0,0,e,i),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${l} ${G}px ${c}`,t.fillText(a,Mt,i*.5);const n=t.getImageData(0,0,e,i).data,o=new Uint8Array(e*i);for(let g=0;g<i;g++)for(let b=0;b<e;b++){const y=g*e+b,z=n[y*4+3]/255,_=Nt(b*.5,g*.5)*.22+Nt(b*1.8,g*1.8)*.1;o[y]=z>.5+(_-.16)?1:0}Ct=o;const d=fe(o,e,i),m=new Float32Array(e*i);for(let g=1;g<i-1;g++)for(let b=1;b<e-1;b++){const y=g*e+b;m[y]=(d[y]*4+d[y-1]+d[y+1]+d[y-e]+d[y+e])/8}const M=new Float32Array(e*i),C=new Float32Array(e*i),F=new Float32Array(e*i),v=new Float32Array(e*i);for(let g=1;g<i-1;g++)for(let b=1;b<e-1;b++){const y=g*e+b;if(!o[y])continue;const z=(m[y+1]-m[y-1])*.5,_=(m[y+e]-m[y-e])*.5;F[y]=z,v[y]=_,M[y]=z*z-_*_,C[y]=2*z*_}const p=Math.max(7,Math.round(i*.05)),w=Zt(M,e,i,p,2),E=Zt(C,e,i,p,2);ft=new Float32Array(e*i),dt=new Float32Array(e*i);for(let g=0;g<e*i;g++){if(!o[g])continue;const b=.5*Math.atan2(E[g],w[g]);ft[g]=Math.cos(b),dt[g]=Math.sin(b)}const $=Math.max(9,i*.04),q=new Float32Array(e*i),st=-.45,lt=-.62,xt=.64;for(let g=1;g<i-1;g++)for(let b=1;b<e-1;b++){const y=g*e+b;if(!o[y])continue;let z=F[y],_=v[y];const Vt=Math.hypot(z,_)||1;z/=Vt,_/=Vt;const Kt=m[y],Yt=(1-Math.min(Kt/$,1))*1.25;let vt=-z*Yt,Lt=-_*Yt;const Jt=1.5,$t=Math.hypot(vt,Lt,Jt);vt/=$t,Lt/=$t;let Pt=vt*st+Lt*lt+Jt/$t*xt;Pt<0&&(Pt=0);const se=Math.min(1,.45+.55*Math.min(Kt/($*.7),1));q[y]=Math.min(1.12,(.5+.75*Pt)*se)}St=q,k=document.createElement("canvas"),k.width=e,k.height=i;const B=k.getContext("2d");U=document.createElement("canvas"),U.width=e,U.height=i;const tt=U.getContext("2d");if(B&&tt){const g=B.createImageData(e,i),b=tt.createImageData(e,i);for(let y=0;y<e*i;y++)o[y]&&(g.data[y*4]=255,g.data[y*4+1]=255,g.data[y*4+2]=255,g.data[y*4+3]=255,b.data[y*4+3]=255);B.putImageData(g,0,0),tt.putImageData(b,0,0)}}function _t(){V=document.createElement("canvas"),V.width=e,V.height=i;const t=V.getContext("2d",{willReadFrequently:!0});if(t){const n=t.createRadialGradient(e*.5,i*.4,0,e*.5,i*.5,e*.72);n.addColorStop(0,j(pt)),n.addColorStop(1,j(H)),t.fillStyle=n,t.fillRect(0,0,e,i);const o=t.getImageData(0,0,e,i),d=o.data;for(let m=0;m<i;m++)for(let M=0;M<e;M++){const C=(m*e+M)*4,F=Math.sin(M*1.9)*.5+.5,v=Math.sin(m*1.9)*.5+.5,p=F*v*9-4.5+(Nt(M*.18,m*.18)-.5)*15;d[C]=D(d[C]+p),d[C+1]=D(d[C+1]+p),d[C+2]=D(d[C+2]+p*1.1)}t.putImageData(o,0,0)}at=document.createElement("canvas"),at.width=e,at.height=i,ut=at.getContext("2d",{willReadFrequently:!0})}function Ft(){const t=Math.max(1.6,et*.6);ht=t;const n=[];for(let o=0;o<i;o+=t)for(let d=0;d<e;d+=t){const m=(Z(Math.floor(d),Math.floor(o))-.5)*t*.9,M=(Z(Math.floor(o),Math.floor(d))-.5)*t*.9,C=Math.round(d+m),F=Math.round(o+M);if(C<1||F<1||C>=e-1||F>=i-1)continue;const v=F*e+C;if(!Ct[v])continue;const p=Math.atan2(dt[v],ft[v]),w=.86+Z(C*7,F*13)*.18;let E=St[v]*w;E=E<0?0:E>1.12?1.12:E,n.push({x:C,y:F,ang:p,idx:Math.min(19,Math.max(0,Math.round(E/1.12*19)))})}n.sort((o,d)=>o.x-d.x),X=n}function gt(t,n){t.save(),t.translate(n.x,n.y),t.rotate(n.ang),t.drawImage(nt[n.idx],-ot/2,-rt/2),t.restore()}function yt(){const t=L.getContext("2d");if(t)for(const n of X)gt(t,n)}function jt(){return X.length?X[X.length-1].x:0}function Et(){return X.length?X[0].x:0}function it(){const t=L.getContext("2d");!t||!V||(t.drawImage(V,0,0),U&&(t.save(),t.globalAlpha=.85,t.filter=`blur(${Math.round(i*.018)}px)`,t.drawImage(U,0,Math.round(i*.02)),t.restore()))}function ne(t){if(!t.length)return[];const n=Math.max(4,ht*1.5),o=new Map,d=(p,w)=>p+","+w;t.forEach((p,w)=>{const E=d(Math.floor(p.x/n),Math.floor(p.y/n));let $=o.get(E);$||o.set(E,$=[]),$.push(w)});const m=ht*1.8*(ht*1.8);function M(p){const w=t[p],E=Math.floor(w.x/n),$=Math.floor(w.y/n),q=[];for(let st=-1;st<=1;st++)for(let lt=-1;lt<=1;lt++){const xt=o.get(d(E+st,$+lt));if(xt)for(const B of xt){if(B===p)continue;const tt=t[B].x-w.x,g=t[B].y-w.y;tt*tt+g*g<=m&&q.push(B)}}return q}const C=new Uint8Array(t.length),F=[],v=t.map((p,w)=>w).sort((p,w)=>t[p].x+t[p].y-(t[w].x+t[w].y));for(const p of v){if(C[p])continue;let w=[p];for(C[p]=1;w.length;){F.push(w.map($=>t[$]));const E=[];for(const $ of w)for(const q of M($))C[q]||(C[q]=1,E.push(q));w=E}}return F}function It(t,n){it();const o=L.getContext("2d");if(!o)return;const d=[];for(const m of X)m.x<=t?gt(o,m):d.push(m);if(f){for(const m of d)gt(o,m);A.on=!1;return}A.rows=ne(d),A.idx=0,A.acc=0,A.rate=n||h,A.on=A.rows.length>0}function oe(t){const n=L.getContext("2d");if(n)for(t>A.rows.length&&(t=A.rows.length);A.idx<t;){const o=A.rows[A.idx++];for(const d of o)gt(n,d)}}function re(t,n){const o=N.getContext("2d");if(!o||(o.clearRect(0,0,e,i),!T||!k))return;const d=e*.32,m=o.createRadialGradient(t,n,0,t,n,d);m.addColorStop(0,"rgba(255,250,238,0.18)"),m.addColorStop(.5,"rgba(255,250,238,0.055)"),m.addColorStop(1,"rgba(255,250,238,0)"),o.fillStyle=m,o.fillRect(0,0,e,i),o.globalCompositeOperation="destination-in",o.drawImage(k,0,0),o.globalCompositeOperation="source-over"}function Xt(){const t=L.getContext("2d");if(!t){G=Math.round(i*.6),Mt=Math.round(e*.14);return}const n=a||"Ag";t.font=`${l} 100px ${c}`;const o=t.measureText(n).width||100;G=Math.round(100*(e*.72)/o),t.font=`${l} ${G}px ${c}`,Mt=Math.round(e/2-t.measureText(n).width/2)}function kt(t){if(J)return;mt||(mt=t);const n=Math.min(.25,(t-mt)/1e3);mt=t,A.on&&(A.acc+=A.rate*n,oe(A.acc),A.idx>=A.rows.length&&(A.on=!1)),Y&&k&&(re(K.set?K.x:e*.5,K.set?K.y:i*.34),Y=!1),Tt=requestAnimationFrame(kt)}function Bt(t){const n=N.getBoundingClientRect();K.x=(t.clientX-n.left)/(n.width||1)*e,K.y=(t.clientY-n.top)/(n.height||1)*i,K.set=!0,Y=!0}T&&window.addEventListener("pointermove",Bt,{passive:!0});function ae(t){bt(),Ft(),S&&!f?It(Et()-1,h):(it(),yt(),A.on=!1),Y=!0}function ie(){J||(qt(),_t(),et=Math.max(3.4,i*.0095),zt(),Xt(),ae(),At=!0,Ot||(Ot=!0,Tt=requestAnimationFrame(kt)))}let ct;function ce(t){const n=`${l} 200px ${I}`;let o=!1;try{o=!!document.fonts&&document.fonts.check(n)}catch{o=!0}if(!document.fonts||o){t();return}let d=!1;const m=()=>{d||(d=!0,ct&&clearTimeout(ct),t())};document.fonts.load(n,a).then(()=>document.fonts.ready).then(m,m),ct=setTimeout(m,1500)}ce(ie);let Rt;function Gt(){clearTimeout(Rt),Rt=setTimeout(()=>Ut.resize(),200)}window.addEventListener("resize",Gt);const Ut={get text(){return a},setText(t){if(J||!At){a=t??"";return}t=t??"";const n=t.length>a.length&&a.length>0&&t.startsWith(a),o=n?jt():-1;a=t,bt(),Ft(),f||!S?(it(),yt(),A.on=!1):It(n&&o>0?Math.min(o,jt()):Et()-1,n?320:h),Y=!0},replay(){J||!At||(f||!S?(it(),yt(),A.on=!1):It(Et()-1,h),Y=!0)},resize(){J||(qt(),_t(),et=Math.max(3.4,i*.0095),zt(),Xt(),bt(),Ft(),it(),yt(),A.on=!1,Y=!0)},destroy(){if(!J){J=!0,cancelAnimationFrame(Tt),clearTimeout(Rt),ct&&clearTimeout(ct),window.removeEventListener("resize",Gt),T&&window.removeEventListener("pointermove",Bt);for(const t of W)t.remove();nt=[],X=[],A.rows=[],Ct=new Uint8Array(0),St=new Float32Array(0),ft=new Float32Array(0),dt=new Float32Array(0),k=U=V=at=null,ut=null}}};return Ut}function te(x){const r=Q.useRef(null),a=Q.useRef(null),c=Q.useRef(x);c.current=x;const{text:l,font:s,weight:h,threadColor:T,fabricColor:S,pitch:I,animate:f,sewRate:u,sheen:R,reducedMotion:P,aspect:H}=x,pt=JSON.stringify({font:s,weight:h,threadColor:T,fabricColor:S,pitch:I,animate:f,sewRate:u,sheen:R,reducedMotion:P,aspect:H});return Q.useLayoutEffect(()=>{const j=r.current;if(!j)return;const W=Wt(j,c.current);a.current=W;let L=0,O=0,N;return typeof ResizeObserver<"u"&&(N=new ResizeObserver(e=>{const i=Math.round(e[0].contentRect.width);i!==O&&(O=i,cancelAnimationFrame(L),L=requestAnimationFrame(()=>{var G;return(G=a.current)==null?void 0:G.resize()}))}),N.observe(j)),()=>{N==null||N.disconnect(),cancelAnimationFrame(L),W.destroy(),a.current=null}},[pt]),Q.useEffect(()=>{var j;(j=a.current)==null||j.setText(l)},[l]),r}const ee=Q.forwardRef(function({className:r,style:a,as:c="div","aria-label":l,role:s,"aria-describedby":h,...T},S){const I=te(T),f=Q.useCallback(u=>{I.current=u,typeof S=="function"?S(u):S&&(S.current=u)},[I,S]);return le.jsx(c,{ref:f,className:r,style:a,role:s??"img","aria-label":l??T.text,"aria-describedby":h})});ee.displayName="ThreadText";exports.THREAD_TEXT_CLASSES=Dt;exports.ThreadText=ee;exports.createThreadText=Wt;exports.useThreadText=te;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const X=require("react"),xe=require("react/jsx-runtime"),pt={bg:"tt-bg",fx:"tt-fx",caret:"tt-caret"};function Q(m,e){let o=Math.imul(m|0,374761393)+Math.imul(e|0,668265263)|0;return o=Math.imul(o^o>>>13,1274126177),((o^o>>>16)>>>0)/4294967295}function Qt(m,e){const o=Math.floor(m),r=Math.floor(e),i=m-o,a=e-r,f=i*i*(3-2*i),A=a*a*(3-2*a),E=Q(o,r),C=Q(o+1,r),c=Q(o,r+1),d=Q(o+1,r+1);return E+(C-E)*f+(c-E)*A+(E-C-c+d)*f*A}const Mt=1e20;function Zt(m,e,o,r,i){let a=0;r[0]=0,i[0]=-Mt,i[1]=Mt;for(let f=1;f<e;f++){let A=(m[f]+f*f-(m[r[a]]+r[a]*r[a]))/(2*f-2*r[a]);for(;A<=i[a];)a--,A=(m[f]+f*f-(m[r[a]]+r[a]*r[a]))/(2*f-2*r[a]);a++,r[a]=f,i[a]=A,i[a+1]=Mt}a=0;for(let f=0;f<e;f++){for(;i[a+1]<f;)a++;o[f]=(f-r[a])*(f-r[a])+m[r[a]]}}function ge(m,e,o){const r=new Float64Array(e*o);for(let c=0;c<e*o;c++)r[c]=m[c]?Mt:0;const i=Math.max(e,o),a=new Float64Array(i),f=new Float64Array(i),A=new Int32Array(i),E=new Float64Array(i+1);for(let c=0;c<e;c++){for(let d=0;d<o;d++)a[d]=r[d*e+c];Zt(a,o,f,A,E);for(let d=0;d<o;d++)r[d*e+c]=f[d]}for(let c=0;c<o;c++){for(let d=0;d<e;d++)a[d]=r[c*e+d];Zt(a,e,f,A,E);for(let d=0;d<e;d++)r[c*e+d]=f[d]}const C=new Float32Array(e*o);for(let c=0;c<e*o;c++)C[c]=Math.sqrt(r[c]);return C}function Ht(m,e,o,r,i){let a=Float32Array.from(m);const f=new Float32Array(e*o),A=1/(2*r+1),E=(C,c)=>C<0?0:C>c?c:C;for(let C=0;C<i;C++){for(let c=0;c<o;c++){const d=c*e;let $=0;for(let B=-r;B<=r;B++)$+=a[d+E(B,e-1)];for(let B=0;B<e;B++)f[d+B]=$*A,$+=a[d+E(B+r+1,e-1)]-a[d+E(B-r,e-1)]}for(let c=0;c<e;c++){let d=0;for(let $=-r;$<=r;$++)d+=f[E($,o-1)*e+c];for(let $=0;$<o;$++)a[$*e+c]=d*A,d+=f[E($+r+1,o-1)*e+c]-f[E($-r,o-1)*e+c]}}return a}function Wt(m,e){if(!m)return e;const o=m.trim();if(o[0]==="#"){let i=o.slice(1);if(i.length===3&&(i=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]),i.length>=6){const a=parseInt(i.slice(0,2),16),f=parseInt(i.slice(2,4),16),A=parseInt(i.slice(4,6),16);if(!Number.isNaN(a)&&!Number.isNaN(f)&&!Number.isNaN(A))return[a,f,A]}return e}const r=o.match(/rgba?\(([^)]+)\)/i);if(r){const i=r[1].split(",").map(a=>parseFloat(a));if(i.length>=3&&i.slice(0,3).every(a=>!Number.isNaN(a)))return[Math.round(i[0]),Math.round(i[1]),Math.round(i[2])]}return e}function K(m){return m<0?0:m>255?255:Math.round(m)}function te(m){return(m.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,"")}function ee(m,e){if(typeof window>"u"||typeof document>"u"||!m)return{setText(){},replay(){},resize(){},update(){},focus(){},destroy(){},get text(){return e.text??""}};let o=e.text??"",r=e.font??"Georgia, serif",i=e.weight??680,a=e.fill??.9,f=e.sewRate??110,A=e.sheen??!0,E=e.animate??!0,C=e.editable??!1,c=e.pitch,d=e.onTextChange,$=te(r);const B=e.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches);let D=Wt(e.threadColor??"#fffbf3",[255,251,243]),tt=[0,0,0],N=[0,0,0];function et(t){D=Wt(t,[255,251,243]),tt=[D[0]*.585,D[1]*.585,D[2]*.585],N=[D[0]*.47,D[1]*.47,D[2]*.47]}et(e.threadColor??"#fffbf3");const G=[];let P,g;m instanceof HTMLCanvasElement?(P=m,g=m.parentElement??m):(g=m,P=document.createElement("canvas"),G.push(P),g.appendChild(P)),P.classList.add(pt.bg);const O=document.createElement("canvas");G.push(O),O.classList.add(pt.fx),g.appendChild(O),getComputedStyle(g).position==="static"&&(g.style.position="relative"),P.style.display="block",P.style.width="100%",Object.assign(O.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let S=null,Z=!1,s=0,h=0,H=0,bt=0,ft=4,nt=[],ot=0,rt=0,Ct=new Uint8Array(0),Tt=new Float32Array(0),ut=new Float32Array(0),dt=new Float32Array(0),U=null,it=null,ht=null,mt=[],yt=3;const L={rows:[],idx:0,acc:0,rate:0,on:!1},Y={x:0,y:0,set:!1};let W=!0,vt=0,Bt=!1,xt=0,q=!1,J=!1;function re(){const t=g.getBoundingClientRect(),n=Math.max(1,Math.round(t.width||Math.min(window.innerWidth*.95,1240))),l=o||"Ag",y=P.getContext("2d");let T=100;y&&(y.font=`${i} 100px ${r}`,T=y.measureText(l).width||100);let b=Math.max(8,100*(n*a)/T),v=b*.7,R=b*.3,I=n*a;if(y){y.font=`${i} ${b}px ${r}`;const p=y.measureText(l);I=p.width||I,p.actualBoundingBoxAscent>0&&(v=p.actualBoundingBoxAscent),p.actualBoundingBoxDescent>0&&(R=p.actualBoundingBoxDescent)}const w=Math.max(1,Math.round(2*Math.max(v,R)*1.12));let u=Math.min(window.devicePixelRatio||1,1.7);for(;n*u*w*u>9e5&&u>.4;)u-=.1;s=Math.max(1,Math.round(n*u)),h=Math.max(1,Math.round(w*u)),H=Math.max(4,Math.round(b*u)),bt=Math.round(s/2-I*u/2);for(const p of[P,O])p.width=s,p.height=h,p.style.height=w+"px";g.style.height=w+"px",ft=c??Math.max(3,h*.0095)}function ie(){it=document.createElement("canvas"),it.width=s,it.height=h,ht=it.getContext("2d",{willReadFrequently:!0})}function Nt(){const t=Math.max(7,ft*2.5),n=Math.max(3.2,ft*1.3);ot=Math.ceil(t)+2,rt=Math.ceil(n)+2,nt=[];for(let l=0;l<20;l++){const y=.34+l/19*.82,T=document.createElement("canvas");T.width=ot,T.height=rt;const b=T.getContext("2d");if(!b){nt.push(T);continue}const v=ot/2,R=rt/2,I=b.createLinearGradient(0,R-n/2,0,R+n/2),w=(k,j)=>`rgba(${K(k[0]*y)},${K(k[1]*y)},${K(k[2]*y)},${j})`;I.addColorStop(0,w(N,0)),I.addColorStop(.16,w(tt,1)),I.addColorStop(.5,w(D,1)),I.addColorStop(.84,w(tt,1)),I.addColorStop(1,w(N,0)),b.fillStyle=I,b.beginPath();const u=n/2;b.moveTo(v-t/2+u,R-u),b.lineTo(v+t/2-u,R-u),b.arc(v+t/2-u,R,u,-Math.PI/2,Math.PI/2),b.lineTo(v-t/2+u,R+u),b.arc(v-t/2+u,R,u,Math.PI/2,-Math.PI/2),b.closePath(),b.fill(),b.globalCompositeOperation="destination-in";const p=b.createLinearGradient(v-t/2,0,v+t/2,0);p.addColorStop(0,"rgba(0,0,0,0)"),p.addColorStop(.22,"rgba(0,0,0,1)"),p.addColorStop(.78,"rgba(0,0,0,1)"),p.addColorStop(1,"rgba(0,0,0,0)"),b.fillStyle=p,b.fillRect(0,0,ot,rt),nt.push(T)}}function ae(){if(!ht)return;const t=ht;t.clearRect(0,0,s,h),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${i} ${H}px ${r}`,t.fillText(o,bt,h*.5);const n=t.getImageData(0,0,s,h).data,l=new Uint8Array(s*h);for(let x=0;x<h;x++)for(let M=0;M<s;M++){const F=x*s+M,_=n[F*4+3]/255,z=Qt(M*.5,x*.5)*.22+Qt(M*1.8,x*1.8)*.1;l[F]=_>.5+(z-.16)?1:0}Ct=l;const y=ge(l,s,h),T=new Float32Array(s*h);for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;T[F]=(y[F]*4+y[F-1]+y[F+1]+y[F-s]+y[F+s])/8}const b=new Float32Array(s*h),v=new Float32Array(s*h),R=new Float32Array(s*h),I=new Float32Array(s*h);for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;if(!l[F])continue;const _=(T[F+1]-T[F-1])*.5,z=(T[F+s]-T[F-s])*.5;R[F]=_,I[F]=z,b[F]=_*_-z*z,v[F]=2*_*z}const w=Math.max(7,Math.round(h*.05)),u=Ht(b,s,h,w,2),p=Ht(v,s,h,w,2);ut=new Float32Array(s*h),dt=new Float32Array(s*h);for(let x=0;x<s*h;x++){if(!l[x])continue;const M=.5*Math.atan2(p[x],u[x]);ut[x]=Math.cos(M),dt[x]=Math.sin(M)}const k=Math.max(9,h*.04),j=new Float32Array(s*h),ct=-.45,st=-.62,wt=.64;for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;if(!l[F])continue;let _=R[F],z=I[F];const Ut=Math.hypot(_,z)||1;_/=Ut,z/=Ut;const Vt=T[F],Yt=(1-Math.min(Vt/k,1))*1.25;let It=-_*Yt,Pt=-z*Yt;const Jt=1.5,Dt=Math.hypot(It,Pt,Jt);It/=Dt,Pt/=Dt;let kt=It*ct+Pt*st+Jt/Dt*wt;kt<0&&(kt=0);const ye=Math.min(1,.45+.55*Math.min(Vt/(k*.7),1));j[F]=Math.min(1.12,(.5+.75*kt)*ye)}Tt=j,U=document.createElement("canvas"),U.width=s,U.height=h;const V=U.getContext("2d");if(V){const x=V.createImageData(s,h);for(let M=0;M<s*h;M++)l[M]&&(x.data[M*4]=255,x.data[M*4+1]=255,x.data[M*4+2]=255,x.data[M*4+3]=255);V.putImageData(x,0,0)}}function le(){const t=Math.max(1.6,ft*.6);yt=t;const n=[];for(let l=0;l<h;l+=t)for(let y=0;y<s;y+=t){const T=(Q(Math.floor(y),Math.floor(l))-.5)*t*.9,b=(Q(Math.floor(l),Math.floor(y))-.5)*t*.9,v=Math.round(y+T),R=Math.round(l+b);if(v<1||R<1||v>=s-1||R>=h-1)continue;const I=R*s+v;if(!Ct[I])continue;const w=Math.atan2(dt[I],ut[I]),u=.86+Q(v*7,R*13)*.18;let p=Tt[I]*u;p=p<0?0:p>1.12?1.12:p,n.push({x:v,y:R,ang:w,idx:Math.min(19,Math.max(0,Math.round(p/1.12*19)))})}n.sort((l,y)=>l.x-y.x),mt=n}function Ot(t,n){t.save(),t.translate(n.x,n.y),t.rotate(n.ang),t.drawImage(nt[n.idx],-ot/2,-rt/2),t.restore()}function At(){const t=P.getContext("2d");if(t)for(const n of mt)Ot(t,n)}function Et(){const t=P.getContext("2d");t&&t.clearRect(0,0,s,h)}function ce(t){if(!t.length)return[];const n=Math.max(4,yt*1.5),l=new Map,y=(w,u)=>w+","+u;t.forEach((w,u)=>{const p=y(Math.floor(w.x/n),Math.floor(w.y/n));let k=l.get(p);k||l.set(p,k=[]),k.push(u)});const T=yt*1.8*(yt*1.8);function b(w){const u=t[w],p=Math.floor(u.x/n),k=Math.floor(u.y/n),j=[];for(let ct=-1;ct<=1;ct++)for(let st=-1;st<=1;st++){const wt=l.get(y(p+ct,k+st));if(wt)for(const V of wt){if(V===w)continue;const x=t[V].x-u.x,M=t[V].y-u.y;x*x+M*M<=T&&j.push(V)}}return j}const v=new Uint8Array(t.length),R=[],I=t.map((w,u)=>u).sort((w,u)=>t[w].x+t[w].y-(t[u].x+t[u].y));for(const w of I){if(v[w])continue;let u=[w];for(v[w]=1;u.length;){R.push(u.map(k=>t[k]));const p=[];for(const k of u)for(const j of b(k))v[j]||(v[j]=1,p.push(j));u=p}}return R}function se(){if(Et(),B||!E){At(),L.on=!1;return}L.rows=ce(mt),L.idx=0,L.acc=0,L.rate=f,L.on=L.rows.length>0}function fe(t){const n=P.getContext("2d");if(n)for(t>L.rows.length&&(t=L.rows.length);L.idx<t;){const l=L.rows[L.idx++];for(const y of l)Ot(n,y)}}function ue(t,n){const l=O.getContext("2d");if(!l||(l.clearRect(0,0,s,h),!A||!U))return;const y=s*.32,T=l.createRadialGradient(t,n,0,t,n,y);T.addColorStop(0,"rgba(255,250,238,0.18)"),T.addColorStop(.5,"rgba(255,250,238,0.055)"),T.addColorStop(1,"rgba(255,250,238,0)"),l.fillStyle=T,l.fillRect(0,0,s,h),l.globalCompositeOperation="destination-in",l.drawImage(U,0,0),l.globalCompositeOperation="source-over"}function de(){S||!C||(S=document.createElement("span"),S.className=pt.caret,S.setAttribute("aria-hidden","true"),Object.assign(S.style,{position:"absolute",pointerEvents:"none",borderRadius:"1px",opacity:"0",background:`rgb(${K(D[0])},${K(D[1])},${K(D[2])})`}),g.appendChild(S),G.push(S))}function St(){if(!C||!S)return;const t=P.getContext("2d");if(!t)return;t.font=`${i} ${H}px ${r}`;const n=t.measureText(o).width,l=(P.clientWidth||s)/s,y=H*.7;S.style.left=(bt+n+H*.05)*l+"px",S.style.top=.5*(P.clientHeight||h)-y*l/2+"px",S.style.height=y*l+"px",S.style.width=Math.max(2,Math.round(H*.02*l))+"px",S.style.background=`rgb(${K(D[0])},${K(D[1])},${K(D[2])})`}function jt(t){if(q)return;xt||(xt=t);const n=Math.min(.25,(t-xt)/1e3);xt=t,L.on&&(L.acc+=L.rate*n,fe(L.acc),L.idx>=L.rows.length&&(L.on=!1)),W&&U&&(ue(Y.set?Y.x:s*.5,Y.set?Y.y:h*.34),W=!1),S&&(S.style.opacity=C&&Z&&Math.floor(t/530)%2===0?"1":"0"),vt=requestAnimationFrame(jt)}function gt(t){const n=O.getBoundingClientRect();Y.x=(t.clientX-n.left)/(n.width||1)*s,Y.y=(t.clientY-n.top)/(n.height||1)*h,Y.set=!0,W=!0}function qt(t){if(!(!C||t.metaKey||t.ctrlKey||t.altKey)){if(t.key==="Backspace"){t.preventDefault(),Rt(o.slice(0,-1),!0);return}if(t.key==="Enter"){t.preventDefault(),$t.replay();return}[...t.key].length===1&&(t.preventDefault(),Rt(o+t.key,!0))}}function _t(){Z=!0}function zt(){Z=!1,S&&(S.style.opacity="0")}function Kt(){C&&g.focus()}function Ft(t){C=t,t?(g.tabIndex=0,g.setAttribute("role","textbox"),g.getAttribute("aria-label")||g.setAttribute("aria-label","Editable embroidered text — type to change it"),de(),g.addEventListener("keydown",qt),g.addEventListener("focus",_t),g.addEventListener("blur",zt),g.addEventListener("pointerdown",Kt),St()):(g.removeAttribute("tabindex"),g.removeAttribute("role"),g.removeEventListener("keydown",qt),g.removeEventListener("focus",_t),g.removeEventListener("blur",zt),g.removeEventListener("pointerdown",Kt),S&&(S.style.opacity="0"))}function he(t){if(t!==A)if(A=t,t)window.addEventListener("pointermove",gt,{passive:!0}),W=!0;else{window.removeEventListener("pointermove",gt);const n=O.getContext("2d");n&&n.clearRect(0,0,s,h)}}function at(t){re(),ie(),Nt(),ae(),le(),t?se():(Et(),At(),L.on=!1),St(),W=!0}function Rt(t,n){t=t??"",!(t===o&&J)&&(o=t,J&&(at(!1),n&&d&&d(o)))}let lt;function Xt(t,n,l){const y=`${n} 200px ${t}`;let T=!1;try{T=!!document.fonts&&document.fonts.check(y)}catch{T=!0}if(!document.fonts||T){l();return}let b=!1;const v=()=>{b||(b=!0,lt&&clearTimeout(lt),l())};document.fonts.load(y,o).then(()=>document.fonts.ready).then(v,v),lt=setTimeout(v,1500)}function me(){q||(at(!0),J=!0,Bt||(Bt=!0,vt=requestAnimationFrame(jt)))}C&&Ft(!0),A&&window.addEventListener("pointermove",gt,{passive:!0}),Xt($,i,me);let Lt;function Gt(){clearTimeout(Lt),Lt=setTimeout(()=>$t.resize(),200)}window.addEventListener("resize",Gt);const $t={get text(){return o},setText(t){if(!q){if(!J){o=t??"";return}Rt(t,!1)}},replay(){q||!J||at(!0)},resize(){q||!J||at(!1)},update(t){if(q)return;let n=!1,l=!1;t.font!==void 0&&t.font!==r&&(r=t.font,$=te(r),n=!0),t.weight!==void 0&&t.weight!==i&&(i=t.weight,n=!0),t.fill!==void 0&&t.fill!==a&&(a=t.fill,n=!0),t.pitch!==void 0&&t.pitch!==c&&(c=t.pitch,n=!0),t.threadColor!==void 0&&(et(t.threadColor),l=!0),t.sewRate!==void 0&&(f=t.sewRate),t.animate!==void 0&&(E=t.animate),t.onTextChange!==void 0&&(d=t.onTextChange),t.sheen!==void 0&&he(t.sheen),t.editable!==void 0&&t.editable!==C&&Ft(t.editable),J&&(n?Xt($,i,()=>{q||at(!1)}):l&&(Nt(),Et(),At(),St()),W=!0)},focus(){!q&&C&&g.focus()},destroy(){if(!q){q=!0,cancelAnimationFrame(vt),clearTimeout(Lt),lt&&clearTimeout(lt),window.removeEventListener("resize",Gt),window.removeEventListener("pointermove",gt),C&&Ft(!1);for(const t of G)t.remove();nt=[],mt=[],L.rows=[],Ct=new Uint8Array(0),Tt=new Float32Array(0),ut=new Float32Array(0),dt=new Float32Array(0),U=it=null,ht=null,S=null}}};return $t}function ne(m){const e=X.useRef(null),o=X.useRef(null),r=X.useRef(m);r.current=m;const i=X.useRef(m.onTextChange);i.current=m.onTextChange;const{text:a,font:f,weight:A,threadColor:E,pitch:C,fill:c,animate:d,sewRate:$,sheen:B,editable:D,reducedMotion:tt}=m;return X.useLayoutEffect(()=>{const N=e.current;if(!N)return;const et=ee(N,{...r.current,onTextChange:O=>{var S;return(S=i.current)==null?void 0:S.call(i,O)}});o.current=et;let G=0,P=0,g;return typeof ResizeObserver<"u"&&(g=new ResizeObserver(O=>{const S=Math.round(O[0].contentRect.width);S!==P&&(P=S,cancelAnimationFrame(G),G=requestAnimationFrame(()=>{var Z;return(Z=o.current)==null?void 0:Z.resize()}))}),g.observe(N)),()=>{g==null||g.disconnect(),cancelAnimationFrame(G),et.destroy(),o.current=null}},[tt]),X.useEffect(()=>{var N;(N=o.current)==null||N.update({font:f,weight:A,threadColor:E,pitch:C,fill:c,animate:d,sewRate:$,sheen:B,editable:D})},[f,A,E,C,c,d,$,B,D]),X.useEffect(()=>{var N;(N=o.current)==null||N.setText(a)},[a]),e}const oe=X.forwardRef(function({className:e,style:o,as:r="div","aria-label":i,role:a,"aria-describedby":f,...A},E){const C=ne(A),c=X.useCallback(d=>{C.current=d,typeof E=="function"?E(d):E&&(E.current=d)},[C,E]);return xe.jsx(r,{ref:c,className:e,style:o,role:a??"img","aria-label":i??A.text,"aria-describedby":f})});oe.displayName="ThreadText";exports.THREAD_TEXT_CLASSES=pt;exports.ThreadText=oe;exports.createThreadText=ee;exports.useThreadText=ne;
package/dist/index.d.ts CHANGED
@@ -12,10 +12,12 @@ export declare function createThreadText(target: HTMLElement, opts: ThreadTextOp
12
12
 
13
13
  /** CSS class names applied to the canvases threadText creates inside a container. */
14
14
  export declare const THREAD_TEXT_CLASSES: {
15
- /** Base canvas: woven fabric + baked satin stitches. */
15
+ /** Base canvas: the baked satin stitches (transparent ground). */
16
16
  readonly bg: "tt-bg";
17
17
  /** Overlay canvas: cursor sheen (`mix-blend-mode: screen`). */
18
18
  readonly fx: "tt-fx";
19
+ /** Blinking text caret shown in editable mode. */
20
+ readonly caret: "tt-caret";
19
21
  };
20
22
 
21
23
  /**
@@ -26,15 +28,19 @@ export declare const ThreadText: default_2.ForwardRefExoticComponent<ThreadTextP
26
28
 
27
29
  /** Live handle to a mounted threadText renderer. */
28
30
  export declare interface ThreadTextInstance {
29
- /**
30
- * Re-embroider with new text. When `text` extends the current word (an append),
31
- * only the newly-added letters animate in; otherwise the whole word is re-sewn.
32
- */
31
+ /** Re-embroider with new text — re-fits to width and redraws instantly (no sew-in). */
33
32
  setText(text: string): void;
34
- /** Re-run the full sew-in animation for the current word. */
33
+ /** Re-run the sew-in animation for the current word (when `animate` is on). */
35
34
  replay(): void;
36
- /** Re-fit the render surface to its container and rebuild. */
35
+ /** Re-fit the render surface to its container and redraw. */
37
36
  resize(): void;
37
+ /**
38
+ * Apply option changes live and redraw instantly — never re-runs the sew-in. Use for
39
+ * colour, font, weight, size (`fill`), sew rate, sheen, and editability changes.
40
+ */
41
+ update(options: Partial<ThreadTextOptions>): void;
42
+ /** Focus the surface for typing (editable mode). */
43
+ focus(): void;
38
44
  /** Cancel the animation loop, remove listeners, and free the created canvases. */
39
45
  destroy(): void;
40
46
  /** The current embroidered text. */
@@ -58,29 +64,36 @@ export declare interface ThreadTextOptions {
58
64
  weight?: number;
59
65
  /** Floss (thread) colour — the lit crest of each thread. (default: warm white '#fffbf3') */
60
66
  threadColor?: string;
61
- /** Woven-ground base colour — the outer edge of the fabric. (default near-black linen '#08080a') */
62
- fabricColor?: string;
63
67
  /**
64
68
  * Thread spacing in internal pixels. Smaller = finer, denser stitching (and more work).
65
- * (default: auto — derived from the canvas height)
69
+ * (default: auto — derived from the fitted text height)
66
70
  */
67
71
  pitch?: number;
68
- /** Play the sew-in animation when the instance mounts. (default: true) */
72
+ /**
73
+ * Fraction of the container width the word spans — the effective text size. The word is
74
+ * re-fitted to `fill × containerWidth` on load and resize, leaving the remainder as
75
+ * horizontal padding. Range ~0.3–1. (default: 0.9)
76
+ */
77
+ fill?: number;
78
+ /** Play the sew-in animation on mount and on `replay()`. (default: true) */
69
79
  animate?: boolean;
70
80
  /** Satin cross-rows laid per second during the sew-in. (default: 110) */
71
81
  sewRate?: number;
72
82
  /** Enable the cursor-following radial sheen on the overlay canvas. (default: true) */
73
83
  sheen?: boolean;
84
+ /**
85
+ * Make the surface focusable and typeable — click (or Tab) to focus, then type to edit
86
+ * the word, Backspace to delete, Enter to replay the sew-in. Shows a blinking caret.
87
+ * (default: false)
88
+ */
89
+ editable?: boolean;
90
+ /** Called with the new text whenever the user edits it directly (editable mode only). */
91
+ onTextChange?: (text: string) => void;
74
92
  /**
75
93
  * Force reduced-motion (skip the sew-in, draw instantly). If omitted, the value is
76
94
  * auto-detected from `prefers-reduced-motion`.
77
95
  */
78
96
  reducedMotion?: boolean;
79
- /**
80
- * Aspect ratio (height / width) of the render surface when the target is a plain
81
- * container and its own canvases are created. (default: 0.46)
82
- */
83
- aspect?: number;
84
97
  }
85
98
 
86
99
  declare interface ThreadTextProps extends ThreadTextOptions {
@@ -100,10 +113,11 @@ declare interface ThreadTextProps extends ThreadTextOptions {
100
113
  /**
101
114
  * React hook that mounts a threadText renderer inside a ref'd container.
102
115
  *
103
- * The instance is (re)created only when a *structural* option changes (font, weight,
104
- * colours, pitch, sizing, motion). Changing just `text` routes through
105
- * `instance.setText()` so appended letters animate in without a full remount.
106
- * Re-fits to the container via ResizeObserver and tears down on unmount.
116
+ * The instance is created once and kept alive; option changes (font, weight, colour,
117
+ * size, sew rate, sheen, editability) are applied live via `instance.update()` no
118
+ * remount, no re-sew. Text changes route through `setText`. The surface re-fits to the
119
+ * container width via ResizeObserver, and tears down on unmount. Only `reducedMotion`
120
+ * (fixed at creation) forces a fresh instance.
107
121
  *
108
122
  * @param options - {@link ThreadTextOptions} for the renderer.
109
123
  * @returns A ref to attach to the target container element.
package/dist/index.js CHANGED
@@ -1,439 +1,493 @@
1
- import { useRef as Pt, useLayoutEffect as ie, useEffect as ce, forwardRef as se, useCallback as le } from "react";
2
- import { jsx as fe } from "react/jsx-runtime";
3
- const Jt = {
4
- /** Base canvas: woven fabric + baked satin stitches. */
1
+ import { useRef as wt, useLayoutEffect as me, useEffect as Qt, forwardRef as ye, useCallback as xe } from "react";
2
+ import { jsx as ge } from "react/jsx-runtime";
3
+ const Bt = {
4
+ /** Base canvas: the baked satin stitches (transparent ground). */
5
5
  bg: "tt-bg",
6
6
  /** Overlay canvas: cursor sheen (`mix-blend-mode: screen`). */
7
- fx: "tt-fx"
7
+ fx: "tt-fx",
8
+ /** Blinking text caret shown in editable mode. */
9
+ caret: "tt-caret"
8
10
  };
9
- function Q(x, r) {
10
- let a = Math.imul(x | 0, 374761393) + Math.imul(r | 0, 668265263) | 0;
11
- return a = Math.imul(a ^ a >>> 13, 1274126177), ((a ^ a >>> 16) >>> 0) / 4294967295;
11
+ function J(m, e) {
12
+ let o = Math.imul(m | 0, 374761393) + Math.imul(e | 0, 668265263) | 0;
13
+ return o = Math.imul(o ^ o >>> 13, 1274126177), ((o ^ o >>> 16) >>> 0) / 4294967295;
12
14
  }
13
- function Nt(x, r) {
14
- const a = Math.floor(x), c = Math.floor(r), l = x - a, s = r - c, h = l * l * (3 - 2 * l), A = s * s * (3 - 2 * s), S = Q(a, c), I = Q(a + 1, c), f = Q(a, c + 1), u = Q(a + 1, c + 1);
15
- return S + (I - S) * h + (f - S) * A + (S - I - f + u) * h * A;
15
+ function Zt(m, e) {
16
+ const o = Math.floor(m), r = Math.floor(e), i = m - o, a = e - r, f = i * i * (3 - 2 * i), A = a * a * (3 - 2 * a), E = J(o, r), C = J(o + 1, r), c = J(o, r + 1), u = J(o + 1, r + 1);
17
+ return E + (C - E) * f + (c - E) * A + (E - C - c + u) * f * A;
16
18
  }
17
- const xt = 1e20;
18
- function Qt(x, r, a, c, l) {
19
- let s = 0;
20
- c[0] = 0, l[0] = -xt, l[1] = xt;
21
- for (let h = 1; h < r; h++) {
22
- let A = (x[h] + h * h - (x[c[s]] + c[s] * c[s])) / (2 * h - 2 * c[s]);
23
- for (; A <= l[s]; )
24
- s--, A = (x[h] + h * h - (x[c[s]] + c[s] * c[s])) / (2 * h - 2 * c[s]);
25
- s++, c[s] = h, l[s] = A, l[s + 1] = xt;
26
- }
27
- s = 0;
28
- for (let h = 0; h < r; h++) {
29
- for (; l[s + 1] < h; ) s++;
30
- a[h] = (h - c[s]) * (h - c[s]) + x[c[s]];
19
+ const pt = 1e20;
20
+ function Ht(m, e, o, r, i) {
21
+ let a = 0;
22
+ r[0] = 0, i[0] = -pt, i[1] = pt;
23
+ for (let f = 1; f < e; f++) {
24
+ let A = (m[f] + f * f - (m[r[a]] + r[a] * r[a])) / (2 * f - 2 * r[a]);
25
+ for (; A <= i[a]; )
26
+ a--, A = (m[f] + f * f - (m[r[a]] + r[a] * r[a])) / (2 * f - 2 * r[a]);
27
+ a++, r[a] = f, i[a] = A, i[a + 1] = pt;
28
+ }
29
+ a = 0;
30
+ for (let f = 0; f < e; f++) {
31
+ for (; i[a + 1] < f; ) a++;
32
+ o[f] = (f - r[a]) * (f - r[a]) + m[r[a]];
31
33
  }
32
34
  }
33
- function de(x, r, a) {
34
- const c = new Float64Array(r * a);
35
- for (let f = 0; f < r * a; f++) c[f] = x[f] ? xt : 0;
36
- const l = Math.max(r, a), s = new Float64Array(l), h = new Float64Array(l), A = new Int32Array(l), S = new Float64Array(l + 1);
37
- for (let f = 0; f < r; f++) {
38
- for (let u = 0; u < a; u++) s[u] = c[u * r + f];
39
- Qt(s, a, h, A, S);
40
- for (let u = 0; u < a; u++) c[u * r + f] = h[u];
41
- }
42
- for (let f = 0; f < a; f++) {
43
- for (let u = 0; u < r; u++) s[u] = c[f * r + u];
44
- Qt(s, r, h, A, S);
45
- for (let u = 0; u < r; u++) c[f * r + u] = h[u];
46
- }
47
- const I = new Float32Array(r * a);
48
- for (let f = 0; f < r * a; f++) I[f] = Math.sqrt(c[f]);
49
- return I;
35
+ function we(m, e, o) {
36
+ const r = new Float64Array(e * o);
37
+ for (let c = 0; c < e * o; c++) r[c] = m[c] ? pt : 0;
38
+ const i = Math.max(e, o), a = new Float64Array(i), f = new Float64Array(i), A = new Int32Array(i), E = new Float64Array(i + 1);
39
+ for (let c = 0; c < e; c++) {
40
+ for (let u = 0; u < o; u++) a[u] = r[u * e + c];
41
+ Ht(a, o, f, A, E);
42
+ for (let u = 0; u < o; u++) r[u * e + c] = f[u];
43
+ }
44
+ for (let c = 0; c < o; c++) {
45
+ for (let u = 0; u < e; u++) a[u] = r[c * e + u];
46
+ Ht(a, e, f, A, E);
47
+ for (let u = 0; u < e; u++) r[c * e + u] = f[u];
48
+ }
49
+ const C = new Float32Array(e * o);
50
+ for (let c = 0; c < e * o; c++) C[c] = Math.sqrt(r[c]);
51
+ return C;
50
52
  }
51
- function Zt(x, r, a, c, l) {
52
- let s = Float32Array.from(x);
53
- const h = new Float32Array(r * a), A = 1 / (2 * c + 1), S = (I, f) => I < 0 ? 0 : I > f ? f : I;
54
- for (let I = 0; I < l; I++) {
55
- for (let f = 0; f < a; f++) {
56
- const u = f * r;
57
- let v = 0;
58
- for (let P = -c; P <= c; P++) v += s[u + S(P, r - 1)];
59
- for (let P = 0; P < r; P++)
60
- h[u + P] = v * A, v += s[u + S(P + c + 1, r - 1)] - s[u + S(P - c, r - 1)];
53
+ function Wt(m, e, o, r, i) {
54
+ let a = Float32Array.from(m);
55
+ const f = new Float32Array(e * o), A = 1 / (2 * r + 1), E = (C, c) => C < 0 ? 0 : C > c ? c : C;
56
+ for (let C = 0; C < i; C++) {
57
+ for (let c = 0; c < o; c++) {
58
+ const u = c * e;
59
+ let $ = 0;
60
+ for (let D = -r; D <= r; D++) $ += a[u + E(D, e - 1)];
61
+ for (let D = 0; D < e; D++)
62
+ f[u + D] = $ * A, $ += a[u + E(D + r + 1, e - 1)] - a[u + E(D - r, e - 1)];
61
63
  }
62
- for (let f = 0; f < r; f++) {
64
+ for (let c = 0; c < e; c++) {
63
65
  let u = 0;
64
- for (let v = -c; v <= c; v++) u += h[S(v, a - 1) * r + f];
65
- for (let v = 0; v < a; v++)
66
- s[v * r + f] = u * A, u += h[S(v + c + 1, a - 1) * r + f] - h[S(v - c, a - 1) * r + f];
66
+ for (let $ = -r; $ <= r; $++) u += f[E($, o - 1) * e + c];
67
+ for (let $ = 0; $ < o; $++)
68
+ a[$ * e + c] = u * A, u += f[E($ + r + 1, o - 1) * e + c] - f[E($ - r, o - 1) * e + c];
67
69
  }
68
70
  }
69
- return s;
71
+ return a;
70
72
  }
71
- function Ht(x, r) {
72
- if (!x) return r;
73
- const a = x.trim();
74
- if (a[0] === "#") {
75
- let l = a.slice(1);
76
- if (l.length === 3 && (l = l[0] + l[0] + l[1] + l[1] + l[2] + l[2]), l.length >= 6) {
77
- const s = parseInt(l.slice(0, 2), 16), h = parseInt(l.slice(2, 4), 16), A = parseInt(l.slice(4, 6), 16);
78
- if (!Number.isNaN(s) && !Number.isNaN(h) && !Number.isNaN(A)) return [s, h, A];
73
+ function te(m, e) {
74
+ if (!m) return e;
75
+ const o = m.trim();
76
+ if (o[0] === "#") {
77
+ let i = o.slice(1);
78
+ if (i.length === 3 && (i = i[0] + i[0] + i[1] + i[1] + i[2] + i[2]), i.length >= 6) {
79
+ const a = parseInt(i.slice(0, 2), 16), f = parseInt(i.slice(2, 4), 16), A = parseInt(i.slice(4, 6), 16);
80
+ if (!Number.isNaN(a) && !Number.isNaN(f) && !Number.isNaN(A)) return [a, f, A];
79
81
  }
80
- return r;
82
+ return e;
81
83
  }
82
- const c = a.match(/rgba?\(([^)]+)\)/i);
83
- if (c) {
84
- const l = c[1].split(",").map((s) => parseFloat(s));
85
- if (l.length >= 3 && l.slice(0, 3).every((s) => !Number.isNaN(s)))
86
- return [Math.round(l[0]), Math.round(l[1]), Math.round(l[2])];
84
+ const r = o.match(/rgba?\(([^)]+)\)/i);
85
+ if (r) {
86
+ const i = r[1].split(",").map((a) => parseFloat(a));
87
+ if (i.length >= 3 && i.slice(0, 3).every((a) => !Number.isNaN(a)))
88
+ return [Math.round(i[0]), Math.round(i[1]), Math.round(i[2])];
87
89
  }
88
- return r;
90
+ return e;
89
91
  }
90
- function D(x) {
91
- return x < 0 ? 0 : x > 255 ? 255 : Math.round(x);
92
+ function K(m) {
93
+ return m < 0 ? 0 : m > 255 ? 255 : Math.round(m);
92
94
  }
93
- function ue(x, r) {
94
- if (typeof window > "u" || typeof document > "u" || !x)
95
+ function ee(m) {
96
+ return (m.split(",")[0] || "serif").trim().replace(/^["']|["']$/g, "");
97
+ }
98
+ function pe(m, e) {
99
+ if (typeof window > "u" || typeof document > "u" || !m)
95
100
  return { setText() {
96
101
  }, replay() {
97
102
  }, resize() {
103
+ }, update() {
104
+ }, focus() {
98
105
  }, destroy() {
99
106
  }, get text() {
100
- return r.text ?? "";
107
+ return e.text ?? "";
101
108
  } };
102
- let a = r.text ?? "";
103
- const c = r.font ?? "Georgia, serif", l = r.weight ?? 680, s = r.aspect ?? 0.46, h = r.sewRate ?? 110, A = r.sheen ?? !0, S = r.animate ?? !0, I = (c.split(",")[0] || "serif").trim().replace(/^["']|["']$/g, ""), f = r.reducedMotion ?? !!(window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches), u = Ht(r.threadColor ?? "#fffbf3", [255, 251, 243]), v = [u[0] * 0.585, u[1] * 0.585, u[2] * 0.585], P = [u[0] * 0.47, u[1] * 0.47, u[2] * 0.47], Z = Ht(r.fabricColor ?? "#08080a", [8, 8, 10]), wt = [D(Z[0] + 14), D(Z[1] + 13), D(Z[2] + 15)], j = (t) => `rgb(${D(t[0])},${D(t[1])},${D(t[2])})`, H = [];
104
- let $, O;
105
- x instanceof HTMLCanvasElement ? ($ = x, O = x.parentElement ?? x) : (O = x, $ = document.createElement("canvas"), H.push($), O.appendChild($)), $.classList.add(Jt.bg);
106
- const N = document.createElement("canvas");
107
- H.push(N), N.classList.add(Jt.fx), O.appendChild(N), getComputedStyle(O).position === "static" && (O.style.position = "relative"), $.style.display = "block", $.style.width = "100%", Object.assign(N.style, { position: "absolute", inset: "0", width: "100%", pointerEvents: "none", mixBlendMode: "screen" });
108
- let e = 0, i = 0, G = 0, pt = 0, tt = 4, et = [], nt = 0, ot = 0, Mt = new Uint8Array(0), Ct = new Float32Array(0), lt = new Float32Array(0), ft = new Float32Array(0), B = null, U = null, V = null, rt = null, dt = null, k = [], ut = 3;
109
- const b = { rows: [], idx: 0, acc: 0, rate: 0, on: !1 }, K = { x: 0, y: 0, set: !1 };
110
- let Y = !0, St = 0, Dt = !1, ht = 0, J = !1, At = !1;
111
- function Ot() {
112
- const t = O.getBoundingClientRect(), n = Math.round(t.width || Math.min(window.innerWidth * 0.95, 1240)), o = Math.round(n * s);
109
+ let o = e.text ?? "", r = e.font ?? "Georgia, serif", i = e.weight ?? 680, a = e.fill ?? 0.9, f = e.sewRate ?? 110, A = e.sheen ?? !0, E = e.animate ?? !0, C = e.editable ?? !1, c = e.pitch, u = e.onTextChange, $ = ee(r);
110
+ const D = e.reducedMotion ?? !!(window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches);
111
+ let k = te(e.threadColor ?? "#fffbf3", [255, 251, 243]), W = [0, 0, 0], N = [0, 0, 0];
112
+ function tt(t) {
113
+ k = te(t, [255, 251, 243]), W = [k[0] * 0.585, k[1] * 0.585, k[2] * 0.585], N = [k[0] * 0.47, k[1] * 0.47, k[2] * 0.47];
114
+ }
115
+ tt(e.threadColor ?? "#fffbf3");
116
+ const G = [];
117
+ let P, g;
118
+ m instanceof HTMLCanvasElement ? (P = m, g = m.parentElement ?? m) : (g = m, P = document.createElement("canvas"), G.push(P), g.appendChild(P)), P.classList.add(Bt.bg);
119
+ const O = document.createElement("canvas");
120
+ G.push(O), O.classList.add(Bt.fx), g.appendChild(O), getComputedStyle(g).position === "static" && (g.style.position = "relative"), P.style.display = "block", P.style.width = "100%", Object.assign(O.style, { position: "absolute", inset: "0", width: "100%", pointerEvents: "none", mixBlendMode: "screen" });
121
+ let S = null, Q = !1, s = 0, h = 0, Z = 0, Mt = 0, st = 4, et = [], nt = 0, ot = 0, bt = new Uint8Array(0), Ct = new Float32Array(0), ft = new Float32Array(0), dt = new Float32Array(0), U = null, rt = null, ut = null, ht = [], mt = 3;
122
+ const R = { rows: [], idx: 0, acc: 0, rate: 0, on: !1 }, V = { x: 0, y: 0, set: !1 };
123
+ let H = !0, vt = 0, Dt = !1, yt = 0, z = !1, Y = !1;
124
+ function ne() {
125
+ const t = g.getBoundingClientRect(), n = Math.max(1, Math.round(t.width || Math.min(window.innerWidth * 0.95, 1240))), l = o || "Ag", y = P.getContext("2d");
126
+ let v = 100;
127
+ y && (y.font = `${i} 100px ${r}`, v = y.measureText(l).width || 100);
128
+ let b = Math.max(8, 100 * (n * a) / v), T = b * 0.7, L = b * 0.3, I = n * a;
129
+ if (y) {
130
+ y.font = `${i} ${b}px ${r}`;
131
+ const p = y.measureText(l);
132
+ I = p.width || I, p.actualBoundingBoxAscent > 0 && (T = p.actualBoundingBoxAscent), p.actualBoundingBoxDescent > 0 && (L = p.actualBoundingBoxDescent);
133
+ }
134
+ const w = Math.max(1, Math.round(2 * Math.max(T, L) * 1.12));
113
135
  let d = Math.min(window.devicePixelRatio || 1, 1.7);
114
- for (; n * d * o * d > 9e5 && d > 0.55; ) d -= 0.1;
115
- e = Math.max(1, Math.round(n * d)), i = Math.max(1, Math.round(o * d));
116
- for (const m of [$, N])
117
- m.width = e, m.height = i, m.style.height = o + "px";
118
- O.style.height = o + "px";
119
- }
120
- function zt() {
121
- const t = Math.max(7, tt * 2.5), n = Math.max(3.2, tt * 1.3);
136
+ for (; n * d * w * d > 9e5 && d > 0.4; ) d -= 0.1;
137
+ s = Math.max(1, Math.round(n * d)), h = Math.max(1, Math.round(w * d)), Z = Math.max(4, Math.round(b * d)), Mt = Math.round(s / 2 - I * d / 2);
138
+ for (const p of [P, O])
139
+ p.width = s, p.height = h, p.style.height = w + "px";
140
+ g.style.height = w + "px", st = c ?? Math.max(3, h * 95e-4);
141
+ }
142
+ function oe() {
143
+ rt = document.createElement("canvas"), rt.width = s, rt.height = h, ut = rt.getContext("2d", { willReadFrequently: !0 });
144
+ }
145
+ function Nt() {
146
+ const t = Math.max(7, st * 2.5), n = Math.max(3.2, st * 1.3);
122
147
  nt = Math.ceil(t) + 2, ot = Math.ceil(n) + 2, et = [];
123
- for (let o = 0; o < 20; o++) {
124
- const d = 0.34 + o / 19 * 0.82, m = document.createElement("canvas");
125
- m.width = nt, m.height = ot;
126
- const M = m.getContext("2d");
127
- if (!M) {
128
- et.push(m);
148
+ for (let l = 0; l < 20; l++) {
149
+ const y = 0.34 + l / 19 * 0.82, v = document.createElement("canvas");
150
+ v.width = nt, v.height = ot;
151
+ const b = v.getContext("2d");
152
+ if (!b) {
153
+ et.push(v);
129
154
  continue;
130
155
  }
131
- const C = nt / 2, T = ot / 2, R = M.createLinearGradient(0, T - n / 2, 0, T + n / 2), p = (L, z) => `rgba(${D(L[0] * d)},${D(L[1] * d)},${D(L[2] * d)},${z})`;
132
- R.addColorStop(0, p(P, 0)), R.addColorStop(0.16, p(v, 1)), R.addColorStop(0.5, p(u, 1)), R.addColorStop(0.84, p(v, 1)), R.addColorStop(1, p(P, 0)), M.fillStyle = R, M.beginPath();
133
- const w = n / 2;
134
- M.moveTo(C - t / 2 + w, T - w), M.lineTo(C + t / 2 - w, T - w), M.arc(C + t / 2 - w, T, w, -Math.PI / 2, Math.PI / 2), M.lineTo(C - t / 2 + w, T + w), M.arc(C - t / 2 + w, T, w, Math.PI / 2, -Math.PI / 2), M.closePath(), M.fill(), M.globalCompositeOperation = "destination-in";
135
- const E = M.createLinearGradient(C - t / 2, 0, C + t / 2, 0);
136
- E.addColorStop(0, "rgba(0,0,0,0)"), E.addColorStop(0.22, "rgba(0,0,0,1)"), E.addColorStop(0.78, "rgba(0,0,0,1)"), E.addColorStop(1, "rgba(0,0,0,0)"), M.fillStyle = E, M.fillRect(0, 0, nt, ot), et.push(m);
156
+ const T = nt / 2, L = ot / 2, I = b.createLinearGradient(0, L - n / 2, 0, L + n / 2), w = (B, j) => `rgba(${K(B[0] * y)},${K(B[1] * y)},${K(B[2] * y)},${j})`;
157
+ I.addColorStop(0, w(N, 0)), I.addColorStop(0.16, w(W, 1)), I.addColorStop(0.5, w(k, 1)), I.addColorStop(0.84, w(W, 1)), I.addColorStop(1, w(N, 0)), b.fillStyle = I, b.beginPath();
158
+ const d = n / 2;
159
+ b.moveTo(T - t / 2 + d, L - d), b.lineTo(T + t / 2 - d, L - d), b.arc(T + t / 2 - d, L, d, -Math.PI / 2, Math.PI / 2), b.lineTo(T - t / 2 + d, L + d), b.arc(T - t / 2 + d, L, d, Math.PI / 2, -Math.PI / 2), b.closePath(), b.fill(), b.globalCompositeOperation = "destination-in";
160
+ const p = b.createLinearGradient(T - t / 2, 0, T + t / 2, 0);
161
+ p.addColorStop(0, "rgba(0,0,0,0)"), p.addColorStop(0.22, "rgba(0,0,0,1)"), p.addColorStop(0.78, "rgba(0,0,0,1)"), p.addColorStop(1, "rgba(0,0,0,0)"), b.fillStyle = p, b.fillRect(0, 0, nt, ot), et.push(v);
137
162
  }
138
163
  }
139
- function bt() {
140
- if (!dt) return;
141
- const t = dt;
142
- t.clearRect(0, 0, e, i), t.fillStyle = "#fff", t.textAlign = "left", t.textBaseline = "middle", t.font = `${l} ${G}px ${c}`, t.fillText(a, pt, i * 0.5);
143
- const n = t.getImageData(0, 0, e, i).data, o = new Uint8Array(e * i);
144
- for (let g = 0; g < i; g++) for (let F = 0; F < e; F++) {
145
- const y = g * e + F, q = n[y * 4 + 3] / 255, _ = Nt(F * 0.5, g * 0.5) * 0.22 + Nt(F * 1.8, g * 1.8) * 0.1;
146
- o[y] = q > 0.5 + (_ - 0.16) ? 1 : 0;
164
+ function re() {
165
+ if (!ut) return;
166
+ const t = ut;
167
+ t.clearRect(0, 0, s, h), t.fillStyle = "#fff", t.textAlign = "left", t.textBaseline = "middle", t.font = `${i} ${Z}px ${r}`, t.fillText(o, Mt, h * 0.5);
168
+ const n = t.getImageData(0, 0, s, h).data, l = new Uint8Array(s * h);
169
+ for (let x = 0; x < h; x++) for (let M = 0; M < s; M++) {
170
+ const F = x * s + M, q = n[F * 4 + 3] / 255, _ = Zt(M * 0.5, x * 0.5) * 0.22 + Zt(M * 1.8, x * 1.8) * 0.1;
171
+ l[F] = q > 0.5 + (_ - 0.16) ? 1 : 0;
147
172
  }
148
- Mt = o;
149
- const d = de(o, e, i), m = new Float32Array(e * i);
150
- for (let g = 1; g < i - 1; g++) for (let F = 1; F < e - 1; F++) {
151
- const y = g * e + F;
152
- m[y] = (d[y] * 4 + d[y - 1] + d[y + 1] + d[y - e] + d[y + e]) / 8;
173
+ bt = l;
174
+ const y = we(l, s, h), v = new Float32Array(s * h);
175
+ for (let x = 1; x < h - 1; x++) for (let M = 1; M < s - 1; M++) {
176
+ const F = x * s + M;
177
+ v[F] = (y[F] * 4 + y[F - 1] + y[F + 1] + y[F - s] + y[F + s]) / 8;
153
178
  }
154
- const M = new Float32Array(e * i), C = new Float32Array(e * i), T = new Float32Array(e * i), R = new Float32Array(e * i);
155
- for (let g = 1; g < i - 1; g++) for (let F = 1; F < e - 1; F++) {
156
- const y = g * e + F;
157
- if (!o[y]) continue;
158
- const q = (m[y + 1] - m[y - 1]) * 0.5, _ = (m[y + e] - m[y - e]) * 0.5;
159
- T[y] = q, R[y] = _, M[y] = q * q - _ * _, C[y] = 2 * q * _;
179
+ const b = new Float32Array(s * h), T = new Float32Array(s * h), L = new Float32Array(s * h), I = new Float32Array(s * h);
180
+ for (let x = 1; x < h - 1; x++) for (let M = 1; M < s - 1; M++) {
181
+ const F = x * s + M;
182
+ if (!l[F]) continue;
183
+ const q = (v[F + 1] - v[F - 1]) * 0.5, _ = (v[F + s] - v[F - s]) * 0.5;
184
+ L[F] = q, I[F] = _, b[F] = q * q - _ * _, T[F] = 2 * q * _;
160
185
  }
161
- const p = Math.max(7, Math.round(i * 0.05)), w = Zt(M, e, i, p, 2), E = Zt(C, e, i, p, 2);
162
- lt = new Float32Array(e * i), ft = new Float32Array(e * i);
163
- for (let g = 0; g < e * i; g++) {
164
- if (!o[g]) continue;
165
- const F = 0.5 * Math.atan2(E[g], w[g]);
166
- lt[g] = Math.cos(F), ft[g] = Math.sin(F);
186
+ const w = Math.max(7, Math.round(h * 0.05)), d = Wt(b, s, h, w, 2), p = Wt(T, s, h, w, 2);
187
+ ft = new Float32Array(s * h), dt = new Float32Array(s * h);
188
+ for (let x = 0; x < s * h; x++) {
189
+ if (!l[x]) continue;
190
+ const M = 0.5 * Math.atan2(p[x], d[x]);
191
+ ft[x] = Math.cos(M), dt[x] = Math.sin(M);
167
192
  }
168
- const L = Math.max(9, i * 0.04), z = new Float32Array(e * i), ct = -0.45, st = -0.62, yt = 0.64;
169
- for (let g = 1; g < i - 1; g++) for (let F = 1; F < e - 1; F++) {
170
- const y = g * e + F;
171
- if (!o[y]) continue;
172
- let q = T[y], _ = R[y];
173
- const Ut = Math.hypot(q, _) || 1;
174
- q /= Ut, _ /= Ut;
175
- const Vt = m[y], Kt = (1 - Math.min(Vt / L, 1)) * 1.25;
176
- let vt = -q * Kt, Rt = -_ * Kt;
177
- const Yt = 1.5, $t = Math.hypot(vt, Rt, Yt);
178
- vt /= $t, Rt /= $t;
179
- let Lt = vt * ct + Rt * st + Yt / $t * yt;
180
- Lt < 0 && (Lt = 0);
181
- const ae = Math.min(1, 0.45 + 0.55 * Math.min(Vt / (L * 0.7), 1));
182
- z[y] = Math.min(1.12, (0.5 + 0.75 * Lt) * ae);
193
+ const B = Math.max(9, h * 0.04), j = new Float32Array(s * h), lt = -0.45, ct = -0.62, gt = 0.64;
194
+ for (let x = 1; x < h - 1; x++) for (let M = 1; M < s - 1; M++) {
195
+ const F = x * s + M;
196
+ if (!l[F]) continue;
197
+ let q = L[F], _ = I[F];
198
+ const Xt = Math.hypot(q, _) || 1;
199
+ q /= Xt, _ /= Xt;
200
+ const Vt = v[F], Yt = (1 - Math.min(Vt / B, 1)) * 1.25;
201
+ let $t = -q * Yt, It = -_ * Yt;
202
+ const Jt = 1.5, Pt = Math.hypot($t, It, Jt);
203
+ $t /= Pt, It /= Pt;
204
+ let kt = $t * lt + It * ct + Jt / Pt * gt;
205
+ kt < 0 && (kt = 0);
206
+ const he = Math.min(1, 0.45 + 0.55 * Math.min(Vt / (B * 0.7), 1));
207
+ j[F] = Math.min(1.12, (0.5 + 0.75 * kt) * he);
183
208
  }
184
- Ct = z, B = document.createElement("canvas"), B.width = e, B.height = i;
185
- const X = B.getContext("2d");
186
- U = document.createElement("canvas"), U.width = e, U.height = i;
187
- const W = U.getContext("2d");
188
- if (X && W) {
189
- const g = X.createImageData(e, i), F = W.createImageData(e, i);
190
- for (let y = 0; y < e * i; y++) o[y] && (g.data[y * 4] = 255, g.data[y * 4 + 1] = 255, g.data[y * 4 + 2] = 255, g.data[y * 4 + 3] = 255, F.data[y * 4 + 3] = 255);
191
- X.putImageData(g, 0, 0), W.putImageData(F, 0, 0);
209
+ Ct = j, U = document.createElement("canvas"), U.width = s, U.height = h;
210
+ const X = U.getContext("2d");
211
+ if (X) {
212
+ const x = X.createImageData(s, h);
213
+ for (let M = 0; M < s * h; M++) l[M] && (x.data[M * 4] = 255, x.data[M * 4 + 1] = 255, x.data[M * 4 + 2] = 255, x.data[M * 4 + 3] = 255);
214
+ X.putImageData(x, 0, 0);
192
215
  }
193
216
  }
194
- function qt() {
195
- V = document.createElement("canvas"), V.width = e, V.height = i;
196
- const t = V.getContext("2d", { willReadFrequently: !0 });
197
- if (t) {
198
- const n = t.createRadialGradient(e * 0.5, i * 0.4, 0, e * 0.5, i * 0.5, e * 0.72);
199
- n.addColorStop(0, j(wt)), n.addColorStop(1, j(Z)), t.fillStyle = n, t.fillRect(0, 0, e, i);
200
- const o = t.getImageData(0, 0, e, i), d = o.data;
201
- for (let m = 0; m < i; m++) for (let M = 0; M < e; M++) {
202
- const C = (m * e + M) * 4, T = Math.sin(M * 1.9) * 0.5 + 0.5, R = Math.sin(m * 1.9) * 0.5 + 0.5, p = T * R * 9 - 4.5 + (Nt(M * 0.18, m * 0.18) - 0.5) * 15;
203
- d[C] = D(d[C] + p), d[C + 1] = D(d[C + 1] + p), d[C + 2] = D(d[C + 2] + p * 1.1);
204
- }
205
- t.putImageData(o, 0, 0);
206
- }
207
- rt = document.createElement("canvas"), rt.width = e, rt.height = i, dt = rt.getContext("2d", { willReadFrequently: !0 });
208
- }
209
- function Ft() {
210
- const t = Math.max(1.6, tt * 0.6);
211
- ut = t;
217
+ function ie() {
218
+ const t = Math.max(1.6, st * 0.6);
219
+ mt = t;
212
220
  const n = [];
213
- for (let o = 0; o < i; o += t) for (let d = 0; d < e; d += t) {
214
- const m = (Q(Math.floor(d), Math.floor(o)) - 0.5) * t * 0.9, M = (Q(Math.floor(o), Math.floor(d)) - 0.5) * t * 0.9, C = Math.round(d + m), T = Math.round(o + M);
215
- if (C < 1 || T < 1 || C >= e - 1 || T >= i - 1) continue;
216
- const R = T * e + C;
217
- if (!Mt[R]) continue;
218
- const p = Math.atan2(ft[R], lt[R]), w = 0.86 + Q(C * 7, T * 13) * 0.18;
219
- let E = Ct[R] * w;
220
- E = E < 0 ? 0 : E > 1.12 ? 1.12 : E, n.push({ x: C, y: T, ang: p, idx: Math.min(19, Math.max(0, Math.round(E / 1.12 * 19))) });
221
+ for (let l = 0; l < h; l += t) for (let y = 0; y < s; y += t) {
222
+ const v = (J(Math.floor(y), Math.floor(l)) - 0.5) * t * 0.9, b = (J(Math.floor(l), Math.floor(y)) - 0.5) * t * 0.9, T = Math.round(y + v), L = Math.round(l + b);
223
+ if (T < 1 || L < 1 || T >= s - 1 || L >= h - 1) continue;
224
+ const I = L * s + T;
225
+ if (!bt[I]) continue;
226
+ const w = Math.atan2(dt[I], ft[I]), d = 0.86 + J(T * 7, L * 13) * 0.18;
227
+ let p = Ct[I] * d;
228
+ p = p < 0 ? 0 : p > 1.12 ? 1.12 : p, n.push({ x: T, y: L, ang: w, idx: Math.min(19, Math.max(0, Math.round(p / 1.12 * 19))) });
221
229
  }
222
- n.sort((o, d) => o.x - d.x), k = n;
230
+ n.sort((l, y) => l.x - y.x), ht = n;
223
231
  }
224
- function mt(t, n) {
232
+ function Ot(t, n) {
225
233
  t.save(), t.translate(n.x, n.y), t.rotate(n.ang), t.drawImage(et[n.idx], -nt / 2, -ot / 2), t.restore();
226
234
  }
227
- function gt() {
228
- const t = $.getContext("2d");
229
- if (t)
230
- for (const n of k) mt(t, n);
231
- }
232
- function _t() {
233
- return k.length ? k[k.length - 1].x : 0;
234
- }
235
235
  function Tt() {
236
- return k.length ? k[0].x : 0;
236
+ const t = P.getContext("2d");
237
+ if (t)
238
+ for (const n of ht) Ot(t, n);
237
239
  }
238
- function at() {
239
- const t = $.getContext("2d");
240
- !t || !V || (t.drawImage(V, 0, 0), U && (t.save(), t.globalAlpha = 0.85, t.filter = `blur(${Math.round(i * 0.018)}px)`, t.drawImage(U, 0, Math.round(i * 0.02)), t.restore()));
240
+ function At() {
241
+ const t = P.getContext("2d");
242
+ t && t.clearRect(0, 0, s, h);
241
243
  }
242
- function Wt(t) {
244
+ function ae(t) {
243
245
  if (!t.length) return [];
244
- const n = Math.max(4, ut * 1.5), o = /* @__PURE__ */ new Map(), d = (p, w) => p + "," + w;
245
- t.forEach((p, w) => {
246
- const E = d(Math.floor(p.x / n), Math.floor(p.y / n));
247
- let L = o.get(E);
248
- L || o.set(E, L = []), L.push(w);
246
+ const n = Math.max(4, mt * 1.5), l = /* @__PURE__ */ new Map(), y = (w, d) => w + "," + d;
247
+ t.forEach((w, d) => {
248
+ const p = y(Math.floor(w.x / n), Math.floor(w.y / n));
249
+ let B = l.get(p);
250
+ B || l.set(p, B = []), B.push(d);
249
251
  });
250
- const m = ut * 1.8 * (ut * 1.8);
251
- function M(p) {
252
- const w = t[p], E = Math.floor(w.x / n), L = Math.floor(w.y / n), z = [];
253
- for (let ct = -1; ct <= 1; ct++) for (let st = -1; st <= 1; st++) {
254
- const yt = o.get(d(E + ct, L + st));
255
- if (yt)
256
- for (const X of yt) {
257
- if (X === p) continue;
258
- const W = t[X].x - w.x, g = t[X].y - w.y;
259
- W * W + g * g <= m && z.push(X);
252
+ const v = mt * 1.8 * (mt * 1.8);
253
+ function b(w) {
254
+ const d = t[w], p = Math.floor(d.x / n), B = Math.floor(d.y / n), j = [];
255
+ for (let lt = -1; lt <= 1; lt++) for (let ct = -1; ct <= 1; ct++) {
256
+ const gt = l.get(y(p + lt, B + ct));
257
+ if (gt)
258
+ for (const X of gt) {
259
+ if (X === w) continue;
260
+ const x = t[X].x - d.x, M = t[X].y - d.y;
261
+ x * x + M * M <= v && j.push(X);
260
262
  }
261
263
  }
262
- return z;
264
+ return j;
263
265
  }
264
- const C = new Uint8Array(t.length), T = [], R = t.map((p, w) => w).sort((p, w) => t[p].x + t[p].y - (t[w].x + t[w].y));
265
- for (const p of R) {
266
- if (C[p]) continue;
267
- let w = [p];
268
- for (C[p] = 1; w.length; ) {
269
- T.push(w.map((L) => t[L]));
270
- const E = [];
271
- for (const L of w) for (const z of M(L)) C[z] || (C[z] = 1, E.push(z));
272
- w = E;
266
+ const T = new Uint8Array(t.length), L = [], I = t.map((w, d) => d).sort((w, d) => t[w].x + t[w].y - (t[d].x + t[d].y));
267
+ for (const w of I) {
268
+ if (T[w]) continue;
269
+ let d = [w];
270
+ for (T[w] = 1; d.length; ) {
271
+ L.push(d.map((B) => t[B]));
272
+ const p = [];
273
+ for (const B of d) for (const j of b(B)) T[j] || (T[j] = 1, p.push(j));
274
+ d = p;
273
275
  }
274
276
  }
275
- return T;
276
- }
277
- function Et(t, n) {
278
- at();
279
- const o = $.getContext("2d");
280
- if (!o) return;
281
- const d = [];
282
- for (const m of k)
283
- m.x <= t ? mt(o, m) : d.push(m);
284
- if (f) {
285
- for (const m of d) mt(o, m);
286
- b.on = !1;
277
+ return L;
278
+ }
279
+ function le() {
280
+ if (At(), D || !E) {
281
+ Tt(), R.on = !1;
287
282
  return;
288
283
  }
289
- b.rows = Wt(d), b.idx = 0, b.acc = 0, b.rate = n || h, b.on = b.rows.length > 0;
284
+ R.rows = ae(ht), R.idx = 0, R.acc = 0, R.rate = f, R.on = R.rows.length > 0;
290
285
  }
291
- function te(t) {
292
- const n = $.getContext("2d");
286
+ function ce(t) {
287
+ const n = P.getContext("2d");
293
288
  if (n)
294
- for (t > b.rows.length && (t = b.rows.length); b.idx < t; ) {
295
- const o = b.rows[b.idx++];
296
- for (const d of o) mt(n, d);
289
+ for (t > R.rows.length && (t = R.rows.length); R.idx < t; ) {
290
+ const l = R.rows[R.idx++];
291
+ for (const y of l) Ot(n, y);
297
292
  }
298
293
  }
299
- function ee(t, n) {
300
- const o = N.getContext("2d");
301
- if (!o || (o.clearRect(0, 0, e, i), !A || !B)) return;
302
- const d = e * 0.32, m = o.createRadialGradient(t, n, 0, t, n, d);
303
- m.addColorStop(0, "rgba(255,250,238,0.18)"), m.addColorStop(0.5, "rgba(255,250,238,0.055)"), m.addColorStop(1, "rgba(255,250,238,0)"), o.fillStyle = m, o.fillRect(0, 0, e, i), o.globalCompositeOperation = "destination-in", o.drawImage(B, 0, 0), o.globalCompositeOperation = "source-over";
294
+ function se(t, n) {
295
+ const l = O.getContext("2d");
296
+ if (!l || (l.clearRect(0, 0, s, h), !A || !U)) return;
297
+ const y = s * 0.32, v = l.createRadialGradient(t, n, 0, t, n, y);
298
+ v.addColorStop(0, "rgba(255,250,238,0.18)"), v.addColorStop(0.5, "rgba(255,250,238,0.055)"), v.addColorStop(1, "rgba(255,250,238,0)"), l.fillStyle = v, l.fillRect(0, 0, s, h), l.globalCompositeOperation = "destination-in", l.drawImage(U, 0, 0), l.globalCompositeOperation = "source-over";
304
299
  }
305
- function jt() {
306
- const t = $.getContext("2d");
307
- if (!t) {
308
- G = Math.round(i * 0.6), pt = Math.round(e * 0.14);
309
- return;
300
+ function fe() {
301
+ S || !C || (S = document.createElement("span"), S.className = Bt.caret, S.setAttribute("aria-hidden", "true"), Object.assign(S.style, { position: "absolute", pointerEvents: "none", borderRadius: "1px", opacity: "0", background: `rgb(${K(k[0])},${K(k[1])},${K(k[2])})` }), g.appendChild(S), G.push(S));
302
+ }
303
+ function Et() {
304
+ if (!C || !S) return;
305
+ const t = P.getContext("2d");
306
+ if (!t) return;
307
+ t.font = `${i} ${Z}px ${r}`;
308
+ const n = t.measureText(o).width, l = (P.clientWidth || s) / s, y = Z * 0.7;
309
+ S.style.left = (Mt + n + Z * 0.05) * l + "px", S.style.top = 0.5 * (P.clientHeight || h) - y * l / 2 + "px", S.style.height = y * l + "px", S.style.width = Math.max(2, Math.round(Z * 0.02 * l)) + "px", S.style.background = `rgb(${K(k[0])},${K(k[1])},${K(k[2])})`;
310
+ }
311
+ function jt(t) {
312
+ if (z) return;
313
+ yt || (yt = t);
314
+ const n = Math.min(0.25, (t - yt) / 1e3);
315
+ yt = t, R.on && (R.acc += R.rate * n, ce(R.acc), R.idx >= R.rows.length && (R.on = !1)), H && U && (se(V.set ? V.x : s * 0.5, V.set ? V.y : h * 0.34), H = !1), S && (S.style.opacity = C && Q && Math.floor(t / 530) % 2 === 0 ? "1" : "0"), vt = requestAnimationFrame(jt);
316
+ }
317
+ function xt(t) {
318
+ const n = O.getBoundingClientRect();
319
+ V.x = (t.clientX - n.left) / (n.width || 1) * s, V.y = (t.clientY - n.top) / (n.height || 1) * h, V.set = !0, H = !0;
320
+ }
321
+ function zt(t) {
322
+ if (!(!C || t.metaKey || t.ctrlKey || t.altKey)) {
323
+ if (t.key === "Backspace") {
324
+ t.preventDefault(), Ft(o.slice(0, -1), !0);
325
+ return;
326
+ }
327
+ if (t.key === "Enter") {
328
+ t.preventDefault(), Rt.replay();
329
+ return;
330
+ }
331
+ [...t.key].length === 1 && (t.preventDefault(), Ft(o + t.key, !0));
310
332
  }
311
- const n = a || "Ag";
312
- t.font = `${l} 100px ${c}`;
313
- const o = t.measureText(n).width || 100;
314
- G = Math.round(100 * (e * 0.72) / o), t.font = `${l} ${G}px ${c}`, pt = Math.round(e / 2 - t.measureText(n).width / 2);
315
333
  }
316
- function kt(t) {
317
- if (J) return;
318
- ht || (ht = t);
319
- const n = Math.min(0.25, (t - ht) / 1e3);
320
- ht = t, b.on && (b.acc += b.rate * n, te(b.acc), b.idx >= b.rows.length && (b.on = !1)), Y && B && (ee(K.set ? K.x : e * 0.5, K.set ? K.y : i * 0.34), Y = !1), St = requestAnimationFrame(kt);
334
+ function qt() {
335
+ Q = !0;
321
336
  }
322
- function Bt(t) {
323
- const n = N.getBoundingClientRect();
324
- K.x = (t.clientX - n.left) / (n.width || 1) * e, K.y = (t.clientY - n.top) / (n.height || 1) * i, K.set = !0, Y = !0;
337
+ function _t() {
338
+ Q = !1, S && (S.style.opacity = "0");
325
339
  }
326
- A && window.addEventListener("pointermove", Bt, { passive: !0 });
327
- function ne(t) {
328
- bt(), Ft(), S && !f ? Et(Tt() - 1, h) : (at(), gt(), b.on = !1), Y = !0;
340
+ function Kt() {
341
+ C && g.focus();
329
342
  }
330
- function oe() {
331
- J || (Ot(), qt(), tt = Math.max(3.4, i * 95e-4), zt(), jt(), ne(), At = !0, Dt || (Dt = !0, St = requestAnimationFrame(kt)));
343
+ function St(t) {
344
+ C = t, t ? (g.tabIndex = 0, g.setAttribute("role", "textbox"), g.getAttribute("aria-label") || g.setAttribute("aria-label", "Editable embroidered text — type to change it"), fe(), g.addEventListener("keydown", zt), g.addEventListener("focus", qt), g.addEventListener("blur", _t), g.addEventListener("pointerdown", Kt), Et()) : (g.removeAttribute("tabindex"), g.removeAttribute("role"), g.removeEventListener("keydown", zt), g.removeEventListener("focus", qt), g.removeEventListener("blur", _t), g.removeEventListener("pointerdown", Kt), S && (S.style.opacity = "0"));
332
345
  }
333
- let it;
334
- function re(t) {
335
- const n = `${l} 200px ${I}`;
336
- let o = !1;
346
+ function de(t) {
347
+ if (t !== A)
348
+ if (A = t, t)
349
+ window.addEventListener("pointermove", xt, { passive: !0 }), H = !0;
350
+ else {
351
+ window.removeEventListener("pointermove", xt);
352
+ const n = O.getContext("2d");
353
+ n && n.clearRect(0, 0, s, h);
354
+ }
355
+ }
356
+ function it(t) {
357
+ ne(), oe(), Nt(), re(), ie(), t ? le() : (At(), Tt(), R.on = !1), Et(), H = !0;
358
+ }
359
+ function Ft(t, n) {
360
+ t = t ?? "", !(t === o && Y) && (o = t, Y && (it(!1), n && u && u(o)));
361
+ }
362
+ let at;
363
+ function Gt(t, n, l) {
364
+ const y = `${n} 200px ${t}`;
365
+ let v = !1;
337
366
  try {
338
- o = !!document.fonts && document.fonts.check(n);
367
+ v = !!document.fonts && document.fonts.check(y);
339
368
  } catch {
340
- o = !0;
369
+ v = !0;
341
370
  }
342
- if (!document.fonts || o) {
343
- t();
371
+ if (!document.fonts || v) {
372
+ l();
344
373
  return;
345
374
  }
346
- let d = !1;
347
- const m = () => {
348
- d || (d = !0, it && clearTimeout(it), t());
375
+ let b = !1;
376
+ const T = () => {
377
+ b || (b = !0, at && clearTimeout(at), l());
349
378
  };
350
- document.fonts.load(n, a).then(() => document.fonts.ready).then(m, m), it = setTimeout(m, 1500);
379
+ document.fonts.load(y, o).then(() => document.fonts.ready).then(T, T), at = setTimeout(T, 1500);
380
+ }
381
+ function ue() {
382
+ z || (it(!0), Y = !0, Dt || (Dt = !0, vt = requestAnimationFrame(jt)));
351
383
  }
352
- re(oe);
353
- let It;
354
- function Xt() {
355
- clearTimeout(It), It = setTimeout(() => Gt.resize(), 200);
384
+ C && St(!0), A && window.addEventListener("pointermove", xt, { passive: !0 }), Gt($, i, ue);
385
+ let Lt;
386
+ function Ut() {
387
+ clearTimeout(Lt), Lt = setTimeout(() => Rt.resize(), 200);
356
388
  }
357
- window.addEventListener("resize", Xt);
358
- const Gt = {
389
+ window.addEventListener("resize", Ut);
390
+ const Rt = {
359
391
  get text() {
360
- return a;
392
+ return o;
361
393
  },
362
394
  setText(t) {
363
- if (J || !At) {
364
- a = t ?? "";
365
- return;
395
+ if (!z) {
396
+ if (!Y) {
397
+ o = t ?? "";
398
+ return;
399
+ }
400
+ Ft(t, !1);
366
401
  }
367
- t = t ?? "";
368
- const n = t.length > a.length && a.length > 0 && t.startsWith(a), o = n ? _t() : -1;
369
- a = t, bt(), Ft(), f || !S ? (at(), gt(), b.on = !1) : Et(n && o > 0 ? Math.min(o, _t()) : Tt() - 1, n ? 320 : h), Y = !0;
370
402
  },
371
403
  replay() {
372
- J || !At || (f || !S ? (at(), gt(), b.on = !1) : Et(Tt() - 1, h), Y = !0);
404
+ z || !Y || it(!0);
373
405
  },
374
406
  resize() {
375
- J || (Ot(), qt(), tt = Math.max(3.4, i * 95e-4), zt(), jt(), bt(), Ft(), at(), gt(), b.on = !1, Y = !0);
407
+ z || !Y || it(!1);
408
+ },
409
+ update(t) {
410
+ if (z) return;
411
+ let n = !1, l = !1;
412
+ t.font !== void 0 && t.font !== r && (r = t.font, $ = ee(r), n = !0), t.weight !== void 0 && t.weight !== i && (i = t.weight, n = !0), t.fill !== void 0 && t.fill !== a && (a = t.fill, n = !0), t.pitch !== void 0 && t.pitch !== c && (c = t.pitch, n = !0), t.threadColor !== void 0 && (tt(t.threadColor), l = !0), t.sewRate !== void 0 && (f = t.sewRate), t.animate !== void 0 && (E = t.animate), t.onTextChange !== void 0 && (u = t.onTextChange), t.sheen !== void 0 && de(t.sheen), t.editable !== void 0 && t.editable !== C && St(t.editable), Y && (n ? Gt($, i, () => {
413
+ z || it(!1);
414
+ }) : l && (Nt(), At(), Tt(), Et()), H = !0);
415
+ },
416
+ focus() {
417
+ !z && C && g.focus();
376
418
  },
377
419
  destroy() {
378
- if (!J) {
379
- J = !0, cancelAnimationFrame(St), clearTimeout(It), it && clearTimeout(it), window.removeEventListener("resize", Xt), A && window.removeEventListener("pointermove", Bt);
380
- for (const t of H) t.remove();
381
- et = [], k = [], b.rows = [], Mt = new Uint8Array(0), Ct = new Float32Array(0), lt = new Float32Array(0), ft = new Float32Array(0), B = U = V = rt = null, dt = null;
420
+ if (!z) {
421
+ z = !0, cancelAnimationFrame(vt), clearTimeout(Lt), at && clearTimeout(at), window.removeEventListener("resize", Ut), window.removeEventListener("pointermove", xt), C && St(!1);
422
+ for (const t of G) t.remove();
423
+ et = [], ht = [], R.rows = [], bt = new Uint8Array(0), Ct = new Float32Array(0), ft = new Float32Array(0), dt = new Float32Array(0), U = rt = null, ut = null, S = null;
382
424
  }
383
425
  }
384
426
  };
385
- return Gt;
427
+ return Rt;
386
428
  }
387
- function he(x) {
388
- const r = Pt(null), a = Pt(null), c = Pt(x);
389
- c.current = x;
390
- const { text: l, font: s, weight: h, threadColor: A, fabricColor: S, pitch: I, animate: f, sewRate: u, sheen: v, reducedMotion: P, aspect: Z } = x, wt = JSON.stringify({ font: s, weight: h, threadColor: A, fabricColor: S, pitch: I, animate: f, sewRate: u, sheen: v, reducedMotion: P, aspect: Z });
391
- return ie(() => {
392
- const j = r.current;
393
- if (!j) return;
394
- const H = ue(j, c.current);
395
- a.current = H;
396
- let $ = 0, O = 0, N;
397
- return typeof ResizeObserver < "u" && (N = new ResizeObserver((e) => {
398
- const i = Math.round(e[0].contentRect.width);
399
- i !== O && (O = i, cancelAnimationFrame($), $ = requestAnimationFrame(() => {
400
- var G;
401
- return (G = a.current) == null ? void 0 : G.resize();
429
+ function Me(m) {
430
+ const e = wt(null), o = wt(null), r = wt(m);
431
+ r.current = m;
432
+ const i = wt(m.onTextChange);
433
+ i.current = m.onTextChange;
434
+ const { text: a, font: f, weight: A, threadColor: E, pitch: C, fill: c, animate: u, sewRate: $, sheen: D, editable: k, reducedMotion: W } = m;
435
+ return me(() => {
436
+ const N = e.current;
437
+ if (!N) return;
438
+ const tt = pe(N, {
439
+ ...r.current,
440
+ // Stable callback wrapper so typing edits always reach the latest handler.
441
+ onTextChange: (O) => {
442
+ var S;
443
+ return (S = i.current) == null ? void 0 : S.call(i, O);
444
+ }
445
+ });
446
+ o.current = tt;
447
+ let G = 0, P = 0, g;
448
+ return typeof ResizeObserver < "u" && (g = new ResizeObserver((O) => {
449
+ const S = Math.round(O[0].contentRect.width);
450
+ S !== P && (P = S, cancelAnimationFrame(G), G = requestAnimationFrame(() => {
451
+ var Q;
452
+ return (Q = o.current) == null ? void 0 : Q.resize();
402
453
  }));
403
- }), N.observe(j)), () => {
404
- N == null || N.disconnect(), cancelAnimationFrame($), H.destroy(), a.current = null;
454
+ }), g.observe(N)), () => {
455
+ g == null || g.disconnect(), cancelAnimationFrame(G), tt.destroy(), o.current = null;
405
456
  };
406
- }, [wt]), ce(() => {
407
- var j;
408
- (j = a.current) == null || j.setText(l);
409
- }, [l]), r;
457
+ }, [W]), Qt(() => {
458
+ var N;
459
+ (N = o.current) == null || N.update({ font: f, weight: A, threadColor: E, pitch: C, fill: c, animate: u, sewRate: $, sheen: D, editable: k });
460
+ }, [f, A, E, C, c, u, $, D, k]), Qt(() => {
461
+ var N;
462
+ (N = o.current) == null || N.setText(a);
463
+ }, [a]), e;
410
464
  }
411
- const me = se(
412
- function({ className: r, style: a, as: c = "div", "aria-label": l, role: s, "aria-describedby": h, ...A }, S) {
413
- const I = he(A), f = le(
465
+ const be = ye(
466
+ function({ className: e, style: o, as: r = "div", "aria-label": i, role: a, "aria-describedby": f, ...A }, E) {
467
+ const C = Me(A), c = xe(
414
468
  (u) => {
415
- I.current = u, typeof S == "function" ? S(u) : S && (S.current = u);
469
+ C.current = u, typeof E == "function" ? E(u) : E && (E.current = u);
416
470
  },
417
471
  // eslint-disable-next-line react-hooks/exhaustive-deps
418
- [I, S]
472
+ [C, E]
419
473
  );
420
- return /* @__PURE__ */ fe(
421
- c,
474
+ return /* @__PURE__ */ ge(
475
+ r,
422
476
  {
423
- ref: f,
424
- className: r,
425
- style: a,
426
- role: s ?? "img",
427
- "aria-label": l ?? A.text,
428
- "aria-describedby": h
477
+ ref: c,
478
+ className: e,
479
+ style: o,
480
+ role: a ?? "img",
481
+ "aria-label": i ?? A.text,
482
+ "aria-describedby": f
429
483
  }
430
484
  );
431
485
  }
432
486
  );
433
- me.displayName = "ThreadText";
487
+ be.displayName = "ThreadText";
434
488
  export {
435
- Jt as THREAD_TEXT_CLASSES,
436
- me as ThreadText,
437
- ue as createThreadText,
438
- he as useThreadText
489
+ Bt as THREAD_TEXT_CLASSES,
490
+ be as ThreadText,
491
+ pe as createThreadText,
492
+ Me as useThreadText
439
493
  };
@@ -1 +1 @@
1
- var ThreadText=(function(at){"use strict";const Dt={bg:"tt-bg",fx:"tt-fx"};function B(s,n){let e=Math.imul(s|0,374761393)+Math.imul(n|0,668265263)|0;return e=Math.imul(e^e>>>13,1274126177),((e^e>>>16)>>>0)/4294967295}function xt(s,n){const e=Math.floor(s),o=Math.floor(n),r=s-e,d=n-o,m=r*r*(3-2*r),b=d*d*(3-2*d),E=B(e,o),L=B(e+1,o),u=B(e,o+1),g=B(e+1,o+1);return E+(L-E)*m+(u-E)*b+(E-L-u+g)*m*b}const it=1e20;function Ot(s,n,e,o,r){let d=0;o[0]=0,r[0]=-it,r[1]=it;for(let m=1;m<n;m++){let b=(s[m]+m*m-(s[o[d]]+o[d]*o[d]))/(2*m-2*o[d]);for(;b<=r[d];)d--,b=(s[m]+m*m-(s[o[d]]+o[d]*o[d]))/(2*m-2*o[d]);d++,o[d]=m,r[d]=b,r[d+1]=it}d=0;for(let m=0;m<n;m++){for(;r[d+1]<m;)d++;e[m]=(m-o[d])*(m-o[d])+s[o[d]]}}function ee(s,n,e){const o=new Float64Array(n*e);for(let u=0;u<n*e;u++)o[u]=s[u]?it:0;const r=Math.max(n,e),d=new Float64Array(r),m=new Float64Array(r),b=new Int32Array(r),E=new Float64Array(r+1);for(let u=0;u<n;u++){for(let g=0;g<e;g++)d[g]=o[g*n+u];Ot(d,e,m,b,E);for(let g=0;g<e;g++)o[g*n+u]=m[g]}for(let u=0;u<e;u++){for(let g=0;g<n;g++)d[g]=o[u*n+g];Ot(d,n,m,b,E);for(let g=0;g<n;g++)o[u*n+g]=m[g]}const L=new Float32Array(n*e);for(let u=0;u<n*e;u++)L[u]=Math.sqrt(o[u]);return L}function _t(s,n,e,o,r){let d=Float32Array.from(s);const m=new Float32Array(n*e),b=1/(2*o+1),E=(L,u)=>L<0?0:L>u?u:L;for(let L=0;L<r;L++){for(let u=0;u<e;u++){const g=u*n;let v=0;for(let $=-o;$<=o;$++)v+=d[g+E($,n-1)];for(let $=0;$<n;$++)m[g+$]=v*b,v+=d[g+E($+o+1,n-1)]-d[g+E($-o,n-1)]}for(let u=0;u<n;u++){let g=0;for(let v=-o;v<=o;v++)g+=m[E(v,e-1)*n+u];for(let v=0;v<e;v++)d[v*n+u]=g*b,g+=m[E(v+o+1,e-1)*n+u]-m[E(v-o,e-1)*n+u]}}return d}function qt(s,n){if(!s)return n;const e=s.trim();if(e[0]==="#"){let r=e.slice(1);if(r.length===3&&(r=r[0]+r[0]+r[1]+r[1]+r[2]+r[2]),r.length>=6){const d=parseInt(r.slice(0,2),16),m=parseInt(r.slice(2,4),16),b=parseInt(r.slice(4,6),16);if(!Number.isNaN(d)&&!Number.isNaN(m)&&!Number.isNaN(b))return[d,m,b]}return n}const o=e.match(/rgba?\(([^)]+)\)/i);if(o){const r=o[1].split(",").map(d=>parseFloat(d));if(r.length>=3&&r.slice(0,3).every(d=>!Number.isNaN(d)))return[Math.round(r[0]),Math.round(r[1]),Math.round(r[2])]}return n}function P(s){return s<0?0:s>255?255:Math.round(s)}function ne(s,n){if(typeof window>"u"||typeof document>"u"||!s)return{setText(){},replay(){},resize(){},destroy(){},get text(){return n.text??""}};let e=n.text??"";const o=n.font??"Georgia, serif",r=n.weight??680,d=n.aspect??.46,m=n.sewRate??110,b=n.sheen??!0,E=n.animate??!0,L=(o.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,""),u=n.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),g=qt(n.threadColor??"#fffbf3",[255,251,243]),v=[g[0]*.585,g[1]*.585,g[2]*.585],$=[g[0]*.47,g[1]*.47,g[2]*.47],st=qt(n.fabricColor??"#08080a",[8,8,10]),ce=[P(st[0]+14),P(st[1]+13),P(st[2]+15)],kt=t=>`rgb(${P(t[0])},${P(t[1])},${P(t[2])})`,Mt=[];let R,j;s instanceof HTMLCanvasElement?(R=s,j=s.parentElement??s):(j=s,R=document.createElement("canvas"),Mt.push(R),j.appendChild(R)),R.classList.add(Dt.bg);const X=document.createElement("canvas");Mt.push(X),X.classList.add(Dt.fx),j.appendChild(X),getComputedStyle(j).position==="static"&&(j.style.position="relative"),R.style.display="block",R.style.width="100%",Object.assign(X.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let c=0,l=0,lt=0,Ct=0,J=4,Q=[],Z=0,W=0,St=new Uint8Array(0),At=new Float32Array(0),ft=new Float32Array(0),dt=new Float32Array(0),k=null,G=null,U=null,tt=null,ut=null,q=[],ht=3;const S={rows:[],idx:0,acc:0,rate:0,on:!1},V={x:0,y:0,set:!1};let H=!0,Tt=0,zt=!1,mt=0,K=!1,Ft=!1;function Bt(){const t=j.getBoundingClientRect(),a=Math.round(t.width||Math.min(window.innerWidth*.95,1240)),i=Math.round(a*d);let f=Math.min(window.devicePixelRatio||1,1.7);for(;a*f*i*f>9e5&&f>.55;)f-=.1;c=Math.max(1,Math.round(a*f)),l=Math.max(1,Math.round(i*f));for(const h of[R,X])h.width=c,h.height=l,h.style.height=i+"px";j.style.height=i+"px"}function Xt(){const t=Math.max(7,J*2.5),a=Math.max(3.2,J*1.3);Z=Math.ceil(t)+2,W=Math.ceil(a)+2,Q=[];for(let i=0;i<20;i++){const f=.34+i/19*.82,h=document.createElement("canvas");h.width=Z,h.height=W;const M=h.getContext("2d");if(!M){Q.push(h);continue}const C=Z/2,T=W/2,I=M.createLinearGradient(0,T-a/2,0,T+a/2),p=(N,D)=>`rgba(${P(N[0]*f)},${P(N[1]*f)},${P(N[2]*f)},${D})`;I.addColorStop(0,p($,0)),I.addColorStop(.16,p(v,1)),I.addColorStop(.5,p(g,1)),I.addColorStop(.84,p(v,1)),I.addColorStop(1,p($,0)),M.fillStyle=I,M.beginPath();const x=a/2;M.moveTo(C-t/2+x,T-x),M.lineTo(C+t/2-x,T-x),M.arc(C+t/2-x,T,x,-Math.PI/2,Math.PI/2),M.lineTo(C-t/2+x,T+x),M.arc(C-t/2+x,T,x,Math.PI/2,-Math.PI/2),M.closePath(),M.fill(),M.globalCompositeOperation="destination-in";const F=M.createLinearGradient(C-t/2,0,C+t/2,0);F.addColorStop(0,"rgba(0,0,0,0)"),F.addColorStop(.22,"rgba(0,0,0,1)"),F.addColorStop(.78,"rgba(0,0,0,1)"),F.addColorStop(1,"rgba(0,0,0,0)"),M.fillStyle=F,M.fillRect(0,0,Z,W),Q.push(h)}}function bt(){if(!ut)return;const t=ut;t.clearRect(0,0,c,l),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${r} ${lt}px ${o}`,t.fillText(e,Ct,l*.5);const a=t.getImageData(0,0,c,l).data,i=new Uint8Array(c*l);for(let y=0;y<l;y++)for(let A=0;A<c;A++){const w=y*c+A,O=a[w*4+3]/255,_=xt(A*.5,y*.5)*.22+xt(A*1.8,y*1.8)*.1;i[w]=O>.5+(_-.16)?1:0}St=i;const f=ee(i,c,l),h=new Float32Array(c*l);for(let y=1;y<l-1;y++)for(let A=1;A<c-1;A++){const w=y*c+A;h[w]=(f[w]*4+f[w-1]+f[w+1]+f[w-c]+f[w+c])/8}const M=new Float32Array(c*l),C=new Float32Array(c*l),T=new Float32Array(c*l),I=new Float32Array(c*l);for(let y=1;y<l-1;y++)for(let A=1;A<c-1;A++){const w=y*c+A;if(!i[w])continue;const O=(h[w+1]-h[w-1])*.5,_=(h[w+c]-h[w-c])*.5;T[w]=O,I[w]=_,M[w]=O*O-_*_,C[w]=2*O*_}const p=Math.max(7,Math.round(l*.05)),x=_t(M,c,l,p,2),F=_t(C,c,l,p,2);ft=new Float32Array(c*l),dt=new Float32Array(c*l);for(let y=0;y<c*l;y++){if(!i[y])continue;const A=.5*Math.atan2(F[y],x[y]);ft[y]=Math.cos(A),dt[y]=Math.sin(A)}const N=Math.max(9,l*.04),D=new Float32Array(c*l),ot=-.45,rt=-.62,wt=.64;for(let y=1;y<l-1;y++)for(let A=1;A<c-1;A++){const w=y*c+A;if(!i[w])continue;let O=T[w],_=I[w];const Qt=Math.hypot(O,_)||1;O/=Qt,_/=Qt;const Zt=h[w],Wt=(1-Math.min(Zt/N,1))*1.25;let Lt=-O*Wt,Rt=-_*Wt;const te=1.5,Pt=Math.hypot(Lt,Rt,te);Lt/=Pt,Rt/=Pt;let $t=Lt*ot+Rt*rt+te/Pt*wt;$t<0&&($t=0);const me=Math.min(1,.45+.55*Math.min(Zt/(N*.7),1));D[w]=Math.min(1.12,(.5+.75*$t)*me)}At=D,k=document.createElement("canvas"),k.width=c,k.height=l;const z=k.getContext("2d");G=document.createElement("canvas"),G.width=c,G.height=l;const Y=G.getContext("2d");if(z&&Y){const y=z.createImageData(c,l),A=Y.createImageData(c,l);for(let w=0;w<c*l;w++)i[w]&&(y.data[w*4]=255,y.data[w*4+1]=255,y.data[w*4+2]=255,y.data[w*4+3]=255,A.data[w*4+3]=255);z.putImageData(y,0,0),Y.putImageData(A,0,0)}}function Gt(){U=document.createElement("canvas"),U.width=c,U.height=l;const t=U.getContext("2d",{willReadFrequently:!0});if(t){const a=t.createRadialGradient(c*.5,l*.4,0,c*.5,l*.5,c*.72);a.addColorStop(0,kt(ce)),a.addColorStop(1,kt(st)),t.fillStyle=a,t.fillRect(0,0,c,l);const i=t.getImageData(0,0,c,l),f=i.data;for(let h=0;h<l;h++)for(let M=0;M<c;M++){const C=(h*c+M)*4,T=Math.sin(M*1.9)*.5+.5,I=Math.sin(h*1.9)*.5+.5,p=T*I*9-4.5+(xt(M*.18,h*.18)-.5)*15;f[C]=P(f[C]+p),f[C+1]=P(f[C+1]+p),f[C+2]=P(f[C+2]+p*1.1)}t.putImageData(i,0,0)}tt=document.createElement("canvas"),tt.width=c,tt.height=l,ut=tt.getContext("2d",{willReadFrequently:!0})}function Et(){const t=Math.max(1.6,J*.6);ht=t;const a=[];for(let i=0;i<l;i+=t)for(let f=0;f<c;f+=t){const h=(B(Math.floor(f),Math.floor(i))-.5)*t*.9,M=(B(Math.floor(i),Math.floor(f))-.5)*t*.9,C=Math.round(f+h),T=Math.round(i+M);if(C<1||T<1||C>=c-1||T>=l-1)continue;const I=T*c+C;if(!St[I])continue;const p=Math.atan2(dt[I],ft[I]),x=.86+B(C*7,T*13)*.18;let F=At[I]*x;F=F<0?0:F>1.12?1.12:F,a.push({x:C,y:T,ang:p,idx:Math.min(19,Math.max(0,Math.round(F/1.12*19)))})}a.sort((i,f)=>i.x-f.x),q=a}function gt(t,a){t.save(),t.translate(a.x,a.y),t.rotate(a.ang),t.drawImage(Q[a.idx],-Z/2,-W/2),t.restore()}function yt(){const t=R.getContext("2d");if(t)for(const a of q)gt(t,a)}function Ut(){return q.length?q[q.length-1].x:0}function It(){return q.length?q[0].x:0}function et(){const t=R.getContext("2d");!t||!U||(t.drawImage(U,0,0),G&&(t.save(),t.globalAlpha=.85,t.filter=`blur(${Math.round(l*.018)}px)`,t.drawImage(G,0,Math.round(l*.02)),t.restore()))}function se(t){if(!t.length)return[];const a=Math.max(4,ht*1.5),i=new Map,f=(p,x)=>p+","+x;t.forEach((p,x)=>{const F=f(Math.floor(p.x/a),Math.floor(p.y/a));let N=i.get(F);N||i.set(F,N=[]),N.push(x)});const h=ht*1.8*(ht*1.8);function M(p){const x=t[p],F=Math.floor(x.x/a),N=Math.floor(x.y/a),D=[];for(let ot=-1;ot<=1;ot++)for(let rt=-1;rt<=1;rt++){const wt=i.get(f(F+ot,N+rt));if(wt)for(const z of wt){if(z===p)continue;const Y=t[z].x-x.x,y=t[z].y-x.y;Y*Y+y*y<=h&&D.push(z)}}return D}const C=new Uint8Array(t.length),T=[],I=t.map((p,x)=>x).sort((p,x)=>t[p].x+t[p].y-(t[x].x+t[x].y));for(const p of I){if(C[p])continue;let x=[p];for(C[p]=1;x.length;){T.push(x.map(N=>t[N]));const F=[];for(const N of x)for(const D of M(N))C[D]||(C[D]=1,F.push(D));x=F}}return T}function vt(t,a){et();const i=R.getContext("2d");if(!i)return;const f=[];for(const h of q)h.x<=t?gt(i,h):f.push(h);if(u){for(const h of f)gt(i,h);S.on=!1;return}S.rows=se(f),S.idx=0,S.acc=0,S.rate=a||m,S.on=S.rows.length>0}function le(t){const a=R.getContext("2d");if(a)for(t>S.rows.length&&(t=S.rows.length);S.idx<t;){const i=S.rows[S.idx++];for(const f of i)gt(a,f)}}function fe(t,a){const i=X.getContext("2d");if(!i||(i.clearRect(0,0,c,l),!b||!k))return;const f=c*.32,h=i.createRadialGradient(t,a,0,t,a,f);h.addColorStop(0,"rgba(255,250,238,0.18)"),h.addColorStop(.5,"rgba(255,250,238,0.055)"),h.addColorStop(1,"rgba(255,250,238,0)"),i.fillStyle=h,i.fillRect(0,0,c,l),i.globalCompositeOperation="destination-in",i.drawImage(k,0,0),i.globalCompositeOperation="source-over"}function Vt(){const t=R.getContext("2d");if(!t){lt=Math.round(l*.6),Ct=Math.round(c*.14);return}const a=e||"Ag";t.font=`${r} 100px ${o}`;const i=t.measureText(a).width||100;lt=Math.round(100*(c*.72)/i),t.font=`${r} ${lt}px ${o}`,Ct=Math.round(c/2-t.measureText(a).width/2)}function Ht(t){if(K)return;mt||(mt=t);const a=Math.min(.25,(t-mt)/1e3);mt=t,S.on&&(S.acc+=S.rate*a,le(S.acc),S.idx>=S.rows.length&&(S.on=!1)),H&&k&&(fe(V.set?V.x:c*.5,V.set?V.y:l*.34),H=!1),Tt=requestAnimationFrame(Ht)}function Kt(t){const a=X.getBoundingClientRect();V.x=(t.clientX-a.left)/(a.width||1)*c,V.y=(t.clientY-a.top)/(a.height||1)*l,V.set=!0,H=!0}b&&window.addEventListener("pointermove",Kt,{passive:!0});function de(t){bt(),Et(),E&&!u?vt(It()-1,m):(et(),yt(),S.on=!1),H=!0}function ue(){K||(Bt(),Gt(),J=Math.max(3.4,l*.0095),Xt(),Vt(),de(),Ft=!0,zt||(zt=!0,Tt=requestAnimationFrame(Ht)))}let nt;function he(t){const a=`${r} 200px ${L}`;let i=!1;try{i=!!document.fonts&&document.fonts.check(a)}catch{i=!0}if(!document.fonts||i){t();return}let f=!1;const h=()=>{f||(f=!0,nt&&clearTimeout(nt),t())};document.fonts.load(a,e).then(()=>document.fonts.ready).then(h,h),nt=setTimeout(h,1500)}he(ue);let Nt;function Yt(){clearTimeout(Nt),Nt=setTimeout(()=>Jt.resize(),200)}window.addEventListener("resize",Yt);const Jt={get text(){return e},setText(t){if(K||!Ft){e=t??"";return}t=t??"";const a=t.length>e.length&&e.length>0&&t.startsWith(e),i=a?Ut():-1;e=t,bt(),Et(),u||!E?(et(),yt(),S.on=!1):vt(a&&i>0?Math.min(i,Ut()):It()-1,a?320:m),H=!0},replay(){K||!Ft||(u||!E?(et(),yt(),S.on=!1):vt(It()-1,m),H=!0)},resize(){K||(Bt(),Gt(),J=Math.max(3.4,l*.0095),Xt(),Vt(),bt(),Et(),et(),yt(),S.on=!1,H=!0)},destroy(){if(!K){K=!0,cancelAnimationFrame(Tt),clearTimeout(Nt),nt&&clearTimeout(nt),window.removeEventListener("resize",Yt),b&&window.removeEventListener("pointermove",Kt);for(const t of Mt)t.remove();Q=[],q=[],S.rows=[],St=new Uint8Array(0),At=new Float32Array(0),ft=new Float32Array(0),dt=new Float32Array(0),k=G=U=tt=null,ut=null}}};return Jt}const oe="data-threadtext",pt=new WeakMap;function re(s,n){const e=s.dataset,o={text:e.ttText??n};if(e.ttFont&&(o.font=e.ttFont),e.ttWeight!==void 0){const r=parseFloat(e.ttWeight);isNaN(r)||(o.weight=r)}if(e.ttThreadColor&&(o.threadColor=e.ttThreadColor),e.ttFabricColor&&(o.fabricColor=e.ttFabricColor),e.ttPitch!==void 0){const r=parseFloat(e.ttPitch);isNaN(r)||(o.pitch=r)}if(e.ttSewRate!==void 0){const r=parseFloat(e.ttSewRate);isNaN(r)||(o.sewRate=r)}if(e.ttAspect!==void 0){const r=parseFloat(e.ttAspect);isNaN(r)||(o.aspect=r)}return e.ttSheen==="false"&&(o.sheen=!1),e.ttAnimate==="false"&&(o.animate=!1),o}function ae(s){jt(s);const n=s.innerHTML,e=(s.dataset.ttText??s.textContent??"").trim();if(!e)return;const o=re(s,e);s.setAttribute("role","img"),s.setAttribute("aria-label",e),s.innerHTML="";const r=ne(s,o);pt.set(s,{instance:r,originalHTML:n})}function jt(s){const n=pt.get(s);n&&(n.instance.destroy(),s.removeAttribute("role"),s.removeAttribute("aria-label"),s.innerHTML=n.originalHTML,pt.delete(s))}function ct(s=document){s.querySelectorAll(`[${oe}]`).forEach(ae)}function ie(){const s=()=>{var n;typeof document<"u"&&((n=document.fonts)!=null&&n.ready)?document.fonts.ready.then(()=>ct()).catch(()=>ct()):ct()};typeof document<"u"&&document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:!0}):s()}return ie(),at.destroy=jt,at.init=ct,Object.defineProperty(at,Symbol.toStringTag,{value:"Module"}),at})({});
1
+ var ThreadText=(function(rt){"use strict";const gt={bg:"tt-bg",fx:"tt-fx",caret:"tt-caret"};function U(a,n){let e=Math.imul(a|0,374761393)+Math.imul(n|0,668265263)|0;return e=Math.imul(e^e>>>13,1274126177),((e^e>>>16)>>>0)/4294967295}function Bt(a,n){const e=Math.floor(a),o=Math.floor(n),r=a-e,s=n-o,h=r*r*(3-2*r),F=s*s*(3-2*s),R=U(e,o),A=U(e+1,o),d=U(e,o+1),y=U(e+1,o+1);return R+(A-R)*h+(d-R)*F+(R-A-d+y)*h*F}const it=1e20;function Ot(a,n,e,o,r){let s=0;o[0]=0,r[0]=-it,r[1]=it;for(let h=1;h<n;h++){let F=(a[h]+h*h-(a[o[s]]+o[s]*o[s]))/(2*h-2*o[s]);for(;F<=r[s];)s--,F=(a[h]+h*h-(a[o[s]]+o[s]*o[s]))/(2*h-2*o[s]);s++,o[s]=h,r[s]=F,r[s+1]=it}s=0;for(let h=0;h<n;h++){for(;r[s+1]<h;)s++;e[h]=(h-o[s])*(h-o[s])+a[o[s]]}}function re(a,n,e){const o=new Float64Array(n*e);for(let d=0;d<n*e;d++)o[d]=a[d]?it:0;const r=Math.max(n,e),s=new Float64Array(r),h=new Float64Array(r),F=new Int32Array(r),R=new Float64Array(r+1);for(let d=0;d<n;d++){for(let y=0;y<e;y++)s[y]=o[y*n+d];Ot(s,e,h,F,R);for(let y=0;y<e;y++)o[y*n+d]=h[y]}for(let d=0;d<e;d++){for(let y=0;y<n;y++)s[y]=o[d*n+y];Ot(s,n,h,F,R);for(let y=0;y<n;y++)o[d*n+y]=h[y]}const A=new Float32Array(n*e);for(let d=0;d<n*e;d++)A[d]=Math.sqrt(o[d]);return A}function _t(a,n,e,o,r){let s=Float32Array.from(a);const h=new Float32Array(n*e),F=1/(2*o+1),R=(A,d)=>A<0?0:A>d?d:A;for(let A=0;A<r;A++){for(let d=0;d<e;d++){const y=d*n;let I=0;for(let k=-o;k<=o;k++)I+=s[y+R(k,n-1)];for(let k=0;k<n;k++)h[y+k]=I*F,I+=s[y+R(k+o+1,n-1)]-s[y+R(k-o,n-1)]}for(let d=0;d<n;d++){let y=0;for(let I=-o;I<=o;I++)y+=h[R(I,e-1)*n+d];for(let I=0;I<e;I++)s[I*n+d]=y*F,y+=h[R(I+o+1,e-1)*n+d]-h[R(I-o,e-1)*n+d]}}return s}function jt(a,n){if(!a)return n;const e=a.trim();if(e[0]==="#"){let r=e.slice(1);if(r.length===3&&(r=r[0]+r[0]+r[1]+r[1]+r[2]+r[2]),r.length>=6){const s=parseInt(r.slice(0,2),16),h=parseInt(r.slice(2,4),16),F=parseInt(r.slice(4,6),16);if(!Number.isNaN(s)&&!Number.isNaN(h)&&!Number.isNaN(F))return[s,h,F]}return n}const o=e.match(/rgba?\(([^)]+)\)/i);if(o){const r=o[1].split(",").map(s=>parseFloat(s));if(r.length>=3&&r.slice(0,3).every(s=>!Number.isNaN(s)))return[Math.round(r[0]),Math.round(r[1]),Math.round(r[2])]}return n}function q(a){return a<0?0:a>255?255:Math.round(a)}function qt(a){return(a.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,"")}function ie(a,n){if(typeof window>"u"||typeof document>"u"||!a)return{setText(){},replay(){},resize(){},update(){},focus(){},destroy(){},get text(){return n.text??""}};let e=n.text??"",o=n.font??"Georgia, serif",r=n.weight??680,s=n.fill??.9,h=n.sewRate??110,F=n.sheen??!0,R=n.animate??!0,A=n.editable??!1,d=n.pitch,y=n.onTextChange,I=qt(o);const k=n.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches);let D=jt(n.threadColor??"#fffbf3",[255,251,243]),pt=[0,0,0],Mt=[0,0,0];function zt(t){D=jt(t,[255,251,243]),pt=[D[0]*.585,D[1]*.585,D[2]*.585],Mt=[D[0]*.47,D[1]*.47,D[2]*.47]}zt(n.threadColor??"#fffbf3");const lt=[];let P,v;a instanceof HTMLCanvasElement?(P=a,v=a.parentElement??a):(v=a,P=document.createElement("canvas"),lt.push(P),v.appendChild(P)),P.classList.add(gt.bg);const K=document.createElement("canvas");lt.push(K),K.classList.add(gt.fx),v.appendChild(K),getComputedStyle(v).position==="static"&&(v.style.position="relative"),P.style.display="block",P.style.width="100%",Object.assign(K.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let L=null,Ct=!1,c=0,u=0,V=0,bt=0,st=4,J=[],Q=0,Z=0,vt=new Uint8Array(0),Tt=new Float32Array(0),ct=new Float32Array(0),ft=new Float32Array(0),z=null,W=null,dt=null,ut=[],ht=3;const E={rows:[],idx:0,acc:0,rate:0,on:!1},X={x:0,y:0,set:!1};let Y=!0,At=0,Gt=!1,mt=0,O=!1,H=!1;function fe(){const t=v.getBoundingClientRect(),i=Math.max(1,Math.round(t.width||Math.min(window.innerWidth*.95,1240))),l=e||"Ag",m=P.getContext("2d");let C=100;m&&(m.font=`${r} 100px ${o}`,C=m.measureText(l).width||100);let M=Math.max(8,100*(i*s)/C),b=M*.7,S=M*.3,N=i*s;if(m){m.font=`${r} ${M}px ${o}`;const w=m.measureText(l);N=w.width||N,w.actualBoundingBoxAscent>0&&(b=w.actualBoundingBoxAscent),w.actualBoundingBoxDescent>0&&(S=w.actualBoundingBoxDescent)}const g=Math.max(1,Math.round(2*Math.max(b,S)*1.12));let f=Math.min(window.devicePixelRatio||1,1.7);for(;i*f*g*f>9e5&&f>.4;)f-=.1;c=Math.max(1,Math.round(i*f)),u=Math.max(1,Math.round(g*f)),V=Math.max(4,Math.round(M*f)),bt=Math.round(c/2-N*f/2);for(const w of[P,K])w.width=c,w.height=u,w.style.height=g+"px";v.style.height=g+"px",st=d??Math.max(3,u*.0095)}function de(){W=document.createElement("canvas"),W.width=c,W.height=u,dt=W.getContext("2d",{willReadFrequently:!0})}function Ut(){const t=Math.max(7,st*2.5),i=Math.max(3.2,st*1.3);Q=Math.ceil(t)+2,Z=Math.ceil(i)+2,J=[];for(let l=0;l<20;l++){const m=.34+l/19*.82,C=document.createElement("canvas");C.width=Q,C.height=Z;const M=C.getContext("2d");if(!M){J.push(C);continue}const b=Q/2,S=Z/2,N=M.createLinearGradient(0,S-i/2,0,S+i/2),g=($,B)=>`rgba(${q($[0]*m)},${q($[1]*m)},${q($[2]*m)},${B})`;N.addColorStop(0,g(Mt,0)),N.addColorStop(.16,g(pt,1)),N.addColorStop(.5,g(D,1)),N.addColorStop(.84,g(pt,1)),N.addColorStop(1,g(Mt,0)),M.fillStyle=N,M.beginPath();const f=i/2;M.moveTo(b-t/2+f,S-f),M.lineTo(b+t/2-f,S-f),M.arc(b+t/2-f,S,f,-Math.PI/2,Math.PI/2),M.lineTo(b-t/2+f,S+f),M.arc(b-t/2+f,S,f,Math.PI/2,-Math.PI/2),M.closePath(),M.fill(),M.globalCompositeOperation="destination-in";const w=M.createLinearGradient(b-t/2,0,b+t/2,0);w.addColorStop(0,"rgba(0,0,0,0)"),w.addColorStop(.22,"rgba(0,0,0,1)"),w.addColorStop(.78,"rgba(0,0,0,1)"),w.addColorStop(1,"rgba(0,0,0,0)"),M.fillStyle=w,M.fillRect(0,0,Q,Z),J.push(C)}}function ue(){if(!dt)return;const t=dt;t.clearRect(0,0,c,u),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${r} ${V}px ${o}`,t.fillText(e,bt,u*.5);const i=t.getImageData(0,0,c,u).data,l=new Uint8Array(c*u);for(let x=0;x<u;x++)for(let p=0;p<c;p++){const T=x*c+p,_=i[T*4+3]/255,j=Bt(p*.5,x*.5)*.22+Bt(p*1.8,x*1.8)*.1;l[T]=_>.5+(j-.16)?1:0}vt=l;const m=re(l,c,u),C=new Float32Array(c*u);for(let x=1;x<u-1;x++)for(let p=1;p<c-1;p++){const T=x*c+p;C[T]=(m[T]*4+m[T-1]+m[T+1]+m[T-c]+m[T+c])/8}const M=new Float32Array(c*u),b=new Float32Array(c*u),S=new Float32Array(c*u),N=new Float32Array(c*u);for(let x=1;x<u-1;x++)for(let p=1;p<c-1;p++){const T=x*c+p;if(!l[T])continue;const _=(C[T+1]-C[T-1])*.5,j=(C[T+c]-C[T-c])*.5;S[T]=_,N[T]=j,M[T]=_*_-j*j,b[T]=2*_*j}const g=Math.max(7,Math.round(u*.05)),f=_t(M,c,u,g,2),w=_t(b,c,u,g,2);ct=new Float32Array(c*u),ft=new Float32Array(c*u);for(let x=0;x<c*u;x++){if(!l[x])continue;const p=.5*Math.atan2(w[x],f[x]);ct[x]=Math.cos(p),ft[x]=Math.sin(p)}const $=Math.max(9,u*.04),B=new Float32Array(c*u),nt=-.45,ot=-.62,xt=.64;for(let x=1;x<u-1;x++)for(let p=1;p<c-1;p++){const T=x*c+p;if(!l[T])continue;let _=S[T],j=N[T];const te=Math.hypot(_,j)||1;_/=te,j/=te;const ee=C[T],ne=(1-Math.min(ee/$,1))*1.25;let $t=-_*ne,Pt=-j*ne;const oe=1.5,Dt=Math.hypot($t,Pt,oe);$t/=Dt,Pt/=Dt;let kt=$t*nt+Pt*ot+oe/Dt*xt;kt<0&&(kt=0);const Ce=Math.min(1,.45+.55*Math.min(ee/($*.7),1));B[T]=Math.min(1.12,(.5+.75*kt)*Ce)}Tt=B,z=document.createElement("canvas"),z.width=c,z.height=u;const G=z.getContext("2d");if(G){const x=G.createImageData(c,u);for(let p=0;p<c*u;p++)l[p]&&(x.data[p*4]=255,x.data[p*4+1]=255,x.data[p*4+2]=255,x.data[p*4+3]=255);G.putImageData(x,0,0)}}function he(){const t=Math.max(1.6,st*.6);ht=t;const i=[];for(let l=0;l<u;l+=t)for(let m=0;m<c;m+=t){const C=(U(Math.floor(m),Math.floor(l))-.5)*t*.9,M=(U(Math.floor(l),Math.floor(m))-.5)*t*.9,b=Math.round(m+C),S=Math.round(l+M);if(b<1||S<1||b>=c-1||S>=u-1)continue;const N=S*c+b;if(!vt[N])continue;const g=Math.atan2(ft[N],ct[N]),f=.86+U(b*7,S*13)*.18;let w=Tt[N]*f;w=w<0?0:w>1.12?1.12:w,i.push({x:b,y:S,ang:g,idx:Math.min(19,Math.max(0,Math.round(w/1.12*19)))})}i.sort((l,m)=>l.x-m.x),ut=i}function Xt(t,i){t.save(),t.translate(i.x,i.y),t.rotate(i.ang),t.drawImage(J[i.idx],-Q/2,-Z/2),t.restore()}function St(){const t=P.getContext("2d");if(t)for(const i of ut)Xt(t,i)}function Et(){const t=P.getContext("2d");t&&t.clearRect(0,0,c,u)}function me(t){if(!t.length)return[];const i=Math.max(4,ht*1.5),l=new Map,m=(g,f)=>g+","+f;t.forEach((g,f)=>{const w=m(Math.floor(g.x/i),Math.floor(g.y/i));let $=l.get(w);$||l.set(w,$=[]),$.push(f)});const C=ht*1.8*(ht*1.8);function M(g){const f=t[g],w=Math.floor(f.x/i),$=Math.floor(f.y/i),B=[];for(let nt=-1;nt<=1;nt++)for(let ot=-1;ot<=1;ot++){const xt=l.get(m(w+nt,$+ot));if(xt)for(const G of xt){if(G===g)continue;const x=t[G].x-f.x,p=t[G].y-f.y;x*x+p*p<=C&&B.push(G)}}return B}const b=new Uint8Array(t.length),S=[],N=t.map((g,f)=>f).sort((g,f)=>t[g].x+t[g].y-(t[f].x+t[f].y));for(const g of N){if(b[g])continue;let f=[g];for(b[g]=1;f.length;){S.push(f.map($=>t[$]));const w=[];for(const $ of f)for(const B of M($))b[B]||(b[B]=1,w.push(B));f=w}}return S}function ye(){if(Et(),k||!R){St(),E.on=!1;return}E.rows=me(ut),E.idx=0,E.acc=0,E.rate=h,E.on=E.rows.length>0}function xe(t){const i=P.getContext("2d");if(i)for(t>E.rows.length&&(t=E.rows.length);E.idx<t;){const l=E.rows[E.idx++];for(const m of l)Xt(i,m)}}function ge(t,i){const l=K.getContext("2d");if(!l||(l.clearRect(0,0,c,u),!F||!z))return;const m=c*.32,C=l.createRadialGradient(t,i,0,t,i,m);C.addColorStop(0,"rgba(255,250,238,0.18)"),C.addColorStop(.5,"rgba(255,250,238,0.055)"),C.addColorStop(1,"rgba(255,250,238,0)"),l.fillStyle=C,l.fillRect(0,0,c,u),l.globalCompositeOperation="destination-in",l.drawImage(z,0,0),l.globalCompositeOperation="source-over"}function we(){L||!A||(L=document.createElement("span"),L.className=gt.caret,L.setAttribute("aria-hidden","true"),Object.assign(L.style,{position:"absolute",pointerEvents:"none",borderRadius:"1px",opacity:"0",background:`rgb(${q(D[0])},${q(D[1])},${q(D[2])})`}),v.appendChild(L),lt.push(L))}function Ft(){if(!A||!L)return;const t=P.getContext("2d");if(!t)return;t.font=`${r} ${V}px ${o}`;const i=t.measureText(e).width,l=(P.clientWidth||c)/c,m=V*.7;L.style.left=(bt+i+V*.05)*l+"px",L.style.top=.5*(P.clientHeight||u)-m*l/2+"px",L.style.height=m*l+"px",L.style.width=Math.max(2,Math.round(V*.02*l))+"px",L.style.background=`rgb(${q(D[0])},${q(D[1])},${q(D[2])})`}function Ht(t){if(O)return;mt||(mt=t);const i=Math.min(.25,(t-mt)/1e3);mt=t,E.on&&(E.acc+=E.rate*i,xe(E.acc),E.idx>=E.rows.length&&(E.on=!1)),Y&&z&&(ge(X.set?X.x:c*.5,X.set?X.y:u*.34),Y=!1),L&&(L.style.opacity=A&&Ct&&Math.floor(t/530)%2===0?"1":"0"),At=requestAnimationFrame(Ht)}function yt(t){const i=K.getBoundingClientRect();X.x=(t.clientX-i.left)/(i.width||1)*c,X.y=(t.clientY-i.top)/(i.height||1)*u,X.set=!0,Y=!0}function Vt(t){if(!(!A||t.metaKey||t.ctrlKey||t.altKey)){if(t.key==="Backspace"){t.preventDefault(),Nt(e.slice(0,-1),!0);return}if(t.key==="Enter"){t.preventDefault(),It.replay();return}[...t.key].length===1&&(t.preventDefault(),Nt(e+t.key,!0))}}function Yt(){Ct=!0}function Jt(){Ct=!1,L&&(L.style.opacity="0")}function Qt(){A&&v.focus()}function Lt(t){A=t,t?(v.tabIndex=0,v.setAttribute("role","textbox"),v.getAttribute("aria-label")||v.setAttribute("aria-label","Editable embroidered text — type to change it"),we(),v.addEventListener("keydown",Vt),v.addEventListener("focus",Yt),v.addEventListener("blur",Jt),v.addEventListener("pointerdown",Qt),Ft()):(v.removeAttribute("tabindex"),v.removeAttribute("role"),v.removeEventListener("keydown",Vt),v.removeEventListener("focus",Yt),v.removeEventListener("blur",Jt),v.removeEventListener("pointerdown",Qt),L&&(L.style.opacity="0"))}function pe(t){if(t!==F)if(F=t,t)window.addEventListener("pointermove",yt,{passive:!0}),Y=!0;else{window.removeEventListener("pointermove",yt);const i=K.getContext("2d");i&&i.clearRect(0,0,c,u)}}function tt(t){fe(),de(),Ut(),ue(),he(),t?ye():(Et(),St(),E.on=!1),Ft(),Y=!0}function Nt(t,i){t=t??"",!(t===e&&H)&&(e=t,H&&(tt(!1),i&&y&&y(e)))}let et;function Zt(t,i,l){const m=`${i} 200px ${t}`;let C=!1;try{C=!!document.fonts&&document.fonts.check(m)}catch{C=!0}if(!document.fonts||C){l();return}let M=!1;const b=()=>{M||(M=!0,et&&clearTimeout(et),l())};document.fonts.load(m,e).then(()=>document.fonts.ready).then(b,b),et=setTimeout(b,1500)}function Me(){O||(tt(!0),H=!0,Gt||(Gt=!0,At=requestAnimationFrame(Ht)))}A&&Lt(!0),F&&window.addEventListener("pointermove",yt,{passive:!0}),Zt(I,r,Me);let Rt;function Wt(){clearTimeout(Rt),Rt=setTimeout(()=>It.resize(),200)}window.addEventListener("resize",Wt);const It={get text(){return e},setText(t){if(!O){if(!H){e=t??"";return}Nt(t,!1)}},replay(){O||!H||tt(!0)},resize(){O||!H||tt(!1)},update(t){if(O)return;let i=!1,l=!1;t.font!==void 0&&t.font!==o&&(o=t.font,I=qt(o),i=!0),t.weight!==void 0&&t.weight!==r&&(r=t.weight,i=!0),t.fill!==void 0&&t.fill!==s&&(s=t.fill,i=!0),t.pitch!==void 0&&t.pitch!==d&&(d=t.pitch,i=!0),t.threadColor!==void 0&&(zt(t.threadColor),l=!0),t.sewRate!==void 0&&(h=t.sewRate),t.animate!==void 0&&(R=t.animate),t.onTextChange!==void 0&&(y=t.onTextChange),t.sheen!==void 0&&pe(t.sheen),t.editable!==void 0&&t.editable!==A&&Lt(t.editable),H&&(i?Zt(I,r,()=>{O||tt(!1)}):l&&(Ut(),Et(),St(),Ft()),Y=!0)},focus(){!O&&A&&v.focus()},destroy(){if(!O){O=!0,cancelAnimationFrame(At),clearTimeout(Rt),et&&clearTimeout(et),window.removeEventListener("resize",Wt),window.removeEventListener("pointermove",yt),A&&Lt(!1);for(const t of lt)t.remove();J=[],ut=[],E.rows=[],vt=new Uint8Array(0),Tt=new Float32Array(0),ct=new Float32Array(0),ft=new Float32Array(0),z=W=null,dt=null,L=null}}};return It}const ae="data-threadtext",wt=new WeakMap;function le(a,n){const e=a.dataset,o={text:e.ttText??n};if(e.ttFont&&(o.font=e.ttFont),e.ttWeight!==void 0){const r=parseFloat(e.ttWeight);isNaN(r)||(o.weight=r)}if(e.ttThreadColor&&(o.threadColor=e.ttThreadColor),e.ttPitch!==void 0){const r=parseFloat(e.ttPitch);isNaN(r)||(o.pitch=r)}if(e.ttFill!==void 0){const r=parseFloat(e.ttFill);isNaN(r)||(o.fill=r)}if(e.ttSewRate!==void 0){const r=parseFloat(e.ttSewRate);isNaN(r)||(o.sewRate=r)}return e.ttSheen==="false"&&(o.sheen=!1),e.ttAnimate==="false"&&(o.animate=!1),e.ttEditable==="true"&&(o.editable=!0),o}function se(a){Kt(a);const n=a.innerHTML,e=(a.dataset.ttText??a.textContent??"").trim();if(!e)return;const o=le(a,e);a.setAttribute("role","img"),a.setAttribute("aria-label",e),a.innerHTML="";const r=ie(a,o);wt.set(a,{instance:r,originalHTML:n})}function Kt(a){const n=wt.get(a);n&&(n.instance.destroy(),a.removeAttribute("role"),a.removeAttribute("aria-label"),a.innerHTML=n.originalHTML,wt.delete(a))}function at(a=document){a.querySelectorAll(`[${ae}]`).forEach(se)}function ce(){const a=()=>{var n;typeof document<"u"&&((n=document.fonts)!=null&&n.ready)?document.fonts.ready.then(()=>at()).catch(()=>at()):at()};typeof document<"u"&&document.readyState==="loading"?document.addEventListener("DOMContentLoaded",a,{once:!0}):a()}return ce(),rt.destroy=Kt,rt.init=at,Object.defineProperty(rt,Symbol.toStringTag,{value:"Module"}),rt})({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liiift-studio/threadtext",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Render any text as photorealistic procedural satin-stitch embroidery, in real time in the browser, from the font's glyph geometry",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -42,6 +42,7 @@
42
42
  "@types/react": "^19.0.0",
43
43
  "@vitejs/plugin-react": "^4.0.0",
44
44
  "happy-dom": "^20.10.6",
45
+ "next": "16.2.2",
45
46
  "react": "^19.0.0",
46
47
  "react-dom": "^19.0.0",
47
48
  "typescript": "^5.0.0",
@@ -73,7 +74,7 @@
73
74
  "homepage": "https://threadtext.com",
74
75
  "repository": {
75
76
  "type": "git",
76
- "url": "https://github.com/Liiift-Studio/ThreadText.git"
77
+ "url": "git+https://github.com/Liiift-Studio/ThreadText.git"
77
78
  },
78
79
  "bugs": {
79
80
  "url": "https://github.com/Liiift-Studio/ThreadText/issues"