typography-toolkit 1.2.0 → 1.2.1

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.
@@ -1,191 +1,191 @@
1
1
  class f {
2
- update(t, o, e, i = {}) {
3
- const s = i.speed || 1, c = i.amplitude || 20, g = o * 0.2, l = (e * 10 * s + g * 5) % c - c / 2;
2
+ update(e, o, n, t = {}) {
3
+ const i = t.speed || 1, l = t.amplitude || 20, r = o * 0.2, c = (n * 10 * i + r * 5) % l - l / 2;
4
4
  return {
5
- ...t,
6
- y: l
5
+ ...e,
6
+ y: c
7
7
  };
8
8
  }
9
9
  }
10
10
  class C {
11
- update(t, o, e, i = {}) {
12
- const s = i.speed || 1, c = i.amplitude || 4, g = o * 0.2, a = Math.sin(e * 0.5 * s + g) * c;
11
+ update(e, o, n, t = {}) {
12
+ const i = t.speed || 1, l = t.amplitude || 4, r = o * 0.2, a = Math.sin(n * 0.5 * i + r) * l;
13
13
  return {
14
- ...t,
14
+ ...e,
15
15
  x: a
16
16
  };
17
17
  }
18
18
  }
19
- class v {
19
+ class x {
20
20
  constructor() {
21
21
  this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
22
22
  }
23
- update(t, o, e, i = {}) {
24
- const s = i.amplitude || 3;
25
- return e - this.lastUpdate > 0.1 && (this.glitchX = (Math.random() - 0.5) * s, this.glitchY = (Math.random() - 0.5) * (s * 0.67), this.glitchRot = (Math.random() - 0.5) * s, this.lastUpdate = e), {
26
- ...t,
23
+ update(e, o, n, t = {}) {
24
+ const i = t.amplitude || 3;
25
+ return n - this.lastUpdate > 0.1 && (this.glitchX = (Math.random() - 0.5) * i, this.glitchY = (Math.random() - 0.5) * (i * 0.67), this.glitchRot = (Math.random() - 0.5) * i, this.lastUpdate = n), {
26
+ ...e,
27
27
  x: this.glitchX,
28
28
  y: this.glitchY,
29
29
  rotation: this.glitchRot
30
30
  };
31
31
  }
32
32
  }
33
- class k {
34
- update(t, o, e, i = {}) {
35
- const s = i.speed || 1, c = i.amplitude || 15, g = o * 0.2, l = -((e * 8 * s + g * 4) % c - c / 2);
33
+ class S {
34
+ update(e, o, n, t = {}) {
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 {
37
- ...t,
38
- y: l
37
+ ...e,
38
+ y: c
39
39
  };
40
40
  }
41
41
  }
42
- function A(n, t) {
43
- const { x: o, y: e, rotation: i, scale: s, opacity: c } = t;
44
- n.style.transform = `translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`, n.style.opacity = c.toString();
42
+ function H(s, e) {
43
+ const { x: o, y: n, rotation: t, scale: i, opacity: l } = e;
44
+ s.style.transform = `translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`, s.style.opacity = l.toString();
45
45
  }
46
- function b(n, t, o, e, i, s) {
47
- if (!s.enabled)
46
+ function b(s, e, o, n, t, i) {
47
+ if (!i.enabled)
48
48
  return {
49
49
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
50
50
  applied: !1
51
51
  };
52
- const c = s.radius || 80, g = s.strength || 1, a = s.behaviors || ["fall-away", "split-apart", "explode"], l = o - n, h = e - t, r = Math.sqrt(l * l + h * h);
53
- if (r >= c)
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);
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 d = (1 - r / c) * g, p = Math.atan2(h, l), N = a[i % a.length];
59
- let u;
60
- switch (N) {
58
+ const g = (1 - d / l) * r, u = Math.atan2(h, c), M = a[t % a.length];
59
+ let m;
60
+ switch (M) {
61
61
  case "fall-away":
62
- const D = Math.cos(p) * d * 20, L = Math.sin(p) * d * 40 + d * 30;
63
- u = {
64
- x: D,
65
- y: L,
66
- rotation: d * 15,
62
+ const A = Math.cos(u) * g * 20, D = Math.sin(u) * g * 40 + g * 30;
63
+ m = {
64
+ x: A,
65
+ y: D,
66
+ rotation: g * 15,
67
67
  scale: 1,
68
- opacity: 1 - d * 0.6
68
+ opacity: 1 - g * 0.6
69
69
  };
70
70
  break;
71
71
  case "split-apart":
72
- const w = i % 2 === 0 ? 1 : -1;
73
- u = {
74
- x: w * d * 50,
75
- y: (Math.random() - 0.5) * d * 10,
76
- rotation: d * 10 * w,
72
+ const w = t % 2 === 0 ? 1 : -1;
73
+ m = {
74
+ x: w * g * 50,
75
+ y: (Math.random() - 0.5) * g * 10,
76
+ rotation: g * 10 * w,
77
77
  scale: 1,
78
- opacity: 1 - d * 0.6
78
+ opacity: 1 - g * 0.6
79
79
  };
80
80
  break;
81
81
  case "explode":
82
- const F = p + (Math.random() - 0.5) * 0.5;
83
- u = {
84
- x: Math.cos(F) * d * 40,
85
- y: Math.sin(F) * d * 40,
86
- rotation: d * 30,
87
- scale: 1 + d * 0.4,
88
- opacity: 1 - d * 0.6
82
+ const F = u + (Math.random() - 0.5) * 0.5;
83
+ m = {
84
+ x: Math.cos(F) * g * 40,
85
+ y: Math.sin(F) * g * 40,
86
+ rotation: g * 30,
87
+ scale: 1 + g * 0.4,
88
+ opacity: 1 - g * 0.6
89
89
  };
90
90
  break;
91
91
  default:
92
- u = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
92
+ m = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
93
93
  }
94
94
  return {
95
- state: u,
95
+ state: m,
96
96
  applied: !0
97
97
  };
98
98
  }
99
- class x {
100
- constructor(t) {
99
+ class v {
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 = t.container, this.animationTypes = t.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = t.cycle !== !1, this.speed = t.speed || 1, this.amplitude = t.amplitude || 1, this.disintegration = t.disintegration || { enabled: !1 }, this.style = t.style || {}, this.fadeOut = t.fadeOut || 0, this.callbacks = t.callbacks, this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", t.containerClass && (this.textContainer.className = t.containerClass), t.containerStyle && Object.entries(t.containerStyle).forEach(([e, i]) => {
103
- this.textContainer.style.setProperty(e, i);
104
- }), t.position) {
105
- let e = t.position.x, i = t.position.y;
106
- if (t.position.constrainToViewport) {
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]) => {
103
+ this.textContainer.style.setProperty(n, t);
104
+ }), e.position) {
105
+ let n = e.position.x, t = e.position.y;
106
+ if (e.position.constrainToViewport) {
107
107
  this.container.getBoundingClientRect();
108
- const s = window.innerWidth, c = window.innerHeight, g = t.text.length * 20;
109
- e !== void 0 && (e = Math.max(0, Math.min(e, s - g))), i !== void 0 && (i = Math.max(0, Math.min(i, c - 50)));
108
+ const i = window.innerWidth, l = window.innerHeight, r = e.text.length * 20;
109
+ n !== void 0 && (n = Math.max(0, Math.min(n, i - r))), t !== void 0 && (t = Math.max(0, Math.min(t, l - 50)));
110
110
  }
111
- e !== void 0 && (this.textContainer.style.left = `${e}px`), i !== void 0 && (this.textContainer.style.top = `${i}px`);
111
+ n !== void 0 && (this.textContainer.style.left = `${n}px`), t !== void 0 && (this.textContainer.style.top = `${t}px`);
112
112
  }
113
- this.createLetters(t.text), this.setupMouseTracking(), this.startAnimation(), (o = this.callbacks) != null && o.onCreate && this.callbacks.onCreate(this.textContainer), this.fadeOut > 0 && setTimeout(() => this.destroy(), this.fadeOut);
113
+ 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);
114
114
  }
115
- createLetters(t) {
116
- t.toUpperCase().split("").forEach((e, i) => {
117
- if (e === " ") {
118
- const g = document.createTextNode(" ");
119
- this.textContainer.appendChild(g);
115
+ createLetters(e) {
116
+ e.toUpperCase().split("").forEach((n, t) => {
117
+ if (n === " ") {
118
+ const r = document.createTextNode(" ");
119
+ this.textContainer.appendChild(r);
120
120
  return;
121
121
  }
122
- const s = document.createElement("span");
123
- s.className = "animated-letter", s.textContent = e, s.dataset.index = i.toString(), s.dataset.char = e, this.applyStyle(s), s.style.display = "inline-block", s.style.position = "relative", s.style.transition = "transform 0.1s ease-out", this.textContainer.appendChild(s);
124
- const c = s.getBoundingClientRect();
122
+ const i = document.createElement("span");
123
+ 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);
124
+ const l = i.getBoundingClientRect();
125
125
  this.letters.push({
126
- element: s,
127
- index: i,
128
- char: e,
129
- baseX: c.left,
130
- baseY: c.top
126
+ element: i,
127
+ index: t,
128
+ char: n,
129
+ baseX: l.left,
130
+ baseY: l.top
131
131
  });
132
132
  }), this.container.appendChild(this.textContainer);
133
133
  }
134
- applyStyle(t) {
135
- this.style.fontFamily && (t.style.fontFamily = this.style.fontFamily), this.style.fontSize && (t.style.fontSize = `${this.style.fontSize}px`), this.style.color && (t.style.color = this.style.color), this.style.fontWeight && (t.style.fontWeight = this.style.fontWeight), this.style.textShadow && (t.style.textShadow = this.style.textShadow), this.style.letterSpacing && (t.style.letterSpacing = this.style.letterSpacing), this.style.textTransform && (t.style.textTransform = this.style.textTransform);
134
+ applyStyle(e) {
135
+ 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);
136
136
  }
137
137
  setupMouseTracking() {
138
- this.disintegration.enabled && (this.mouseMoveHandler = (t) => {
139
- this.mouseX = t.clientX, this.mouseY = t.clientY;
138
+ this.disintegration.enabled && (this.mouseMoveHandler = (e) => {
139
+ this.mouseX = e.clientX, this.mouseY = e.clientY;
140
140
  }, document.addEventListener("mousemove", this.mouseMoveHandler));
141
141
  }
142
142
  startAnimation() {
143
- const t = () => {
143
+ const e = () => {
144
144
  if (this.isDestroyed) return;
145
145
  const o = (Date.now() - this.startTime) * 1e-3;
146
- this.letters.forEach((e, i) => {
146
+ this.letters.forEach((n, t) => {
147
147
  var h;
148
- const s = e.element.getBoundingClientRect(), c = s.left + s.width / 2, g = s.top + s.height / 2, a = b(
149
- c,
150
- g,
148
+ const i = n.element.getBoundingClientRect(), l = i.left + i.width / 2, r = i.top + i.height / 2, a = b(
149
+ l,
150
+ r,
151
151
  this.mouseX,
152
152
  this.mouseY,
153
- i,
153
+ t,
154
154
  this.disintegration
155
155
  );
156
- let l;
156
+ let c;
157
157
  if (a.applied)
158
- l = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(i);
158
+ c = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(t);
159
159
  else {
160
- const r = this.getAnimationType(i);
161
- l = this.getAnimation(r).update(
160
+ const d = this.getAnimationType(t);
161
+ c = this.getAnimation(d).update(
162
162
  { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
163
- i,
163
+ t,
164
164
  o,
165
165
  {
166
166
  speed: this.speed,
167
- amplitude: this.amplitude * (r === "falling" || r === "floating" ? 20 : 4)
167
+ amplitude: this.amplitude * (d === "falling" || d === "floating" ? 20 : 4)
168
168
  }
169
169
  );
170
170
  }
171
- A(e.element, l);
172
- }), this.animationFrame = requestAnimationFrame(t);
171
+ H(n.element, c);
172
+ }), this.animationFrame = requestAnimationFrame(e);
173
173
  };
174
- this.animationFrame = requestAnimationFrame(t);
174
+ this.animationFrame = requestAnimationFrame(e);
175
175
  }
176
- getAnimationType(t) {
177
- return this.cycle ? this.animationTypes[t % this.animationTypes.length] : this.animationTypes[0];
176
+ getAnimationType(e) {
177
+ return this.cycle ? this.animationTypes[e % this.animationTypes.length] : this.animationTypes[0];
178
178
  }
179
- getAnimation(t) {
180
- switch (t) {
179
+ getAnimation(e) {
180
+ switch (e) {
181
181
  case "falling":
182
182
  return new f();
183
183
  case "splitting":
184
184
  return new C();
185
185
  case "glitching":
186
- return new v();
186
+ return new x();
187
187
  case "floating":
188
- return new k();
188
+ return new S();
189
189
  default:
190
190
  return new f();
191
191
  }
@@ -194,8 +194,8 @@ class x {
194
194
  * Destroy the animated text instance
195
195
  */
196
196
  destroy() {
197
- var t;
198
- this.isDestroyed || (this.isDestroyed = !0, this.animationFrame !== null && cancelAnimationFrame(this.animationFrame), this.mouseMoveHandler && document.removeEventListener("mousemove", this.mouseMoveHandler), (t = this.callbacks) != null && t.onDestroy && this.callbacks.onDestroy(), this.textContainer.style.transition = "opacity 3s ease", this.textContainer.style.opacity = "0", setTimeout(() => {
197
+ var e;
198
+ 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(() => {
199
199
  this.textContainer.parentNode && this.textContainer.parentNode.removeChild(this.textContainer);
200
200
  }, 3e3));
201
201
  }
@@ -206,7 +206,16 @@ class x {
206
206
  return this.textContainer;
207
207
  }
208
208
  }
209
- const S = [
209
+ const E = [
210
+ "unsettling",
211
+ "eerie",
212
+ "decayed",
213
+ "weathered",
214
+ "organic",
215
+ "imperfect",
216
+ "uneven",
217
+ "scratchy"
218
+ ], R = ["subtle", "moderate", "intense"], k = [
210
219
  // Hand-drawn / Handwriting
211
220
  {
212
221
  name: "Hand-drawn Casual",
@@ -240,7 +249,7 @@ const S = [
240
249
  {
241
250
  name: "Gothic Horror",
242
251
  googleFontsName: "Creepster",
243
- categories: ["gothic", "horror", "creepy", "dripping", "display", "striking"],
252
+ categories: ["gothic", "horror", "creepy", "dripping", "display", "striking", "intense"],
244
253
  description: "Horror-style font with dripping effects, very striking",
245
254
  artistic: !0
246
255
  },
@@ -321,7 +330,7 @@ const S = [
321
330
  {
322
331
  name: "Horror Dripping",
323
332
  googleFontsName: "Nosifer",
324
- categories: ["horror", "creepy", "dripping", "blood", "striking", "display"],
333
+ categories: ["horror", "creepy", "dripping", "blood", "striking", "display", "intense"],
325
334
  description: "Creepy font with blood-dripping effects, very striking",
326
335
  artistic: !0
327
336
  },
@@ -377,110 +386,271 @@ const S = [
377
386
  categories: ["bold", "aggressive", "display", "striking", "powerful"],
378
387
  description: "Bold aggressive display font, powerful and striking",
379
388
  artistic: !0
389
+ },
390
+ // Subtle Unsettling / Organic Imperfect
391
+ {
392
+ name: "Handwritten Thin",
393
+ googleFontsName: "Amatic SC",
394
+ categories: ["hand-drawn", "uneven", "organic", "unsettling", "subtle", "scratchy"],
395
+ description: "Thin hand-drawn letters with subtle irregularity, organic feel",
396
+ artistic: !0
397
+ },
398
+ {
399
+ name: "Rough Handwriting",
400
+ googleFontsName: "Rock Salt",
401
+ categories: ["hand-drawn", "scratchy", "weathered", "rough", "unsettling", "moderate"],
402
+ description: "Rough, weathered handwriting with natural imperfection",
403
+ artistic: !0
404
+ },
405
+ {
406
+ name: "Typewriter Degraded",
407
+ googleFontsName: "Special Elite",
408
+ categories: ["typewriter", "decayed", "weathered", "imperfect", "unsettling", "moderate"],
409
+ description: "Degraded typewriter font, vintage with imperfection",
410
+ artistic: !0
411
+ },
412
+ {
413
+ name: "Casual Handwriting",
414
+ googleFontsName: "Handlee",
415
+ categories: ["hand-drawn", "casual", "imperfect", "organic", "subtle"],
416
+ description: "Casual handwriting with subtle imperfection",
417
+ artistic: !1
418
+ },
419
+ {
420
+ name: "Childlike Organic",
421
+ googleFontsName: "Indie Flower",
422
+ categories: ["hand-drawn", "childlike", "organic", "imperfect", "eerie", "subtle"],
423
+ description: "Childlike handwriting, can feel innocent or eerie depending on context",
424
+ artistic: !1
425
+ },
426
+ {
427
+ name: "Scratchy Personal",
428
+ googleFontsName: "Shadows Into Light",
429
+ categories: ["hand-drawn", "scratchy", "personal", "unsettling", "uneven", "moderate"],
430
+ description: "Scratchy personal handwriting with unsettling quality",
431
+ artistic: !0
432
+ },
433
+ {
434
+ name: "Hurried Scratchy",
435
+ googleFontsName: "Reenie Beanie",
436
+ categories: ["hand-drawn", "scratchy", "hurried", "uneven", "unsettling", "moderate"],
437
+ description: "Hurried scratchy handwriting with nervous energy",
438
+ artistic: !0
439
+ },
440
+ {
441
+ name: "Architectural Irregular",
442
+ googleFontsName: "Architects Daughter",
443
+ categories: ["hand-drawn", "imperfect", "uneven", "organic", "subtle"],
444
+ description: "Hand-drawn with architectural irregularity",
445
+ artistic: !1
446
+ },
447
+ {
448
+ name: "Informal Unsettling",
449
+ googleFontsName: "Coming Soon",
450
+ categories: ["hand-drawn", "informal", "imperfect", "unsettling", "subtle"],
451
+ description: "Informal handwriting that feels slightly off",
452
+ artistic: !1
453
+ },
454
+ {
455
+ name: "Manic Handwriting",
456
+ googleFontsName: "Gloria Hallelujah",
457
+ categories: ["hand-drawn", "playful", "manic", "uneven", "unsettling", "moderate"],
458
+ description: "Playful handwriting that can feel manic or unsettled",
459
+ artistic: !0
460
+ },
461
+ {
462
+ name: "Quick Imperfect",
463
+ googleFontsName: "Just Another Hand",
464
+ categories: ["hand-drawn", "scratchy", "quick", "imperfect", "uneven", "subtle"],
465
+ description: "Quick scratchy handwriting with natural imperfection",
466
+ artistic: !1
467
+ },
468
+ {
469
+ name: "Organic Handwriting",
470
+ googleFontsName: "Kalam",
471
+ categories: ["hand-drawn", "organic", "natural", "flowing", "subtle"],
472
+ description: "Organic natural handwriting with flowing quality",
473
+ artistic: !1
474
+ },
475
+ {
476
+ name: "Flowing Tension",
477
+ googleFontsName: "Satisfy",
478
+ categories: ["script", "flowing", "tension", "elegant", "unsettling", "subtle"],
479
+ description: "Flowing script with underlying tension",
480
+ artistic: !0
481
+ },
482
+ {
483
+ name: "Unsettling Elegance",
484
+ googleFontsName: "Yellowtail",
485
+ categories: ["script", "elegant", "stylized", "unsettling", "uneven", "moderate"],
486
+ description: "Stylized elegance with unsettling undertones",
487
+ artistic: !0
488
+ },
489
+ {
490
+ name: "Typewriter Imperfect",
491
+ googleFontsName: "Cutive Mono",
492
+ categories: ["typewriter", "monospace", "imperfect", "decayed", "vintage", "subtle"],
493
+ description: "Imperfect vintage typewriter with character",
494
+ artistic: !0
380
495
  }
381
496
  ];
382
- function y(n) {
383
- const t = n.toLowerCase();
384
- return S.map((e) => {
385
- let i = 0;
386
- for (const s of e.categories)
387
- t.includes(s) && (i += 10);
388
- return (e.name.toLowerCase().includes(t) || t.includes(e.name.toLowerCase())) && (i += 15), (e.description.toLowerCase().includes(t) || t.includes(e.description.toLowerCase())) && (i += 8), e.artistic && (i += 1), { font: e, score: i };
389
- }).filter((e) => e.score > 0).sort((e, i) => i.score - e.score).map((e) => e.font);
497
+ function L(s) {
498
+ const e = s.toLowerCase().split(/\s+/).filter((t) => t.length > 0), o = [], n = [];
499
+ for (const t of e)
500
+ t.startsWith("-") && t.length > 1 ? n.push(t.slice(1)) : o.push(t);
501
+ return { positive: o, negative: n };
502
+ }
503
+ function O(s, e) {
504
+ const o = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), t = 2, i = [];
505
+ for (const l of s) {
506
+ if (i.length >= e) break;
507
+ if (o.has(l.font.googleFontsName))
508
+ continue;
509
+ const r = l.font.categories[0], a = n.get(r) || 0;
510
+ a >= t || (o.add(l.font.googleFontsName), n.set(r, a + 1), i.push(l.font));
511
+ }
512
+ return i;
513
+ }
514
+ function y(s, e) {
515
+ const { positive: o, negative: n } = L(s), t = (e == null ? void 0 : e.limit) ?? 10, l = k.map((r) => {
516
+ let a = 0;
517
+ for (const c of o) {
518
+ for (const h of r.categories)
519
+ (h.includes(c) || c.includes(h)) && (a += 10);
520
+ r.name.toLowerCase().includes(c) && (a += 15), r.description.toLowerCase().includes(c) && (a += 8);
521
+ }
522
+ for (const c of n) {
523
+ for (const h of r.categories)
524
+ (h.includes(c) || c.includes(h)) && (a -= 20);
525
+ r.name.toLowerCase().includes(c) && (a -= 15), r.description.toLowerCase().includes(c) && (a -= 10);
526
+ }
527
+ return r.artistic && (a += 1), { font: r, score: a };
528
+ }).filter((r) => r.score > 0).sort((r, a) => a.score - r.score);
529
+ return O(l, t);
390
530
  }
391
- function E(n) {
392
- return y(n)[0];
531
+ function P(s) {
532
+ return y(s)[0];
393
533
  }
394
- const m = /* @__PURE__ */ new Set();
395
- function T(n) {
396
- return new Promise((t, o) => {
397
- const e = n.replace(/\s+/g, "+");
398
- if (m.has(e)) {
399
- t();
534
+ const p = /* @__PURE__ */ new Set();
535
+ function N(s) {
536
+ return new Promise((e, o) => {
537
+ const n = s.replace(/\s+/g, "+");
538
+ if (p.has(n)) {
539
+ e();
400
540
  return;
401
541
  }
402
542
  if (document.querySelector(
403
- `link[href*="fonts.googleapis.com"][href*="${e}"]`
543
+ `link[href*="fonts.googleapis.com"][href*="${n}"]`
404
544
  )) {
405
- m.add(e), t();
545
+ p.add(n), e();
406
546
  return;
407
547
  }
408
- const s = document.createElement("link");
409
- s.rel = "stylesheet", s.href = `https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`, s.onload = () => {
410
- m.add(e), t();
411
- }, s.onerror = () => {
412
- console.warn(`Failed to load Google Font: ${n}`), o(new Error(`Failed to load Google Font: ${n}`));
413
- }, document.head.appendChild(s);
548
+ const i = document.createElement("link");
549
+ i.rel = "stylesheet", i.href = `https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`, i.onload = () => {
550
+ p.add(n), e();
551
+ }, i.onerror = () => {
552
+ console.warn(`Failed to load Google Font: ${s}`), o(new Error(`Failed to load Google Font: ${s}`));
553
+ }, document.head.appendChild(i);
414
554
  });
415
555
  }
416
- function B(n) {
417
- return Promise.all(n.map((t) => T(t)));
556
+ function B(s) {
557
+ return Promise.all(s.map((e) => N(e)));
418
558
  }
419
- function P(n) {
420
- const t = n.replace(/\s+/g, "+");
421
- return m.has(t);
559
+ function G(s) {
560
+ const e = s.replace(/\s+/g, "+");
561
+ return p.has(e);
422
562
  }
423
- function R(n, t = "sans-serif") {
424
- const o = ["Caveat", "Dancing Script", "Finger Paint", "Fredericka the Great"], e = ["VT323", "Press Start 2P", "Share Tech Mono"];
425
- let i = t;
426
- return o.includes(n) ? i = "cursive" : e.includes(n) && (i = "monospace"), `'${n}', ${i}`;
563
+ function I(s, e = "sans-serif") {
564
+ const o = [
565
+ "Caveat",
566
+ "Dancing Script",
567
+ "Finger Paint",
568
+ "Fredericka the Great",
569
+ // Subtle unsettling / organic fonts
570
+ "Amatic SC",
571
+ "Handlee",
572
+ "Indie Flower",
573
+ "Shadows Into Light",
574
+ "Rock Salt",
575
+ "Reenie Beanie",
576
+ "Architects Daughter",
577
+ "Coming Soon",
578
+ "Gloria Hallelujah",
579
+ "Just Another Hand",
580
+ "Kalam",
581
+ "Satisfy",
582
+ "Yellowtail"
583
+ ], n = [
584
+ "VT323",
585
+ "Press Start 2P",
586
+ "Share Tech Mono",
587
+ // Typewriter fonts
588
+ "Special Elite",
589
+ "Cutive Mono"
590
+ ];
591
+ let t = e;
592
+ return o.includes(s) ? t = "cursive" : n.includes(s) && (t = "monospace"), `'${s}', ${t}`;
427
593
  }
428
- function M(n, t) {
429
- const o = n.toLowerCase(), e = t.rejectedFont.toLowerCase(), i = t.negativeAspects.map((a) => a.toLowerCase()), s = t.positiveAspects.map((a) => a.toLowerCase());
430
- return y(n).filter(
431
- (a) => a.googleFontsName.toLowerCase() !== e && a.name.toLowerCase() !== e
594
+ function T(s, e) {
595
+ const o = s.toLowerCase(), n = e.rejectedFont.toLowerCase(), t = e.negativeAspects.map((a) => a.toLowerCase()), i = e.positiveAspects.map((a) => a.toLowerCase());
596
+ return y(s).filter(
597
+ (a) => a.googleFontsName.toLowerCase() !== n && a.name.toLowerCase() !== n
432
598
  ).map((a) => {
433
- let l = 0;
434
- for (const r of a.categories)
435
- o.includes(r) && (l += 5);
436
- for (const r of s)
437
- (a.categories.some((p) => p.includes(r) || r.includes(p)) || a.name.toLowerCase().includes(r) || a.description.toLowerCase().includes(r)) && (l += 15);
438
- for (const r of i)
439
- (a.categories.some((p) => p.includes(r) || r.includes(p)) || a.name.toLowerCase().includes(r) || a.description.toLowerCase().includes(r)) && (l -= 20);
440
- const h = s.some(
441
- (r) => r.includes("striking") || r.includes("artistic") || r.includes("unique")
599
+ let c = 0;
600
+ for (const d of a.categories)
601
+ o.includes(d) && (c += 5);
602
+ 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);
604
+ 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(
607
+ (d) => d.includes("striking") || d.includes("artistic") || d.includes("unique")
442
608
  );
443
- return h && a.artistic && (l += 10), h && !a.artistic && (l -= 5), { font: a, score: l };
444
- }).filter((a) => a.score > 0).sort((a, l) => l.score - a.score).map((a) => a.font);
609
+ return h && a.artistic && (c += 10), h && !a.artistic && (c -= 5), { font: a, score: c };
610
+ }).filter((a) => a.score > 0).sort((a, c) => c.score - a.score).map((a) => a.font);
445
611
  }
446
- function H(n, t) {
447
- return M(n, t)[0];
612
+ function Y(s, e) {
613
+ return T(s, e)[0];
448
614
  }
449
615
  if (typeof window < "u") {
450
- const n = {
451
- AnimatedText: x,
616
+ const s = {
617
+ AnimatedText: v,
452
618
  FallingAnimation: f,
453
619
  SplittingAnimation: C,
454
- GlitchingAnimation: v,
455
- FloatingAnimation: k,
620
+ GlitchingAnimation: x,
621
+ FloatingAnimation: S,
456
622
  calculateDisintegration: b,
457
623
  // Font utilities
458
- fontSuggestions: S,
624
+ fontSuggestions: k,
459
625
  suggestFonts: y,
460
- suggestFont: E,
461
- loadGoogleFont: T,
626
+ suggestFont: P,
627
+ loadGoogleFont: N,
462
628
  loadGoogleFonts: B,
463
- isFontLoaded: P,
464
- getFontFamily: R,
465
- refineSuggestion: M,
466
- refineFont: H
629
+ isFontLoaded: G,
630
+ getFontFamily: I,
631
+ refineSuggestion: T,
632
+ refineFont: Y,
633
+ MOOD_CATEGORIES: E,
634
+ INTENSITY_CATEGORIES: R
467
635
  };
468
- window.TypographyToolkit = n, window.AnimatedText = x;
636
+ window.TypographyToolkit = s, window.AnimatedText = v;
469
637
  }
470
638
  export {
471
- x as AnimatedText,
639
+ v as AnimatedText,
472
640
  f as FallingAnimation,
473
- k as FloatingAnimation,
474
- v as GlitchingAnimation,
641
+ S as FloatingAnimation,
642
+ x as GlitchingAnimation,
643
+ R as INTENSITY_CATEGORIES,
644
+ E as MOOD_CATEGORIES,
475
645
  C as SplittingAnimation,
476
646
  b as calculateDisintegration,
477
- S as fontSuggestions,
478
- R as getFontFamily,
479
- P as isFontLoaded,
480
- T as loadGoogleFont,
647
+ k as fontSuggestions,
648
+ I as getFontFamily,
649
+ G as isFontLoaded,
650
+ N as loadGoogleFont,
481
651
  B as loadGoogleFonts,
482
- H as refineFont,
483
- M as refineSuggestion,
484
- E as suggestFont,
652
+ Y as refineFont,
653
+ T as refineSuggestion,
654
+ P as suggestFont,
485
655
  y as suggestFonts
486
656
  };
@@ -1 +1 @@
1
- var TypographyToolkit=function(d){"use strict";class f{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||20,h=o*.2,c=(e*10*s+h*5)%l-l/2;return{...t,y:c}}}class w{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||4,h=o*.2,a=Math.sin(e*.5*s+h)*l;return{...t,x:a}}}class C{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,e,i={}){const s=i.amplitude||3;return e-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*s,this.glitchY=(Math.random()-.5)*(s*.67),this.glitchRot=(Math.random()-.5)*s,this.lastUpdate=e),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||15,h=o*.2,c=-((e*8*s+h*4)%l-l/2);return{...t,y:c}}}function B(n,t){const{x:o,y:e,rotation:i,scale:s,opacity:l}=t;n.style.transform=`translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`,n.style.opacity=l.toString()}function k(n,t,o,e,i,s){if(!s.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=s.radius||80,h=s.strength||1,a=s.behaviors||["fall-away","split-apart","explode"],c=o-n,u=e-t,r=Math.sqrt(c*c+u*u);if(r>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const g=(1-r/l)*h,m=Math.atan2(u,c),R=a[i%a.length];let p;switch(R){case"fall-away":const H=Math.cos(m)*g*20,G=Math.sin(m)*g*40+g*30;p={x:H,y:G,rotation:g*15,scale:1,opacity:1-g*.6};break;case"split-apart":const E=i%2===0?1:-1;p={x:E*g*50,y:(Math.random()-.5)*g*10,rotation:g*10*E,scale:1,opacity:1-g*.6};break;case"explode":const P=m+(Math.random()-.5)*.5;p={x:Math.cos(P)*g*40,y:Math.sin(P)*g*40,rotation:g*30,scale:1+g*.4,opacity:1-g*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(t){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=t.container,this.animationTypes=t.animations||["falling","splitting","glitching","floating"],this.cycle=t.cycle!==!1,this.speed=t.speed||1,this.amplitude=t.amplitude||1,this.disintegration=t.disintegration||{enabled:!1},this.style=t.style||{},this.fadeOut=t.fadeOut||0,this.callbacks=t.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.containerClass&&(this.textContainer.className=t.containerClass),t.containerStyle&&Object.entries(t.containerStyle).forEach(([e,i])=>{this.textContainer.style.setProperty(e,i)}),t.position){let e=t.position.x,i=t.position.y;if(t.position.constrainToViewport){this.container.getBoundingClientRect();const s=window.innerWidth,l=window.innerHeight,h=t.text.length*20;e!==void 0&&(e=Math.max(0,Math.min(e,s-h))),i!==void 0&&(i=Math.max(0,Math.min(i,l-50)))}e!==void 0&&(this.textContainer.style.left=`${e}px`),i!==void 0&&(this.textContainer.style.top=`${i}px`)}this.createLetters(t.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(t){t.toUpperCase().split("").forEach((e,i)=>{if(e===" "){const h=document.createTextNode(" ");this.textContainer.appendChild(h);return}const s=document.createElement("span");s.className="animated-letter",s.textContent=e,s.dataset.index=i.toString(),s.dataset.char=e,this.applyStyle(s),s.style.display="inline-block",s.style.position="relative",s.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(s);const l=s.getBoundingClientRect();this.letters.push({element:s,index:i,char:e,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(t){this.style.fontFamily&&(t.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(t.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(t.style.color=this.style.color),this.style.fontWeight&&(t.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(t.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(t.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(t.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=t=>{this.mouseX=t.clientX,this.mouseY=t.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const t=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((e,i)=>{var u;const s=e.element.getBoundingClientRect(),l=s.left+s.width/2,h=s.top+s.height/2,a=k(l,h,this.mouseX,this.mouseY,i,this.disintegration);let c;if(a.applied)c=a.state,(u=this.callbacks)!=null&&u.onDisintegrate&&this.callbacks.onDisintegrate(i);else{const r=this.getAnimationType(i);c=this.getAnimation(r).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(r==="falling"||r==="floating"?20:4)})}B(e.element,c)}),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}getAnimationType(t){return this.cycle?this.animationTypes[t%this.animationTypes.length]:this.animationTypes[0]}getAnimation(t){switch(t){case"falling":return new f;case"splitting":return new w;case"glitching":return new C;case"floating":return new v;default:return new f}}destroy(){var t;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(t=this.callbacks)!=null&&t.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=[{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"],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"],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}];function y(n){const t=n.toLowerCase();return x.map(e=>{let i=0;for(const s of e.categories)t.includes(s)&&(i+=10);return(e.name.toLowerCase().includes(t)||t.includes(e.name.toLowerCase()))&&(i+=15),(e.description.toLowerCase().includes(t)||t.includes(e.description.toLowerCase()))&&(i+=8),e.artistic&&(i+=1),{font:e,score:i}}).filter(e=>e.score>0).sort((e,i)=>i.score-e.score).map(e=>e.font)}function M(n){return y(n)[0]}const F=new Set;function S(n){return new Promise((t,o)=>{const e=n.replace(/\s+/g,"+");if(F.has(e)){t();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${e}"]`)){F.add(e),t();return}const s=document.createElement("link");s.rel="stylesheet",s.href=`https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`,s.onload=()=>{F.add(e),t()},s.onerror=()=>{console.warn(`Failed to load Google Font: ${n}`),o(new Error(`Failed to load Google Font: ${n}`))},document.head.appendChild(s)})}function N(n){return Promise.all(n.map(t=>S(t)))}function D(n){const t=n.replace(/\s+/g,"+");return F.has(t)}function A(n,t="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great"],e=["VT323","Press Start 2P","Share Tech Mono"];let i=t;return o.includes(n)?i="cursive":e.includes(n)&&(i="monospace"),`'${n}', ${i}`}function T(n,t){const o=n.toLowerCase(),e=t.rejectedFont.toLowerCase(),i=t.negativeAspects.map(a=>a.toLowerCase()),s=t.positiveAspects.map(a=>a.toLowerCase());return y(n).filter(a=>a.googleFontsName.toLowerCase()!==e&&a.name.toLowerCase()!==e).map(a=>{let c=0;for(const r of a.categories)o.includes(r)&&(c+=5);for(const r of s)(a.categories.some(m=>m.includes(r)||r.includes(m))||a.name.toLowerCase().includes(r)||a.description.toLowerCase().includes(r))&&(c+=15);for(const r of i)(a.categories.some(m=>m.includes(r)||r.includes(m))||a.name.toLowerCase().includes(r)||a.description.toLowerCase().includes(r))&&(c-=20);const u=s.some(r=>r.includes("striking")||r.includes("artistic")||r.includes("unique"));return u&&a.artistic&&(c+=10),u&&!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 L(n,t){return T(n,t)[0]}if(typeof window<"u"){const n={AnimatedText:b,FallingAnimation:f,SplittingAnimation:w,GlitchingAnimation:C,FloatingAnimation:v,calculateDisintegration:k,fontSuggestions:x,suggestFonts:y,suggestFont:M,loadGoogleFont:S,loadGoogleFonts:N,isFontLoaded:D,getFontFamily:A,refineSuggestion:T,refineFont:L};window.TypographyToolkit=n,window.AnimatedText=b}return d.AnimatedText=b,d.FallingAnimation=f,d.FloatingAnimation=v,d.GlitchingAnimation=C,d.SplittingAnimation=w,d.calculateDisintegration=k,d.fontSuggestions=x,d.getFontFamily=A,d.isFontLoaded=D,d.loadGoogleFont=S,d.loadGoogleFonts=N,d.refineFont=L,d.refineSuggestion=T,d.suggestFont=M,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d}({});
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 +1 @@
1
- (function(l,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(l=typeof globalThis<"u"?globalThis:l||self,m(l.TypographyToolkit={}))})(this,function(l){"use strict";class m{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||20,h=o*.2,d=(e*10*s+h*5)%c-c/2;return{...t,y:d}}}class w{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||4,h=o*.2,n=Math.sin(e*.5*s+h)*c;return{...t,x:n}}}class C{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,e,i={}){const s=i.amplitude||3;return e-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*s,this.glitchY=(Math.random()-.5)*(s*.67),this.glitchRot=(Math.random()-.5)*s,this.lastUpdate=e),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||15,h=o*.2,d=-((e*8*s+h*4)%c-c/2);return{...t,y:d}}}function B(a,t){const{x:o,y:e,rotation:i,scale:s,opacity:c}=t;a.style.transform=`translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`,a.style.opacity=c.toString()}function x(a,t,o,e,i,s){if(!s.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const c=s.radius||80,h=s.strength||1,n=s.behaviors||["fall-away","split-apart","explode"],d=o-a,u=e-t,r=Math.sqrt(d*d+u*u);if(r>=c)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const g=(1-r/c)*h,p=Math.atan2(u,d),R=n[i%n.length];let f;switch(R){case"fall-away":const H=Math.cos(p)*g*20,G=Math.sin(p)*g*40+g*30;f={x:H,y:G,rotation:g*15,scale:1,opacity:1-g*.6};break;case"split-apart":const E=i%2===0?1:-1;f={x:E*g*50,y:(Math.random()-.5)*g*10,rotation:g*10*E,scale:1,opacity:1-g*.6};break;case"explode":const P=p+(Math.random()-.5)*.5;f={x:Math.cos(P)*g*40,y:Math.sin(P)*g*40,rotation:g*30,scale:1+g*.4,opacity:1-g*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(t){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=t.container,this.animationTypes=t.animations||["falling","splitting","glitching","floating"],this.cycle=t.cycle!==!1,this.speed=t.speed||1,this.amplitude=t.amplitude||1,this.disintegration=t.disintegration||{enabled:!1},this.style=t.style||{},this.fadeOut=t.fadeOut||0,this.callbacks=t.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.containerClass&&(this.textContainer.className=t.containerClass),t.containerStyle&&Object.entries(t.containerStyle).forEach(([e,i])=>{this.textContainer.style.setProperty(e,i)}),t.position){let e=t.position.x,i=t.position.y;if(t.position.constrainToViewport){this.container.getBoundingClientRect();const s=window.innerWidth,c=window.innerHeight,h=t.text.length*20;e!==void 0&&(e=Math.max(0,Math.min(e,s-h))),i!==void 0&&(i=Math.max(0,Math.min(i,c-50)))}e!==void 0&&(this.textContainer.style.left=`${e}px`),i!==void 0&&(this.textContainer.style.top=`${i}px`)}this.createLetters(t.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(t){t.toUpperCase().split("").forEach((e,i)=>{if(e===" "){const h=document.createTextNode(" ");this.textContainer.appendChild(h);return}const s=document.createElement("span");s.className="animated-letter",s.textContent=e,s.dataset.index=i.toString(),s.dataset.char=e,this.applyStyle(s),s.style.display="inline-block",s.style.position="relative",s.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(s);const c=s.getBoundingClientRect();this.letters.push({element:s,index:i,char:e,baseX:c.left,baseY:c.top})}),this.container.appendChild(this.textContainer)}applyStyle(t){this.style.fontFamily&&(t.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(t.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(t.style.color=this.style.color),this.style.fontWeight&&(t.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(t.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(t.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(t.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=t=>{this.mouseX=t.clientX,this.mouseY=t.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const t=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((e,i)=>{var u;const s=e.element.getBoundingClientRect(),c=s.left+s.width/2,h=s.top+s.height/2,n=x(c,h,this.mouseX,this.mouseY,i,this.disintegration);let d;if(n.applied)d=n.state,(u=this.callbacks)!=null&&u.onDisintegrate&&this.callbacks.onDisintegrate(i);else{const r=this.getAnimationType(i);d=this.getAnimation(r).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(r==="falling"||r==="floating"?20:4)})}B(e.element,d)}),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}getAnimationType(t){return this.cycle?this.animationTypes[t%this.animationTypes.length]:this.animationTypes[0]}getAnimation(t){switch(t){case"falling":return new m;case"splitting":return new w;case"glitching":return new C;case"floating":return new v;default:return new m}}destroy(){var t;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(t=this.callbacks)!=null&&t.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 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"],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"],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}];function y(a){const t=a.toLowerCase();return k.map(e=>{let i=0;for(const s of e.categories)t.includes(s)&&(i+=10);return(e.name.toLowerCase().includes(t)||t.includes(e.name.toLowerCase()))&&(i+=15),(e.description.toLowerCase().includes(t)||t.includes(e.description.toLowerCase()))&&(i+=8),e.artistic&&(i+=1),{font:e,score:i}}).filter(e=>e.score>0).sort((e,i)=>i.score-e.score).map(e=>e.font)}function M(a){return y(a)[0]}const F=new Set;function S(a){return new Promise((t,o)=>{const e=a.replace(/\s+/g,"+");if(F.has(e)){t();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${e}"]`)){F.add(e),t();return}const s=document.createElement("link");s.rel="stylesheet",s.href=`https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`,s.onload=()=>{F.add(e),t()},s.onerror=()=>{console.warn(`Failed to load Google Font: ${a}`),o(new Error(`Failed to load Google Font: ${a}`))},document.head.appendChild(s)})}function N(a){return Promise.all(a.map(t=>S(t)))}function D(a){const t=a.replace(/\s+/g,"+");return F.has(t)}function A(a,t="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great"],e=["VT323","Press Start 2P","Share Tech Mono"];let i=t;return o.includes(a)?i="cursive":e.includes(a)&&(i="monospace"),`'${a}', ${i}`}function T(a,t){const o=a.toLowerCase(),e=t.rejectedFont.toLowerCase(),i=t.negativeAspects.map(n=>n.toLowerCase()),s=t.positiveAspects.map(n=>n.toLowerCase());return y(a).filter(n=>n.googleFontsName.toLowerCase()!==e&&n.name.toLowerCase()!==e).map(n=>{let d=0;for(const r of n.categories)o.includes(r)&&(d+=5);for(const r of s)(n.categories.some(p=>p.includes(r)||r.includes(p))||n.name.toLowerCase().includes(r)||n.description.toLowerCase().includes(r))&&(d+=15);for(const r of i)(n.categories.some(p=>p.includes(r)||r.includes(p))||n.name.toLowerCase().includes(r)||n.description.toLowerCase().includes(r))&&(d-=20);const u=s.some(r=>r.includes("striking")||r.includes("artistic")||r.includes("unique"));return u&&n.artistic&&(d+=10),u&&!n.artistic&&(d-=5),{font:n,score:d}}).filter(n=>n.score>0).sort((n,d)=>d.score-n.score).map(n=>n.font)}function L(a,t){return T(a,t)[0]}if(typeof window<"u"){const a={AnimatedText:b,FallingAnimation:m,SplittingAnimation:w,GlitchingAnimation:C,FloatingAnimation:v,calculateDisintegration:x,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:S,loadGoogleFonts:N,isFontLoaded:D,getFontFamily:A,refineSuggestion:T,refineFont:L};window.TypographyToolkit=a,window.AnimatedText=b}l.AnimatedText=b,l.FallingAnimation=m,l.FloatingAnimation=v,l.GlitchingAnimation=C,l.SplittingAnimation=w,l.calculateDisintegration=x,l.fontSuggestions=k,l.getFontFamily=A,l.isFontLoaded=D,l.loadGoogleFont=S,l.loadGoogleFonts=N,l.refineFont=L,l.refineSuggestion=T,l.suggestFont=M,l.suggestFonts=y,Object.defineProperty(l,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 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"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typography-toolkit",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
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",