Building USAL.js: From Weekend Project to Animation Game-Changer
Three months ago, I was working on a project that needed smooth text animations. You know, the fancy stuff where words appear one by one as you scroll, or letters shimmer with that premium feel.
I looked at the existing options: AOS.js and SAL.js. They're great libraries, don't get me wrong, but they had limitations that frustrated me:
- No text-specific animations (word-by-word, letter-by-letter)
- Limited framework support (especially for web components)
- Basic animation sets that felt… well, basic
- Configuration complexity for simple tasks
So I did what any developer does when existing tools don't fit: I built my own.
USAL.js started as a weekend project and evolved into something I never expected - a complete animation ecosystem that works everywhere, weighs almost nothing, and solves problems I didn't even know I had.
The Problem That Started Everything
I was building a landing page for a SaaS product. The client wanted that "wow factor" - text that animates word by word, numbers that count up, elements that fade in with perfect timing.
I tried extending AOS.js for text animations, but it felt like forcing a square peg into a round hole. The bundle was getting heavy, the API was getting messy, and I still couldn't animate text the way I wanted.
That's when I realized: there wasn't a single library that handled both element animations AND text animations elegantly.
Building From the Ground Up
I started with SAL.js as inspiration for the basic structure - I loved its simplicity. But as I added features, I realized I needed to rebuild everything from scratch to achieve what I wanted:
The Requirements I Set
- Tiny footprint - Had to be under 10KB
- Framework agnostic - Work with React, Vue, Svelte, Angular, AND vanilla JS
- Web Components support - Something almost no library handles well
- Rich text animations - The main reason I started this
- Tailwind-inspired syntax - Because developers love that approach
- Zero dependencies - No external requirements
- 60fps performance - Smooth on all devices
The Technical Challenges
Challenge 1: Text Animation Architecture
The biggest hurdle was creating a system that could split text by words, letters, or items, then animate each piece individually with staggered timing. This required:
// Splitting text while preserving HTML structure
// Handling different languages and character sets
// Managing thousands of micro-animations efficiently
// Cleaning up DOM when animations complete
Challenge 2: Framework Compatibility
Each framework has its own way of handling DOM updates, component lifecycles, and reactive data. I needed a core that could adapt:
// Core vanilla JS library
// React wrapper with useEffect hooks
// Vue wrapper with composition API
// Svelte wrapper with actions
// Angular wrapper with directives
// Web Components with custom elements
Challenge 3: Performance Optimization
With potentially hundreds of animated elements, I needed smart throttling:
// Intersection Observer for viewport detection
// Request Animation Frame for smooth updates
// Memory management for dynamic content
// Concurrent animation limiting
// GPU acceleration where possible
The Breakthrough: Tailwind-Inspired Syntax
The turning point was adopting a Tailwind-like approach. Instead of complex configuration objects, why not use simple, chainable attributes?
Before (complex):
new Animation({
element: '.title',
animation: 'fadeUp',
duration: 800,
delay: 200,
easing: 'ease-out'
});
After (simple):
<h1 data-usal="fade-u duration-800 delay-200 ease-out">Title</h1>
This syntax felt natural to developers already using Tailwind, and it made the library incredibly approachable.
What Makes USAL.js Different
1. Text Animations That Actually Work
<!-- Each word appears separately -->
<p data-usal="split-word split-fade-u split-delay-200">
Your message appears word by word
</p>
<!-- Each letter gets a shimmer effect -->
<h1 data-usal="text-shimmer split-letter">
PREMIUM FEELING TEXT
</h1>
<!-- Fluid weight animation per letter -->
<h2 data-usal="text-fluid split-letter duration-3000">
Dynamic Typography
</h2>
2. Number Counters Built-In
<!-- Counts from 0 to target number -->
<span data-usal="count-[1234]">1234</span>
<span data-usal="count-[98.5]">98.5%</span>
<span data-usal="count-[42,350]">$42,350</span>
3. Framework Integration Done Right
React/Next.js Setup:
npm install @usal/react
// app.js or layout.js
import { USALProvider } from '@usal/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<USALProvider>
{children}
</USALProvider>
</body>
</html>
);
}
// Any component
function Hero() {
return (
<div>
<h1 data-usal="fade-u duration-1200">Welcome</h1>
<p data-usal="split-word split-fade-r split-delay-100">
Each word slides in from right
</p>
</div>
);
}
Solidjs/SolidStart Setup:
npm install @usal/solid
// app.tsx
import { USALProvider } from '@usal/solid';
export default function App() {
return (
<Router
root={(props) => (
<Suspense>
<USALProvider>
{props.children}
</USALProvider>
</Suspense>
)}
>
<FileRoutes />
</Router>
);
}
// Any component
function Hero() {
return (
<div>
<h1 data-usal="fade-u duration-1200">Welcome</h1>
<p data-usal="split-word split-fade-r split-delay-100">
Each word slides in from right
</p>
</div>
);
}
Vue/Nuxt Setup:
npm install @usal/vue
// nuxt.config.js
export default defineNuxtConfig({
modules: ['@usal/vue/nuxt']
});
<!-- pages/index.vue -->
<template>
<div>
<h1 v-usal="'fade-u duration-800'">Vue Animations</h1>
<div v-usal="'split-item split-zoomin split-delay-150'">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
</div>
</template>
Svelte/SvelteKit Setup:
npm install @usal/svelte
<!-- Any component -->
<script>
import { usal } from '@usal/svelte';
</script>
<div use:usal={'fade-u duration-800'}>
Svelte animation
</div>
<p use:usal={'split-letter split-text-shimmer'}>
Shimmer effect in Svelte
</p>
Angular Setup:
npm install @usal/angular
// app.component.ts
import { USALModule } from '@usal/angular';
@Component({
imports: [USALModule],
template: `
<div [usal]="'fade-u duration-800'">
Angular animation
</div>
<h1 [usal]="'split-word split-flip-r split-delay-200'">
Each word flips in
</h1>
`
})
export class AppComponent { }
Web Components (The Game Changer):
npm install @usal/lit
import { LitElement, html } from 'lit';
import { useUSAL } from '@usal/lit';
const usalInstance = useUSAL();
import { usal } from '@usal/lit';
class MyElement extends LitElement {
render() {
return html`
<div ${usal('fade-u duration-800')}>
Web Component with animations
</div>
`;
}
}
Vanilla JavaScript (Zero Setup):
<script src="https://cdn.jsdelivr.net/npm/usal@latest/usal.min.js"></script>
<div data-usal="fade-u">Instant animations</div>
The Numbers That Matter
After three months of development and optimization:
- 9KB minified (smaller than a typical favicon)
- 40+ animations (fade, zoom, flip with all directions)
- 60fps performance (tested with 500+ elements)
- Zero dependencies (no external requirements)
- 6 framework integrations (more than any competitor)
- Web Components support (unique feature)
Real-World Usage Examples
E-commerce Product Page
<!-- Hero section -->
<div class="product-hero">
<img data-usal="zoomin duration-800" src="product.jpg">
<h1 data-usal="split-word split-fade-u split-delay-150">
Revolutionary Product Name
</h1>
<p data-usal="fade-u delay-600">Perfect for your needs</p>
</div>
<!-- Stats section -->
<div class="stats">
<div data-usal="fade-u delay-200">
<span data-usal="count-[1000] duration-2000">1000</span>
<p>Happy Customers</p>
</div>
<div data-usal="fade-u delay-400">
<span data-usal="count-[4.9] duration-2000">4.9</span>
<p>Average Rating</p>
</div>
</div>
SaaS Landing Page
<!-- Feature cards -->
<div class="features" data-usal="split-item split-fade-u split-delay-200">
<div class="feature-card">
<h3>Fast Performance</h3>
<p>Lightning quick animations</p>
</div>
<div class="feature-card">
<h3>Easy Setup</h3>
<p>One attribute, infinite possibilities</p>
</div>
<div class="feature-card">
<h3>Framework Agnostic</h3>
<p>Works everywhere</p>
</div>
</div>
Blog Article Enhancement
<article>
<h1 data-usal="split-word split-fade-r split-delay-100">
How to Build Better Web Experiences
</h1>
<div data-usal="fade-u delay-800" class="article-meta">
<span data-usal="count-[5] duration-1000">5</span> min read
</div>
<div class="content" data-usal="split-item split-fade-u split-delay-300">
<p>First paragraph slides in</p>
<p>Second paragraph follows</p>
<p>Creating reading rhythm</p>
</div>
</article>
Lessons Learned
What Worked
- Tailwind-inspired syntax - Developers adopted it immediately
- Framework-first approach - Each integration feels native
- Text animations - The killer feature that differentiated us
- Performance focus - Never compromised on speed
- Web Components support - Future-proofing paid off
What Was Challenging
- Cross-browser testing - Especially for text animations
- Memory management - With thousands of animated elements
- Framework integration - Each has unique quirks
- Bundle size optimization - Every byte mattered
- Documentation - Making complex features feel simple
The Future of USAL.js
Based on community feedback, I'm working on:
- More text effects (typewriter, glitch, gradient)
- Timeline animations (choreographed sequences)
- Scroll-triggered interactions (parallax, morphing)
- Visual editor (drag-and-drop animation builder)
- More framework support (Pure Vite, Qwik)
Try USAL.js Today
The easiest way to get started:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/usal@latest/usal.min.js"></script>
</head>
<body>
<h1 data-usal="fade-u duration-1200">Hello USAL!</h1>
<p data-usal="split-word split-fade-r split-delay-200">
Each word appears from the right
</p>
<div data-usal="count-[100] duration-2000">100</div>
</body>
</html>
Save this as an HTML file, open in your browser, and scroll. You'll see why I built this.
Why I Open-Sourced It
I could have kept USAL.js as a commercial product, but I believe great tools should be accessible to everyone. The web animation ecosystem needed something that just works, and I hope USAL fills that gap.
Building USAL taught me that sometimes the best solution isn't the most complex one - it's the one that gets out of your way and lets you focus on creating great experiences.
Ready to try USAL.js?
What animations will you build with USAL? I'd love to see your creations - tag me and share your projects!
Follow me for more insights on building developer tools that people actually want to use.




Top comments (0)