typography-toolkit
v1.5.2
Published
Letter-by-letter text animations with proximity-based disintegration effects and Google Fonts selection
Maintainers
Readme
Typography Toolkit
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.
Features
- Letter-by-Letter Control - Each letter is a separate DOM element with independent animations
- Base Animations - Falling, splitting, glitching, and floating animations
- Proximity-Based Disintegration - Letters react to cursor without direct interaction
- Font Selection - Suggest Google Fonts based on natural language descriptions
- Font Refinement - Refine suggestions based on feedback (e.g., "too casual, want gothic")
- Dynamic Font Loading - Automatically load Google Fonts without manual
<link>tags - DOM-Based - Uses CSS transforms (GPU-accelerated), accessible, and styleable
- Modular & Extensible - Easy to add new animation types and behaviors
- Zero Dependencies - Vanilla TypeScript/JavaScript
Installation
npm
npm install typography-toolkitCDN (UMD)
<script src="https://unpkg.com/typography-toolkit/dist/typography-toolkit.umd.js"></script>
<script>
// Option 1: Use TypographyToolkit namespace
const text = new TypographyToolkit.AnimatedText({...});
// Option 2: Use AnimatedText directly (also available on window)
const text = new AnimatedText({...});
</script>Global Names: When using the UMD build, the library exposes:
window.TypographyToolkit- Full namespace objectwindow.AnimatedText- Direct access to AnimatedText class (for convenience)
ES Modules
import { AnimatedText } from 'typography-toolkit';Quick Start
Basic Usage
import { AnimatedText } from 'typography-toolkit';
const text = new AnimatedText({
text: 'HELLO',
container: document.body,
animations: ['falling', 'glitching']
});
// Clean up when done
setTimeout(() => text.destroy(), 10000);With Disintegration
const text = new AnimatedText({
text: 'FEED ME',
container: document.body,
animations: ['falling', 'splitting'],
disintegration: {
enabled: true,
radius: 80,
behaviors: ['fall-away', 'explode'],
strength: 0.8
},
style: {
fontFamily: 'Arial',
fontSize: 24,
color: 'rgba(60, 60, 60, 0.8)',
textShadow: '2px 2px 4px rgba(0,0,0,0.5)',
letterSpacing: '2px'
}
});Advanced Usage
const text = new AnimatedText({
text: 'ANIMATED TEXT',
container: document.getElementById('container'),
animations: ['falling', 'splitting', 'glitching', 'floating'],
cycle: true, // Cycle through animation types per letter
speed: 1.5, // Animation speed multiplier
amplitude: 1.2, // Animation amplitude multiplier
disintegration: {
enabled: true,
radius: 100,
behaviors: ['fall-away', 'split-apart', 'explode'],
strength: 1.0
},
style: {
fontFamily: 'Georgia, serif',
fontSize: 32,
color: 'rgba(100, 50, 50, 0.9)',
fontWeight: 'bold'
},
position: {
x: 100,
y: 200
},
fadeOut: 8000 // Auto-destroy after 8 seconds
});API Reference
AnimatedText
Main class for creating animated text.
Constructor Options
interface AnimatedTextOptions {
text: string; // Text to animate
container: HTMLElement; // Container element
animations?: AnimationType[]; // Animation types (default: all)
cycle?: boolean; // Cycle through types per letter (default: true)
speed?: number; // Speed multiplier (default: 1.0)
amplitude?: number; // Amplitude multiplier (default: 1.0)
disintegration?: DisintegrationOptions; // Disintegration config
style?: StyleOptions; // CSS style options
position?: { x?: number; y?: number }; // Position (default: random)
fadeOut?: number; // Auto-destroy after ms (default: 0 = never)
}Methods
destroy()- Clean up and remove the animated textgetElement()- Get the text container element
Animation Types
'falling'- Letters drift downward'splitting'- Letters drift outward horizontally'glitching'- Letters randomly shift position'floating'- Letters slowly rise
Disintegration Behaviors
'fall-away'- Letters drop down when cursor approaches'split-apart'- Letters spread horizontally'explode'- Letters scatter in all directions
Style Options
interface StyleOptions {
fontFamily?: string;
fontSize?: number;
color?: string;
fontWeight?: string;
textShadow?: string; // CSS text-shadow value
letterSpacing?: string; // CSS letter-spacing value
textTransform?: string; // CSS text-transform value
}Container Styling
containerClass?: string; // CSS class to add to container
containerStyle?: Record<string, string>; // Inline styles for containerPosition Constraints
position?: {
x?: number;
y?: number;
constrainToViewport?: boolean; // Keep text within viewport bounds
}Event Callbacks
callbacks?: {
onCreate?: (element: HTMLElement) => void; // Called when text is created
onDestroy?: () => void; // Called when text is destroyed
onDisintegrate?: (letterIndex: number) => void; // Called when a letter disintegrates
}Font Selection API
suggestFont(description: string): FontSuggestion | undefined
Get a single font suggestion based on a natural language description.
const font = suggestFont('gothic horror');
// Returns best matching font, or undefined if no matchessuggestFonts(description: string): FontSuggestion[]
Get multiple font suggestions sorted by relevance.
const fonts = suggestFonts('hand-drawn');
// Returns array of matching fonts, sorted by relevanceloadGoogleFont(fontName: string): Promise<void>
Dynamically load a Google Font. Prevents duplicate loading.
await loadGoogleFont('Caveat');
// Adds <link> tag to document head if not already loadedgetFontFamily(fontName: string, fallback?: string): string
Get CSS font-family string with appropriate fallback.
getFontFamily('Caveat'); // "'Caveat', cursive"
getFontFamily('VT323'); // "'VT323', monospace"refineFont(description: string, feedback: RefinementFeedback): FontSuggestion | undefined
Refine font suggestions based on user feedback using scoring algorithm.
const refined = refineFont('hand-drawn', {
rejectedFont: 'Caveat',
negativeAspects: ['too casual'],
positiveAspects: ['gothic', 'ornate']
});refineSuggestion(description: string, feedback: RefinementFeedback): FontSuggestion[]
Get multiple refined suggestions sorted by score.
Font Suggestion Types
interface FontSuggestion {
name: string; // Display name
googleFontsName: string; // Exact Google Fonts name
categories: string[]; // Tags for matching
description: string; // Human-readable description
artistic: boolean; // True if striking/unique (not "safe")
}
interface RefinementFeedback {
rejectedFont: string; // Font name they didn't like
negativeAspects: string[]; // What they don't like
positiveAspects: string[]; // What they want instead
}Examples
Simple Falling Text
const text = new AnimatedText({
text: 'FALLING',
container: document.body,
animations: ['falling']
});Glitching Text with Disintegration
const text = new AnimatedText({
text: 'GLITCH',
container: document.body,
animations: ['glitching'],
disintegration: {
enabled: true,
radius: 60,
behaviors: ['explode']
}
});Multiple Animation Types
const text = new AnimatedText({
text: 'VARIED',
container: document.body,
animations: ['falling', 'splitting', 'glitching', 'floating'],
cycle: true // Each letter uses different animation
});Font Selection & Loading
import { suggestFont, loadGoogleFont, getFontFamily, AnimatedText } from 'typography-toolkit';
// Suggest a font based on description
const font = suggestFont('hand-drawn');
// Returns: { name: 'Hand-drawn Casual', googleFontsName: 'Caveat', ... }
// Load the font dynamically
await loadGoogleFont(font.googleFontsName);
// Use in animation
const text = new AnimatedText({
text: 'HELLO',
container: document.body,
style: {
fontFamily: getFontFamily(font.googleFontsName) // "'Caveat', cursive"
}
});Font Refinement with Feedback
import { suggestFont, refineFont, loadGoogleFont, getFontFamily, AnimatedText } from 'typography-toolkit';
// Initial suggestion
const initial = suggestFont('hand-drawn');
// User doesn't like it: "too casual, want gothic and ornate"
// Refine based on feedback
const refined = refineFont('hand-drawn', {
rejectedFont: initial.googleFontsName,
negativeAspects: ['too casual', 'too simple'],
positiveAspects: ['gothic', 'ornate', 'striking']
});
// Returns: { name: 'Gothic Blackletter', googleFontsName: 'UnifrakturMaguntia', ... }
// Load and use
await loadGoogleFont(refined.googleFontsName);
const text = new AnimatedText({
text: 'GOTHIC',
container: document.body,
style: {
fontFamily: getFontFamily(refined.googleFontsName)
}
});Performance
- Uses
requestAnimationFramefor smooth 60fps animations - CSS transforms are GPU-accelerated
- Efficient proximity calculations
- Automatic cleanup on destroy
Common Patterns
Creating Multiple Texts
const messages = ['HELLO', 'WORLD', 'ANIMATED'];
messages.forEach((msg, i) => {
new AnimatedText({
text: msg,
container: document.body,
position: { x: 100 + i * 200, y: 100 },
fadeOut: 5000
});
});Styling with CSS Classes
const text = new AnimatedText({
text: 'STYLED',
container: document.body,
containerClass: 'my-custom-class',
style: {
fontSize: 32,
color: '#ff0000'
}
});
// CSS:
// .my-custom-class { background: rgba(0,0,0,0.1); padding: 10px; }Tracking Lifecycle Events
const text = new AnimatedText({
text: 'TRACKED',
container: document.body,
callbacks: {
onCreate: (element) => {
console.log('Text created:', element);
// Analytics tracking, etc.
},
onDestroy: () => {
console.log('Text destroyed');
},
onDisintegrate: (letterIndex) => {
console.log('Letter disintegrated:', letterIndex);
}
}
});Constraining to Viewport
const text = new AnimatedText({
text: 'CONSTRAINED',
container: document.body,
position: {
x: window.innerWidth - 100, // Might be off-screen
y: window.innerHeight - 50,
constrainToViewport: true // Automatically adjusts to stay on screen
}
});Troubleshooting
Text Not Animating?
- Check container: Ensure the container element exists and is visible
- Check animations array: Make sure at least one animation type is specified
- Check browser support: Requires modern browser with
requestAnimationFramesupport
Disintegration Not Working?
- Check disintegration.enabled: Must be set to
true - Check radius: Increase
radiusif cursor needs to be closer - Check mouse tracking: Ensure mouse events are not being blocked
Text Positioned Off-Screen?
- Use constrainToViewport: Set
position.constrainToViewport: true - Check container bounds: Ensure container has proper dimensions
- Manual bounds checking: Calculate position manually based on container size
Performance Issues?
- Reduce animation types: Fewer animations = better performance
- Reduce letter count: Shorter text = better performance
- Use fadeOut: Auto-destroy texts after a delay to prevent memory buildup
- Destroy manually: Call
destroy()when done with text instances
Fonts Not Loading?
- Check font name: Ensure Google Font name is correct
- Check network: Verify Google Fonts CDN is accessible
- Check font-family: Use
getFontFamily()helper for correct CSS format
Browser Support
- Modern browsers with ES2020 support
- Requires
requestAnimationFrameAPI - CSS transforms support
- Mobile browsers supported (touch events coming soon)
License
MIT
