typography-toolkit 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,201 +1,242 @@
1
1
  class f {
2
- update(t, o, e, i = {}) {
3
- const s = i.speed || 1, c = i.amplitude || 20, g = o * 0.2, l = (e * 10 * s + g * 5) % c - c / 2;
2
+ update(e, o, n, t = {}) {
3
+ const i = t.speed || 1, l = t.amplitude || 20, r = o * 0.2, c = (n * 10 * i + r * 5) % l - l / 2;
4
4
  return {
5
- ...t,
6
- y: l
5
+ ...e,
6
+ y: c
7
7
  };
8
8
  }
9
9
  }
10
10
  class C {
11
- update(t, o, e, i = {}) {
12
- const s = i.speed || 1, c = i.amplitude || 4, g = o * 0.2, a = Math.sin(e * 0.5 * s + g) * c;
11
+ update(e, o, n, t = {}) {
12
+ const i = t.speed || 1, l = t.amplitude || 4, r = o * 0.2, a = Math.sin(n * 0.5 * i + r) * l;
13
13
  return {
14
- ...t,
14
+ ...e,
15
15
  x: a
16
16
  };
17
17
  }
18
18
  }
19
- class v {
19
+ class S {
20
20
  constructor() {
21
21
  this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
22
22
  }
23
- update(t, o, e, i = {}) {
24
- const s = i.amplitude || 3;
25
- return e - this.lastUpdate > 0.1 && (this.glitchX = (Math.random() - 0.5) * s, this.glitchY = (Math.random() - 0.5) * (s * 0.67), this.glitchRot = (Math.random() - 0.5) * s, this.lastUpdate = e), {
26
- ...t,
23
+ update(e, o, n, t = {}) {
24
+ const i = t.amplitude || 3;
25
+ return n - this.lastUpdate > 0.1 && (this.glitchX = (Math.random() - 0.5) * i, this.glitchY = (Math.random() - 0.5) * (i * 0.67), this.glitchRot = (Math.random() - 0.5) * i, this.lastUpdate = n), {
26
+ ...e,
27
27
  x: this.glitchX,
28
28
  y: this.glitchY,
29
29
  rotation: this.glitchRot
30
30
  };
31
31
  }
32
32
  }
33
- class k {
34
- update(t, o, e, i = {}) {
35
- const s = i.speed || 1, c = i.amplitude || 15, g = o * 0.2, l = -((e * 8 * s + g * 4) % c - c / 2);
33
+ class x {
34
+ update(e, o, n, t = {}) {
35
+ const i = t.speed || 1, l = t.amplitude || 15, r = o * 0.2, c = -((n * 8 * i + r * 4) % l - l / 2);
36
36
  return {
37
- ...t,
38
- y: l
37
+ ...e,
38
+ y: c
39
39
  };
40
40
  }
41
41
  }
42
- function A(n, t) {
43
- const { x: o, y: e, rotation: i, scale: s, opacity: c } = t;
44
- n.style.transform = `translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`, n.style.opacity = c.toString();
42
+ function D(s, e) {
43
+ const { x: o, y: n, rotation: t, scale: i, opacity: l } = e;
44
+ s.style.transform = `translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`, s.style.opacity = l.toString();
45
45
  }
46
- function b(n, t, o, e, i, s) {
47
- if (!s.enabled)
46
+ function b(s, e, o, n, t, i) {
47
+ if (!i.enabled)
48
48
  return {
49
49
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
50
50
  applied: !1
51
51
  };
52
- const c = s.radius || 80, g = s.strength || 1, a = s.behaviors || ["fall-away", "split-apart", "explode"], l = o - n, h = e - t, r = Math.sqrt(l * l + h * h);
53
- if (r >= c)
52
+ const l = i.radius || 80, r = i.strength || 1, a = i.behaviors || ["fall-away", "split-apart", "explode"], c = o - s, u = n - e, d = Math.sqrt(c * c + u * u);
53
+ if (d >= l)
54
54
  return {
55
55
  state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
56
56
  applied: !1
57
57
  };
58
- const d = (1 - r / c) * g, p = Math.atan2(h, l), N = a[i % a.length];
59
- let u;
60
- switch (N) {
58
+ const g = (1 - d / l) * r, h = Math.atan2(u, c), T = a[t % a.length];
59
+ let m;
60
+ switch (T) {
61
61
  case "fall-away":
62
- const D = Math.cos(p) * d * 20, L = Math.sin(p) * d * 40 + d * 30;
63
- u = {
64
- x: D,
65
- y: L,
66
- rotation: d * 15,
62
+ const A = Math.cos(h) * g * 20, E = Math.sin(h) * g * 40 + g * 30;
63
+ m = {
64
+ x: A,
65
+ y: E,
66
+ rotation: g * 15,
67
67
  scale: 1,
68
- opacity: 1 - d * 0.6
68
+ opacity: 1 - g * 0.6
69
69
  };
70
70
  break;
71
71
  case "split-apart":
72
- const w = i % 2 === 0 ? 1 : -1;
73
- u = {
74
- x: w * d * 50,
75
- y: (Math.random() - 0.5) * d * 10,
76
- rotation: d * 10 * w,
72
+ const w = t % 2 === 0 ? 1 : -1;
73
+ m = {
74
+ x: w * g * 50,
75
+ y: (Math.random() - 0.5) * g * 10,
76
+ rotation: g * 10 * w,
77
77
  scale: 1,
78
- opacity: 1 - d * 0.6
78
+ opacity: 1 - g * 0.6
79
79
  };
80
80
  break;
81
81
  case "explode":
82
- const F = p + (Math.random() - 0.5) * 0.5;
83
- u = {
84
- x: Math.cos(F) * d * 40,
85
- y: Math.sin(F) * d * 40,
86
- rotation: d * 30,
87
- scale: 1 + d * 0.4,
88
- opacity: 1 - d * 0.6
82
+ const F = h + (Math.random() - 0.5) * 0.5;
83
+ m = {
84
+ x: Math.cos(F) * g * 40,
85
+ y: Math.sin(F) * g * 40,
86
+ rotation: g * 30,
87
+ scale: 1 + g * 0.4,
88
+ opacity: 1 - g * 0.6
89
89
  };
90
90
  break;
91
91
  default:
92
- u = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
92
+ m = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
93
93
  }
94
94
  return {
95
- state: u,
95
+ state: m,
96
96
  applied: !0
97
97
  };
98
98
  }
99
- class x {
100
- constructor(t) {
99
+ class v {
100
+ constructor(e) {
101
101
  var o;
102
- if (this.letters = [], this.animationFrame = null, this.mouseX = 0, this.mouseY = 0, this.mouseMoveHandler = null, this.startTime = Date.now(), this.isDestroyed = !1, this.container = t.container, this.animationTypes = t.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = t.cycle !== !1, this.speed = t.speed || 1, this.amplitude = t.amplitude || 1, this.disintegration = t.disintegration || { enabled: !1 }, this.style = t.style || {}, this.fadeOut = t.fadeOut || 0, this.callbacks = t.callbacks, this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", t.containerClass && (this.textContainer.className = t.containerClass), t.containerStyle && Object.entries(t.containerStyle).forEach(([e, i]) => {
103
- this.textContainer.style.setProperty(e, i);
104
- }), t.position) {
105
- let e = t.position.x, i = t.position.y;
106
- if (t.position.constrainToViewport) {
102
+ if (this.letters = [], this.animationSpeedMultiplier = 1, this.animationFrame = null, this.mouseX = 0, this.mouseY = 0, this.mouseMoveHandler = null, this.startTime = Date.now(), this.isDestroyed = !1, this.container = e.container, this.animationTypes = e.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = e.cycle !== !1, this.speed = e.speed || 1, this.amplitude = e.amplitude || 1, this.animationEasing = e.animationEasing || "linear", this.disintegration = e.disintegration || { enabled: !1 }, this.style = e.style || {}, this.fadeOut = e.fadeOut || 0, this.callbacks = e.callbacks, e.animationSpeed !== void 0 && (this.animationSpeedMultiplier = this.parseAnimationSpeed(e.animationSpeed)), this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", e.containerClass && (this.textContainer.className = e.containerClass), e.containerStyle && Object.entries(e.containerStyle).forEach(([n, t]) => {
103
+ this.textContainer.style.setProperty(n, t);
104
+ }), e.position) {
105
+ let n = e.position.x, t = e.position.y;
106
+ if (e.position.constrainToViewport) {
107
107
  this.container.getBoundingClientRect();
108
- const s = window.innerWidth, c = window.innerHeight, g = t.text.length * 20;
109
- e !== void 0 && (e = Math.max(0, Math.min(e, s - g))), i !== void 0 && (i = Math.max(0, Math.min(i, c - 50)));
108
+ const i = window.innerWidth, l = window.innerHeight, r = e.text.length * 20;
109
+ n !== void 0 && (n = Math.max(0, Math.min(n, i - r))), t !== void 0 && (t = Math.max(0, Math.min(t, l - 50)));
110
110
  }
111
- e !== void 0 && (this.textContainer.style.left = `${e}px`), i !== void 0 && (this.textContainer.style.top = `${i}px`);
111
+ n !== void 0 && (this.textContainer.style.left = `${n}px`), t !== void 0 && (this.textContainer.style.top = `${t}px`);
112
112
  }
113
- this.createLetters(t.text), this.setupMouseTracking(), this.startAnimation(), (o = this.callbacks) != null && o.onCreate && this.callbacks.onCreate(this.textContainer), this.fadeOut > 0 && setTimeout(() => this.destroy(), this.fadeOut);
113
+ this.createLetters(e.text), this.setupMouseTracking(), this.startAnimation(), (o = this.callbacks) != null && o.onCreate && this.callbacks.onCreate(this.textContainer), this.fadeOut > 0 && setTimeout(() => this.destroy(), this.fadeOut);
114
114
  }
115
- createLetters(t) {
116
- t.toUpperCase().split("").forEach((e, i) => {
117
- if (e === " ") {
118
- const g = document.createTextNode(" ");
119
- this.textContainer.appendChild(g);
115
+ createLetters(e) {
116
+ e.toUpperCase().split("").forEach((n, t) => {
117
+ if (n === " ") {
118
+ const r = document.createTextNode(" ");
119
+ this.textContainer.appendChild(r);
120
120
  return;
121
121
  }
122
- const s = document.createElement("span");
123
- s.className = "animated-letter", s.textContent = e, s.dataset.index = i.toString(), s.dataset.char = e, this.applyStyle(s), s.style.display = "inline-block", s.style.position = "relative", s.style.transition = "transform 0.1s ease-out", this.textContainer.appendChild(s);
124
- const c = s.getBoundingClientRect();
122
+ const i = document.createElement("span");
123
+ i.className = "animated-letter", i.textContent = n, i.dataset.index = t.toString(), i.dataset.char = n, this.applyStyle(i), i.style.display = "inline-block", i.style.position = "relative", i.style.transition = "transform 0.1s ease-out", this.textContainer.appendChild(i);
124
+ const l = i.getBoundingClientRect();
125
125
  this.letters.push({
126
- element: s,
127
- index: i,
128
- char: e,
129
- baseX: c.left,
130
- baseY: c.top
126
+ element: i,
127
+ index: t,
128
+ char: n,
129
+ baseX: l.left,
130
+ baseY: l.top
131
131
  });
132
132
  }), this.container.appendChild(this.textContainer);
133
133
  }
134
- applyStyle(t) {
135
- this.style.fontFamily && (t.style.fontFamily = this.style.fontFamily), this.style.fontSize && (t.style.fontSize = `${this.style.fontSize}px`), this.style.color && (t.style.color = this.style.color), this.style.fontWeight && (t.style.fontWeight = this.style.fontWeight), this.style.textShadow && (t.style.textShadow = this.style.textShadow), this.style.letterSpacing && (t.style.letterSpacing = this.style.letterSpacing), this.style.textTransform && (t.style.textTransform = this.style.textTransform);
134
+ applyStyle(e) {
135
+ this.style.fontFamily && (e.style.fontFamily = this.style.fontFamily), this.style.fontSize && (e.style.fontSize = `${this.style.fontSize}px`), this.style.color && (e.style.color = this.style.color), this.style.fontWeight && (e.style.fontWeight = this.style.fontWeight), this.style.textShadow && (e.style.textShadow = this.style.textShadow), this.style.letterSpacing && (e.style.letterSpacing = this.style.letterSpacing), this.style.textTransform && (e.style.textTransform = this.style.textTransform);
136
136
  }
137
137
  setupMouseTracking() {
138
- this.disintegration.enabled && (this.mouseMoveHandler = (t) => {
139
- this.mouseX = t.clientX, this.mouseY = t.clientY;
138
+ this.disintegration.enabled && (this.mouseMoveHandler = (e) => {
139
+ this.mouseX = e.clientX, this.mouseY = e.clientY;
140
140
  }, document.addEventListener("mousemove", this.mouseMoveHandler));
141
141
  }
142
142
  startAnimation() {
143
- const t = () => {
143
+ const e = () => {
144
144
  if (this.isDestroyed) return;
145
145
  const o = (Date.now() - this.startTime) * 1e-3;
146
- this.letters.forEach((e, i) => {
147
- var h;
148
- const s = e.element.getBoundingClientRect(), c = s.left + s.width / 2, g = s.top + s.height / 2, a = b(
149
- c,
150
- g,
146
+ this.letters.forEach((n, t) => {
147
+ var u;
148
+ const i = n.element.getBoundingClientRect(), l = i.left + i.width / 2, r = i.top + i.height / 2, a = b(
149
+ l,
150
+ r,
151
151
  this.mouseX,
152
152
  this.mouseY,
153
- i,
153
+ t,
154
154
  this.disintegration
155
155
  );
156
- let l;
156
+ let c;
157
157
  if (a.applied)
158
- l = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(i);
158
+ c = a.state, (u = this.callbacks) != null && u.onDisintegrate && this.callbacks.onDisintegrate(t);
159
159
  else {
160
- const r = this.getAnimationType(i);
161
- l = this.getAnimation(r).update(
160
+ const d = this.getAnimationType(t);
161
+ c = this.getAnimation(d).update(
162
162
  { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
163
- i,
163
+ t,
164
164
  o,
165
165
  {
166
- speed: this.speed,
167
- amplitude: this.amplitude * (r === "falling" || r === "floating" ? 20 : 4)
166
+ speed: this.speed * this.animationSpeedMultiplier,
167
+ amplitude: this.amplitude * (d === "falling" || d === "floating" ? 20 : 4)
168
168
  }
169
169
  );
170
170
  }
171
- A(e.element, l);
172
- }), this.animationFrame = requestAnimationFrame(t);
171
+ D(n.element, c);
172
+ }), this.animationFrame = requestAnimationFrame(e);
173
173
  };
174
- this.animationFrame = requestAnimationFrame(t);
174
+ this.animationFrame = requestAnimationFrame(e);
175
175
  }
176
- getAnimationType(t) {
177
- return this.cycle ? this.animationTypes[t % this.animationTypes.length] : this.animationTypes[0];
176
+ getAnimationType(e) {
177
+ return this.cycle ? this.animationTypes[e % this.animationTypes.length] : this.animationTypes[0];
178
178
  }
179
- getAnimation(t) {
180
- switch (t) {
179
+ getAnimation(e) {
180
+ switch (e) {
181
181
  case "falling":
182
182
  return new f();
183
183
  case "splitting":
184
184
  return new C();
185
185
  case "glitching":
186
- return new v();
186
+ return new S();
187
187
  case "floating":
188
- return new k();
188
+ return new x();
189
189
  default:
190
190
  return new f();
191
191
  }
192
192
  }
193
+ /**
194
+ * Parse animation speed preset or numeric value to a multiplier
195
+ */
196
+ parseAnimationSpeed(e) {
197
+ if (typeof e == "number")
198
+ return e;
199
+ switch (e) {
200
+ case "slow":
201
+ return 0.5;
202
+ case "normal":
203
+ return 1;
204
+ case "fast":
205
+ return 2;
206
+ default:
207
+ return 1;
208
+ }
209
+ }
210
+ /**
211
+ * Get the current animation speed multiplier
212
+ */
213
+ getAnimationSpeed() {
214
+ return this.animationSpeedMultiplier;
215
+ }
216
+ /**
217
+ * Set the animation speed multiplier (supports numeric values and presets)
218
+ */
219
+ setAnimationSpeed(e) {
220
+ this.animationSpeedMultiplier = this.parseAnimationSpeed(e);
221
+ }
222
+ /**
223
+ * Get the current animation easing function
224
+ */
225
+ getAnimationEasing() {
226
+ return this.animationEasing;
227
+ }
228
+ /**
229
+ * Set the animation easing function
230
+ */
231
+ setAnimationEasing(e) {
232
+ this.animationEasing = e;
233
+ }
193
234
  /**
194
235
  * Destroy the animated text instance
195
236
  */
196
237
  destroy() {
197
- var t;
198
- this.isDestroyed || (this.isDestroyed = !0, this.animationFrame !== null && cancelAnimationFrame(this.animationFrame), this.mouseMoveHandler && document.removeEventListener("mousemove", this.mouseMoveHandler), (t = this.callbacks) != null && t.onDestroy && this.callbacks.onDestroy(), this.textContainer.style.transition = "opacity 3s ease", this.textContainer.style.opacity = "0", setTimeout(() => {
238
+ var e;
239
+ this.isDestroyed || (this.isDestroyed = !0, this.animationFrame !== null && cancelAnimationFrame(this.animationFrame), this.mouseMoveHandler && document.removeEventListener("mousemove", this.mouseMoveHandler), (e = this.callbacks) != null && e.onDestroy && this.callbacks.onDestroy(), this.textContainer.style.transition = "opacity 3s ease", this.textContainer.style.opacity = "0", setTimeout(() => {
199
240
  this.textContainer.parentNode && this.textContainer.parentNode.removeChild(this.textContainer);
200
241
  }, 3e3));
201
242
  }
@@ -206,7 +247,16 @@ class x {
206
247
  return this.textContainer;
207
248
  }
208
249
  }
209
- const S = [
250
+ const H = [
251
+ "unsettling",
252
+ "eerie",
253
+ "decayed",
254
+ "weathered",
255
+ "organic",
256
+ "imperfect",
257
+ "uneven",
258
+ "scratchy"
259
+ ], R = ["subtle", "moderate", "intense"], k = [
210
260
  // Hand-drawn / Handwriting
211
261
  {
212
262
  name: "Hand-drawn Casual",
@@ -240,7 +290,7 @@ const S = [
240
290
  {
241
291
  name: "Gothic Horror",
242
292
  googleFontsName: "Creepster",
243
- categories: ["gothic", "horror", "creepy", "dripping", "display", "striking"],
293
+ categories: ["gothic", "horror", "creepy", "dripping", "display", "striking", "intense"],
244
294
  description: "Horror-style font with dripping effects, very striking",
245
295
  artistic: !0
246
296
  },
@@ -321,7 +371,7 @@ const S = [
321
371
  {
322
372
  name: "Horror Dripping",
323
373
  googleFontsName: "Nosifer",
324
- categories: ["horror", "creepy", "dripping", "blood", "striking", "display"],
374
+ categories: ["horror", "creepy", "dripping", "blood", "striking", "display", "intense"],
325
375
  description: "Creepy font with blood-dripping effects, very striking",
326
376
  artistic: !0
327
377
  },
@@ -377,110 +427,271 @@ const S = [
377
427
  categories: ["bold", "aggressive", "display", "striking", "powerful"],
378
428
  description: "Bold aggressive display font, powerful and striking",
379
429
  artistic: !0
430
+ },
431
+ // Subtle Unsettling / Organic Imperfect
432
+ {
433
+ name: "Handwritten Thin",
434
+ googleFontsName: "Amatic SC",
435
+ categories: ["hand-drawn", "uneven", "organic", "unsettling", "subtle", "scratchy"],
436
+ description: "Thin hand-drawn letters with subtle irregularity, organic feel",
437
+ artistic: !0
438
+ },
439
+ {
440
+ name: "Rough Handwriting",
441
+ googleFontsName: "Rock Salt",
442
+ categories: ["hand-drawn", "scratchy", "weathered", "rough", "unsettling", "moderate"],
443
+ description: "Rough, weathered handwriting with natural imperfection",
444
+ artistic: !0
445
+ },
446
+ {
447
+ name: "Typewriter Degraded",
448
+ googleFontsName: "Special Elite",
449
+ categories: ["typewriter", "decayed", "weathered", "imperfect", "unsettling", "moderate"],
450
+ description: "Degraded typewriter font, vintage with imperfection",
451
+ artistic: !0
452
+ },
453
+ {
454
+ name: "Casual Handwriting",
455
+ googleFontsName: "Handlee",
456
+ categories: ["hand-drawn", "casual", "imperfect", "organic", "subtle"],
457
+ description: "Casual handwriting with subtle imperfection",
458
+ artistic: !1
459
+ },
460
+ {
461
+ name: "Childlike Organic",
462
+ googleFontsName: "Indie Flower",
463
+ categories: ["hand-drawn", "childlike", "organic", "imperfect", "eerie", "subtle"],
464
+ description: "Childlike handwriting, can feel innocent or eerie depending on context",
465
+ artistic: !1
466
+ },
467
+ {
468
+ name: "Scratchy Personal",
469
+ googleFontsName: "Shadows Into Light",
470
+ categories: ["hand-drawn", "scratchy", "personal", "unsettling", "uneven", "moderate"],
471
+ description: "Scratchy personal handwriting with unsettling quality",
472
+ artistic: !0
473
+ },
474
+ {
475
+ name: "Hurried Scratchy",
476
+ googleFontsName: "Reenie Beanie",
477
+ categories: ["hand-drawn", "scratchy", "hurried", "uneven", "unsettling", "moderate"],
478
+ description: "Hurried scratchy handwriting with nervous energy",
479
+ artistic: !0
480
+ },
481
+ {
482
+ name: "Architectural Irregular",
483
+ googleFontsName: "Architects Daughter",
484
+ categories: ["hand-drawn", "imperfect", "uneven", "organic", "subtle"],
485
+ description: "Hand-drawn with architectural irregularity",
486
+ artistic: !1
487
+ },
488
+ {
489
+ name: "Informal Unsettling",
490
+ googleFontsName: "Coming Soon",
491
+ categories: ["hand-drawn", "informal", "imperfect", "unsettling", "subtle"],
492
+ description: "Informal handwriting that feels slightly off",
493
+ artistic: !1
494
+ },
495
+ {
496
+ name: "Manic Handwriting",
497
+ googleFontsName: "Gloria Hallelujah",
498
+ categories: ["hand-drawn", "playful", "manic", "uneven", "unsettling", "moderate"],
499
+ description: "Playful handwriting that can feel manic or unsettled",
500
+ artistic: !0
501
+ },
502
+ {
503
+ name: "Quick Imperfect",
504
+ googleFontsName: "Just Another Hand",
505
+ categories: ["hand-drawn", "scratchy", "quick", "imperfect", "uneven", "subtle"],
506
+ description: "Quick scratchy handwriting with natural imperfection",
507
+ artistic: !1
508
+ },
509
+ {
510
+ name: "Organic Handwriting",
511
+ googleFontsName: "Kalam",
512
+ categories: ["hand-drawn", "organic", "natural", "flowing", "subtle"],
513
+ description: "Organic natural handwriting with flowing quality",
514
+ artistic: !1
515
+ },
516
+ {
517
+ name: "Flowing Tension",
518
+ googleFontsName: "Satisfy",
519
+ categories: ["script", "flowing", "tension", "elegant", "unsettling", "subtle"],
520
+ description: "Flowing script with underlying tension",
521
+ artistic: !0
522
+ },
523
+ {
524
+ name: "Unsettling Elegance",
525
+ googleFontsName: "Yellowtail",
526
+ categories: ["script", "elegant", "stylized", "unsettling", "uneven", "moderate"],
527
+ description: "Stylized elegance with unsettling undertones",
528
+ artistic: !0
529
+ },
530
+ {
531
+ name: "Typewriter Imperfect",
532
+ googleFontsName: "Cutive Mono",
533
+ categories: ["typewriter", "monospace", "imperfect", "decayed", "vintage", "subtle"],
534
+ description: "Imperfect vintage typewriter with character",
535
+ artistic: !0
380
536
  }
381
537
  ];
382
- function y(n) {
383
- const t = n.toLowerCase();
384
- return S.map((e) => {
385
- let i = 0;
386
- for (const s of e.categories)
387
- t.includes(s) && (i += 10);
388
- return (e.name.toLowerCase().includes(t) || t.includes(e.name.toLowerCase())) && (i += 15), (e.description.toLowerCase().includes(t) || t.includes(e.description.toLowerCase())) && (i += 8), e.artistic && (i += 1), { font: e, score: i };
389
- }).filter((e) => e.score > 0).sort((e, i) => i.score - e.score).map((e) => e.font);
538
+ function L(s) {
539
+ const e = s.toLowerCase().split(/\s+/).filter((t) => t.length > 0), o = [], n = [];
540
+ for (const t of e)
541
+ t.startsWith("-") && t.length > 1 ? n.push(t.slice(1)) : o.push(t);
542
+ return { positive: o, negative: n };
543
+ }
544
+ function O(s, e) {
545
+ const o = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), t = 2, i = [];
546
+ for (const l of s) {
547
+ if (i.length >= e) break;
548
+ if (o.has(l.font.googleFontsName))
549
+ continue;
550
+ const r = l.font.categories[0], a = n.get(r) || 0;
551
+ a >= t || (o.add(l.font.googleFontsName), n.set(r, a + 1), i.push(l.font));
552
+ }
553
+ return i;
554
+ }
555
+ function y(s, e) {
556
+ const { positive: o, negative: n } = L(s), t = (e == null ? void 0 : e.limit) ?? 10, l = k.map((r) => {
557
+ let a = 0;
558
+ for (const c of o) {
559
+ for (const u of r.categories)
560
+ (u.includes(c) || c.includes(u)) && (a += 10);
561
+ r.name.toLowerCase().includes(c) && (a += 15), r.description.toLowerCase().includes(c) && (a += 8);
562
+ }
563
+ for (const c of n) {
564
+ for (const u of r.categories)
565
+ (u.includes(c) || c.includes(u)) && (a -= 20);
566
+ r.name.toLowerCase().includes(c) && (a -= 15), r.description.toLowerCase().includes(c) && (a -= 10);
567
+ }
568
+ return r.artistic && (a += 1), { font: r, score: a };
569
+ }).filter((r) => r.score > 0).sort((r, a) => a.score - r.score);
570
+ return O(l, t);
390
571
  }
391
- function E(n) {
392
- return y(n)[0];
572
+ function P(s) {
573
+ return y(s)[0];
393
574
  }
394
- const m = /* @__PURE__ */ new Set();
395
- function T(n) {
396
- return new Promise((t, o) => {
397
- const e = n.replace(/\s+/g, "+");
398
- if (m.has(e)) {
399
- t();
575
+ const p = /* @__PURE__ */ new Set();
576
+ function N(s) {
577
+ return new Promise((e, o) => {
578
+ const n = s.replace(/\s+/g, "+");
579
+ if (p.has(n)) {
580
+ e();
400
581
  return;
401
582
  }
402
583
  if (document.querySelector(
403
- `link[href*="fonts.googleapis.com"][href*="${e}"]`
584
+ `link[href*="fonts.googleapis.com"][href*="${n}"]`
404
585
  )) {
405
- m.add(e), t();
586
+ p.add(n), e();
406
587
  return;
407
588
  }
408
- const s = document.createElement("link");
409
- s.rel = "stylesheet", s.href = `https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`, s.onload = () => {
410
- m.add(e), t();
411
- }, s.onerror = () => {
412
- console.warn(`Failed to load Google Font: ${n}`), o(new Error(`Failed to load Google Font: ${n}`));
413
- }, document.head.appendChild(s);
589
+ const i = document.createElement("link");
590
+ i.rel = "stylesheet", i.href = `https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`, i.onload = () => {
591
+ p.add(n), e();
592
+ }, i.onerror = () => {
593
+ console.warn(`Failed to load Google Font: ${s}`), o(new Error(`Failed to load Google Font: ${s}`));
594
+ }, document.head.appendChild(i);
414
595
  });
415
596
  }
416
- function B(n) {
417
- return Promise.all(n.map((t) => T(t)));
597
+ function B(s) {
598
+ return Promise.all(s.map((e) => N(e)));
418
599
  }
419
- function P(n) {
420
- const t = n.replace(/\s+/g, "+");
421
- return m.has(t);
600
+ function G(s) {
601
+ const e = s.replace(/\s+/g, "+");
602
+ return p.has(e);
422
603
  }
423
- function R(n, t = "sans-serif") {
424
- const o = ["Caveat", "Dancing Script", "Finger Paint", "Fredericka the Great"], e = ["VT323", "Press Start 2P", "Share Tech Mono"];
425
- let i = t;
426
- return o.includes(n) ? i = "cursive" : e.includes(n) && (i = "monospace"), `'${n}', ${i}`;
604
+ function I(s, e = "sans-serif") {
605
+ const o = [
606
+ "Caveat",
607
+ "Dancing Script",
608
+ "Finger Paint",
609
+ "Fredericka the Great",
610
+ // Subtle unsettling / organic fonts
611
+ "Amatic SC",
612
+ "Handlee",
613
+ "Indie Flower",
614
+ "Shadows Into Light",
615
+ "Rock Salt",
616
+ "Reenie Beanie",
617
+ "Architects Daughter",
618
+ "Coming Soon",
619
+ "Gloria Hallelujah",
620
+ "Just Another Hand",
621
+ "Kalam",
622
+ "Satisfy",
623
+ "Yellowtail"
624
+ ], n = [
625
+ "VT323",
626
+ "Press Start 2P",
627
+ "Share Tech Mono",
628
+ // Typewriter fonts
629
+ "Special Elite",
630
+ "Cutive Mono"
631
+ ];
632
+ let t = e;
633
+ return o.includes(s) ? t = "cursive" : n.includes(s) && (t = "monospace"), `'${s}', ${t}`;
427
634
  }
428
- function M(n, t) {
429
- const o = n.toLowerCase(), e = t.rejectedFont.toLowerCase(), i = t.negativeAspects.map((a) => a.toLowerCase()), s = t.positiveAspects.map((a) => a.toLowerCase());
430
- return y(n).filter(
431
- (a) => a.googleFontsName.toLowerCase() !== e && a.name.toLowerCase() !== e
635
+ function M(s, e) {
636
+ const o = s.toLowerCase(), n = e.rejectedFont.toLowerCase(), t = e.negativeAspects.map((a) => a.toLowerCase()), i = e.positiveAspects.map((a) => a.toLowerCase());
637
+ return y(s).filter(
638
+ (a) => a.googleFontsName.toLowerCase() !== n && a.name.toLowerCase() !== n
432
639
  ).map((a) => {
433
- let l = 0;
434
- for (const r of a.categories)
435
- o.includes(r) && (l += 5);
436
- for (const r of s)
437
- (a.categories.some((p) => p.includes(r) || r.includes(p)) || a.name.toLowerCase().includes(r) || a.description.toLowerCase().includes(r)) && (l += 15);
438
- for (const r of i)
439
- (a.categories.some((p) => p.includes(r) || r.includes(p)) || a.name.toLowerCase().includes(r) || a.description.toLowerCase().includes(r)) && (l -= 20);
440
- const h = s.some(
441
- (r) => r.includes("striking") || r.includes("artistic") || r.includes("unique")
640
+ let c = 0;
641
+ for (const d of a.categories)
642
+ o.includes(d) && (c += 5);
643
+ for (const d of i)
644
+ (a.categories.some((h) => h.includes(d) || d.includes(h)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c += 15);
645
+ for (const d of t)
646
+ (a.categories.some((h) => h.includes(d) || d.includes(h)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c -= 20);
647
+ const u = i.some(
648
+ (d) => d.includes("striking") || d.includes("artistic") || d.includes("unique")
442
649
  );
443
- return h && a.artistic && (l += 10), h && !a.artistic && (l -= 5), { font: a, score: l };
444
- }).filter((a) => a.score > 0).sort((a, l) => l.score - a.score).map((a) => a.font);
650
+ return u && a.artistic && (c += 10), u && !a.artistic && (c -= 5), { font: a, score: c };
651
+ }).filter((a) => a.score > 0).sort((a, c) => c.score - a.score).map((a) => a.font);
445
652
  }
446
- function H(n, t) {
447
- return M(n, t)[0];
653
+ function Y(s, e) {
654
+ return M(s, e)[0];
448
655
  }
449
656
  if (typeof window < "u") {
450
- const n = {
451
- AnimatedText: x,
657
+ const s = {
658
+ AnimatedText: v,
452
659
  FallingAnimation: f,
453
660
  SplittingAnimation: C,
454
- GlitchingAnimation: v,
455
- FloatingAnimation: k,
661
+ GlitchingAnimation: S,
662
+ FloatingAnimation: x,
456
663
  calculateDisintegration: b,
457
664
  // Font utilities
458
- fontSuggestions: S,
665
+ fontSuggestions: k,
459
666
  suggestFonts: y,
460
- suggestFont: E,
461
- loadGoogleFont: T,
667
+ suggestFont: P,
668
+ loadGoogleFont: N,
462
669
  loadGoogleFonts: B,
463
- isFontLoaded: P,
464
- getFontFamily: R,
670
+ isFontLoaded: G,
671
+ getFontFamily: I,
465
672
  refineSuggestion: M,
466
- refineFont: H
673
+ refineFont: Y,
674
+ MOOD_CATEGORIES: H,
675
+ INTENSITY_CATEGORIES: R
467
676
  };
468
- window.TypographyToolkit = n, window.AnimatedText = x;
677
+ window.TypographyToolkit = s, window.AnimatedText = v;
469
678
  }
470
679
  export {
471
- x as AnimatedText,
680
+ v as AnimatedText,
472
681
  f as FallingAnimation,
473
- k as FloatingAnimation,
474
- v as GlitchingAnimation,
682
+ x as FloatingAnimation,
683
+ S as GlitchingAnimation,
684
+ R as INTENSITY_CATEGORIES,
685
+ H as MOOD_CATEGORIES,
475
686
  C as SplittingAnimation,
476
687
  b as calculateDisintegration,
477
- S as fontSuggestions,
478
- R as getFontFamily,
479
- P as isFontLoaded,
480
- T as loadGoogleFont,
688
+ k as fontSuggestions,
689
+ I as getFontFamily,
690
+ G as isFontLoaded,
691
+ N as loadGoogleFont,
481
692
  B as loadGoogleFonts,
482
- H as refineFont,
693
+ Y as refineFont,
483
694
  M as refineSuggestion,
484
- E as suggestFont,
695
+ P as suggestFont,
485
696
  y as suggestFonts
486
697
  };
@@ -1 +1 @@
1
- var TypographyToolkit=function(d){"use strict";class f{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||20,h=o*.2,c=(e*10*s+h*5)%l-l/2;return{...t,y:c}}}class w{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||4,h=o*.2,a=Math.sin(e*.5*s+h)*l;return{...t,x:a}}}class C{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,e,i={}){const s=i.amplitude||3;return e-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*s,this.glitchY=(Math.random()-.5)*(s*.67),this.glitchRot=(Math.random()-.5)*s,this.lastUpdate=e),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(t,o,e,i={}){const s=i.speed||1,l=i.amplitude||15,h=o*.2,c=-((e*8*s+h*4)%l-l/2);return{...t,y:c}}}function B(n,t){const{x:o,y:e,rotation:i,scale:s,opacity:l}=t;n.style.transform=`translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`,n.style.opacity=l.toString()}function k(n,t,o,e,i,s){if(!s.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=s.radius||80,h=s.strength||1,a=s.behaviors||["fall-away","split-apart","explode"],c=o-n,u=e-t,r=Math.sqrt(c*c+u*u);if(r>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const g=(1-r/l)*h,m=Math.atan2(u,c),R=a[i%a.length];let p;switch(R){case"fall-away":const H=Math.cos(m)*g*20,G=Math.sin(m)*g*40+g*30;p={x:H,y:G,rotation:g*15,scale:1,opacity:1-g*.6};break;case"split-apart":const E=i%2===0?1:-1;p={x:E*g*50,y:(Math.random()-.5)*g*10,rotation:g*10*E,scale:1,opacity:1-g*.6};break;case"explode":const P=m+(Math.random()-.5)*.5;p={x:Math.cos(P)*g*40,y:Math.sin(P)*g*40,rotation:g*30,scale:1+g*.4,opacity:1-g*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(t){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=t.container,this.animationTypes=t.animations||["falling","splitting","glitching","floating"],this.cycle=t.cycle!==!1,this.speed=t.speed||1,this.amplitude=t.amplitude||1,this.disintegration=t.disintegration||{enabled:!1},this.style=t.style||{},this.fadeOut=t.fadeOut||0,this.callbacks=t.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.containerClass&&(this.textContainer.className=t.containerClass),t.containerStyle&&Object.entries(t.containerStyle).forEach(([e,i])=>{this.textContainer.style.setProperty(e,i)}),t.position){let e=t.position.x,i=t.position.y;if(t.position.constrainToViewport){this.container.getBoundingClientRect();const s=window.innerWidth,l=window.innerHeight,h=t.text.length*20;e!==void 0&&(e=Math.max(0,Math.min(e,s-h))),i!==void 0&&(i=Math.max(0,Math.min(i,l-50)))}e!==void 0&&(this.textContainer.style.left=`${e}px`),i!==void 0&&(this.textContainer.style.top=`${i}px`)}this.createLetters(t.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(t){t.toUpperCase().split("").forEach((e,i)=>{if(e===" "){const h=document.createTextNode(" ");this.textContainer.appendChild(h);return}const s=document.createElement("span");s.className="animated-letter",s.textContent=e,s.dataset.index=i.toString(),s.dataset.char=e,this.applyStyle(s),s.style.display="inline-block",s.style.position="relative",s.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(s);const l=s.getBoundingClientRect();this.letters.push({element:s,index:i,char:e,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(t){this.style.fontFamily&&(t.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(t.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(t.style.color=this.style.color),this.style.fontWeight&&(t.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(t.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(t.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(t.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=t=>{this.mouseX=t.clientX,this.mouseY=t.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const t=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((e,i)=>{var u;const s=e.element.getBoundingClientRect(),l=s.left+s.width/2,h=s.top+s.height/2,a=k(l,h,this.mouseX,this.mouseY,i,this.disintegration);let c;if(a.applied)c=a.state,(u=this.callbacks)!=null&&u.onDisintegrate&&this.callbacks.onDisintegrate(i);else{const r=this.getAnimationType(i);c=this.getAnimation(r).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(r==="falling"||r==="floating"?20:4)})}B(e.element,c)}),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}getAnimationType(t){return this.cycle?this.animationTypes[t%this.animationTypes.length]:this.animationTypes[0]}getAnimation(t){switch(t){case"falling":return new f;case"splitting":return new w;case"glitching":return new C;case"floating":return new v;default:return new f}}destroy(){var t;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(t=this.callbacks)!=null&&t.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0}];function y(n){const t=n.toLowerCase();return x.map(e=>{let i=0;for(const s of e.categories)t.includes(s)&&(i+=10);return(e.name.toLowerCase().includes(t)||t.includes(e.name.toLowerCase()))&&(i+=15),(e.description.toLowerCase().includes(t)||t.includes(e.description.toLowerCase()))&&(i+=8),e.artistic&&(i+=1),{font:e,score:i}}).filter(e=>e.score>0).sort((e,i)=>i.score-e.score).map(e=>e.font)}function M(n){return y(n)[0]}const F=new Set;function S(n){return new Promise((t,o)=>{const e=n.replace(/\s+/g,"+");if(F.has(e)){t();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${e}"]`)){F.add(e),t();return}const s=document.createElement("link");s.rel="stylesheet",s.href=`https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`,s.onload=()=>{F.add(e),t()},s.onerror=()=>{console.warn(`Failed to load Google Font: ${n}`),o(new Error(`Failed to load Google Font: ${n}`))},document.head.appendChild(s)})}function N(n){return Promise.all(n.map(t=>S(t)))}function D(n){const t=n.replace(/\s+/g,"+");return F.has(t)}function A(n,t="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great"],e=["VT323","Press Start 2P","Share Tech Mono"];let i=t;return o.includes(n)?i="cursive":e.includes(n)&&(i="monospace"),`'${n}', ${i}`}function T(n,t){const o=n.toLowerCase(),e=t.rejectedFont.toLowerCase(),i=t.negativeAspects.map(a=>a.toLowerCase()),s=t.positiveAspects.map(a=>a.toLowerCase());return y(n).filter(a=>a.googleFontsName.toLowerCase()!==e&&a.name.toLowerCase()!==e).map(a=>{let c=0;for(const r of a.categories)o.includes(r)&&(c+=5);for(const r of s)(a.categories.some(m=>m.includes(r)||r.includes(m))||a.name.toLowerCase().includes(r)||a.description.toLowerCase().includes(r))&&(c+=15);for(const r of i)(a.categories.some(m=>m.includes(r)||r.includes(m))||a.name.toLowerCase().includes(r)||a.description.toLowerCase().includes(r))&&(c-=20);const u=s.some(r=>r.includes("striking")||r.includes("artistic")||r.includes("unique"));return u&&a.artistic&&(c+=10),u&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function L(n,t){return T(n,t)[0]}if(typeof window<"u"){const n={AnimatedText:b,FallingAnimation:f,SplittingAnimation:w,GlitchingAnimation:C,FloatingAnimation:v,calculateDisintegration:k,fontSuggestions:x,suggestFonts:y,suggestFont:M,loadGoogleFont:S,loadGoogleFonts:N,isFontLoaded:D,getFontFamily:A,refineSuggestion:T,refineFont:L};window.TypographyToolkit=n,window.AnimatedText=b}return d.AnimatedText=b,d.FallingAnimation=f,d.FloatingAnimation=v,d.GlitchingAnimation=C,d.SplittingAnimation=w,d.calculateDisintegration=k,d.fontSuggestions=x,d.getFontFamily=A,d.isFontLoaded=D,d.loadGoogleFont=S,d.loadGoogleFonts=N,d.refineFont=L,d.refineSuggestion=T,d.suggestFont=M,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d}({});
1
+ var TypographyToolkit=function(g){"use strict";class f{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class S{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function C(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,d=Math.sqrt(c*c+h*h);if(d>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-d/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let p;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;p={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;p={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;p={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationSpeedMultiplier=1,this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.animationEasing=e.animationEasing||"linear",this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,e.animationSpeed!==void 0&&(this.animationSpeedMultiplier=this.parseAnimationSpeed(e.animationSpeed)),this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=C(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const d=this.getAnimationType(t);c=this.getAnimation(d).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed*this.animationSpeedMultiplier,amplitude:this.amplitude*(d==="falling"||d==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new f;case"splitting":return new F;case"glitching":return new v;case"floating":return new S;default:return new f}}parseAnimationSpeed(e){if(typeof e=="number")return e;switch(e){case"slow":return .5;case"normal":return 1;case"fast":return 2;default:return 1}}getAnimationSpeed(){return this.animationSpeedMultiplier}setAnimationSpeed(e){this.animationSpeedMultiplier=this.parseAnimationSpeed(e)}getAnimationEasing(){return this.animationEasing}setAnimationEasing(e){this.animationEasing=e}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const A=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],x=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function M(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function E(s){return Promise.all(s.map(e=>N(e)))}function D(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const d of a.categories)o.includes(d)&&(c+=5);for(const d of i)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c+=15);for(const d of t)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c-=20);const h=i.some(d=>d.includes("striking")||d.includes("artistic")||d.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:f,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:S,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:A,INTENSITY_CATEGORIES:x};window.TypographyToolkit=s,window.AnimatedText=b}return g.AnimatedText=b,g.FallingAnimation=f,g.FloatingAnimation=S,g.GlitchingAnimation=v,g.INTENSITY_CATEGORIES=x,g.MOOD_CATEGORIES=A,g.SplittingAnimation=F,g.calculateDisintegration=C,g.fontSuggestions=k,g.getFontFamily=H,g.isFontLoaded=D,g.loadGoogleFont=N,g.loadGoogleFonts=E,g.refineFont=R,g.refineSuggestion=T,g.suggestFont=M,g.suggestFonts=y,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),g}({});
@@ -1 +1 @@
1
- (function(l,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(l=typeof globalThis<"u"?globalThis:l||self,m(l.TypographyToolkit={}))})(this,function(l){"use strict";class m{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||20,h=o*.2,d=(e*10*s+h*5)%c-c/2;return{...t,y:d}}}class w{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||4,h=o*.2,n=Math.sin(e*.5*s+h)*c;return{...t,x:n}}}class C{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,e,i={}){const s=i.amplitude||3;return e-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*s,this.glitchY=(Math.random()-.5)*(s*.67),this.glitchRot=(Math.random()-.5)*s,this.lastUpdate=e),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(t,o,e,i={}){const s=i.speed||1,c=i.amplitude||15,h=o*.2,d=-((e*8*s+h*4)%c-c/2);return{...t,y:d}}}function B(a,t){const{x:o,y:e,rotation:i,scale:s,opacity:c}=t;a.style.transform=`translate(${o}px, ${e}px) rotate(${i}deg) scale(${s})`,a.style.opacity=c.toString()}function x(a,t,o,e,i,s){if(!s.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const c=s.radius||80,h=s.strength||1,n=s.behaviors||["fall-away","split-apart","explode"],d=o-a,u=e-t,r=Math.sqrt(d*d+u*u);if(r>=c)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const g=(1-r/c)*h,p=Math.atan2(u,d),R=n[i%n.length];let f;switch(R){case"fall-away":const H=Math.cos(p)*g*20,G=Math.sin(p)*g*40+g*30;f={x:H,y:G,rotation:g*15,scale:1,opacity:1-g*.6};break;case"split-apart":const E=i%2===0?1:-1;f={x:E*g*50,y:(Math.random()-.5)*g*10,rotation:g*10*E,scale:1,opacity:1-g*.6};break;case"explode":const P=p+(Math.random()-.5)*.5;f={x:Math.cos(P)*g*40,y:Math.sin(P)*g*40,rotation:g*30,scale:1+g*.4,opacity:1-g*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(t){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=t.container,this.animationTypes=t.animations||["falling","splitting","glitching","floating"],this.cycle=t.cycle!==!1,this.speed=t.speed||1,this.amplitude=t.amplitude||1,this.disintegration=t.disintegration||{enabled:!1},this.style=t.style||{},this.fadeOut=t.fadeOut||0,this.callbacks=t.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.containerClass&&(this.textContainer.className=t.containerClass),t.containerStyle&&Object.entries(t.containerStyle).forEach(([e,i])=>{this.textContainer.style.setProperty(e,i)}),t.position){let e=t.position.x,i=t.position.y;if(t.position.constrainToViewport){this.container.getBoundingClientRect();const s=window.innerWidth,c=window.innerHeight,h=t.text.length*20;e!==void 0&&(e=Math.max(0,Math.min(e,s-h))),i!==void 0&&(i=Math.max(0,Math.min(i,c-50)))}e!==void 0&&(this.textContainer.style.left=`${e}px`),i!==void 0&&(this.textContainer.style.top=`${i}px`)}this.createLetters(t.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(t){t.toUpperCase().split("").forEach((e,i)=>{if(e===" "){const h=document.createTextNode(" ");this.textContainer.appendChild(h);return}const s=document.createElement("span");s.className="animated-letter",s.textContent=e,s.dataset.index=i.toString(),s.dataset.char=e,this.applyStyle(s),s.style.display="inline-block",s.style.position="relative",s.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(s);const c=s.getBoundingClientRect();this.letters.push({element:s,index:i,char:e,baseX:c.left,baseY:c.top})}),this.container.appendChild(this.textContainer)}applyStyle(t){this.style.fontFamily&&(t.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(t.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(t.style.color=this.style.color),this.style.fontWeight&&(t.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(t.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(t.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(t.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=t=>{this.mouseX=t.clientX,this.mouseY=t.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const t=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((e,i)=>{var u;const s=e.element.getBoundingClientRect(),c=s.left+s.width/2,h=s.top+s.height/2,n=x(c,h,this.mouseX,this.mouseY,i,this.disintegration);let d;if(n.applied)d=n.state,(u=this.callbacks)!=null&&u.onDisintegrate&&this.callbacks.onDisintegrate(i);else{const r=this.getAnimationType(i);d=this.getAnimation(r).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(r==="falling"||r==="floating"?20:4)})}B(e.element,d)}),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}getAnimationType(t){return this.cycle?this.animationTypes[t%this.animationTypes.length]:this.animationTypes[0]}getAnimation(t){switch(t){case"falling":return new m;case"splitting":return new w;case"glitching":return new C;case"floating":return new v;default:return new m}}destroy(){var t;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(t=this.callbacks)!=null&&t.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0}];function y(a){const t=a.toLowerCase();return k.map(e=>{let i=0;for(const s of e.categories)t.includes(s)&&(i+=10);return(e.name.toLowerCase().includes(t)||t.includes(e.name.toLowerCase()))&&(i+=15),(e.description.toLowerCase().includes(t)||t.includes(e.description.toLowerCase()))&&(i+=8),e.artistic&&(i+=1),{font:e,score:i}}).filter(e=>e.score>0).sort((e,i)=>i.score-e.score).map(e=>e.font)}function M(a){return y(a)[0]}const F=new Set;function S(a){return new Promise((t,o)=>{const e=a.replace(/\s+/g,"+");if(F.has(e)){t();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${e}"]`)){F.add(e),t();return}const s=document.createElement("link");s.rel="stylesheet",s.href=`https://fonts.googleapis.com/css2?family=${e}:wght@400&display=swap`,s.onload=()=>{F.add(e),t()},s.onerror=()=>{console.warn(`Failed to load Google Font: ${a}`),o(new Error(`Failed to load Google Font: ${a}`))},document.head.appendChild(s)})}function N(a){return Promise.all(a.map(t=>S(t)))}function D(a){const t=a.replace(/\s+/g,"+");return F.has(t)}function A(a,t="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great"],e=["VT323","Press Start 2P","Share Tech Mono"];let i=t;return o.includes(a)?i="cursive":e.includes(a)&&(i="monospace"),`'${a}', ${i}`}function T(a,t){const o=a.toLowerCase(),e=t.rejectedFont.toLowerCase(),i=t.negativeAspects.map(n=>n.toLowerCase()),s=t.positiveAspects.map(n=>n.toLowerCase());return y(a).filter(n=>n.googleFontsName.toLowerCase()!==e&&n.name.toLowerCase()!==e).map(n=>{let d=0;for(const r of n.categories)o.includes(r)&&(d+=5);for(const r of s)(n.categories.some(p=>p.includes(r)||r.includes(p))||n.name.toLowerCase().includes(r)||n.description.toLowerCase().includes(r))&&(d+=15);for(const r of i)(n.categories.some(p=>p.includes(r)||r.includes(p))||n.name.toLowerCase().includes(r)||n.description.toLowerCase().includes(r))&&(d-=20);const u=s.some(r=>r.includes("striking")||r.includes("artistic")||r.includes("unique"));return u&&n.artistic&&(d+=10),u&&!n.artistic&&(d-=5),{font:n,score:d}}).filter(n=>n.score>0).sort((n,d)=>d.score-n.score).map(n=>n.font)}function L(a,t){return T(a,t)[0]}if(typeof window<"u"){const a={AnimatedText:b,FallingAnimation:m,SplittingAnimation:w,GlitchingAnimation:C,FloatingAnimation:v,calculateDisintegration:x,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:S,loadGoogleFonts:N,isFontLoaded:D,getFontFamily:A,refineSuggestion:T,refineFont:L};window.TypographyToolkit=a,window.AnimatedText=b}l.AnimatedText=b,l.FallingAnimation=m,l.FloatingAnimation=v,l.GlitchingAnimation=C,l.SplittingAnimation=w,l.calculateDisintegration=x,l.fontSuggestions=k,l.getFontFamily=A,l.isFontLoaded=D,l.loadGoogleFont=S,l.loadGoogleFonts=N,l.refineFont=L,l.refineSuggestion=T,l.suggestFont=M,l.suggestFonts=y,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(d=typeof globalThis<"u"?globalThis:d||self,p(d.TypographyToolkit={}))})(this,function(d){"use strict";class p{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class S{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class v{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function C(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,g=Math.sqrt(c*c+h*h);if(g>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-g/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let f;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;f={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;f={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;f={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationSpeedMultiplier=1,this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.animationEasing=e.animationEasing||"linear",this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,e.animationSpeed!==void 0&&(this.animationSpeedMultiplier=this.parseAnimationSpeed(e.animationSpeed)),this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=C(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const g=this.getAnimationType(t);c=this.getAnimation(g).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed*this.animationSpeedMultiplier,amplitude:this.amplitude*(g==="falling"||g==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new p;case"splitting":return new F;case"glitching":return new S;case"floating":return new v;default:return new p}}parseAnimationSpeed(e){if(typeof e=="number")return e;switch(e){case"slow":return .5;case"normal":return 1;case"fast":return 2;default:return 1}}getAnimationSpeed(){return this.animationSpeedMultiplier}setAnimationSpeed(e){this.animationSpeedMultiplier=this.parseAnimationSpeed(e)}getAnimationEasing(){return this.animationEasing}setAnimationEasing(e){this.animationEasing=e}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],A=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function M(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function E(s){return Promise.all(s.map(e=>N(e)))}function D(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const g of a.categories)o.includes(g)&&(c+=5);for(const g of i)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c+=15);for(const g of t)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c-=20);const h=i.some(g=>g.includes("striking")||g.includes("artistic")||g.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:p,SplittingAnimation:F,GlitchingAnimation:S,FloatingAnimation:v,calculateDisintegration:C,fontSuggestions:k,suggestFonts:y,suggestFont:M,loadGoogleFont:N,loadGoogleFonts:E,isFontLoaded:D,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:A};window.TypographyToolkit=s,window.AnimatedText=b}d.AnimatedText=b,d.FallingAnimation=p,d.FloatingAnimation=v,d.GlitchingAnimation=S,d.INTENSITY_CATEGORIES=A,d.MOOD_CATEGORIES=x,d.SplittingAnimation=F,d.calculateDisintegration=C,d.fontSuggestions=k,d.getFontFamily=H,d.isFontLoaded=D,d.loadGoogleFont=N,d.loadGoogleFonts=E,d.refineFont=R,d.refineSuggestion=T,d.suggestFont=M,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typography-toolkit",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Letter-by-letter text animations with proximity-based disintegration effects and Google Fonts selection",
5
5
  "main": "dist/typography-toolkit.umd.js",
6
6
  "module": "dist/typography-toolkit.esm.js",