typography-toolkit 1.2.1 → 1.3.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,6 +1,6 @@
1
1
  class f {
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;
2
+ update(e, o, a, t = {}) {
3
+ const i = t.speed || 1, l = t.amplitude || 20, s = o * 0.2, c = (a * 10 * i + s * 5) % l - l / 2;
4
4
  return {
5
5
  ...e,
6
6
  y: c
@@ -8,61 +8,69 @@ class f {
8
8
  }
9
9
  }
10
10
  class 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;
11
+ update(e, o, a, t = {}) {
12
+ const i = t.speed || 1, l = t.amplitude || 4, s = o * 0.2, n = Math.sin(a * 0.5 * i + s) * l;
13
13
  return {
14
14
  ...e,
15
- x: a
15
+ x: n
16
16
  };
17
17
  }
18
18
  }
19
- class x {
19
+ class S {
20
20
  constructor() {
21
- this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
21
+ this.letterStates = /* @__PURE__ */ new Map();
22
22
  }
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), {
23
+ update(e, o, a, t = {}) {
24
+ const i = t.amplitude || 3, l = t.speed || 1;
25
+ let s = this.letterStates.get(o);
26
+ s || (s = {
27
+ lastUpdate: a,
28
+ glitchX: 0,
29
+ glitchY: 0,
30
+ glitchRot: 0
31
+ }, this.letterStates.set(o, s));
32
+ const n = 0.1 / l;
33
+ return a - s.lastUpdate > n && (s.glitchX = (Math.random() - 0.5) * i, s.glitchY = (Math.random() - 0.5) * (i * 0.67), s.glitchRot = (Math.random() - 0.5) * i, s.lastUpdate = a), {
26
34
  ...e,
27
- x: this.glitchX,
28
- y: this.glitchY,
29
- rotation: this.glitchRot
35
+ x: s.glitchX,
36
+ y: s.glitchY,
37
+ rotation: s.glitchRot
30
38
  };
31
39
  }
32
40
  }
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);
41
+ class b {
42
+ update(e, o, a, t = {}) {
43
+ const i = t.speed || 1, l = t.amplitude || 15, s = o * 0.2, c = -((a * 8 * i + s * 4) % l - l / 2);
36
44
  return {
37
45
  ...e,
38
46
  y: c
39
47
  };
40
48
  }
41
49
  }
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();
50
+ function D(r, e) {
51
+ const { x: o, y: a, rotation: t, scale: i, opacity: l } = e;
52
+ r.style.transform = `translate(${o}px, ${a}px) rotate(${t}deg) scale(${i})`, r.style.opacity = l.toString();
45
53
  }
46
- function b(s, e, o, n, t, i) {
54
+ function k(r, e, o, a, t, i) {
47
55
  if (!i.enabled)
48
56
  return {
49
57
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
50
58
  applied: !1
51
59
  };
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);
60
+ const l = i.radius || 80, s = i.strength || 1, n = i.behaviors || ["fall-away", "split-apart", "explode"], c = o - r, u = a - e, d = Math.sqrt(c * c + u * u);
53
61
  if (d >= l)
54
62
  return {
55
63
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
56
64
  applied: !1
57
65
  };
58
- const g = (1 - d / l) * r, u = Math.atan2(h, c), M = a[t % a.length];
66
+ const g = (1 - d / l) * s, h = Math.atan2(u, c), T = n[t % n.length];
59
67
  let m;
60
- switch (M) {
68
+ switch (T) {
61
69
  case "fall-away":
62
- const A = Math.cos(u) * g * 20, D = Math.sin(u) * g * 40 + g * 30;
70
+ const A = Math.cos(h) * g * 20, E = Math.sin(h) * g * 40 + g * 30;
63
71
  m = {
64
72
  x: A,
65
- y: D,
73
+ y: E,
66
74
  rotation: g * 15,
67
75
  scale: 1,
68
76
  opacity: 1 - g * 0.6
@@ -79,7 +87,7 @@ function b(s, e, o, n, t, i) {
79
87
  };
80
88
  break;
81
89
  case "explode":
82
- const F = u + (Math.random() - 0.5) * 0.5;
90
+ const F = h + (Math.random() - 0.5) * 0.5;
83
91
  m = {
84
92
  x: Math.cos(F) * g * 40,
85
93
  y: Math.sin(F) * g * 40,
@@ -99,33 +107,33 @@ function b(s, e, o, n, t, i) {
99
107
  class v {
100
108
  constructor(e) {
101
109
  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]) => {
103
- this.textContainer.style.setProperty(n, t);
110
+ 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.animationInstances = /* @__PURE__ */ new Map(), 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(([a, t]) => {
111
+ this.textContainer.style.setProperty(a, t);
104
112
  }), e.position) {
105
- let n = e.position.x, t = e.position.y;
113
+ let a = e.position.x, t = e.position.y;
106
114
  if (e.position.constrainToViewport) {
107
115
  this.container.getBoundingClientRect();
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)));
116
+ const i = window.innerWidth, l = window.innerHeight, s = e.text.length * 20;
117
+ a !== void 0 && (a = Math.max(0, Math.min(a, i - s))), t !== void 0 && (t = Math.max(0, Math.min(t, l - 50)));
110
118
  }
111
- n !== void 0 && (this.textContainer.style.left = `${n}px`), t !== void 0 && (this.textContainer.style.top = `${t}px`);
119
+ a !== void 0 && (this.textContainer.style.left = `${a}px`), t !== void 0 && (this.textContainer.style.top = `${t}px`);
112
120
  }
113
121
  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
122
  }
115
123
  createLetters(e) {
116
- e.toUpperCase().split("").forEach((n, t) => {
117
- if (n === " ") {
118
- const r = document.createTextNode(" ");
119
- this.textContainer.appendChild(r);
124
+ e.toUpperCase().split("").forEach((a, t) => {
125
+ if (a === " ") {
126
+ const s = document.createTextNode(" ");
127
+ this.textContainer.appendChild(s);
120
128
  return;
121
129
  }
122
130
  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);
131
+ i.className = "animated-letter", i.textContent = a, i.dataset.index = t.toString(), i.dataset.char = a, 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
132
  const l = i.getBoundingClientRect();
125
133
  this.letters.push({
126
134
  element: i,
127
135
  index: t,
128
- char: n,
136
+ char: a,
129
137
  baseX: l.left,
130
138
  baseY: l.top
131
139
  });
@@ -143,19 +151,19 @@ class v {
143
151
  const e = () => {
144
152
  if (this.isDestroyed) return;
145
153
  const o = (Date.now() - this.startTime) * 1e-3;
146
- this.letters.forEach((n, t) => {
147
- var h;
148
- const i = n.element.getBoundingClientRect(), l = i.left + i.width / 2, r = i.top + i.height / 2, a = b(
154
+ this.letters.forEach((a, t) => {
155
+ var u;
156
+ const i = a.element.getBoundingClientRect(), l = i.left + i.width / 2, s = i.top + i.height / 2, n = k(
149
157
  l,
150
- r,
158
+ s,
151
159
  this.mouseX,
152
160
  this.mouseY,
153
161
  t,
154
162
  this.disintegration
155
163
  );
156
164
  let c;
157
- if (a.applied)
158
- c = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(t);
165
+ if (n.applied)
166
+ c = n.state, (u = this.callbacks) != null && u.onDisintegrate && this.callbacks.onDisintegrate(t);
159
167
  else {
160
168
  const d = this.getAnimationType(t);
161
169
  c = this.getAnimation(d).update(
@@ -163,12 +171,12 @@ class v {
163
171
  t,
164
172
  o,
165
173
  {
166
- speed: this.speed,
174
+ speed: this.speed * this.animationSpeedMultiplier,
167
175
  amplitude: this.amplitude * (d === "falling" || d === "floating" ? 20 : 4)
168
176
  }
169
177
  );
170
178
  }
171
- H(n.element, c);
179
+ D(a.element, c);
172
180
  }), this.animationFrame = requestAnimationFrame(e);
173
181
  };
174
182
  this.animationFrame = requestAnimationFrame(e);
@@ -177,25 +185,74 @@ class v {
177
185
  return this.cycle ? this.animationTypes[e % this.animationTypes.length] : this.animationTypes[0];
178
186
  }
179
187
  getAnimation(e) {
188
+ if (this.animationInstances.has(e))
189
+ return this.animationInstances.get(e);
190
+ let o;
180
191
  switch (e) {
181
192
  case "falling":
182
- return new f();
193
+ o = new f();
194
+ break;
183
195
  case "splitting":
184
- return new C();
196
+ o = new C();
197
+ break;
185
198
  case "glitching":
186
- return new x();
199
+ o = new S();
200
+ break;
187
201
  case "floating":
188
- return new S();
202
+ o = new b();
203
+ break;
204
+ default:
205
+ o = new f();
206
+ }
207
+ return this.animationInstances.set(e, o), o;
208
+ }
209
+ /**
210
+ * Parse animation speed preset or numeric value to a multiplier
211
+ */
212
+ parseAnimationSpeed(e) {
213
+ if (typeof e == "number")
214
+ return e;
215
+ switch (e) {
216
+ case "slow":
217
+ return 0.5;
218
+ case "normal":
219
+ return 1;
220
+ case "fast":
221
+ return 2;
189
222
  default:
190
- return new f();
223
+ return 1;
191
224
  }
192
225
  }
226
+ /**
227
+ * Get the current animation speed multiplier
228
+ */
229
+ getAnimationSpeed() {
230
+ return this.animationSpeedMultiplier;
231
+ }
232
+ /**
233
+ * Set the animation speed multiplier (supports numeric values and presets)
234
+ */
235
+ setAnimationSpeed(e) {
236
+ this.animationSpeedMultiplier = this.parseAnimationSpeed(e);
237
+ }
238
+ /**
239
+ * Get the current animation easing function
240
+ */
241
+ getAnimationEasing() {
242
+ return this.animationEasing;
243
+ }
244
+ /**
245
+ * Set the animation easing function
246
+ */
247
+ setAnimationEasing(e) {
248
+ this.animationEasing = e;
249
+ }
193
250
  /**
194
251
  * Destroy the animated text instance
195
252
  */
196
253
  destroy() {
197
254
  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(() => {
255
+ this.isDestroyed || (this.isDestroyed = !0, this.animationFrame !== null && cancelAnimationFrame(this.animationFrame), this.mouseMoveHandler && document.removeEventListener("mousemove", this.mouseMoveHandler), this.animationInstances.clear(), (e = this.callbacks) != null && e.onDestroy && this.callbacks.onDestroy(), this.textContainer.style.transition = "opacity 3s ease", this.textContainer.style.opacity = "0", setTimeout(() => {
199
256
  this.textContainer.parentNode && this.textContainer.parentNode.removeChild(this.textContainer);
200
257
  }, 3e3));
201
258
  }
@@ -206,7 +263,7 @@ class v {
206
263
  return this.textContainer;
207
264
  }
208
265
  }
209
- const E = [
266
+ const H = [
210
267
  "unsettling",
211
268
  "eerie",
212
269
  "decayed",
@@ -215,7 +272,7 @@ const E = [
215
272
  "imperfect",
216
273
  "uneven",
217
274
  "scratchy"
218
- ], R = ["subtle", "moderate", "intense"], k = [
275
+ ], R = ["subtle", "moderate", "intense"], x = [
219
276
  // Hand-drawn / Handwriting
220
277
  {
221
278
  name: "Hand-drawn Casual",
@@ -494,73 +551,73 @@ const E = [
494
551
  artistic: !0
495
552
  }
496
553
  ];
497
- function L(s) {
498
- const e = s.toLowerCase().split(/\s+/).filter((t) => t.length > 0), o = [], n = [];
554
+ function L(r) {
555
+ const e = r.toLowerCase().split(/\s+/).filter((t) => t.length > 0), o = [], a = [];
499
556
  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 };
557
+ t.startsWith("-") && t.length > 1 ? a.push(t.slice(1)) : o.push(t);
558
+ return { positive: o, negative: a };
502
559
  }
503
- function O(s, e) {
504
- const o = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), t = 2, i = [];
505
- for (const l of s) {
560
+ function I(r, e) {
561
+ const o = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Map(), t = 2, i = [];
562
+ for (const l of r) {
506
563
  if (i.length >= e) break;
507
564
  if (o.has(l.font.googleFontsName))
508
565
  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));
566
+ const s = l.font.categories[0], n = a.get(s) || 0;
567
+ n >= t || (o.add(l.font.googleFontsName), a.set(s, n + 1), i.push(l.font));
511
568
  }
512
569
  return i;
513
570
  }
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;
571
+ function y(r, e) {
572
+ const { positive: o, negative: a } = L(r), t = (e == null ? void 0 : e.limit) ?? 10, l = x.map((s) => {
573
+ let n = 0;
517
574
  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);
575
+ for (const u of s.categories)
576
+ (u.includes(c) || c.includes(u)) && (n += 10);
577
+ s.name.toLowerCase().includes(c) && (n += 15), s.description.toLowerCase().includes(c) && (n += 8);
521
578
  }
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);
579
+ for (const c of a) {
580
+ for (const u of s.categories)
581
+ (u.includes(c) || c.includes(u)) && (n -= 20);
582
+ s.name.toLowerCase().includes(c) && (n -= 15), s.description.toLowerCase().includes(c) && (n -= 10);
526
583
  }
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);
584
+ return s.artistic && (n += 1), { font: s, score: n };
585
+ }).filter((s) => s.score > 0).sort((s, n) => n.score - s.score);
586
+ return I(l, t);
530
587
  }
531
- function P(s) {
532
- return y(s)[0];
588
+ function O(r) {
589
+ return y(r)[0];
533
590
  }
534
591
  const p = /* @__PURE__ */ new Set();
535
- function N(s) {
592
+ function N(r) {
536
593
  return new Promise((e, o) => {
537
- const n = s.replace(/\s+/g, "+");
538
- if (p.has(n)) {
594
+ const a = r.replace(/\s+/g, "+");
595
+ if (p.has(a)) {
539
596
  e();
540
597
  return;
541
598
  }
542
599
  if (document.querySelector(
543
- `link[href*="fonts.googleapis.com"][href*="${n}"]`
600
+ `link[href*="fonts.googleapis.com"][href*="${a}"]`
544
601
  )) {
545
- p.add(n), e();
602
+ p.add(a), e();
546
603
  return;
547
604
  }
548
605
  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();
606
+ i.rel = "stylesheet", i.href = `https://fonts.googleapis.com/css2?family=${a}:wght@400&display=swap`, i.onload = () => {
607
+ p.add(a), e();
551
608
  }, i.onerror = () => {
552
- console.warn(`Failed to load Google Font: ${s}`), o(new Error(`Failed to load Google Font: ${s}`));
609
+ console.warn(`Failed to load Google Font: ${r}`), o(new Error(`Failed to load Google Font: ${r}`));
553
610
  }, document.head.appendChild(i);
554
611
  });
555
612
  }
556
- function B(s) {
557
- return Promise.all(s.map((e) => N(e)));
613
+ function P(r) {
614
+ return Promise.all(r.map((e) => N(e)));
558
615
  }
559
- function G(s) {
560
- const e = s.replace(/\s+/g, "+");
616
+ function B(r) {
617
+ const e = r.replace(/\s+/g, "+");
561
618
  return p.has(e);
562
619
  }
563
- function I(s, e = "sans-serif") {
620
+ function G(r, e = "sans-serif") {
564
621
  const o = [
565
622
  "Caveat",
566
623
  "Dancing Script",
@@ -580,7 +637,7 @@ function I(s, e = "sans-serif") {
580
637
  "Kalam",
581
638
  "Satisfy",
582
639
  "Yellowtail"
583
- ], n = [
640
+ ], a = [
584
641
  "VT323",
585
642
  "Press Start 2P",
586
643
  "Share Tech Mono",
@@ -589,68 +646,68 @@ function I(s, e = "sans-serif") {
589
646
  "Cutive Mono"
590
647
  ];
591
648
  let t = e;
592
- return o.includes(s) ? t = "cursive" : n.includes(s) && (t = "monospace"), `'${s}', ${t}`;
649
+ return o.includes(r) ? t = "cursive" : a.includes(r) && (t = "monospace"), `'${r}', ${t}`;
593
650
  }
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
598
- ).map((a) => {
651
+ function M(r, e) {
652
+ const o = r.toLowerCase(), a = e.rejectedFont.toLowerCase(), t = e.negativeAspects.map((n) => n.toLowerCase()), i = e.positiveAspects.map((n) => n.toLowerCase());
653
+ return y(r).filter(
654
+ (n) => n.googleFontsName.toLowerCase() !== a && n.name.toLowerCase() !== a
655
+ ).map((n) => {
599
656
  let c = 0;
600
- for (const d of a.categories)
657
+ for (const d of n.categories)
601
658
  o.includes(d) && (c += 5);
602
659
  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);
660
+ (n.categories.some((h) => h.includes(d) || d.includes(h)) || n.name.toLowerCase().includes(d) || n.description.toLowerCase().includes(d)) && (c += 15);
604
661
  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(
662
+ (n.categories.some((h) => h.includes(d) || d.includes(h)) || n.name.toLowerCase().includes(d) || n.description.toLowerCase().includes(d)) && (c -= 20);
663
+ const u = i.some(
607
664
  (d) => d.includes("striking") || d.includes("artistic") || d.includes("unique")
608
665
  );
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);
666
+ return u && n.artistic && (c += 10), u && !n.artistic && (c -= 5), { font: n, score: c };
667
+ }).filter((n) => n.score > 0).sort((n, c) => c.score - n.score).map((n) => n.font);
611
668
  }
612
- function Y(s, e) {
613
- return T(s, e)[0];
669
+ function Y(r, e) {
670
+ return M(r, e)[0];
614
671
  }
615
672
  if (typeof window < "u") {
616
- const s = {
673
+ const r = {
617
674
  AnimatedText: v,
618
675
  FallingAnimation: f,
619
676
  SplittingAnimation: C,
620
- GlitchingAnimation: x,
621
- FloatingAnimation: S,
622
- calculateDisintegration: b,
677
+ GlitchingAnimation: S,
678
+ FloatingAnimation: b,
679
+ calculateDisintegration: k,
623
680
  // Font utilities
624
- fontSuggestions: k,
681
+ fontSuggestions: x,
625
682
  suggestFonts: y,
626
- suggestFont: P,
683
+ suggestFont: O,
627
684
  loadGoogleFont: N,
628
- loadGoogleFonts: B,
629
- isFontLoaded: G,
630
- getFontFamily: I,
631
- refineSuggestion: T,
685
+ loadGoogleFonts: P,
686
+ isFontLoaded: B,
687
+ getFontFamily: G,
688
+ refineSuggestion: M,
632
689
  refineFont: Y,
633
- MOOD_CATEGORIES: E,
690
+ MOOD_CATEGORIES: H,
634
691
  INTENSITY_CATEGORIES: R
635
692
  };
636
- window.TypographyToolkit = s, window.AnimatedText = v;
693
+ window.TypographyToolkit = r, window.AnimatedText = v;
637
694
  }
638
695
  export {
639
696
  v as AnimatedText,
640
697
  f as FallingAnimation,
641
- S as FloatingAnimation,
642
- x as GlitchingAnimation,
698
+ b as FloatingAnimation,
699
+ S as GlitchingAnimation,
643
700
  R as INTENSITY_CATEGORIES,
644
- E as MOOD_CATEGORIES,
701
+ H as MOOD_CATEGORIES,
645
702
  C as SplittingAnimation,
646
- b as calculateDisintegration,
647
- k as fontSuggestions,
648
- I as getFontFamily,
649
- G as isFontLoaded,
703
+ k as calculateDisintegration,
704
+ x as fontSuggestions,
705
+ G as getFontFamily,
706
+ B as isFontLoaded,
650
707
  N as loadGoogleFont,
651
- B as loadGoogleFonts,
708
+ P as loadGoogleFonts,
652
709
  Y as refineFont,
653
- T as refineSuggestion,
654
- P as suggestFont,
710
+ M as refineSuggestion,
711
+ O as suggestFont,
655
712
  y as suggestFonts
656
713
  };
@@ -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,a,t={}){const i=t.speed||1,l=t.amplitude||20,s=o*.2,c=(a*10*i+s*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,a,t={}){const i=t.speed||1,l=t.amplitude||4,s=o*.2,n=Math.sin(a*.5*i+s)*l;return{...e,x:n}}}class S{constructor(){this.letterStates=new Map}update(e,o,a,t={}){const i=t.amplitude||3,l=t.speed||1;let s=this.letterStates.get(o);s||(s={lastUpdate:a,glitchX:0,glitchY:0,glitchRot:0},this.letterStates.set(o,s));const n=.1/l;return a-s.lastUpdate>n&&(s.glitchX=(Math.random()-.5)*i,s.glitchY=(Math.random()-.5)*(i*.67),s.glitchRot=(Math.random()-.5)*i,s.lastUpdate=a),{...e,x:s.glitchX,y:s.glitchY,rotation:s.glitchRot}}}class v{update(e,o,a,t={}){const i=t.speed||1,l=t.amplitude||15,s=o*.2,c=-((a*8*i+s*4)%l-l/2);return{...e,y:c}}}function O(r,e){const{x:o,y:a,rotation:t,scale:i,opacity:l}=e;r.style.transform=`translate(${o}px, ${a}px) rotate(${t}deg) scale(${i})`,r.style.opacity=l.toString()}function C(r,e,o,a,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,s=i.strength||1,n=i.behaviors||["fall-away","split-apart","explode"],c=o-r,h=a-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)*s,m=Math.atan2(h,c),B=n[t%n.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 I=t%2===0?1:-1;p={x:I*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*I,scale:1,opacity:1-u*.6};break;case"explode":const L=m+(Math.random()-.5)*.5;p={x:Math.cos(L)*u*40,y:Math.sin(L)*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.animationInstances=new Map,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(([a,t])=>{this.textContainer.style.setProperty(a,t)}),e.position){let a=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,s=e.text.length*20;a!==void 0&&(a=Math.max(0,Math.min(a,i-s))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}a!==void 0&&(this.textContainer.style.left=`${a}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((a,t)=>{if(a===" "){const s=document.createTextNode(" ");this.textContainer.appendChild(s);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=a,i.dataset.index=t.toString(),i.dataset.char=a,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:a,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((a,t)=>{var h;const i=a.element.getBoundingClientRect(),l=i.left+i.width/2,s=i.top+i.height/2,n=C(l,s,this.mouseX,this.mouseY,t,this.disintegration);let c;if(n.applied)c=n.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)})}O(a.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){if(this.animationInstances.has(e))return this.animationInstances.get(e);let o;switch(e){case"falling":o=new f;break;case"splitting":o=new F;break;case"glitching":o=new S;break;case"floating":o=new v;break;default:o=new f}return this.animationInstances.set(e,o),o}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),this.animationInstances.clear(),(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 M=["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 G(r){const e=r.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],a=[];for(const t of e)t.startsWith("-")&&t.length>1?a.push(t.slice(1)):o.push(t);return{positive:o,negative:a}}function P(r,e){const o=new Set,a=new Map,t=2,i=[];for(const l of r){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const s=l.font.categories[0],n=a.get(s)||0;n>=t||(o.add(l.font.googleFontsName),a.set(s,n+1),i.push(l.font))}return i}function y(r,e){const{positive:o,negative:a}=G(r),t=(e==null?void 0:e.limit)??10,l=k.map(s=>{let n=0;for(const c of o){for(const h of s.categories)(h.includes(c)||c.includes(h))&&(n+=10);s.name.toLowerCase().includes(c)&&(n+=15),s.description.toLowerCase().includes(c)&&(n+=8)}for(const c of a){for(const h of s.categories)(h.includes(c)||c.includes(h))&&(n-=20);s.name.toLowerCase().includes(c)&&(n-=15),s.description.toLowerCase().includes(c)&&(n-=10)}return s.artistic&&(n+=1),{font:s,score:n}}).filter(s=>s.score>0).sort((s,n)=>n.score-s.score);return P(l,t)}function x(r){return y(r)[0]}const w=new Set;function N(r){return new Promise((e,o)=>{const a=r.replace(/\s+/g,"+");if(w.has(a)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${a}"]`)){w.add(a),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${a}:wght@400&display=swap`,i.onload=()=>{w.add(a),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${r}`),o(new Error(`Failed to load Google Font: ${r}`))},document.head.appendChild(i)})}function E(r){return Promise.all(r.map(e=>N(e)))}function D(r){const e=r.replace(/\s+/g,"+");return w.has(e)}function H(r,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"],a=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(r)?t="cursive":a.includes(r)&&(t="monospace"),`'${r}', ${t}`}function T(r,e){const o=r.toLowerCase(),a=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(n=>n.toLowerCase()),i=e.positiveAspects.map(n=>n.toLowerCase());return y(r).filter(n=>n.googleFontsName.toLowerCase()!==a&&n.name.toLowerCase()!==a).map(n=>{let c=0;for(const d of n.categories)o.includes(d)&&(c+=5);for(const d of i)(n.categories.some(m=>m.includes(d)||d.includes(m))||n.name.toLowerCase().includes(d)||n.description.toLowerCase().includes(d))&&(c+=15);for(const d of t)(n.categories.some(m=>m.includes(d)||d.includes(m))||n.name.toLowerCase().includes(d)||n.description.toLowerCase().includes(d))&&(c-=20);const h=i.some(d=>d.includes("striking")||d.includes("artistic")||d.includes("unique"));return h&&n.artistic&&(c+=10),h&&!n.artistic&&(c-=5),{font:n,score:c}}).filter(n=>n.score>0).sort((n,c)=>c.score-n.score).map(n=>n.font)}function R(r,e){return T(r,e)[0]}if(typeof window<"u"){const r={AnimatedText:b,FallingAnimation:f,SplittingAnimation:F,GlitchingAnimation:S,FloatingAnimation:v,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:x,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:M,INTENSITY_CATEGORIES:A};window.TypographyToolkit=r,window.AnimatedText=b}return g.AnimatedText=b,g.FallingAnimation=f,g.FloatingAnimation=v,g.GlitchingAnimation=S,g.INTENSITY_CATEGORIES=A,g.MOOD_CATEGORIES=M,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=x,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,a,t={}){const i=t.speed||1,l=t.amplitude||20,s=o*.2,c=(a*10*i+s*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,a,t={}){const i=t.speed||1,l=t.amplitude||4,s=o*.2,n=Math.sin(a*.5*i+s)*l;return{...e,x:n}}}class S{constructor(){this.letterStates=new Map}update(e,o,a,t={}){const i=t.amplitude||3,l=t.speed||1;let s=this.letterStates.get(o);s||(s={lastUpdate:a,glitchX:0,glitchY:0,glitchRot:0},this.letterStates.set(o,s));const n=.1/l;return a-s.lastUpdate>n&&(s.glitchX=(Math.random()-.5)*i,s.glitchY=(Math.random()-.5)*(i*.67),s.glitchRot=(Math.random()-.5)*i,s.lastUpdate=a),{...e,x:s.glitchX,y:s.glitchY,rotation:s.glitchRot}}}class v{update(e,o,a,t={}){const i=t.speed||1,l=t.amplitude||15,s=o*.2,c=-((a*8*i+s*4)%l-l/2);return{...e,y:c}}}function O(r,e){const{x:o,y:a,rotation:t,scale:i,opacity:l}=e;r.style.transform=`translate(${o}px, ${a}px) rotate(${t}deg) scale(${i})`,r.style.opacity=l.toString()}function C(r,e,o,a,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,s=i.strength||1,n=i.behaviors||["fall-away","split-apart","explode"],c=o-r,h=a-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)*s,m=Math.atan2(h,c),B=n[t%n.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 I=t%2===0?1:-1;f={x:I*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*I,scale:1,opacity:1-u*.6};break;case"explode":const L=m+(Math.random()-.5)*.5;f={x:Math.cos(L)*u*40,y:Math.sin(L)*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.animationInstances=new Map,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(([a,t])=>{this.textContainer.style.setProperty(a,t)}),e.position){let a=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,s=e.text.length*20;a!==void 0&&(a=Math.max(0,Math.min(a,i-s))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}a!==void 0&&(this.textContainer.style.left=`${a}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((a,t)=>{if(a===" "){const s=document.createTextNode(" ");this.textContainer.appendChild(s);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=a,i.dataset.index=t.toString(),i.dataset.char=a,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:a,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((a,t)=>{var h;const i=a.element.getBoundingClientRect(),l=i.left+i.width/2,s=i.top+i.height/2,n=C(l,s,this.mouseX,this.mouseY,t,this.disintegration);let c;if(n.applied)c=n.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)})}O(a.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){if(this.animationInstances.has(e))return this.animationInstances.get(e);let o;switch(e){case"falling":o=new p;break;case"splitting":o=new F;break;case"glitching":o=new S;break;case"floating":o=new v;break;default:o=new p}return this.animationInstances.set(e,o),o}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),this.animationInstances.clear(),(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 G(r){const e=r.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],a=[];for(const t of e)t.startsWith("-")&&t.length>1?a.push(t.slice(1)):o.push(t);return{positive:o,negative:a}}function P(r,e){const o=new Set,a=new Map,t=2,i=[];for(const l of r){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const s=l.font.categories[0],n=a.get(s)||0;n>=t||(o.add(l.font.googleFontsName),a.set(s,n+1),i.push(l.font))}return i}function y(r,e){const{positive:o,negative:a}=G(r),t=(e==null?void 0:e.limit)??10,l=k.map(s=>{let n=0;for(const c of o){for(const h of s.categories)(h.includes(c)||c.includes(h))&&(n+=10);s.name.toLowerCase().includes(c)&&(n+=15),s.description.toLowerCase().includes(c)&&(n+=8)}for(const c of a){for(const h of s.categories)(h.includes(c)||c.includes(h))&&(n-=20);s.name.toLowerCase().includes(c)&&(n-=15),s.description.toLowerCase().includes(c)&&(n-=10)}return s.artistic&&(n+=1),{font:s,score:n}}).filter(s=>s.score>0).sort((s,n)=>n.score-s.score);return P(l,t)}function A(r){return y(r)[0]}const w=new Set;function N(r){return new Promise((e,o)=>{const a=r.replace(/\s+/g,"+");if(w.has(a)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${a}"]`)){w.add(a),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${a}:wght@400&display=swap`,i.onload=()=>{w.add(a),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${r}`),o(new Error(`Failed to load Google Font: ${r}`))},document.head.appendChild(i)})}function E(r){return Promise.all(r.map(e=>N(e)))}function D(r){const e=r.replace(/\s+/g,"+");return w.has(e)}function H(r,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"],a=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(r)?t="cursive":a.includes(r)&&(t="monospace"),`'${r}', ${t}`}function T(r,e){const o=r.toLowerCase(),a=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(n=>n.toLowerCase()),i=e.positiveAspects.map(n=>n.toLowerCase());return y(r).filter(n=>n.googleFontsName.toLowerCase()!==a&&n.name.toLowerCase()!==a).map(n=>{let c=0;for(const g of n.categories)o.includes(g)&&(c+=5);for(const g of i)(n.categories.some(m=>m.includes(g)||g.includes(m))||n.name.toLowerCase().includes(g)||n.description.toLowerCase().includes(g))&&(c+=15);for(const g of t)(n.categories.some(m=>m.includes(g)||g.includes(m))||n.name.toLowerCase().includes(g)||n.description.toLowerCase().includes(g))&&(c-=20);const h=i.some(g=>g.includes("striking")||g.includes("artistic")||g.includes("unique"));return h&&n.artistic&&(c+=10),h&&!n.artistic&&(c-=5),{font:n,score:c}}).filter(n=>n.score>0).sort((n,c)=>c.score-n.score).map(n=>n.font)}function R(r,e){return T(r,e)[0]}if(typeof window<"u"){const r={AnimatedText:b,FallingAnimation:p,SplittingAnimation:F,GlitchingAnimation:S,FloatingAnimation:v,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:A,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:M};window.TypographyToolkit=r,window.AnimatedText=b}d.AnimatedText=b,d.FallingAnimation=p,d.FloatingAnimation=v,d.GlitchingAnimation=S,d.INTENSITY_CATEGORIES=M,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=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.1",
3
+ "version": "1.3.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",