Glaze Cheat Sheet
Tailwind-style animations for HTML. Describe GSAP animations with data attributes—no JS animation code.
1. Core Concept
Glaze is a ~3kb syntax layer on top of GSAP. You write animation strings in HTML attributes; Glaze parses them into GSAP calls.
<div data-animate="from:opacity-0|y-50|duration-1"></div>
<!-- becomes -->
gsap.from(element, { opacity: 0, y: 50, duration: 1 })
Requirements: GSAP must be installed and passed to Glaze. (GSAP has its own license—check compliance for commercial use. Glaze itself is MIT.)
Features: responsive breakpoints (via GSAP matchMedia), timelines, dot notation for nested props, full GSAP access (ScrollTrigger, easing, stagger), library-agnostic design.
2. Install & Setup
npm i glazejs # or yarn add / pnpm add / bun add glazejs
import gsap from "gsap";
import glaze from "glazejs";
glaze({
lib: { gsap: { core: gsap } }, // ONLY required option
});
CDN:
import glaze from "https://esm.sh/glazejs";
import gsap from "https://esm.sh/gsap";
glaze({ lib: { gsap: { core: gsap } } });
Glaze auto-finds all data-animate elements and animates them.
3. Full Configuration
glaze({
lib: { gsap: { core: gsap } }, // required
element: document.querySelector("#app"), // search scope (default: document)
dataAttribute: "data-move", // custom attr (default: "data-animate")
className: "animate", // enable class-based syntax instead
breakpoints: { // responsive (GSAP matchMedia)
default: "(min-width: 1px)", // runs when no bp specified
sm: "(min-width: 640px)",
md: "(min-width: 768px)",
lg: "(min-width: 1024px)",
},
defaults: { // global default settings
tl: "ease-power2.inOut", // applies to every timeline
element: "duration-1", // applies to every element
},
presets: { // reusable animation shortcuts
fadeIn: "from:opacity-0|duration-1",
slideUp: "from:y-50|opacity-0",
},
watch: { debounceTime: 500 }, // watch DOM & re-animate (default: false)
});
4. Anatomy of an Animation String
[breakpoint][selector]:state:properties
Example: @lg:[&>div]:from:opacity-0|y-50|stagger-0.1|duration-0.5|ease-power2.out
5. States (every animation needs one)
| Syntax | GSAP equivalent | Meaning |
|---|---|---|
from:... |
gsap.from |
Start at these values → animate to natural state |
to:... |
gsap.to |
Animate from current state → these values |
from:... to:... |
gsap.fromTo |
Animate between two explicit states |
<div data-animate="from:opacity-0"></div>
<div data-animate="to:xPercent-50"></div>
<div data-animate="from:opacity-0.5 to:opacity-1"></div>
6. Properties
- List after state, separated by pipes
|. - Parsed by splitting at the dash
-: first part = property name, second = value. - Values auto-convert to number, boolean, or string.
<div data-animate="to:opacity-1|yPercent-10|duration-0.5"></div>
| Need | Syntax | Result |
|---|---|---|
| Nested props (dots) | to:scale.x-2|scale.y-2 |
{ scale: { x: 2, y: 2 } } |
| Negative values (brackets) | to:xPercent-[-50] |
{ xPercent: -50 } |
| Values with spaces (underscores) | to:boxShadow-[0_0_50px_20px_red] |
0 0 50px 20px red |
7. Breakpoints
Prefix with @breakpoint: — animation only runs at that screen size.
<div data-animate="@sm:from:opacity-0"></div> <!-- sm only -->
<div data-animate="@lg:from:opacity-0|rotate-180"></div>
Stack multiple with spaces; larger breakpoints add to/override smaller:
<div data-animate="@sm:from:opacity-0|y-50 @lg:from:scale-0.5"></div>
default breakpoint runs when none specified (defaults to (min-width: 1px)).
8. Selectors (target children)
Bracket notation [selector]:. The & = the parent element.
<div data-animate="[&>h1]:to:opacity-1|stagger-0.25">
<h1>One</h1><h1>Two</h1><h1>Three</h1>
</div>
Combine with breakpoints: @sm:[&>h1]:to:opacity-1|stagger-0.25
9. Alternative Input Modes
Custom attribute: set dataAttribute: "data-move" → use <div data-move="from:opacity-0">.
Class-based: set className: "animate" → write:
<div class="animate-from:opacity-0|duration-1"></div>
10. Timelines (tl)
Add tl keyword to make an element a timeline container. All child elements are automatically included in its scope.
<div data-animate="tl defaults:ease-elastic|duration-1">
<div data-animate="to:rotate-360"></div>
<div data-animate="to:rotate-360"></div>
</div>
Timeline defaults: tl defaults:ease-elastic|duration-4 yoyo-true
Timing control with tl:[...] on children:
| Value | Meaning |
|---|---|
tl:[+=1] |
Start 1s after previous ends |
tl:[-=1] |
Start 1s before previous ends (overlap) |
tl:[<] |
Start at same time as previous |
Responsive timelines: mix breakpoints inside children:
<div data-animate="tl defaults:power2.inOut|duration-2">
<div data-animate="to:rotate-360 @lg:to:xPercent-[50]"></div>
<div data-animate="tl:[-=1] to:rotate-360 @lg:to:xPercent-[-50]"></div>
</div>
Named timelines — reference from anywhere in the DOM:
<div data-animate="tl/main defaults:power2.inOut|duration-2">
<div data-animate="to:rotate-360"></div>
</div>
<div data-animate="tl:main-[-=1] to:scale-1.5"></div>
tl/name = create named timeline · tl:name = join it.
Internally, Glaze creates a timeline for every element even without
tl, sotldefaults apply globally.
11. ScrollTrigger
No special syntax—it's just the GSAP scrollTrigger property via dot notation.
Setup:
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
<div data-animate="from:opacity-0|y-50|scrollTrigger.trigger-[&]"></div>
| Option | What it does |
|---|---|
scrollTrigger.trigger-[&] |
Element that triggers animation ([&] = this element) |
scrollTrigger.start-[top_center] |
When to start (element pos + viewport pos) |
scrollTrigger.end-[bottom_top] |
When to end |
scrollTrigger.scrub=true |
Link progress to scroll position |
scrollTrigger.markers=true |
Show debug markers |
Use underscores for spaces:
[top_center]not[top center].
12. Defaults (behavior)
defaults: {
tl: "defaults:ease-power2.inOut scrollTrigger.trigger-[&]", // every timeline
element: "duration-1", // every element
}
Because every element gets an internal timeline, tl defaults effectively apply everywhere (great for global ScrollTrigger/easing).
Override per element:
<div data-animate="from:opacity-0"></div> <!-- default 1s -->
<div data-animate="from:opacity-0|duration-0.5"></div> <!-- overrides -->
13. Presets
Define reusable strings in config; reference with preset-.
presets: {
fadeIn: "from:opacity-0|duration-1",
slideUp: "from:y-50|opacity-0|duration-0.5",
helicopter: "from:rotate-2160|duration-5",
}
<div data-animate="preset-fadeIn"></div>
<div class="animate-preset-helicopter"></div> <!-- class mode -->
<div data-animate="preset-fadeIn scrollTrigger.trigger-[&]"></div> <!-- combine -->
Presets simply expand into the full string before processing.
14. Quick Syntax Reference
| Token | Purpose |
|---|---|
from: to: |
states (fromTo = use both) |
| |
separates properties |
- |
splits property name / value |
. |
nested property (scale.x-2) |
[-50] |
negative / literal value |
[0_0_50px_red] |
value with spaces (underscores) |
@bp: |
breakpoint prefix |
[&>sel]: |
child selector (& = parent) |
tl |
timeline container |
tl/name |
named timeline |
tl:name / tl:[+=1] |
join timeline / timing offset |
preset-name |
apply preset |
defaults: |
timeline-scoped defaults |
scrollTrigger.* |
ScrollTrigger options |
[&] |
"this element" (trigger/self) |
Full complex example:
<div data-animate="@lg:[&>div]:from:opacity-0|y-50|stagger-0.1|duration-0.5|ease-power2.out">
<div>Card 1</div><div>Card 2</div><div>Card 3</div>
</div>
On large screens, each child div fades in from 50px below, staggered by 0.1s.