# 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.

```html
<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

```bash
npm i glazejs   # or yarn add / pnpm add / bun add glazejs
```

```js
import gsap from "gsap";
import glaze from "glazejs";

glaze({
  lib: { gsap: { core: gsap } },   // ONLY required option
});
```

**CDN:**

```js
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

```js
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              |

```html
<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.

```html
<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.

```html
<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:

```html
<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.

```html
<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:

```html
<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.

```html
<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:

```html
<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:

```html
<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`, so `tl` defaults apply globally.

---

## 11. ScrollTrigger

No special syntax—it's just the GSAP `scrollTrigger` property via dot notation.

**Setup:**

```js
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
```

```html
<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)

```js
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:**

```html
<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-`.

```js
presets: {
  fadeIn: "from:opacity-0|duration-1",
  slideUp: "from:y-50|opacity-0|duration-0.5",
  helicopter: "from:rotate-2160|duration-5",
}
```

```html
<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:**

```html
<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.*