typography-toolkit 1.0.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.
- package/README.md +207 -0
- package/dist/typography-toolkit.es.js +210 -0
- package/dist/typography-toolkit.iife.js +1 -0
- package/dist/typography-toolkit.umd.js +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Typography Toolkit
|
|
2
|
+
|
|
3
|
+
Letter-by-letter text animations with proximity-based disintegration effects. Create animated text where each letter moves independently with base animations (falling, splitting, glitching, floating) and reacts to cursor proximity.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Letter-by-Letter Control** - Each letter is a separate DOM element with independent animations
|
|
8
|
+
- **Base Animations** - Falling, splitting, glitching, and floating animations
|
|
9
|
+
- **Proximity-Based Disintegration** - Letters react to cursor without direct interaction
|
|
10
|
+
- **DOM-Based** - Uses CSS transforms (GPU-accelerated), accessible, and styleable
|
|
11
|
+
- **Modular & Extensible** - Easy to add new animation types and behaviors
|
|
12
|
+
- **Zero Dependencies** - Vanilla TypeScript/JavaScript
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### npm
|
|
17
|
+
```bash
|
|
18
|
+
npm install typography-toolkit
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### CDN (UMD)
|
|
22
|
+
```html
|
|
23
|
+
<script src="https://unpkg.com/typography-toolkit/dist/typography-toolkit.umd.js"></script>
|
|
24
|
+
<script>
|
|
25
|
+
const { AnimatedText } = TypographyToolkit;
|
|
26
|
+
</script>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### ES Modules
|
|
30
|
+
```javascript
|
|
31
|
+
import { AnimatedText } from 'typography-toolkit';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
### Basic Usage
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { AnimatedText } from 'typography-toolkit';
|
|
40
|
+
|
|
41
|
+
const text = new AnimatedText({
|
|
42
|
+
text: 'HELLO',
|
|
43
|
+
container: document.body,
|
|
44
|
+
animations: ['falling', 'glitching']
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Clean up when done
|
|
48
|
+
setTimeout(() => text.destroy(), 10000);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### With Disintegration
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
const text = new AnimatedText({
|
|
55
|
+
text: 'FEED ME',
|
|
56
|
+
container: document.body,
|
|
57
|
+
animations: ['falling', 'splitting'],
|
|
58
|
+
disintegration: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
radius: 80,
|
|
61
|
+
behaviors: ['fall-away', 'explode'],
|
|
62
|
+
strength: 0.8
|
|
63
|
+
},
|
|
64
|
+
style: {
|
|
65
|
+
fontFamily: 'Arial',
|
|
66
|
+
fontSize: 24,
|
|
67
|
+
color: 'rgba(60, 60, 60, 0.8)'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Advanced Usage
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
const text = new AnimatedText({
|
|
76
|
+
text: 'ANIMATED TEXT',
|
|
77
|
+
container: document.getElementById('container'),
|
|
78
|
+
animations: ['falling', 'splitting', 'glitching', 'floating'],
|
|
79
|
+
cycle: true, // Cycle through animation types per letter
|
|
80
|
+
speed: 1.5, // Animation speed multiplier
|
|
81
|
+
amplitude: 1.2, // Animation amplitude multiplier
|
|
82
|
+
disintegration: {
|
|
83
|
+
enabled: true,
|
|
84
|
+
radius: 100,
|
|
85
|
+
behaviors: ['fall-away', 'split-apart', 'explode'],
|
|
86
|
+
strength: 1.0
|
|
87
|
+
},
|
|
88
|
+
style: {
|
|
89
|
+
fontFamily: 'Georgia, serif',
|
|
90
|
+
fontSize: 32,
|
|
91
|
+
color: 'rgba(100, 50, 50, 0.9)',
|
|
92
|
+
fontWeight: 'bold'
|
|
93
|
+
},
|
|
94
|
+
position: {
|
|
95
|
+
x: 100,
|
|
96
|
+
y: 200
|
|
97
|
+
},
|
|
98
|
+
fadeOut: 8000 // Auto-destroy after 8 seconds
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## API Reference
|
|
103
|
+
|
|
104
|
+
### `AnimatedText`
|
|
105
|
+
|
|
106
|
+
Main class for creating animated text.
|
|
107
|
+
|
|
108
|
+
#### Constructor Options
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
interface AnimatedTextOptions {
|
|
112
|
+
text: string; // Text to animate
|
|
113
|
+
container: HTMLElement; // Container element
|
|
114
|
+
animations?: AnimationType[]; // Animation types (default: all)
|
|
115
|
+
cycle?: boolean; // Cycle through types per letter (default: true)
|
|
116
|
+
speed?: number; // Speed multiplier (default: 1.0)
|
|
117
|
+
amplitude?: number; // Amplitude multiplier (default: 1.0)
|
|
118
|
+
disintegration?: DisintegrationOptions; // Disintegration config
|
|
119
|
+
style?: StyleOptions; // CSS style options
|
|
120
|
+
position?: { x?: number; y?: number }; // Position (default: random)
|
|
121
|
+
fadeOut?: number; // Auto-destroy after ms (default: 0 = never)
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Methods
|
|
126
|
+
|
|
127
|
+
- `destroy()` - Clean up and remove the animated text
|
|
128
|
+
- `getElement()` - Get the text container element
|
|
129
|
+
|
|
130
|
+
### Animation Types
|
|
131
|
+
|
|
132
|
+
- `'falling'` - Letters drift downward
|
|
133
|
+
- `'splitting'` - Letters drift outward horizontally
|
|
134
|
+
- `'glitching'` - Letters randomly shift position
|
|
135
|
+
- `'floating'` - Letters slowly rise
|
|
136
|
+
|
|
137
|
+
### Disintegration Behaviors
|
|
138
|
+
|
|
139
|
+
- `'fall-away'` - Letters drop down when cursor approaches
|
|
140
|
+
- `'split-apart'` - Letters spread horizontally
|
|
141
|
+
- `'explode'` - Letters scatter in all directions
|
|
142
|
+
|
|
143
|
+
### Style Options
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
interface StyleOptions {
|
|
147
|
+
fontFamily?: string;
|
|
148
|
+
fontSize?: number;
|
|
149
|
+
color?: string;
|
|
150
|
+
fontWeight?: string;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Examples
|
|
155
|
+
|
|
156
|
+
### Simple Falling Text
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const text = new AnimatedText({
|
|
160
|
+
text: 'FALLING',
|
|
161
|
+
container: document.body,
|
|
162
|
+
animations: ['falling']
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Glitching Text with Disintegration
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
const text = new AnimatedText({
|
|
170
|
+
text: 'GLITCH',
|
|
171
|
+
container: document.body,
|
|
172
|
+
animations: ['glitching'],
|
|
173
|
+
disintegration: {
|
|
174
|
+
enabled: true,
|
|
175
|
+
radius: 60,
|
|
176
|
+
behaviors: ['explode']
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Multiple Animation Types
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
const text = new AnimatedText({
|
|
185
|
+
text: 'VARIED',
|
|
186
|
+
container: document.body,
|
|
187
|
+
animations: ['falling', 'splitting', 'glitching', 'floating'],
|
|
188
|
+
cycle: true // Each letter uses different animation
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Performance
|
|
193
|
+
|
|
194
|
+
- Uses `requestAnimationFrame` for smooth 60fps animations
|
|
195
|
+
- CSS transforms are GPU-accelerated
|
|
196
|
+
- Efficient proximity calculations
|
|
197
|
+
- Automatic cleanup on destroy
|
|
198
|
+
|
|
199
|
+
## Browser Support
|
|
200
|
+
|
|
201
|
+
- Modern browsers with ES2020 support
|
|
202
|
+
- Requires `requestAnimationFrame` API
|
|
203
|
+
- CSS transforms support
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
class y {
|
|
2
|
+
update(t, o, s, i = {}) {
|
|
3
|
+
const e = i.speed || 1, a = i.amplitude || 20, l = o * 0.2, r = (s * 10 * e + l * 5) % a - a / 2;
|
|
4
|
+
return {
|
|
5
|
+
...t,
|
|
6
|
+
y: r
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
class x {
|
|
11
|
+
update(t, o, s, i = {}) {
|
|
12
|
+
const e = i.speed || 1, a = i.amplitude || 4, l = o * 0.2, h = Math.sin(s * 0.5 * e + l) * a;
|
|
13
|
+
return {
|
|
14
|
+
...t,
|
|
15
|
+
x: h
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
class C {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.lastUpdate = 0, this.glitchX = 0, this.glitchY = 0, this.glitchRot = 0;
|
|
22
|
+
}
|
|
23
|
+
update(t, o, s, i = {}) {
|
|
24
|
+
const e = i.amplitude || 3;
|
|
25
|
+
return s - this.lastUpdate > 0.1 && (this.glitchX = (Math.random() - 0.5) * e, this.glitchY = (Math.random() - 0.5) * (e * 0.67), this.glitchRot = (Math.random() - 0.5) * e, this.lastUpdate = s), {
|
|
26
|
+
...t,
|
|
27
|
+
x: this.glitchX,
|
|
28
|
+
y: this.glitchY,
|
|
29
|
+
rotation: this.glitchRot
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class T {
|
|
34
|
+
update(t, o, s, i = {}) {
|
|
35
|
+
const e = i.speed || 1, a = i.amplitude || 15, l = o * 0.2, r = -((s * 8 * e + l * 4) % a - a / 2);
|
|
36
|
+
return {
|
|
37
|
+
...t,
|
|
38
|
+
y: r
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function b(c, t) {
|
|
43
|
+
const { x: o, y: s, rotation: i, scale: e, opacity: a } = t;
|
|
44
|
+
c.style.transform = `translate(${o}px, ${s}px) rotate(${i}deg) scale(${e})`, c.style.opacity = a.toString();
|
|
45
|
+
}
|
|
46
|
+
function v(c, t, o, s, i, e) {
|
|
47
|
+
if (!e.enabled)
|
|
48
|
+
return {
|
|
49
|
+
state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
|
|
50
|
+
applied: !1
|
|
51
|
+
};
|
|
52
|
+
const a = e.radius || 80, l = e.strength || 1, h = e.behaviors || ["fall-away", "split-apart", "explode"], r = o - c, d = s - t, m = Math.sqrt(r * r + d * d);
|
|
53
|
+
if (m >= a)
|
|
54
|
+
return {
|
|
55
|
+
state: { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
|
|
56
|
+
applied: !1
|
|
57
|
+
};
|
|
58
|
+
const n = (1 - m / a) * l, u = Math.atan2(d, r), M = h[i % h.length];
|
|
59
|
+
let p;
|
|
60
|
+
switch (M) {
|
|
61
|
+
case "fall-away":
|
|
62
|
+
const w = Math.cos(u) * n * 20, A = Math.sin(u) * n * 40 + n * 30;
|
|
63
|
+
p = {
|
|
64
|
+
x: w,
|
|
65
|
+
y: A,
|
|
66
|
+
rotation: n * 15,
|
|
67
|
+
scale: 1,
|
|
68
|
+
opacity: 1 - n * 0.6
|
|
69
|
+
};
|
|
70
|
+
break;
|
|
71
|
+
case "split-apart":
|
|
72
|
+
const f = i % 2 === 0 ? 1 : -1;
|
|
73
|
+
p = {
|
|
74
|
+
x: f * n * 50,
|
|
75
|
+
y: (Math.random() - 0.5) * n * 10,
|
|
76
|
+
rotation: n * 10 * f,
|
|
77
|
+
scale: 1,
|
|
78
|
+
opacity: 1 - n * 0.6
|
|
79
|
+
};
|
|
80
|
+
break;
|
|
81
|
+
case "explode":
|
|
82
|
+
const g = u + (Math.random() - 0.5) * 0.5;
|
|
83
|
+
p = {
|
|
84
|
+
x: Math.cos(g) * n * 40,
|
|
85
|
+
y: Math.sin(g) * n * 40,
|
|
86
|
+
rotation: n * 30,
|
|
87
|
+
scale: 1 + n * 0.4,
|
|
88
|
+
opacity: 1 - n * 0.6
|
|
89
|
+
};
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
p = { x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 };
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
state: p,
|
|
96
|
+
applied: !0
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
class F {
|
|
100
|
+
constructor(t) {
|
|
101
|
+
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);
|
|
102
|
+
}
|
|
103
|
+
createLetters(t) {
|
|
104
|
+
t.toUpperCase().split("").forEach((s, i) => {
|
|
105
|
+
if (s === " ") {
|
|
106
|
+
const l = document.createTextNode(" ");
|
|
107
|
+
this.textContainer.appendChild(l);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const e = document.createElement("span");
|
|
111
|
+
e.className = "animated-letter", e.textContent = s, e.dataset.index = i.toString(), e.dataset.char = s, this.applyStyle(e), e.style.display = "inline-block", e.style.position = "relative", e.style.transition = "transform 0.1s ease-out", this.textContainer.appendChild(e);
|
|
112
|
+
const a = e.getBoundingClientRect();
|
|
113
|
+
this.letters.push({
|
|
114
|
+
element: e,
|
|
115
|
+
index: i,
|
|
116
|
+
char: s,
|
|
117
|
+
baseX: a.left,
|
|
118
|
+
baseY: a.top
|
|
119
|
+
});
|
|
120
|
+
}), this.container.appendChild(this.textContainer);
|
|
121
|
+
}
|
|
122
|
+
applyStyle(t) {
|
|
123
|
+
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);
|
|
124
|
+
}
|
|
125
|
+
setupMouseTracking() {
|
|
126
|
+
this.disintegration.enabled && (this.mouseMoveHandler = (t) => {
|
|
127
|
+
this.mouseX = t.clientX, this.mouseY = t.clientY;
|
|
128
|
+
}, document.addEventListener("mousemove", this.mouseMoveHandler));
|
|
129
|
+
}
|
|
130
|
+
startAnimation() {
|
|
131
|
+
const t = () => {
|
|
132
|
+
if (this.isDestroyed) return;
|
|
133
|
+
const o = (Date.now() - this.startTime) * 1e-3;
|
|
134
|
+
this.letters.forEach((s, i) => {
|
|
135
|
+
const e = s.element.getBoundingClientRect(), a = e.left + e.width / 2, l = e.top + e.height / 2, h = v(
|
|
136
|
+
a,
|
|
137
|
+
l,
|
|
138
|
+
this.mouseX,
|
|
139
|
+
this.mouseY,
|
|
140
|
+
i,
|
|
141
|
+
this.disintegration
|
|
142
|
+
);
|
|
143
|
+
let r;
|
|
144
|
+
if (h.applied)
|
|
145
|
+
r = h.state;
|
|
146
|
+
else {
|
|
147
|
+
const d = this.getAnimationType(i);
|
|
148
|
+
r = this.getAnimation(d).update(
|
|
149
|
+
{ x: 0, y: 0, rotation: 0, scale: 1, opacity: 1 },
|
|
150
|
+
i,
|
|
151
|
+
o,
|
|
152
|
+
{
|
|
153
|
+
speed: this.speed,
|
|
154
|
+
amplitude: this.amplitude * (d === "falling" || d === "floating" ? 20 : 4)
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
b(s.element, r);
|
|
159
|
+
}), this.animationFrame = requestAnimationFrame(t);
|
|
160
|
+
};
|
|
161
|
+
this.animationFrame = requestAnimationFrame(t);
|
|
162
|
+
}
|
|
163
|
+
getAnimationType(t) {
|
|
164
|
+
return this.cycle ? this.animationTypes[t % this.animationTypes.length] : this.animationTypes[0];
|
|
165
|
+
}
|
|
166
|
+
getAnimation(t) {
|
|
167
|
+
switch (t) {
|
|
168
|
+
case "falling":
|
|
169
|
+
return new y();
|
|
170
|
+
case "splitting":
|
|
171
|
+
return new x();
|
|
172
|
+
case "glitching":
|
|
173
|
+
return new C();
|
|
174
|
+
case "floating":
|
|
175
|
+
return new T();
|
|
176
|
+
default:
|
|
177
|
+
return new y();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Destroy the animated text instance
|
|
182
|
+
*/
|
|
183
|
+
destroy() {
|
|
184
|
+
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(() => {
|
|
185
|
+
this.textContainer.parentNode && this.textContainer.parentNode.removeChild(this.textContainer);
|
|
186
|
+
}, 3e3));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get the text container element
|
|
190
|
+
*/
|
|
191
|
+
getElement() {
|
|
192
|
+
return this.textContainer;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
typeof window < "u" && (window.TypographyToolkit = {
|
|
196
|
+
AnimatedText: F,
|
|
197
|
+
FallingAnimation: y,
|
|
198
|
+
SplittingAnimation: x,
|
|
199
|
+
GlitchingAnimation: C,
|
|
200
|
+
FloatingAnimation: T,
|
|
201
|
+
calculateDisintegration: v
|
|
202
|
+
});
|
|
203
|
+
export {
|
|
204
|
+
F as AnimatedText,
|
|
205
|
+
y as FallingAnimation,
|
|
206
|
+
T as FloatingAnimation,
|
|
207
|
+
C as GlitchingAnimation,
|
|
208
|
+
x as SplittingAnimation,
|
|
209
|
+
v as calculateDisintegration
|
|
210
|
+
};
|
|
@@ -0,0 +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}({});
|
|
@@ -0,0 +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"})});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typography-toolkit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Letter-by-letter text animations with proximity-based disintegration effects",
|
|
5
|
+
"main": "dist/typography-toolkit.umd.js",
|
|
6
|
+
"module": "dist/typography-toolkit.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"unpkg": "dist/typography-toolkit.umd.js",
|
|
9
|
+
"jsdelivr": "dist/typography-toolkit.umd.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && vite build",
|
|
16
|
+
"dev": "vite",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"typography",
|
|
21
|
+
"animation",
|
|
22
|
+
"text",
|
|
23
|
+
"letters",
|
|
24
|
+
"disintegration",
|
|
25
|
+
"interactive",
|
|
26
|
+
"dom"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/mathonsunday/typography-toolkit.git"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.0.0",
|
|
36
|
+
"vite": "^5.0.0",
|
|
37
|
+
"@types/node": "^20.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|