typography-toolkit 1.2.1 → 1.3.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.
@@ -16,7 +16,7 @@ class C {
16
16
  };
17
17
  }
18
18
  }
19
- class x {
19
+ class S {
20
20
  constructor() {
21
21
  this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
22
22
  }
@@ -30,7 +30,7 @@ class x {
30
30
  };
31
31
  }
32
32
  }
33
- class S {
33
+ class x {
34
34
  update(e, o, n, t = {}) {
35
35
  const i = t.speed || 1, l = t.amplitude || 15, r = o * 0.2, c = -((n * 8 * i + r * 4) % l - l / 2);
36
36
  return {
@@ -39,7 +39,7 @@ class S {
39
39
  };
40
40
  }
41
41
  }
42
- function H(s, e) {
42
+ function D(s, e) {
43
43
  const { x: o, y: n, rotation: t, scale: i, opacity: l } = e;
44
44
  s.style.transform = `translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`, s.style.opacity = l.toString();
45
45
  }
@@ -49,20 +49,20 @@ function b(s, e, o, n, t, i) {
49
49
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
50
50
  applied: !1
51
51
  };
52
- const l = i.radius || 80, r = i.strength || 1, a = i.behaviors || ["fall-away", "split-apart", "explode"], c = o - s, h = n - e, d = Math.sqrt(c * c + h * h);
52
+ const l = i.radius || 80, r = i.strength || 1, a = i.behaviors || ["fall-away", "split-apart", "explode"], c = o - s, u = n - e, d = Math.sqrt(c * c + u * u);
53
53
  if (d >= l)
54
54
  return {
55
55
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
56
56
  applied: !1
57
57
  };
58
- const g = (1 - d / l) * r, u = Math.atan2(h, c), M = a[t % a.length];
58
+ const g = (1 - d / l) * r, h = Math.atan2(u, c), T = a[t % a.length];
59
59
  let m;
60
- switch (M) {
60
+ switch (T) {
61
61
  case "fall-away":
62
- const A = Math.cos(u) * g * 20, D = Math.sin(u) * g * 40 + g * 30;
62
+ const A = Math.cos(h) * g * 20, E = Math.sin(h) * g * 40 + g * 30;
63
63
  m = {
64
64
  x: A,
65
- y: D,
65
+ y: E,
66
66
  rotation: g * 15,
67
67
  scale: 1,
68
68
  opacity: 1 - g * 0.6
@@ -79,7 +79,7 @@ function b(s, e, o, n, t, i) {
79
79
  };
80
80
  break;
81
81
  case "explode":
82
- const F = u + (Math.random() - 0.5) * 0.5;
82
+ const F = h + (Math.random() - 0.5) * 0.5;
83
83
  m = {
84
84
  x: Math.cos(F) * g * 40,
85
85
  y: Math.sin(F) * g * 40,
@@ -99,7 +99,7 @@ function b(s, e, o, n, t, i) {
99
99
  class v {
100
100
  constructor(e) {
101
101
  var o;
102
- if (this.letters = [], this.animationFrame = null, this.mouseX = 0, this.mouseY = 0, this.mouseMoveHandler = null, this.startTime = Date.now(), this.isDestroyed = !1, this.container = e.container, this.animationTypes = e.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = e.cycle !== !1, this.speed = e.speed || 1, this.amplitude = e.amplitude || 1, this.disintegration = e.disintegration || { enabled: !1 }, this.style = e.style || {}, this.fadeOut = e.fadeOut || 0, this.callbacks = e.callbacks, this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", e.containerClass && (this.textContainer.className = e.containerClass), e.containerStyle && Object.entries(e.containerStyle).forEach(([n, t]) => {
102
+ if (this.letters = [], this.animationSpeedMultiplier = 1, this.animationFrame = null, this.mouseX = 0, this.mouseY = 0, this.mouseMoveHandler = null, this.startTime = Date.now(), this.isDestroyed = !1, this.container = e.container, this.animationTypes = e.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = e.cycle !== !1, this.speed = e.speed || 1, this.amplitude = e.amplitude || 1, this.animationEasing = e.animationEasing || "linear", this.disintegration = e.disintegration || { enabled: !1 }, this.style = e.style || {}, this.fadeOut = e.fadeOut || 0, this.callbacks = e.callbacks, e.animationSpeed !== void 0 && (this.animationSpeedMultiplier = this.parseAnimationSpeed(e.animationSpeed)), this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", e.containerClass && (this.textContainer.className = e.containerClass), e.containerStyle && Object.entries(e.containerStyle).forEach(([n, t]) => {
103
103
  this.textContainer.style.setProperty(n, t);
104
104
  }), e.position) {
105
105
  let n = e.position.x, t = e.position.y;
@@ -144,7 +144,7 @@ class v {
144
144
  if (this.isDestroyed) return;
145
145
  const o = (Date.now() - this.startTime) * 1e-3;
146
146
  this.letters.forEach((n, t) => {
147
- var h;
147
+ var u;
148
148
  const i = n.element.getBoundingClientRect(), l = i.left + i.width / 2, r = i.top + i.height / 2, a = b(
149
149
  l,
150
150
  r,
@@ -155,7 +155,7 @@ class v {
155
155
  );
156
156
  let c;
157
157
  if (a.applied)
158
- c = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(t);
158
+ c = a.state, (u = this.callbacks) != null && u.onDisintegrate && this.callbacks.onDisintegrate(t);
159
159
  else {
160
160
  const d = this.getAnimationType(t);
161
161
  c = this.getAnimation(d).update(
@@ -163,12 +163,12 @@ class v {
163
163
  t,
164
164
  o,
165
165
  {
166
- speed: this.speed,
166
+ speed: this.speed * this.animationSpeedMultiplier,
167
167
  amplitude: this.amplitude * (d === "falling" || d === "floating" ? 20 : 4)
168
168
  }
169
169
  );
170
170
  }
171
- H(n.element, c);
171
+ D(n.element, c);
172
172
  }), this.animationFrame = requestAnimationFrame(e);
173
173
  };
174
174
  this.animationFrame = requestAnimationFrame(e);
@@ -183,13 +183,54 @@ class v {
183
183
  case "splitting":
184
184
  return new C();
185
185
  case "glitching":
186
- return new x();
187
- case "floating":
188
186
  return new S();
187
+ case "floating":
188
+ return new x();
189
189
  default:
190
190
  return new f();
191
191
  }
192
192
  }
193
+ /**
194
+ * Parse animation speed preset or numeric value to a multiplier
195
+ */
196
+ parseAnimationSpeed(e) {
197
+ if (typeof e == "number")
198
+ return e;
199
+ switch (e) {
200
+ case "slow":
201
+ return 0.5;
202
+ case "normal":
203
+ return 1;
204
+ case "fast":
205
+ return 2;
206
+ default:
207
+ return 1;
208
+ }
209
+ }
210
+ /**
211
+ * Get the current animation speed multiplier
212
+ */
213
+ getAnimationSpeed() {
214
+ return this.animationSpeedMultiplier;
215
+ }
216
+ /**
217
+ * Set the animation speed multiplier (supports numeric values and presets)
218
+ */
219
+ setAnimationSpeed(e) {
220
+ this.animationSpeedMultiplier = this.parseAnimationSpeed(e);
221
+ }
222
+ /**
223
+ * Get the current animation easing function
224
+ */
225
+ getAnimationEasing() {
226
+ return this.animationEasing;
227
+ }
228
+ /**
229
+ * Set the animation easing function
230
+ */
231
+ setAnimationEasing(e) {
232
+ this.animationEasing = e;
233
+ }
193
234
  /**
194
235
  * Destroy the animated text instance
195
236
  */
@@ -206,7 +247,7 @@ class v {
206
247
  return this.textContainer;
207
248
  }
208
249
  }
209
- const E = [
250
+ const H = [
210
251
  "unsettling",
211
252
  "eerie",
212
253
  "decayed",
@@ -515,13 +556,13 @@ function y(s, e) {
515
556
  const { positive: o, negative: n } = L(s), t = (e == null ? void 0 : e.limit) ?? 10, l = k.map((r) => {
516
557
  let a = 0;
517
558
  for (const c of o) {
518
- for (const h of r.categories)
519
- (h.includes(c) || c.includes(h)) && (a += 10);
559
+ for (const u of r.categories)
560
+ (u.includes(c) || c.includes(u)) && (a += 10);
520
561
  r.name.toLowerCase().includes(c) && (a += 15), r.description.toLowerCase().includes(c) && (a += 8);
521
562
  }
522
563
  for (const c of n) {
523
- for (const h of r.categories)
524
- (h.includes(c) || c.includes(h)) && (a -= 20);
564
+ for (const u of r.categories)
565
+ (u.includes(c) || c.includes(u)) && (a -= 20);
525
566
  r.name.toLowerCase().includes(c) && (a -= 15), r.description.toLowerCase().includes(c) && (a -= 10);
526
567
  }
527
568
  return r.artistic && (a += 1), { font: r, score: a };
@@ -591,7 +632,7 @@ function I(s, e = "sans-serif") {
591
632
  let t = e;
592
633
  return o.includes(s) ? t = "cursive" : n.includes(s) && (t = "monospace"), `'${s}', ${t}`;
593
634
  }
594
- function T(s, e) {
635
+ function M(s, e) {
595
636
  const o = s.toLowerCase(), n = e.rejectedFont.toLowerCase(), t = e.negativeAspects.map((a) => a.toLowerCase()), i = e.positiveAspects.map((a) => a.toLowerCase());
596
637
  return y(s).filter(
597
638
  (a) => a.googleFontsName.toLowerCase() !== n && a.name.toLowerCase() !== n
@@ -600,25 +641,25 @@ function T(s, e) {
600
641
  for (const d of a.categories)
601
642
  o.includes(d) && (c += 5);
602
643
  for (const d of i)
603
- (a.categories.some((u) => u.includes(d) || d.includes(u)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c += 15);
644
+ (a.categories.some((h) => h.includes(d) || d.includes(h)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c += 15);
604
645
  for (const d of t)
605
- (a.categories.some((u) => u.includes(d) || d.includes(u)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c -= 20);
606
- const h = i.some(
646
+ (a.categories.some((h) => h.includes(d) || d.includes(h)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c -= 20);
647
+ const u = i.some(
607
648
  (d) => d.includes("striking") || d.includes("artistic") || d.includes("unique")
608
649
  );
609
- return h && a.artistic && (c += 10), h && !a.artistic && (c -= 5), { font: a, score: c };
650
+ return u && a.artistic && (c += 10), u && !a.artistic && (c -= 5), { font: a, score: c };
610
651
  }).filter((a) => a.score > 0).sort((a, c) => c.score - a.score).map((a) => a.font);
611
652
  }
612
653
  function Y(s, e) {
613
- return T(s, e)[0];
654
+ return M(s, e)[0];
614
655
  }
615
656
  if (typeof window < "u") {
616
657
  const s = {
617
658
  AnimatedText: v,
618
659
  FallingAnimation: f,
619
660
  SplittingAnimation: C,
620
- GlitchingAnimation: x,
621
- FloatingAnimation: S,
661
+ GlitchingAnimation: S,
662
+ FloatingAnimation: x,
622
663
  calculateDisintegration: b,
623
664
  // Font utilities
624
665
  fontSuggestions: k,
@@ -628,9 +669,9 @@ if (typeof window < "u") {
628
669
  loadGoogleFonts: B,
629
670
  isFontLoaded: G,
630
671
  getFontFamily: I,
631
- refineSuggestion: T,
672
+ refineSuggestion: M,
632
673
  refineFont: Y,
633
- MOOD_CATEGORIES: E,
674
+ MOOD_CATEGORIES: H,
634
675
  INTENSITY_CATEGORIES: R
635
676
  };
636
677
  window.TypographyToolkit = s, window.AnimatedText = v;
@@ -638,10 +679,10 @@ if (typeof window < "u") {
638
679
  export {
639
680
  v as AnimatedText,
640
681
  f as FallingAnimation,
641
- S as FloatingAnimation,
642
- x as GlitchingAnimation,
682
+ x as FloatingAnimation,
683
+ S as GlitchingAnimation,
643
684
  R as INTENSITY_CATEGORIES,
644
- E as MOOD_CATEGORIES,
685
+ H as MOOD_CATEGORIES,
645
686
  C as SplittingAnimation,
646
687
  b as calculateDisintegration,
647
688
  k as fontSuggestions,
@@ -650,7 +691,7 @@ export {
650
691
  N as loadGoogleFont,
651
692
  B as loadGoogleFonts,
652
693
  Y as refineFont,
653
- T as refineSuggestion,
694
+ M as refineSuggestion,
654
695
  P as suggestFont,
655
696
  y as suggestFonts
656
697
  };
@@ -1 +1 @@
1
- var TypographyToolkit=function(g){"use strict";class f{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class C{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function S(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,d=Math.sqrt(c*c+h*h);if(d>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-d/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let p;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;p={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;p={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;p={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=S(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const d=this.getAnimationType(t);c=this.getAnimation(d).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed,amplitude:this.amplitude*(d==="falling"||d==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new f;case"splitting":return new F;case"glitching":return new v;case"floating":return new C;default:return new f}}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],M=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function A(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function D(s){return Promise.all(s.map(e=>N(e)))}function E(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const d of a.categories)o.includes(d)&&(c+=5);for(const d of i)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c+=15);for(const d of t)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c-=20);const h=i.some(d=>d.includes("striking")||d.includes("artistic")||d.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:f,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:C,calculateDisintegration:S,fontSuggestions:k,suggestFonts:y,suggestFont:A,loadGoogleFont:N,loadGoogleFonts:D,isFontLoaded:E,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:M};window.TypographyToolkit=s,window.AnimatedText=b}return g.AnimatedText=b,g.FallingAnimation=f,g.FloatingAnimation=C,g.GlitchingAnimation=v,g.INTENSITY_CATEGORIES=M,g.MOOD_CATEGORIES=x,g.SplittingAnimation=F,g.calculateDisintegration=S,g.fontSuggestions=k,g.getFontFamily=H,g.isFontLoaded=E,g.loadGoogleFont=N,g.loadGoogleFonts=D,g.refineFont=R,g.refineSuggestion=T,g.suggestFont=A,g.suggestFonts=y,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),g}({});
1
+ var TypographyToolkit=function(g){"use strict";class f{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class S{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function C(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,d=Math.sqrt(c*c+h*h);if(d>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-d/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let p;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;p={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;p={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;p={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationSpeedMultiplier=1,this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.animationEasing=e.animationEasing||"linear",this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,e.animationSpeed!==void 0&&(this.animationSpeedMultiplier=this.parseAnimationSpeed(e.animationSpeed)),this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=C(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const d=this.getAnimationType(t);c=this.getAnimation(d).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed*this.animationSpeedMultiplier,amplitude:this.amplitude*(d==="falling"||d==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new f;case"splitting":return new F;case"glitching":return new v;case"floating":return new S;default:return new f}}parseAnimationSpeed(e){if(typeof e=="number")return e;switch(e){case"slow":return .5;case"normal":return 1;case"fast":return 2;default:return 1}}getAnimationSpeed(){return this.animationSpeedMultiplier}setAnimationSpeed(e){this.animationSpeedMultiplier=this.parseAnimationSpeed(e)}getAnimationEasing(){return this.animationEasing}setAnimationEasing(e){this.animationEasing=e}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const A=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],x=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function M(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function E(s){return Promise.all(s.map(e=>N(e)))}function D(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const d of a.categories)o.includes(d)&&(c+=5);for(const d of i)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c+=15);for(const d of t)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c-=20);const h=i.some(d=>d.includes("striking")||d.includes("artistic")||d.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:f,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:S,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:A,INTENSITY_CATEGORIES:x};window.TypographyToolkit=s,window.AnimatedText=b}return g.AnimatedText=b,g.FallingAnimation=f,g.FloatingAnimation=S,g.GlitchingAnimation=v,g.INTENSITY_CATEGORIES=x,g.MOOD_CATEGORIES=A,g.SplittingAnimation=F,g.calculateDisintegration=C,g.fontSuggestions=k,g.getFontFamily=H,g.isFontLoaded=D,g.loadGoogleFont=N,g.loadGoogleFonts=E,g.refineFont=R,g.refineSuggestion=T,g.suggestFont=M,g.suggestFonts=y,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),g}({});
@@ -1 +1 @@
1
- (function(d,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(d=typeof globalThis<"u"?globalThis:d||self,p(d.TypographyToolkit={}))})(this,function(d){"use strict";class p{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class C{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function S(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,g=Math.sqrt(c*c+h*h);if(g>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-g/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let f;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;f={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;f={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;f={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=S(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const g=this.getAnimationType(t);c=this.getAnimation(g).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed,amplitude:this.amplitude*(g==="falling"||g==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new p;case"splitting":return new F;case"glitching":return new v;case"floating":return new C;default:return new p}}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],M=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function A(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function D(s){return Promise.all(s.map(e=>N(e)))}function E(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const g of a.categories)o.includes(g)&&(c+=5);for(const g of i)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c+=15);for(const g of t)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c-=20);const h=i.some(g=>g.includes("striking")||g.includes("artistic")||g.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:p,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:C,calculateDisintegration:S,fontSuggestions:k,suggestFonts:y,suggestFont:A,loadGoogleFont:N,loadGoogleFonts:D,isFontLoaded:E,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:M};window.TypographyToolkit=s,window.AnimatedText=b}d.AnimatedText=b,d.FallingAnimation=p,d.FloatingAnimation=C,d.GlitchingAnimation=v,d.INTENSITY_CATEGORIES=M,d.MOOD_CATEGORIES=x,d.SplittingAnimation=F,d.calculateDisintegration=S,d.fontSuggestions=k,d.getFontFamily=H,d.isFontLoaded=E,d.loadGoogleFont=N,d.loadGoogleFonts=D,d.refineFont=R,d.refineSuggestion=T,d.suggestFont=A,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(d=typeof globalThis<"u"?globalThis:d||self,p(d.TypographyToolkit={}))})(this,function(d){"use strict";class p{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class S{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function C(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,g=Math.sqrt(c*c+h*h);if(g>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-g/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let f;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;f={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;f={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;f={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationSpeedMultiplier=1,this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.animationEasing=e.animationEasing||"linear",this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,e.animationSpeed!==void 0&&(this.animationSpeedMultiplier=this.parseAnimationSpeed(e.animationSpeed)),this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=C(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const g=this.getAnimationType(t);c=this.getAnimation(g).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed*this.animationSpeedMultiplier,amplitude:this.amplitude*(g==="falling"||g==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new p;case"splitting":return new F;case"glitching":return new S;case"floating":return new v;default:return new p}}parseAnimationSpeed(e){if(typeof e=="number")return e;switch(e){case"slow":return .5;case"normal":return 1;case"fast":return 2;default:return 1}}getAnimationSpeed(){return this.animationSpeedMultiplier}setAnimationSpeed(e){this.animationSpeedMultiplier=this.parseAnimationSpeed(e)}getAnimationEasing(){return this.animationEasing}setAnimationEasing(e){this.animationEasing=e}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],A=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function M(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function E(s){return Promise.all(s.map(e=>N(e)))}function D(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const g of a.categories)o.includes(g)&&(c+=5);for(const g of i)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c+=15);for(const g of t)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c-=20);const h=i.some(g=>g.includes("striking")||g.includes("artistic")||g.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:p,SplittingAnimation:F,GlitchingAnimation:S,FloatingAnimation:v,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:A};window.TypographyToolkit=s,window.AnimatedText=b}d.AnimatedText=b,d.FallingAnimation=p,d.FloatingAnimation=v,d.GlitchingAnimation=S,d.INTENSITY_CATEGORIES=A,d.MOOD_CATEGORIES=x,d.SplittingAnimation=F,d.calculateDisintegration=C,d.fontSuggestions=k,d.getFontFamily=H,d.isFontLoaded=D,d.loadGoogleFont=N,d.loadGoogleFonts=E,d.refineFont=R,d.refineSuggestion=T,d.suggestFont=M,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typography-toolkit",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Letter-by-letter text animations with proximity-based disintegration effects and Google Fonts selection",
5
5
  "main": "dist/typography-toolkit.umd.js",
6
6
  "module": "dist/typography-toolkit.esm.js",