typography-toolkit 1.0.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +269 -2
- package/dist/typography-toolkit.es.js +554 -108
- package/dist/typography-toolkit.iife.js +1 -1
- package/dist/typography-toolkit.umd.js +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -7,6 +7,9 @@ Letter-by-letter text animations with proximity-based disintegration effects. Cr
|
|
|
7
7
|
- **Letter-by-Letter Control** - Each letter is a separate DOM element with independent animations
|
|
8
8
|
- **Base Animations** - Falling, splitting, glitching, and floating animations
|
|
9
9
|
- **Proximity-Based Disintegration** - Letters react to cursor without direct interaction
|
|
10
|
+
- **Font Selection** - Suggest Google Fonts based on natural language descriptions
|
|
11
|
+
- **Font Refinement** - Refine suggestions based on feedback (e.g., "too casual, want gothic")
|
|
12
|
+
- **Dynamic Font Loading** - Automatically load Google Fonts without manual `<link>` tags
|
|
10
13
|
- **DOM-Based** - Uses CSS transforms (GPU-accelerated), accessible, and styleable
|
|
11
14
|
- **Modular & Extensible** - Easy to add new animation types and behaviors
|
|
12
15
|
- **Zero Dependencies** - Vanilla TypeScript/JavaScript
|
|
@@ -22,10 +25,18 @@ npm install typography-toolkit
|
|
|
22
25
|
```html
|
|
23
26
|
<script src="https://unpkg.com/typography-toolkit/dist/typography-toolkit.umd.js"></script>
|
|
24
27
|
<script>
|
|
25
|
-
|
|
28
|
+
// Option 1: Use TypographyToolkit namespace
|
|
29
|
+
const text = new TypographyToolkit.AnimatedText({...});
|
|
30
|
+
|
|
31
|
+
// Option 2: Use AnimatedText directly (also available on window)
|
|
32
|
+
const text = new AnimatedText({...});
|
|
26
33
|
</script>
|
|
27
34
|
```
|
|
28
35
|
|
|
36
|
+
**Global Names:** When using the UMD build, the library exposes:
|
|
37
|
+
- `window.TypographyToolkit` - Full namespace object
|
|
38
|
+
- `window.AnimatedText` - Direct access to AnimatedText class (for convenience)
|
|
39
|
+
|
|
29
40
|
### ES Modules
|
|
30
41
|
```javascript
|
|
31
42
|
import { AnimatedText } from 'typography-toolkit';
|
|
@@ -64,7 +75,9 @@ const text = new AnimatedText({
|
|
|
64
75
|
style: {
|
|
65
76
|
fontFamily: 'Arial',
|
|
66
77
|
fontSize: 24,
|
|
67
|
-
color: 'rgba(60, 60, 60, 0.8)'
|
|
78
|
+
color: 'rgba(60, 60, 60, 0.8)',
|
|
79
|
+
textShadow: '2px 2px 4px rgba(0,0,0,0.5)',
|
|
80
|
+
letterSpacing: '2px'
|
|
68
81
|
}
|
|
69
82
|
});
|
|
70
83
|
```
|
|
@@ -148,6 +161,108 @@ interface StyleOptions {
|
|
|
148
161
|
fontSize?: number;
|
|
149
162
|
color?: string;
|
|
150
163
|
fontWeight?: string;
|
|
164
|
+
textShadow?: string; // CSS text-shadow value
|
|
165
|
+
letterSpacing?: string; // CSS letter-spacing value
|
|
166
|
+
textTransform?: string; // CSS text-transform value
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Container Styling
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
containerClass?: string; // CSS class to add to container
|
|
174
|
+
containerStyle?: Record<string, string>; // Inline styles for container
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Position Constraints
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
position?: {
|
|
181
|
+
x?: number;
|
|
182
|
+
y?: number;
|
|
183
|
+
constrainToViewport?: boolean; // Keep text within viewport bounds
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Event Callbacks
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
callbacks?: {
|
|
191
|
+
onCreate?: (element: HTMLElement) => void; // Called when text is created
|
|
192
|
+
onDestroy?: () => void; // Called when text is destroyed
|
|
193
|
+
onDisintegrate?: (letterIndex: number) => void; // Called when a letter disintegrates
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Font Selection API
|
|
198
|
+
|
|
199
|
+
#### `suggestFont(description: string): FontSuggestion | undefined`
|
|
200
|
+
|
|
201
|
+
Get a single font suggestion based on a natural language description.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const font = suggestFont('gothic horror');
|
|
205
|
+
// Returns best matching font, or undefined if no matches
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `suggestFonts(description: string): FontSuggestion[]`
|
|
209
|
+
|
|
210
|
+
Get multiple font suggestions sorted by relevance.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const fonts = suggestFonts('hand-drawn');
|
|
214
|
+
// Returns array of matching fonts, sorted by relevance
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### `loadGoogleFont(fontName: string): Promise<void>`
|
|
218
|
+
|
|
219
|
+
Dynamically load a Google Font. Prevents duplicate loading.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
await loadGoogleFont('Caveat');
|
|
223
|
+
// Adds <link> tag to document head if not already loaded
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### `getFontFamily(fontName: string, fallback?: string): string`
|
|
227
|
+
|
|
228
|
+
Get CSS font-family string with appropriate fallback.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
getFontFamily('Caveat'); // "'Caveat', cursive"
|
|
232
|
+
getFontFamily('VT323'); // "'VT323', monospace"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### `refineFont(description: string, feedback: RefinementFeedback): FontSuggestion | undefined`
|
|
236
|
+
|
|
237
|
+
Refine font suggestions based on user feedback using scoring algorithm.
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
const refined = refineFont('hand-drawn', {
|
|
241
|
+
rejectedFont: 'Caveat',
|
|
242
|
+
negativeAspects: ['too casual'],
|
|
243
|
+
positiveAspects: ['gothic', 'ornate']
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `refineSuggestion(description: string, feedback: RefinementFeedback): FontSuggestion[]`
|
|
248
|
+
|
|
249
|
+
Get multiple refined suggestions sorted by score.
|
|
250
|
+
|
|
251
|
+
### Font Suggestion Types
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
interface FontSuggestion {
|
|
255
|
+
name: string; // Display name
|
|
256
|
+
googleFontsName: string; // Exact Google Fonts name
|
|
257
|
+
categories: string[]; // Tags for matching
|
|
258
|
+
description: string; // Human-readable description
|
|
259
|
+
artistic: boolean; // True if striking/unique (not "safe")
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
interface RefinementFeedback {
|
|
263
|
+
rejectedFont: string; // Font name they didn't like
|
|
264
|
+
negativeAspects: string[]; // What they don't like
|
|
265
|
+
positiveAspects: string[]; // What they want instead
|
|
151
266
|
}
|
|
152
267
|
```
|
|
153
268
|
|
|
@@ -189,6 +304,56 @@ const text = new AnimatedText({
|
|
|
189
304
|
});
|
|
190
305
|
```
|
|
191
306
|
|
|
307
|
+
### Font Selection & Loading
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
import { suggestFont, loadGoogleFont, getFontFamily, AnimatedText } from 'typography-toolkit';
|
|
311
|
+
|
|
312
|
+
// Suggest a font based on description
|
|
313
|
+
const font = suggestFont('hand-drawn');
|
|
314
|
+
// Returns: { name: 'Hand-drawn Casual', googleFontsName: 'Caveat', ... }
|
|
315
|
+
|
|
316
|
+
// Load the font dynamically
|
|
317
|
+
await loadGoogleFont(font.googleFontsName);
|
|
318
|
+
|
|
319
|
+
// Use in animation
|
|
320
|
+
const text = new AnimatedText({
|
|
321
|
+
text: 'HELLO',
|
|
322
|
+
container: document.body,
|
|
323
|
+
style: {
|
|
324
|
+
fontFamily: getFontFamily(font.googleFontsName) // "'Caveat', cursive"
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Font Refinement with Feedback
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
import { suggestFont, refineFont, loadGoogleFont, getFontFamily, AnimatedText } from 'typography-toolkit';
|
|
333
|
+
|
|
334
|
+
// Initial suggestion
|
|
335
|
+
const initial = suggestFont('hand-drawn');
|
|
336
|
+
// User doesn't like it: "too casual, want gothic and ornate"
|
|
337
|
+
|
|
338
|
+
// Refine based on feedback
|
|
339
|
+
const refined = refineFont('hand-drawn', {
|
|
340
|
+
rejectedFont: initial.googleFontsName,
|
|
341
|
+
negativeAspects: ['too casual', 'too simple'],
|
|
342
|
+
positiveAspects: ['gothic', 'ornate', 'striking']
|
|
343
|
+
});
|
|
344
|
+
// Returns: { name: 'Gothic Blackletter', googleFontsName: 'UnifrakturMaguntia', ... }
|
|
345
|
+
|
|
346
|
+
// Load and use
|
|
347
|
+
await loadGoogleFont(refined.googleFontsName);
|
|
348
|
+
const text = new AnimatedText({
|
|
349
|
+
text: 'GOTHIC',
|
|
350
|
+
container: document.body,
|
|
351
|
+
style: {
|
|
352
|
+
fontFamily: getFontFamily(refined.googleFontsName)
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
192
357
|
## Performance
|
|
193
358
|
|
|
194
359
|
- Uses `requestAnimationFrame` for smooth 60fps animations
|
|
@@ -196,11 +361,113 @@ const text = new AnimatedText({
|
|
|
196
361
|
- Efficient proximity calculations
|
|
197
362
|
- Automatic cleanup on destroy
|
|
198
363
|
|
|
364
|
+
## Common Patterns
|
|
365
|
+
|
|
366
|
+
### Creating Multiple Texts
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
const messages = ['HELLO', 'WORLD', 'ANIMATED'];
|
|
370
|
+
messages.forEach((msg, i) => {
|
|
371
|
+
new AnimatedText({
|
|
372
|
+
text: msg,
|
|
373
|
+
container: document.body,
|
|
374
|
+
position: { x: 100 + i * 200, y: 100 },
|
|
375
|
+
fadeOut: 5000
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Styling with CSS Classes
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
const text = new AnimatedText({
|
|
384
|
+
text: 'STYLED',
|
|
385
|
+
container: document.body,
|
|
386
|
+
containerClass: 'my-custom-class',
|
|
387
|
+
style: {
|
|
388
|
+
fontSize: 32,
|
|
389
|
+
color: '#ff0000'
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// CSS:
|
|
394
|
+
// .my-custom-class { background: rgba(0,0,0,0.1); padding: 10px; }
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Tracking Lifecycle Events
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
const text = new AnimatedText({
|
|
401
|
+
text: 'TRACKED',
|
|
402
|
+
container: document.body,
|
|
403
|
+
callbacks: {
|
|
404
|
+
onCreate: (element) => {
|
|
405
|
+
console.log('Text created:', element);
|
|
406
|
+
// Analytics tracking, etc.
|
|
407
|
+
},
|
|
408
|
+
onDestroy: () => {
|
|
409
|
+
console.log('Text destroyed');
|
|
410
|
+
},
|
|
411
|
+
onDisintegrate: (letterIndex) => {
|
|
412
|
+
console.log('Letter disintegrated:', letterIndex);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Constraining to Viewport
|
|
419
|
+
|
|
420
|
+
```javascript
|
|
421
|
+
const text = new AnimatedText({
|
|
422
|
+
text: 'CONSTRAINED',
|
|
423
|
+
container: document.body,
|
|
424
|
+
position: {
|
|
425
|
+
x: window.innerWidth - 100, // Might be off-screen
|
|
426
|
+
y: window.innerHeight - 50,
|
|
427
|
+
constrainToViewport: true // Automatically adjusts to stay on screen
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Troubleshooting
|
|
433
|
+
|
|
434
|
+
### Text Not Animating?
|
|
435
|
+
|
|
436
|
+
- **Check container**: Ensure the container element exists and is visible
|
|
437
|
+
- **Check animations array**: Make sure at least one animation type is specified
|
|
438
|
+
- **Check browser support**: Requires modern browser with `requestAnimationFrame` support
|
|
439
|
+
|
|
440
|
+
### Disintegration Not Working?
|
|
441
|
+
|
|
442
|
+
- **Check disintegration.enabled**: Must be set to `true`
|
|
443
|
+
- **Check radius**: Increase `radius` if cursor needs to be closer
|
|
444
|
+
- **Check mouse tracking**: Ensure mouse events are not being blocked
|
|
445
|
+
|
|
446
|
+
### Text Positioned Off-Screen?
|
|
447
|
+
|
|
448
|
+
- **Use constrainToViewport**: Set `position.constrainToViewport: true`
|
|
449
|
+
- **Check container bounds**: Ensure container has proper dimensions
|
|
450
|
+
- **Manual bounds checking**: Calculate position manually based on container size
|
|
451
|
+
|
|
452
|
+
### Performance Issues?
|
|
453
|
+
|
|
454
|
+
- **Reduce animation types**: Fewer animations = better performance
|
|
455
|
+
- **Reduce letter count**: Shorter text = better performance
|
|
456
|
+
- **Use fadeOut**: Auto-destroy texts after a delay to prevent memory buildup
|
|
457
|
+
- **Destroy manually**: Call `destroy()` when done with text instances
|
|
458
|
+
|
|
459
|
+
### Fonts Not Loading?
|
|
460
|
+
|
|
461
|
+
- **Check font name**: Ensure Google Font name is correct
|
|
462
|
+
- **Check network**: Verify Google Fonts CDN is accessible
|
|
463
|
+
- **Check font-family**: Use `getFontFamily()` helper for correct CSS format
|
|
464
|
+
|
|
199
465
|
## Browser Support
|
|
200
466
|
|
|
201
467
|
- Modern browsers with ES2020 support
|
|
202
468
|
- Requires `requestAnimationFrame` API
|
|
203
469
|
- CSS transforms support
|
|
470
|
+
- Mobile browsers supported (touch events coming soon)
|
|
204
471
|
|
|
205
472
|
## License
|
|
206
473
|
|
|
@@ -1,153 +1,166 @@
|
|
|
1
|
-
class
|
|
2
|
-
update(
|
|
3
|
-
const
|
|
1
|
+
class f {
|
|
2
|
+
update(e, o, n, t = {}) {
|
|
3
|
+
const i = t.speed || 1, l = t.amplitude || 20, r = o * 0.2, c = (n * 10 * i + r * 5) % l - l / 2;
|
|
4
4
|
return {
|
|
5
|
-
...
|
|
6
|
-
y:
|
|
5
|
+
...e,
|
|
6
|
+
y: c
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
class
|
|
11
|
-
update(
|
|
12
|
-
const
|
|
10
|
+
class C {
|
|
11
|
+
update(e, o, n, t = {}) {
|
|
12
|
+
const i = t.speed || 1, l = t.amplitude || 4, r = o * 0.2, a = Math.sin(n * 0.5 * i + r) * l;
|
|
13
13
|
return {
|
|
14
|
-
...
|
|
15
|
-
x:
|
|
14
|
+
...e,
|
|
15
|
+
x: a
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
class
|
|
19
|
+
class x {
|
|
20
20
|
constructor() {
|
|
21
21
|
this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
|
|
22
22
|
}
|
|
23
|
-
update(
|
|
24
|
-
const
|
|
25
|
-
return
|
|
26
|
-
...
|
|
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
|
|
34
|
-
update(
|
|
35
|
-
const
|
|
33
|
+
class S {
|
|
34
|
+
update(e, o, n, t = {}) {
|
|
35
|
+
const i = t.speed || 1, l = t.amplitude || 15, r = o * 0.2, c = -((n * 8 * i + r * 4) % l - l / 2);
|
|
36
36
|
return {
|
|
37
|
-
...
|
|
38
|
-
y:
|
|
37
|
+
...e,
|
|
38
|
+
y: c
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
const { x: o, y:
|
|
44
|
-
|
|
42
|
+
function H(s, e) {
|
|
43
|
+
const { x: o, y: n, rotation: t, scale: i, opacity: l } = e;
|
|
44
|
+
s.style.transform = `translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`, s.style.opacity = l.toString();
|
|
45
45
|
}
|
|
46
|
-
function
|
|
47
|
-
if (!
|
|
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
|
|
53
|
-
if (
|
|
52
|
+
const l = i.radius || 80, r = i.strength || 1, a = i.behaviors || ["fall-away", "split-apart", "explode"], c = o - s, h = n - e, d = Math.sqrt(c * c + h * h);
|
|
53
|
+
if (d >= l)
|
|
54
54
|
return {
|
|
55
55
|
state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
|
|
56
56
|
applied: !1
|
|
57
57
|
};
|
|
58
|
-
const
|
|
59
|
-
let
|
|
58
|
+
const g = (1 - d / l) * r, u = Math.atan2(h, c), M = a[t % a.length];
|
|
59
|
+
let m;
|
|
60
60
|
switch (M) {
|
|
61
61
|
case "fall-away":
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
x:
|
|
65
|
-
y:
|
|
66
|
-
rotation:
|
|
62
|
+
const A = Math.cos(u) * g * 20, D = Math.sin(u) * g * 40 + g * 30;
|
|
63
|
+
m = {
|
|
64
|
+
x: A,
|
|
65
|
+
y: D,
|
|
66
|
+
rotation: g * 15,
|
|
67
67
|
scale: 1,
|
|
68
|
-
opacity: 1 -
|
|
68
|
+
opacity: 1 - g * 0.6
|
|
69
69
|
};
|
|
70
70
|
break;
|
|
71
71
|
case "split-apart":
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
x:
|
|
75
|
-
y: (Math.random() - 0.5) *
|
|
76
|
-
rotation:
|
|
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 -
|
|
78
|
+
opacity: 1 - g * 0.6
|
|
79
79
|
};
|
|
80
80
|
break;
|
|
81
81
|
case "explode":
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
x: Math.cos(
|
|
85
|
-
y: Math.sin(
|
|
86
|
-
rotation:
|
|
87
|
-
scale: 1 +
|
|
88
|
-
opacity: 1 -
|
|
82
|
+
const F = u + (Math.random() - 0.5) * 0.5;
|
|
83
|
+
m = {
|
|
84
|
+
x: Math.cos(F) * g * 40,
|
|
85
|
+
y: Math.sin(F) * g * 40,
|
|
86
|
+
rotation: g * 30,
|
|
87
|
+
scale: 1 + g * 0.4,
|
|
88
|
+
opacity: 1 - g * 0.6
|
|
89
89
|
};
|
|
90
90
|
break;
|
|
91
91
|
default:
|
|
92
|
-
|
|
92
|
+
m = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
|
|
93
93
|
}
|
|
94
94
|
return {
|
|
95
|
-
state:
|
|
95
|
+
state: m,
|
|
96
96
|
applied: !0
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
class
|
|
100
|
-
constructor(
|
|
101
|
-
|
|
99
|
+
class v {
|
|
100
|
+
constructor(e) {
|
|
101
|
+
var o;
|
|
102
|
+
if (this.letters = [], this.animationFrame = null, this.mouseX = 0, this.mouseY = 0, this.mouseMoveHandler = null, this.startTime = Date.now(), this.isDestroyed = !1, this.container = e.container, this.animationTypes = e.animations || ["falling", "splitting", "glitching", "floating"], this.cycle = e.cycle !== !1, this.speed = e.speed || 1, this.amplitude = e.amplitude || 1, this.disintegration = e.disintegration || { enabled: !1 }, this.style = e.style || {}, this.fadeOut = e.fadeOut || 0, this.callbacks = e.callbacks, this.textContainer = document.createElement("div"), this.textContainer.style.position = "absolute", this.textContainer.style.pointerEvents = "none", this.textContainer.style.zIndex = "1", e.containerClass && (this.textContainer.className = e.containerClass), e.containerStyle && Object.entries(e.containerStyle).forEach(([n, t]) => {
|
|
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
|
+
this.container.getBoundingClientRect();
|
|
108
|
+
const i = window.innerWidth, l = window.innerHeight, r = e.text.length * 20;
|
|
109
|
+
n !== void 0 && (n = Math.max(0, Math.min(n, i - r))), t !== void 0 && (t = Math.max(0, Math.min(t, l - 50)));
|
|
110
|
+
}
|
|
111
|
+
n !== void 0 && (this.textContainer.style.left = `${n}px`), t !== void 0 && (this.textContainer.style.top = `${t}px`);
|
|
112
|
+
}
|
|
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);
|
|
102
114
|
}
|
|
103
|
-
createLetters(
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
const
|
|
107
|
-
this.textContainer.appendChild(
|
|
115
|
+
createLetters(e) {
|
|
116
|
+
e.toUpperCase().split("").forEach((n, t) => {
|
|
117
|
+
if (n === " ") {
|
|
118
|
+
const r = document.createTextNode(" ");
|
|
119
|
+
this.textContainer.appendChild(r);
|
|
108
120
|
return;
|
|
109
121
|
}
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
const
|
|
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();
|
|
113
125
|
this.letters.push({
|
|
114
|
-
element:
|
|
115
|
-
index:
|
|
116
|
-
char:
|
|
117
|
-
baseX:
|
|
118
|
-
baseY:
|
|
126
|
+
element: i,
|
|
127
|
+
index: t,
|
|
128
|
+
char: n,
|
|
129
|
+
baseX: l.left,
|
|
130
|
+
baseY: l.top
|
|
119
131
|
});
|
|
120
132
|
}), this.container.appendChild(this.textContainer);
|
|
121
133
|
}
|
|
122
|
-
applyStyle(
|
|
123
|
-
this.style.fontFamily && (
|
|
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);
|
|
124
136
|
}
|
|
125
137
|
setupMouseTracking() {
|
|
126
|
-
this.disintegration.enabled && (this.mouseMoveHandler = (
|
|
127
|
-
this.mouseX =
|
|
138
|
+
this.disintegration.enabled && (this.mouseMoveHandler = (e) => {
|
|
139
|
+
this.mouseX = e.clientX, this.mouseY = e.clientY;
|
|
128
140
|
}, document.addEventListener("mousemove", this.mouseMoveHandler));
|
|
129
141
|
}
|
|
130
142
|
startAnimation() {
|
|
131
|
-
const
|
|
143
|
+
const e = () => {
|
|
132
144
|
if (this.isDestroyed) return;
|
|
133
145
|
const o = (Date.now() - this.startTime) * 1e-3;
|
|
134
|
-
this.letters.forEach((
|
|
135
|
-
|
|
136
|
-
|
|
146
|
+
this.letters.forEach((n, t) => {
|
|
147
|
+
var h;
|
|
148
|
+
const i = n.element.getBoundingClientRect(), l = i.left + i.width / 2, r = i.top + i.height / 2, a = b(
|
|
137
149
|
l,
|
|
150
|
+
r,
|
|
138
151
|
this.mouseX,
|
|
139
152
|
this.mouseY,
|
|
140
|
-
|
|
153
|
+
t,
|
|
141
154
|
this.disintegration
|
|
142
155
|
);
|
|
143
|
-
let
|
|
144
|
-
if (
|
|
145
|
-
|
|
156
|
+
let c;
|
|
157
|
+
if (a.applied)
|
|
158
|
+
c = a.state, (h = this.callbacks) != null && h.onDisintegrate && this.callbacks.onDisintegrate(t);
|
|
146
159
|
else {
|
|
147
|
-
const d = this.getAnimationType(
|
|
148
|
-
|
|
160
|
+
const d = this.getAnimationType(t);
|
|
161
|
+
c = this.getAnimation(d).update(
|
|
149
162
|
{ x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
|
|
150
|
-
|
|
163
|
+
t,
|
|
151
164
|
o,
|
|
152
165
|
{
|
|
153
166
|
speed: this.speed,
|
|
@@ -155,33 +168,34 @@ class F {
|
|
|
155
168
|
}
|
|
156
169
|
);
|
|
157
170
|
}
|
|
158
|
-
|
|
159
|
-
}), this.animationFrame = requestAnimationFrame(
|
|
171
|
+
H(n.element, c);
|
|
172
|
+
}), this.animationFrame = requestAnimationFrame(e);
|
|
160
173
|
};
|
|
161
|
-
this.animationFrame = requestAnimationFrame(
|
|
174
|
+
this.animationFrame = requestAnimationFrame(e);
|
|
162
175
|
}
|
|
163
|
-
getAnimationType(
|
|
164
|
-
return this.cycle ? this.animationTypes[
|
|
176
|
+
getAnimationType(e) {
|
|
177
|
+
return this.cycle ? this.animationTypes[e % this.animationTypes.length] : this.animationTypes[0];
|
|
165
178
|
}
|
|
166
|
-
getAnimation(
|
|
167
|
-
switch (
|
|
179
|
+
getAnimation(e) {
|
|
180
|
+
switch (e) {
|
|
168
181
|
case "falling":
|
|
169
|
-
return new
|
|
182
|
+
return new f();
|
|
170
183
|
case "splitting":
|
|
171
|
-
return new x();
|
|
172
|
-
case "glitching":
|
|
173
184
|
return new C();
|
|
185
|
+
case "glitching":
|
|
186
|
+
return new x();
|
|
174
187
|
case "floating":
|
|
175
|
-
return new
|
|
188
|
+
return new S();
|
|
176
189
|
default:
|
|
177
|
-
return new
|
|
190
|
+
return new f();
|
|
178
191
|
}
|
|
179
192
|
}
|
|
180
193
|
/**
|
|
181
194
|
* Destroy the animated text instance
|
|
182
195
|
*/
|
|
183
196
|
destroy() {
|
|
184
|
-
|
|
197
|
+
var e;
|
|
198
|
+
this.isDestroyed || (this.isDestroyed = !0, this.animationFrame !== null && cancelAnimationFrame(this.animationFrame), this.mouseMoveHandler && document.removeEventListener("mousemove", this.mouseMoveHandler), (e = this.callbacks) != null && e.onDestroy && this.callbacks.onDestroy(), this.textContainer.style.transition = "opacity 3s ease", this.textContainer.style.opacity = "0", setTimeout(() => {
|
|
185
199
|
this.textContainer.parentNode && this.textContainer.parentNode.removeChild(this.textContainer);
|
|
186
200
|
}, 3e3));
|
|
187
201
|
}
|
|
@@ -192,19 +206,451 @@ class F {
|
|
|
192
206
|
return this.textContainer;
|
|
193
207
|
}
|
|
194
208
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
const E = [
|
|
210
|
+
"unsettling",
|
|
211
|
+
"eerie",
|
|
212
|
+
"decayed",
|
|
213
|
+
"weathered",
|
|
214
|
+
"organic",
|
|
215
|
+
"imperfect",
|
|
216
|
+
"uneven",
|
|
217
|
+
"scratchy"
|
|
218
|
+
], R = ["subtle", "moderate", "intense"], k = [
|
|
219
|
+
// Hand-drawn / Handwriting
|
|
220
|
+
{
|
|
221
|
+
name: "Hand-drawn Casual",
|
|
222
|
+
googleFontsName: "Caveat",
|
|
223
|
+
categories: ["hand-drawn", "handwriting", "casual", "sketchy", "informal"],
|
|
224
|
+
description: "Casual handwritten style, friendly and approachable",
|
|
225
|
+
artistic: !1
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "Hand-drawn Playful",
|
|
229
|
+
googleFontsName: "Finger Paint",
|
|
230
|
+
categories: ["hand-drawn", "playful", "childlike", "casual", "sketchy"],
|
|
231
|
+
description: "Bold hand-drawn style, playful and energetic",
|
|
232
|
+
artistic: !0
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "Hand-drawn Script",
|
|
236
|
+
googleFontsName: "Dancing Script",
|
|
237
|
+
categories: ["hand-drawn", "script", "elegant", "flowing", "cursive"],
|
|
238
|
+
description: "Elegant flowing script, graceful and organic",
|
|
239
|
+
artistic: !1
|
|
240
|
+
},
|
|
241
|
+
// Gothic / Medieval
|
|
242
|
+
{
|
|
243
|
+
name: "Gothic Blackletter",
|
|
244
|
+
googleFontsName: "UnifrakturMaguntia",
|
|
245
|
+
categories: ["gothic", "medieval", "blackletter", "ornate", "historical"],
|
|
246
|
+
description: "Medieval blackletter style, ornate and historical",
|
|
247
|
+
artistic: !0
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: "Gothic Horror",
|
|
251
|
+
googleFontsName: "Creepster",
|
|
252
|
+
categories: ["gothic", "horror", "creepy", "dripping", "display", "striking", "intense"],
|
|
253
|
+
description: "Horror-style font with dripping effects, very striking",
|
|
254
|
+
artistic: !0
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "Gothic Bold",
|
|
258
|
+
googleFontsName: "Eater",
|
|
259
|
+
categories: ["gothic", "bold", "aggressive", "display", "striking"],
|
|
260
|
+
description: "Bold aggressive display font, powerful impact",
|
|
261
|
+
artistic: !0
|
|
262
|
+
},
|
|
263
|
+
// Futuristic / Sci-fi
|
|
264
|
+
{
|
|
265
|
+
name: "Futuristic Digital",
|
|
266
|
+
googleFontsName: "Orbitron",
|
|
267
|
+
categories: ["futuristic", "sci-fi", "digital", "tech", "modern", "geometric"],
|
|
268
|
+
description: "Futuristic geometric font, tech-forward and modern",
|
|
269
|
+
artistic: !0
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: "Futuristic Display",
|
|
273
|
+
googleFontsName: "Bungee",
|
|
274
|
+
categories: ["futuristic", "display", "bold", "condensed", "striking"],
|
|
275
|
+
description: "Bold condensed display font, high impact",
|
|
276
|
+
artistic: !0
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "Futuristic Outline",
|
|
280
|
+
googleFontsName: "Bungee Shade",
|
|
281
|
+
categories: ["futuristic", "outline", "display", "bold", "striking"],
|
|
282
|
+
description: "Outlined version of Bungee, bold and striking",
|
|
283
|
+
artistic: !0
|
|
284
|
+
},
|
|
285
|
+
// Retro / Vintage
|
|
286
|
+
{
|
|
287
|
+
name: "Retro Terminal",
|
|
288
|
+
googleFontsName: "VT323",
|
|
289
|
+
categories: ["retro", "terminal", "monospace", "pixel", "80s", "tech"],
|
|
290
|
+
description: "Retro terminal font, pixelated and nostalgic",
|
|
291
|
+
artistic: !0
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
name: "Retro Pixel",
|
|
295
|
+
googleFontsName: "Press Start 2P",
|
|
296
|
+
categories: ["retro", "pixel", "8-bit", "arcade", "nostalgic", "display"],
|
|
297
|
+
description: "8-bit pixel font, classic arcade style",
|
|
298
|
+
artistic: !0
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: "Retro Display",
|
|
302
|
+
googleFontsName: "Frijole",
|
|
303
|
+
categories: ["retro", "playful", "rounded", "display", "casual"],
|
|
304
|
+
description: "Playful rounded retro font, fun and casual",
|
|
305
|
+
artistic: !0
|
|
306
|
+
},
|
|
307
|
+
// Decorative / Ornate
|
|
308
|
+
{
|
|
309
|
+
name: "Decorative Ornate",
|
|
310
|
+
googleFontsName: "Fascinate",
|
|
311
|
+
categories: ["decorative", "ornate", "display", "striking", "elaborate"],
|
|
312
|
+
description: "Highly decorative display font, ornate and elaborate",
|
|
313
|
+
artistic: !0
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "Decorative Outline",
|
|
317
|
+
googleFontsName: "Fascinate Inline",
|
|
318
|
+
categories: ["decorative", "outline", "display", "ornate", "striking"],
|
|
319
|
+
description: "Outlined decorative font, ornate and striking",
|
|
320
|
+
artistic: !0
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "Decorative Script",
|
|
324
|
+
googleFontsName: "Fredericka the Great",
|
|
325
|
+
categories: ["decorative", "script", "ornate", "elegant", "display"],
|
|
326
|
+
description: "Elegant decorative script, ornate and sophisticated",
|
|
327
|
+
artistic: !0
|
|
328
|
+
},
|
|
329
|
+
// Creepy / Horror
|
|
330
|
+
{
|
|
331
|
+
name: "Horror Dripping",
|
|
332
|
+
googleFontsName: "Nosifer",
|
|
333
|
+
categories: ["horror", "creepy", "dripping", "blood", "striking", "display", "intense"],
|
|
334
|
+
description: "Creepy font with blood-dripping effects, very striking",
|
|
335
|
+
artistic: !0
|
|
336
|
+
},
|
|
337
|
+
// Tech / Monospace
|
|
338
|
+
{
|
|
339
|
+
name: "Tech Monospace",
|
|
340
|
+
googleFontsName: "Share Tech Mono",
|
|
341
|
+
categories: ["tech", "monospace", "terminal", "code", "modern"],
|
|
342
|
+
description: "Clean tech monospace font, modern and readable",
|
|
343
|
+
artistic: !1
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "Tech Display",
|
|
347
|
+
googleFontsName: "Rajdhani",
|
|
348
|
+
categories: ["tech", "modern", "geometric", "sans-serif", "futuristic"],
|
|
349
|
+
description: "Modern geometric tech font, clean and futuristic",
|
|
350
|
+
artistic: !1
|
|
351
|
+
},
|
|
352
|
+
// Organic / Natural
|
|
353
|
+
{
|
|
354
|
+
name: "Organic Flowing",
|
|
355
|
+
googleFontsName: "Dancing Script",
|
|
356
|
+
categories: ["organic", "flowing", "natural", "script", "elegant"],
|
|
357
|
+
description: "Flowing organic script, natural and elegant",
|
|
358
|
+
artistic: !1
|
|
359
|
+
},
|
|
360
|
+
// Modern / Clean
|
|
361
|
+
{
|
|
362
|
+
name: "Modern Sans",
|
|
363
|
+
googleFontsName: "Roboto",
|
|
364
|
+
categories: ["modern", "clean", "sans-serif", "readable", "professional"],
|
|
365
|
+
description: "Clean modern sans-serif, professional and readable",
|
|
366
|
+
artistic: !1
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "Modern Serif",
|
|
370
|
+
googleFontsName: "Playfair Display",
|
|
371
|
+
categories: ["modern", "serif", "elegant", "sophisticated", "readable"],
|
|
372
|
+
description: "Elegant modern serif, sophisticated and readable",
|
|
373
|
+
artistic: !1
|
|
374
|
+
},
|
|
375
|
+
// Bold / Display
|
|
376
|
+
{
|
|
377
|
+
name: "Bold Condensed",
|
|
378
|
+
googleFontsName: "Bungee",
|
|
379
|
+
categories: ["bold", "condensed", "display", "striking", "impact"],
|
|
380
|
+
description: "Bold condensed display font, high impact",
|
|
381
|
+
artistic: !0
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "Bold Aggressive",
|
|
385
|
+
googleFontsName: "Eater",
|
|
386
|
+
categories: ["bold", "aggressive", "display", "striking", "powerful"],
|
|
387
|
+
description: "Bold aggressive display font, powerful and striking",
|
|
388
|
+
artistic: !0
|
|
389
|
+
},
|
|
390
|
+
// Subtle Unsettling / Organic Imperfect
|
|
391
|
+
{
|
|
392
|
+
name: "Handwritten Thin",
|
|
393
|
+
googleFontsName: "Amatic SC",
|
|
394
|
+
categories: ["hand-drawn", "uneven", "organic", "unsettling", "subtle", "scratchy"],
|
|
395
|
+
description: "Thin hand-drawn letters with subtle irregularity, organic feel",
|
|
396
|
+
artistic: !0
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "Rough Handwriting",
|
|
400
|
+
googleFontsName: "Rock Salt",
|
|
401
|
+
categories: ["hand-drawn", "scratchy", "weathered", "rough", "unsettling", "moderate"],
|
|
402
|
+
description: "Rough, weathered handwriting with natural imperfection",
|
|
403
|
+
artistic: !0
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: "Typewriter Degraded",
|
|
407
|
+
googleFontsName: "Special Elite",
|
|
408
|
+
categories: ["typewriter", "decayed", "weathered", "imperfect", "unsettling", "moderate"],
|
|
409
|
+
description: "Degraded typewriter font, vintage with imperfection",
|
|
410
|
+
artistic: !0
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "Casual Handwriting",
|
|
414
|
+
googleFontsName: "Handlee",
|
|
415
|
+
categories: ["hand-drawn", "casual", "imperfect", "organic", "subtle"],
|
|
416
|
+
description: "Casual handwriting with subtle imperfection",
|
|
417
|
+
artistic: !1
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: "Childlike Organic",
|
|
421
|
+
googleFontsName: "Indie Flower",
|
|
422
|
+
categories: ["hand-drawn", "childlike", "organic", "imperfect", "eerie", "subtle"],
|
|
423
|
+
description: "Childlike handwriting, can feel innocent or eerie depending on context",
|
|
424
|
+
artistic: !1
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
name: "Scratchy Personal",
|
|
428
|
+
googleFontsName: "Shadows Into Light",
|
|
429
|
+
categories: ["hand-drawn", "scratchy", "personal", "unsettling", "uneven", "moderate"],
|
|
430
|
+
description: "Scratchy personal handwriting with unsettling quality",
|
|
431
|
+
artistic: !0
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
name: "Hurried Scratchy",
|
|
435
|
+
googleFontsName: "Reenie Beanie",
|
|
436
|
+
categories: ["hand-drawn", "scratchy", "hurried", "uneven", "unsettling", "moderate"],
|
|
437
|
+
description: "Hurried scratchy handwriting with nervous energy",
|
|
438
|
+
artistic: !0
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: "Architectural Irregular",
|
|
442
|
+
googleFontsName: "Architects Daughter",
|
|
443
|
+
categories: ["hand-drawn", "imperfect", "uneven", "organic", "subtle"],
|
|
444
|
+
description: "Hand-drawn with architectural irregularity",
|
|
445
|
+
artistic: !1
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "Informal Unsettling",
|
|
449
|
+
googleFontsName: "Coming Soon",
|
|
450
|
+
categories: ["hand-drawn", "informal", "imperfect", "unsettling", "subtle"],
|
|
451
|
+
description: "Informal handwriting that feels slightly off",
|
|
452
|
+
artistic: !1
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
name: "Manic Handwriting",
|
|
456
|
+
googleFontsName: "Gloria Hallelujah",
|
|
457
|
+
categories: ["hand-drawn", "playful", "manic", "uneven", "unsettling", "moderate"],
|
|
458
|
+
description: "Playful handwriting that can feel manic or unsettled",
|
|
459
|
+
artistic: !0
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
name: "Quick Imperfect",
|
|
463
|
+
googleFontsName: "Just Another Hand",
|
|
464
|
+
categories: ["hand-drawn", "scratchy", "quick", "imperfect", "uneven", "subtle"],
|
|
465
|
+
description: "Quick scratchy handwriting with natural imperfection",
|
|
466
|
+
artistic: !1
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: "Organic Handwriting",
|
|
470
|
+
googleFontsName: "Kalam",
|
|
471
|
+
categories: ["hand-drawn", "organic", "natural", "flowing", "subtle"],
|
|
472
|
+
description: "Organic natural handwriting with flowing quality",
|
|
473
|
+
artistic: !1
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: "Flowing Tension",
|
|
477
|
+
googleFontsName: "Satisfy",
|
|
478
|
+
categories: ["script", "flowing", "tension", "elegant", "unsettling", "subtle"],
|
|
479
|
+
description: "Flowing script with underlying tension",
|
|
480
|
+
artistic: !0
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: "Unsettling Elegance",
|
|
484
|
+
googleFontsName: "Yellowtail",
|
|
485
|
+
categories: ["script", "elegant", "stylized", "unsettling", "uneven", "moderate"],
|
|
486
|
+
description: "Stylized elegance with unsettling undertones",
|
|
487
|
+
artistic: !0
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
name: "Typewriter Imperfect",
|
|
491
|
+
googleFontsName: "Cutive Mono",
|
|
492
|
+
categories: ["typewriter", "monospace", "imperfect", "decayed", "vintage", "subtle"],
|
|
493
|
+
description: "Imperfect vintage typewriter with character",
|
|
494
|
+
artistic: !0
|
|
495
|
+
}
|
|
496
|
+
];
|
|
497
|
+
function L(s) {
|
|
498
|
+
const e = s.toLowerCase().split(/\s+/).filter((t) => t.length > 0), o = [], n = [];
|
|
499
|
+
for (const t of e)
|
|
500
|
+
t.startsWith("-") && t.length > 1 ? n.push(t.slice(1)) : o.push(t);
|
|
501
|
+
return { positive: o, negative: n };
|
|
502
|
+
}
|
|
503
|
+
function O(s, e) {
|
|
504
|
+
const o = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), t = 2, i = [];
|
|
505
|
+
for (const l of s) {
|
|
506
|
+
if (i.length >= e) break;
|
|
507
|
+
if (o.has(l.font.googleFontsName))
|
|
508
|
+
continue;
|
|
509
|
+
const r = l.font.categories[0], a = n.get(r) || 0;
|
|
510
|
+
a >= t || (o.add(l.font.googleFontsName), n.set(r, a + 1), i.push(l.font));
|
|
511
|
+
}
|
|
512
|
+
return i;
|
|
513
|
+
}
|
|
514
|
+
function y(s, e) {
|
|
515
|
+
const { positive: o, negative: n } = L(s), t = (e == null ? void 0 : e.limit) ?? 10, l = k.map((r) => {
|
|
516
|
+
let a = 0;
|
|
517
|
+
for (const c of o) {
|
|
518
|
+
for (const h of r.categories)
|
|
519
|
+
(h.includes(c) || c.includes(h)) && (a += 10);
|
|
520
|
+
r.name.toLowerCase().includes(c) && (a += 15), r.description.toLowerCase().includes(c) && (a += 8);
|
|
521
|
+
}
|
|
522
|
+
for (const c of n) {
|
|
523
|
+
for (const h of r.categories)
|
|
524
|
+
(h.includes(c) || c.includes(h)) && (a -= 20);
|
|
525
|
+
r.name.toLowerCase().includes(c) && (a -= 15), r.description.toLowerCase().includes(c) && (a -= 10);
|
|
526
|
+
}
|
|
527
|
+
return r.artistic && (a += 1), { font: r, score: a };
|
|
528
|
+
}).filter((r) => r.score > 0).sort((r, a) => a.score - r.score);
|
|
529
|
+
return O(l, t);
|
|
530
|
+
}
|
|
531
|
+
function P(s) {
|
|
532
|
+
return y(s)[0];
|
|
533
|
+
}
|
|
534
|
+
const p = /* @__PURE__ */ new Set();
|
|
535
|
+
function N(s) {
|
|
536
|
+
return new Promise((e, o) => {
|
|
537
|
+
const n = s.replace(/\s+/g, "+");
|
|
538
|
+
if (p.has(n)) {
|
|
539
|
+
e();
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
if (document.querySelector(
|
|
543
|
+
`link[href*="fonts.googleapis.com"][href*="${n}"]`
|
|
544
|
+
)) {
|
|
545
|
+
p.add(n), e();
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const i = document.createElement("link");
|
|
549
|
+
i.rel = "stylesheet", i.href = `https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`, i.onload = () => {
|
|
550
|
+
p.add(n), e();
|
|
551
|
+
}, i.onerror = () => {
|
|
552
|
+
console.warn(`Failed to load Google Font: ${s}`), o(new Error(`Failed to load Google Font: ${s}`));
|
|
553
|
+
}, document.head.appendChild(i);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
function B(s) {
|
|
557
|
+
return Promise.all(s.map((e) => N(e)));
|
|
558
|
+
}
|
|
559
|
+
function G(s) {
|
|
560
|
+
const e = s.replace(/\s+/g, "+");
|
|
561
|
+
return p.has(e);
|
|
562
|
+
}
|
|
563
|
+
function I(s, e = "sans-serif") {
|
|
564
|
+
const o = [
|
|
565
|
+
"Caveat",
|
|
566
|
+
"Dancing Script",
|
|
567
|
+
"Finger Paint",
|
|
568
|
+
"Fredericka the Great",
|
|
569
|
+
// Subtle unsettling / organic fonts
|
|
570
|
+
"Amatic SC",
|
|
571
|
+
"Handlee",
|
|
572
|
+
"Indie Flower",
|
|
573
|
+
"Shadows Into Light",
|
|
574
|
+
"Rock Salt",
|
|
575
|
+
"Reenie Beanie",
|
|
576
|
+
"Architects Daughter",
|
|
577
|
+
"Coming Soon",
|
|
578
|
+
"Gloria Hallelujah",
|
|
579
|
+
"Just Another Hand",
|
|
580
|
+
"Kalam",
|
|
581
|
+
"Satisfy",
|
|
582
|
+
"Yellowtail"
|
|
583
|
+
], n = [
|
|
584
|
+
"VT323",
|
|
585
|
+
"Press Start 2P",
|
|
586
|
+
"Share Tech Mono",
|
|
587
|
+
// Typewriter fonts
|
|
588
|
+
"Special Elite",
|
|
589
|
+
"Cutive Mono"
|
|
590
|
+
];
|
|
591
|
+
let t = e;
|
|
592
|
+
return o.includes(s) ? t = "cursive" : n.includes(s) && (t = "monospace"), `'${s}', ${t}`;
|
|
593
|
+
}
|
|
594
|
+
function T(s, e) {
|
|
595
|
+
const o = s.toLowerCase(), n = e.rejectedFont.toLowerCase(), t = e.negativeAspects.map((a) => a.toLowerCase()), i = e.positiveAspects.map((a) => a.toLowerCase());
|
|
596
|
+
return y(s).filter(
|
|
597
|
+
(a) => a.googleFontsName.toLowerCase() !== n && a.name.toLowerCase() !== n
|
|
598
|
+
).map((a) => {
|
|
599
|
+
let c = 0;
|
|
600
|
+
for (const d of a.categories)
|
|
601
|
+
o.includes(d) && (c += 5);
|
|
602
|
+
for (const d of i)
|
|
603
|
+
(a.categories.some((u) => u.includes(d) || d.includes(u)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c += 15);
|
|
604
|
+
for (const d of t)
|
|
605
|
+
(a.categories.some((u) => u.includes(d) || d.includes(u)) || a.name.toLowerCase().includes(d) || a.description.toLowerCase().includes(d)) && (c -= 20);
|
|
606
|
+
const h = i.some(
|
|
607
|
+
(d) => d.includes("striking") || d.includes("artistic") || d.includes("unique")
|
|
608
|
+
);
|
|
609
|
+
return h && a.artistic && (c += 10), h && !a.artistic && (c -= 5), { font: a, score: c };
|
|
610
|
+
}).filter((a) => a.score > 0).sort((a, c) => c.score - a.score).map((a) => a.font);
|
|
611
|
+
}
|
|
612
|
+
function Y(s, e) {
|
|
613
|
+
return T(s, e)[0];
|
|
614
|
+
}
|
|
615
|
+
if (typeof window < "u") {
|
|
616
|
+
const s = {
|
|
617
|
+
AnimatedText: v,
|
|
618
|
+
FallingAnimation: f,
|
|
619
|
+
SplittingAnimation: C,
|
|
620
|
+
GlitchingAnimation: x,
|
|
621
|
+
FloatingAnimation: S,
|
|
622
|
+
calculateDisintegration: b,
|
|
623
|
+
// Font utilities
|
|
624
|
+
fontSuggestions: k,
|
|
625
|
+
suggestFonts: y,
|
|
626
|
+
suggestFont: P,
|
|
627
|
+
loadGoogleFont: N,
|
|
628
|
+
loadGoogleFonts: B,
|
|
629
|
+
isFontLoaded: G,
|
|
630
|
+
getFontFamily: I,
|
|
631
|
+
refineSuggestion: T,
|
|
632
|
+
refineFont: Y,
|
|
633
|
+
MOOD_CATEGORIES: E,
|
|
634
|
+
INTENSITY_CATEGORIES: R
|
|
635
|
+
};
|
|
636
|
+
window.TypographyToolkit = s, window.AnimatedText = v;
|
|
637
|
+
}
|
|
203
638
|
export {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
639
|
+
v as AnimatedText,
|
|
640
|
+
f as FallingAnimation,
|
|
641
|
+
S as FloatingAnimation,
|
|
642
|
+
x as GlitchingAnimation,
|
|
643
|
+
R as INTENSITY_CATEGORIES,
|
|
644
|
+
E as MOOD_CATEGORIES,
|
|
645
|
+
C as SplittingAnimation,
|
|
646
|
+
b as calculateDisintegration,
|
|
647
|
+
k as fontSuggestions,
|
|
648
|
+
I as getFontFamily,
|
|
649
|
+
G as isFontLoaded,
|
|
650
|
+
N as loadGoogleFont,
|
|
651
|
+
B as loadGoogleFonts,
|
|
652
|
+
Y as refineFont,
|
|
653
|
+
T as refineSuggestion,
|
|
654
|
+
P as suggestFont,
|
|
655
|
+
y as suggestFonts
|
|
210
656
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var TypographyToolkit=function(d){"use strict";class u{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||20,l=o*.2,r=(n*10*e+l*5)%s-s/2;return{...t,y:r}}}class y{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||4,l=o*.2,h=Math.sin(n*.5*e+l)*s;return{...t,x:h}}}class f{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,n,i={}){const e=i.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*e,this.glitchY=(Math.random()-.5)*(e*.67),this.glitchRot=(Math.random()-.5)*e,this.lastUpdate=n),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class g{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||15,l=o*.2,r=-((n*8*e+l*4)%s-s/2);return{...t,y:r}}}function w(c,t){const{x:o,y:n,rotation:i,scale:e,opacity:s}=t;c.style.transform=`translate(${o}px, ${n}px) rotate(${i}deg) scale(${e})`,c.style.opacity=s.toString()}function x(c,t,o,n,i,e){if(!e.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const s=e.radius||80,l=e.strength||1,h=e.behaviors||["fall-away","split-apart","explode"],r=o-c,m=n-t,C=Math.sqrt(r*r+m*m);if(C>=s)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const a=(1-C/s)*l,T=Math.atan2(m,r),b=h[i%h.length];let p;switch(b){case"fall-away":const F=Math.cos(T)*a*20,S=Math.sin(T)*a*40+a*30;p={x:F,y:S,rotation:a*15,scale:1,opacity:1-a*.6};break;case"split-apart":const A=i%2===0?1:-1;p={x:A*a*50,y:(Math.random()-.5)*a*10,rotation:a*10*A,scale:1,opacity:1-a*.6};break;case"explode":const M=T+(Math.random()-.5)*.5;p={x:Math.cos(M)*a*40,y:Math.sin(M)*a*40,rotation:a*30,scale:1+a*.4,opacity:1-a*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class v{constructor(t){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.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.position&&(t.position.x!==void 0&&(this.textContainer.style.left=`${t.position.x}px`),t.position.y!==void 0&&(this.textContainer.style.top=`${t.position.y}px`)),this.createLetters(t.text),this.setupMouseTracking(),this.startAnimation(),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(t){t.toUpperCase().split("").forEach((n,i)=>{if(n===" "){const l=document.createTextNode(" ");this.textContainer.appendChild(l);return}const e=document.createElement("span");e.className="animated-letter",e.textContent=n,e.dataset.index=i.toString(),e.dataset.char=n,this.applyStyle(e),e.style.display="inline-block",e.style.position="relative",e.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(e);const s=e.getBoundingClientRect();this.letters.push({element:e,index:i,char:n,baseX:s.left,baseY:s.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)}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((n,i)=>{const e=n.element.getBoundingClientRect(),s=e.left+e.width/2,l=e.top+e.height/2,h=x(s,l,this.mouseX,this.mouseY,i,this.disintegration);let r;if(h.applied)r=h.state;else{const m=this.getAnimationType(i);r=this.getAnimation(m).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(m==="falling"||m==="floating"?20:4)})}w(n.element,r)}),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 u;case"splitting":return new y;case"glitching":return new f;case"floating":return new g;default:return new u}}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),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}}return typeof window<"u"&&(window.TypographyToolkit={AnimatedText:v,FallingAnimation:u,SplittingAnimation:y,GlitchingAnimation:f,FloatingAnimation:g,calculateDisintegration:x}),d.AnimatedText=v,d.FallingAnimation=u,d.FloatingAnimation=g,d.GlitchingAnimation=f,d.SplittingAnimation=y,d.calculateDisintegration=x,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d}({});
|
|
1
|
+
var TypographyToolkit=function(g){"use strict";class f{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class C{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function S(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,d=Math.sqrt(c*c+h*h);if(d>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-d/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let p;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;p={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;p={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;p={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:p={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:p,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=S(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const d=this.getAnimationType(t);c=this.getAnimation(d).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed,amplitude:this.amplitude*(d==="falling"||d==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new f;case"splitting":return new F;case"glitching":return new v;case"floating":return new C;default:return new f}}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],M=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function A(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function D(s){return Promise.all(s.map(e=>N(e)))}function E(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const d of a.categories)o.includes(d)&&(c+=5);for(const d of i)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c+=15);for(const d of t)(a.categories.some(m=>m.includes(d)||d.includes(m))||a.name.toLowerCase().includes(d)||a.description.toLowerCase().includes(d))&&(c-=20);const h=i.some(d=>d.includes("striking")||d.includes("artistic")||d.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:f,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:C,calculateDisintegration:S,fontSuggestions:k,suggestFonts:y,suggestFont:A,loadGoogleFont:N,loadGoogleFonts:D,isFontLoaded:E,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:M};window.TypographyToolkit=s,window.AnimatedText=b}return g.AnimatedText=b,g.FallingAnimation=f,g.FloatingAnimation=C,g.GlitchingAnimation=v,g.INTENSITY_CATEGORIES=M,g.MOOD_CATEGORIES=x,g.SplittingAnimation=F,g.calculateDisintegration=S,g.fontSuggestions=k,g.getFontFamily=H,g.isFontLoaded=E,g.loadGoogleFont=N,g.loadGoogleFonts=D,g.refineFont=R,g.refineSuggestion=T,g.suggestFont=A,g.suggestFonts=y,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),g}({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(l,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(l=typeof globalThis<"u"?globalThis:l||self,p(l.TypographyToolkit={}))})(this,function(l){"use strict";class p{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||20,r=o*.2,c=(n*10*e+r*5)%s-s/2;return{...t,y:c}}}class y{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||4,r=o*.2,d=Math.sin(n*.5*e+r)*s;return{...t,x:d}}}class f{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(t,o,n,i={}){const e=i.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*e,this.glitchY=(Math.random()-.5)*(e*.67),this.glitchRot=(Math.random()-.5)*e,this.lastUpdate=n),{...t,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class g{update(t,o,n,i={}){const e=i.speed||1,s=i.amplitude||15,r=o*.2,c=-((n*8*e+r*4)%s-s/2);return{...t,y:c}}}function b(h,t){const{x:o,y:n,rotation:i,scale:e,opacity:s}=t;h.style.transform=`translate(${o}px, ${n}px) rotate(${i}deg) scale(${e})`,h.style.opacity=s.toString()}function x(h,t,o,n,i,e){if(!e.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const s=e.radius||80,r=e.strength||1,d=e.behaviors||["fall-away","split-apart","explode"],c=o-h,u=n-t,T=Math.sqrt(c*c+u*u);if(T>=s)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const a=(1-T/s)*r,C=Math.atan2(u,c),w=d[i%d.length];let m;switch(w){case"fall-away":const F=Math.cos(C)*a*20,S=Math.sin(C)*a*40+a*30;m={x:F,y:S,rotation:a*15,scale:1,opacity:1-a*.6};break;case"split-apart":const v=i%2===0?1:-1;m={x:v*a*50,y:(Math.random()-.5)*a*10,rotation:a*10*v,scale:1,opacity:1-a*.6};break;case"explode":const M=C+(Math.random()-.5)*.5;m={x:Math.cos(M)*a*40,y:Math.sin(M)*a*40,rotation:a*30,scale:1+a*.4,opacity:1-a*.6};break;default:m={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:m,applied:!0}}class A{constructor(t){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.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",t.position&&(t.position.x!==void 0&&(this.textContainer.style.left=`${t.position.x}px`),t.position.y!==void 0&&(this.textContainer.style.top=`${t.position.y}px`)),this.createLetters(t.text),this.setupMouseTracking(),this.startAnimation(),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(t){t.toUpperCase().split("").forEach((n,i)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const e=document.createElement("span");e.className="animated-letter",e.textContent=n,e.dataset.index=i.toString(),e.dataset.char=n,this.applyStyle(e),e.style.display="inline-block",e.style.position="relative",e.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(e);const s=e.getBoundingClientRect();this.letters.push({element:e,index:i,char:n,baseX:s.left,baseY:s.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)}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((n,i)=>{const e=n.element.getBoundingClientRect(),s=e.left+e.width/2,r=e.top+e.height/2,d=x(s,r,this.mouseX,this.mouseY,i,this.disintegration);let c;if(d.applied)c=d.state;else{const u=this.getAnimationType(i);c=this.getAnimation(u).update({x:0,y:0,rotation:0,scale:1,opacity:1},i,o,{speed:this.speed,amplitude:this.amplitude*(u==="falling"||u==="floating"?20:4)})}b(n.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 p;case"splitting":return new y;case"glitching":return new f;case"floating":return new g;default:return new p}}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),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}}typeof window<"u"&&(window.TypographyToolkit={AnimatedText:A,FallingAnimation:p,SplittingAnimation:y,GlitchingAnimation:f,FloatingAnimation:g,calculateDisintegration:x}),l.AnimatedText=A,l.FallingAnimation=p,l.FloatingAnimation=g,l.GlitchingAnimation=f,l.SplittingAnimation=y,l.calculateDisintegration=x,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(d,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(d=typeof globalThis<"u"?globalThis:d||self,p(d.TypographyToolkit={}))})(this,function(d){"use strict";class p{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||20,r=o*.2,c=(n*10*i+r*5)%l-l/2;return{...e,y:c}}}class F{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||4,r=o*.2,a=Math.sin(n*.5*i+r)*l;return{...e,x:a}}}class v{constructor(){this.lastUpdate=0,this.glitchX=0,this.glitchY=0,this.glitchRot=0}update(e,o,n,t={}){const i=t.amplitude||3;return n-this.lastUpdate>.1&&(this.glitchX=(Math.random()-.5)*i,this.glitchY=(Math.random()-.5)*(i*.67),this.glitchRot=(Math.random()-.5)*i,this.lastUpdate=n),{...e,x:this.glitchX,y:this.glitchY,rotation:this.glitchRot}}}class C{update(e,o,n,t={}){const i=t.speed||1,l=t.amplitude||15,r=o*.2,c=-((n*8*i+r*4)%l-l/2);return{...e,y:c}}}function G(s,e){const{x:o,y:n,rotation:t,scale:i,opacity:l}=e;s.style.transform=`translate(${o}px, ${n}px) rotate(${t}deg) scale(${i})`,s.style.opacity=l.toString()}function S(s,e,o,n,t,i){if(!i.enabled)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const l=i.radius||80,r=i.strength||1,a=i.behaviors||["fall-away","split-apart","explode"],c=o-s,h=n-e,g=Math.sqrt(c*c+h*h);if(g>=l)return{state:{x:0,y:0,rotation:0,scale:1,opacity:1},applied:!1};const u=(1-g/l)*r,m=Math.atan2(h,c),B=a[t%a.length];let f;switch(B){case"fall-away":const Y=Math.cos(m)*u*20,$=Math.sin(m)*u*40+u*30;f={x:Y,y:$,rotation:u*15,scale:1,opacity:1-u*.6};break;case"split-apart":const L=t%2===0?1:-1;f={x:L*u*50,y:(Math.random()-.5)*u*10,rotation:u*10*L,scale:1,opacity:1-u*.6};break;case"explode":const O=m+(Math.random()-.5)*.5;f={x:Math.cos(O)*u*40,y:Math.sin(O)*u*40,rotation:u*30,scale:1+u*.4,opacity:1-u*.6};break;default:f={x:0,y:0,rotation:0,scale:1,opacity:1}}return{state:f,applied:!0}}class b{constructor(e){var o;if(this.letters=[],this.animationFrame=null,this.mouseX=0,this.mouseY=0,this.mouseMoveHandler=null,this.startTime=Date.now(),this.isDestroyed=!1,this.container=e.container,this.animationTypes=e.animations||["falling","splitting","glitching","floating"],this.cycle=e.cycle!==!1,this.speed=e.speed||1,this.amplitude=e.amplitude||1,this.disintegration=e.disintegration||{enabled:!1},this.style=e.style||{},this.fadeOut=e.fadeOut||0,this.callbacks=e.callbacks,this.textContainer=document.createElement("div"),this.textContainer.style.position="absolute",this.textContainer.style.pointerEvents="none",this.textContainer.style.zIndex="1",e.containerClass&&(this.textContainer.className=e.containerClass),e.containerStyle&&Object.entries(e.containerStyle).forEach(([n,t])=>{this.textContainer.style.setProperty(n,t)}),e.position){let n=e.position.x,t=e.position.y;if(e.position.constrainToViewport){this.container.getBoundingClientRect();const i=window.innerWidth,l=window.innerHeight,r=e.text.length*20;n!==void 0&&(n=Math.max(0,Math.min(n,i-r))),t!==void 0&&(t=Math.max(0,Math.min(t,l-50)))}n!==void 0&&(this.textContainer.style.left=`${n}px`),t!==void 0&&(this.textContainer.style.top=`${t}px`)}this.createLetters(e.text),this.setupMouseTracking(),this.startAnimation(),(o=this.callbacks)!=null&&o.onCreate&&this.callbacks.onCreate(this.textContainer),this.fadeOut>0&&setTimeout(()=>this.destroy(),this.fadeOut)}createLetters(e){e.toUpperCase().split("").forEach((n,t)=>{if(n===" "){const r=document.createTextNode(" ");this.textContainer.appendChild(r);return}const i=document.createElement("span");i.className="animated-letter",i.textContent=n,i.dataset.index=t.toString(),i.dataset.char=n,this.applyStyle(i),i.style.display="inline-block",i.style.position="relative",i.style.transition="transform 0.1s ease-out",this.textContainer.appendChild(i);const l=i.getBoundingClientRect();this.letters.push({element:i,index:t,char:n,baseX:l.left,baseY:l.top})}),this.container.appendChild(this.textContainer)}applyStyle(e){this.style.fontFamily&&(e.style.fontFamily=this.style.fontFamily),this.style.fontSize&&(e.style.fontSize=`${this.style.fontSize}px`),this.style.color&&(e.style.color=this.style.color),this.style.fontWeight&&(e.style.fontWeight=this.style.fontWeight),this.style.textShadow&&(e.style.textShadow=this.style.textShadow),this.style.letterSpacing&&(e.style.letterSpacing=this.style.letterSpacing),this.style.textTransform&&(e.style.textTransform=this.style.textTransform)}setupMouseTracking(){this.disintegration.enabled&&(this.mouseMoveHandler=e=>{this.mouseX=e.clientX,this.mouseY=e.clientY},document.addEventListener("mousemove",this.mouseMoveHandler))}startAnimation(){const e=()=>{if(this.isDestroyed)return;const o=(Date.now()-this.startTime)*.001;this.letters.forEach((n,t)=>{var h;const i=n.element.getBoundingClientRect(),l=i.left+i.width/2,r=i.top+i.height/2,a=S(l,r,this.mouseX,this.mouseY,t,this.disintegration);let c;if(a.applied)c=a.state,(h=this.callbacks)!=null&&h.onDisintegrate&&this.callbacks.onDisintegrate(t);else{const g=this.getAnimationType(t);c=this.getAnimation(g).update({x:0,y:0,rotation:0,scale:1,opacity:1},t,o,{speed:this.speed,amplitude:this.amplitude*(g==="falling"||g==="floating"?20:4)})}G(n.element,c)}),this.animationFrame=requestAnimationFrame(e)};this.animationFrame=requestAnimationFrame(e)}getAnimationType(e){return this.cycle?this.animationTypes[e%this.animationTypes.length]:this.animationTypes[0]}getAnimation(e){switch(e){case"falling":return new p;case"splitting":return new F;case"glitching":return new v;case"floating":return new C;default:return new p}}destroy(){var e;this.isDestroyed||(this.isDestroyed=!0,this.animationFrame!==null&&cancelAnimationFrame(this.animationFrame),this.mouseMoveHandler&&document.removeEventListener("mousemove",this.mouseMoveHandler),(e=this.callbacks)!=null&&e.onDestroy&&this.callbacks.onDestroy(),this.textContainer.style.transition="opacity 3s ease",this.textContainer.style.opacity="0",setTimeout(()=>{this.textContainer.parentNode&&this.textContainer.parentNode.removeChild(this.textContainer)},3e3))}getElement(){return this.textContainer}}const x=["unsettling","eerie","decayed","weathered","organic","imperfect","uneven","scratchy"],M=["subtle","moderate","intense"],k=[{name:"Hand-drawn Casual",googleFontsName:"Caveat",categories:["hand-drawn","handwriting","casual","sketchy","informal"],description:"Casual handwritten style, friendly and approachable",artistic:!1},{name:"Hand-drawn Playful",googleFontsName:"Finger Paint",categories:["hand-drawn","playful","childlike","casual","sketchy"],description:"Bold hand-drawn style, playful and energetic",artistic:!0},{name:"Hand-drawn Script",googleFontsName:"Dancing Script",categories:["hand-drawn","script","elegant","flowing","cursive"],description:"Elegant flowing script, graceful and organic",artistic:!1},{name:"Gothic Blackletter",googleFontsName:"UnifrakturMaguntia",categories:["gothic","medieval","blackletter","ornate","historical"],description:"Medieval blackletter style, ornate and historical",artistic:!0},{name:"Gothic Horror",googleFontsName:"Creepster",categories:["gothic","horror","creepy","dripping","display","striking","intense"],description:"Horror-style font with dripping effects, very striking",artistic:!0},{name:"Gothic Bold",googleFontsName:"Eater",categories:["gothic","bold","aggressive","display","striking"],description:"Bold aggressive display font, powerful impact",artistic:!0},{name:"Futuristic Digital",googleFontsName:"Orbitron",categories:["futuristic","sci-fi","digital","tech","modern","geometric"],description:"Futuristic geometric font, tech-forward and modern",artistic:!0},{name:"Futuristic Display",googleFontsName:"Bungee",categories:["futuristic","display","bold","condensed","striking"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Futuristic Outline",googleFontsName:"Bungee Shade",categories:["futuristic","outline","display","bold","striking"],description:"Outlined version of Bungee, bold and striking",artistic:!0},{name:"Retro Terminal",googleFontsName:"VT323",categories:["retro","terminal","monospace","pixel","80s","tech"],description:"Retro terminal font, pixelated and nostalgic",artistic:!0},{name:"Retro Pixel",googleFontsName:"Press Start 2P",categories:["retro","pixel","8-bit","arcade","nostalgic","display"],description:"8-bit pixel font, classic arcade style",artistic:!0},{name:"Retro Display",googleFontsName:"Frijole",categories:["retro","playful","rounded","display","casual"],description:"Playful rounded retro font, fun and casual",artistic:!0},{name:"Decorative Ornate",googleFontsName:"Fascinate",categories:["decorative","ornate","display","striking","elaborate"],description:"Highly decorative display font, ornate and elaborate",artistic:!0},{name:"Decorative Outline",googleFontsName:"Fascinate Inline",categories:["decorative","outline","display","ornate","striking"],description:"Outlined decorative font, ornate and striking",artistic:!0},{name:"Decorative Script",googleFontsName:"Fredericka the Great",categories:["decorative","script","ornate","elegant","display"],description:"Elegant decorative script, ornate and sophisticated",artistic:!0},{name:"Horror Dripping",googleFontsName:"Nosifer",categories:["horror","creepy","dripping","blood","striking","display","intense"],description:"Creepy font with blood-dripping effects, very striking",artistic:!0},{name:"Tech Monospace",googleFontsName:"Share Tech Mono",categories:["tech","monospace","terminal","code","modern"],description:"Clean tech monospace font, modern and readable",artistic:!1},{name:"Tech Display",googleFontsName:"Rajdhani",categories:["tech","modern","geometric","sans-serif","futuristic"],description:"Modern geometric tech font, clean and futuristic",artistic:!1},{name:"Organic Flowing",googleFontsName:"Dancing Script",categories:["organic","flowing","natural","script","elegant"],description:"Flowing organic script, natural and elegant",artistic:!1},{name:"Modern Sans",googleFontsName:"Roboto",categories:["modern","clean","sans-serif","readable","professional"],description:"Clean modern sans-serif, professional and readable",artistic:!1},{name:"Modern Serif",googleFontsName:"Playfair Display",categories:["modern","serif","elegant","sophisticated","readable"],description:"Elegant modern serif, sophisticated and readable",artistic:!1},{name:"Bold Condensed",googleFontsName:"Bungee",categories:["bold","condensed","display","striking","impact"],description:"Bold condensed display font, high impact",artistic:!0},{name:"Bold Aggressive",googleFontsName:"Eater",categories:["bold","aggressive","display","striking","powerful"],description:"Bold aggressive display font, powerful and striking",artistic:!0},{name:"Handwritten Thin",googleFontsName:"Amatic SC",categories:["hand-drawn","uneven","organic","unsettling","subtle","scratchy"],description:"Thin hand-drawn letters with subtle irregularity, organic feel",artistic:!0},{name:"Rough Handwriting",googleFontsName:"Rock Salt",categories:["hand-drawn","scratchy","weathered","rough","unsettling","moderate"],description:"Rough, weathered handwriting with natural imperfection",artistic:!0},{name:"Typewriter Degraded",googleFontsName:"Special Elite",categories:["typewriter","decayed","weathered","imperfect","unsettling","moderate"],description:"Degraded typewriter font, vintage with imperfection",artistic:!0},{name:"Casual Handwriting",googleFontsName:"Handlee",categories:["hand-drawn","casual","imperfect","organic","subtle"],description:"Casual handwriting with subtle imperfection",artistic:!1},{name:"Childlike Organic",googleFontsName:"Indie Flower",categories:["hand-drawn","childlike","organic","imperfect","eerie","subtle"],description:"Childlike handwriting, can feel innocent or eerie depending on context",artistic:!1},{name:"Scratchy Personal",googleFontsName:"Shadows Into Light",categories:["hand-drawn","scratchy","personal","unsettling","uneven","moderate"],description:"Scratchy personal handwriting with unsettling quality",artistic:!0},{name:"Hurried Scratchy",googleFontsName:"Reenie Beanie",categories:["hand-drawn","scratchy","hurried","uneven","unsettling","moderate"],description:"Hurried scratchy handwriting with nervous energy",artistic:!0},{name:"Architectural Irregular",googleFontsName:"Architects Daughter",categories:["hand-drawn","imperfect","uneven","organic","subtle"],description:"Hand-drawn with architectural irregularity",artistic:!1},{name:"Informal Unsettling",googleFontsName:"Coming Soon",categories:["hand-drawn","informal","imperfect","unsettling","subtle"],description:"Informal handwriting that feels slightly off",artistic:!1},{name:"Manic Handwriting",googleFontsName:"Gloria Hallelujah",categories:["hand-drawn","playful","manic","uneven","unsettling","moderate"],description:"Playful handwriting that can feel manic or unsettled",artistic:!0},{name:"Quick Imperfect",googleFontsName:"Just Another Hand",categories:["hand-drawn","scratchy","quick","imperfect","uneven","subtle"],description:"Quick scratchy handwriting with natural imperfection",artistic:!1},{name:"Organic Handwriting",googleFontsName:"Kalam",categories:["hand-drawn","organic","natural","flowing","subtle"],description:"Organic natural handwriting with flowing quality",artistic:!1},{name:"Flowing Tension",googleFontsName:"Satisfy",categories:["script","flowing","tension","elegant","unsettling","subtle"],description:"Flowing script with underlying tension",artistic:!0},{name:"Unsettling Elegance",googleFontsName:"Yellowtail",categories:["script","elegant","stylized","unsettling","uneven","moderate"],description:"Stylized elegance with unsettling undertones",artistic:!0},{name:"Typewriter Imperfect",googleFontsName:"Cutive Mono",categories:["typewriter","monospace","imperfect","decayed","vintage","subtle"],description:"Imperfect vintage typewriter with character",artistic:!0}];function I(s){const e=s.toLowerCase().split(/\s+/).filter(t=>t.length>0),o=[],n=[];for(const t of e)t.startsWith("-")&&t.length>1?n.push(t.slice(1)):o.push(t);return{positive:o,negative:n}}function P(s,e){const o=new Set,n=new Map,t=2,i=[];for(const l of s){if(i.length>=e)break;if(o.has(l.font.googleFontsName))continue;const r=l.font.categories[0],a=n.get(r)||0;a>=t||(o.add(l.font.googleFontsName),n.set(r,a+1),i.push(l.font))}return i}function y(s,e){const{positive:o,negative:n}=I(s),t=(e==null?void 0:e.limit)??10,l=k.map(r=>{let a=0;for(const c of o){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a+=10);r.name.toLowerCase().includes(c)&&(a+=15),r.description.toLowerCase().includes(c)&&(a+=8)}for(const c of n){for(const h of r.categories)(h.includes(c)||c.includes(h))&&(a-=20);r.name.toLowerCase().includes(c)&&(a-=15),r.description.toLowerCase().includes(c)&&(a-=10)}return r.artistic&&(a+=1),{font:r,score:a}}).filter(r=>r.score>0).sort((r,a)=>a.score-r.score);return P(l,t)}function A(s){return y(s)[0]}const w=new Set;function N(s){return new Promise((e,o)=>{const n=s.replace(/\s+/g,"+");if(w.has(n)){e();return}if(document.querySelector(`link[href*="fonts.googleapis.com"][href*="${n}"]`)){w.add(n),e();return}const i=document.createElement("link");i.rel="stylesheet",i.href=`https://fonts.googleapis.com/css2?family=${n}:wght@400&display=swap`,i.onload=()=>{w.add(n),e()},i.onerror=()=>{console.warn(`Failed to load Google Font: ${s}`),o(new Error(`Failed to load Google Font: ${s}`))},document.head.appendChild(i)})}function D(s){return Promise.all(s.map(e=>N(e)))}function E(s){const e=s.replace(/\s+/g,"+");return w.has(e)}function H(s,e="sans-serif"){const o=["Caveat","Dancing Script","Finger Paint","Fredericka the Great","Amatic SC","Handlee","Indie Flower","Shadows Into Light","Rock Salt","Reenie Beanie","Architects Daughter","Coming Soon","Gloria Hallelujah","Just Another Hand","Kalam","Satisfy","Yellowtail"],n=["VT323","Press Start 2P","Share Tech Mono","Special Elite","Cutive Mono"];let t=e;return o.includes(s)?t="cursive":n.includes(s)&&(t="monospace"),`'${s}', ${t}`}function T(s,e){const o=s.toLowerCase(),n=e.rejectedFont.toLowerCase(),t=e.negativeAspects.map(a=>a.toLowerCase()),i=e.positiveAspects.map(a=>a.toLowerCase());return y(s).filter(a=>a.googleFontsName.toLowerCase()!==n&&a.name.toLowerCase()!==n).map(a=>{let c=0;for(const g of a.categories)o.includes(g)&&(c+=5);for(const g of i)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c+=15);for(const g of t)(a.categories.some(m=>m.includes(g)||g.includes(m))||a.name.toLowerCase().includes(g)||a.description.toLowerCase().includes(g))&&(c-=20);const h=i.some(g=>g.includes("striking")||g.includes("artistic")||g.includes("unique"));return h&&a.artistic&&(c+=10),h&&!a.artistic&&(c-=5),{font:a,score:c}}).filter(a=>a.score>0).sort((a,c)=>c.score-a.score).map(a=>a.font)}function R(s,e){return T(s,e)[0]}if(typeof window<"u"){const s={AnimatedText:b,FallingAnimation:p,SplittingAnimation:F,GlitchingAnimation:v,FloatingAnimation:C,calculateDisintegration:S,fontSuggestions:k,suggestFonts:y,suggestFont:A,loadGoogleFont:N,loadGoogleFonts:D,isFontLoaded:E,getFontFamily:H,refineSuggestion:T,refineFont:R,MOOD_CATEGORIES:x,INTENSITY_CATEGORIES:M};window.TypographyToolkit=s,window.AnimatedText=b}d.AnimatedText=b,d.FallingAnimation=p,d.FloatingAnimation=C,d.GlitchingAnimation=v,d.INTENSITY_CATEGORIES=M,d.MOOD_CATEGORIES=x,d.SplittingAnimation=F,d.calculateDisintegration=S,d.fontSuggestions=k,d.getFontFamily=H,d.isFontLoaded=E,d.loadGoogleFont=N,d.loadGoogleFonts=D,d.refineFont=R,d.refineSuggestion=T,d.suggestFont=A,d.suggestFonts=y,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typography-toolkit",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Letter-by-letter text animations with proximity-based disintegration effects",
|
|
3
|
+
"version": "1.2.1",
|
|
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",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
"letters",
|
|
24
24
|
"disintegration",
|
|
25
25
|
"interactive",
|
|
26
|
-
"dom"
|
|
26
|
+
"dom",
|
|
27
|
+
"fonts",
|
|
28
|
+
"google-fonts",
|
|
29
|
+
"font-selection"
|
|
27
30
|
],
|
|
28
31
|
"author": "",
|
|
29
32
|
"license": "MIT",
|