# Animate Skill Build Sequence: The 7-Step Motion Pipeline in emilkowalski/skills

> Discover the 7-step animate skill build sequence in emilkowalski/skills. Transform motion design requests into production-ready code with this detailed motion pipeline.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: how-to-guide
- Published: 2026-08-07

---

**The `animate` skill follows a strict 7-stage build sequence—frequency gating, purpose definition, tool selection, property constraints, easing/duration choices, interruption handling, and accessibility gating—that transforms motion design requests into production-ready, review-passing code.**

The `animate` skill in the [emilkowalski/skills](https://github.com/emilkowalski/skills) repository is a **construction-only** automation that enforces disciplined motion design through a fixed, ordered pipeline. Unlike flexible creative tools, this skill rejects requests that skip steps or violate constraints. The entire `animate` build sequence is codified in [[`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md)](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) (lines 30-86), with ready-to-use implementations available in [[`skills/animate/RECIPES.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md)](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md).

## The 7-Stage Animate Skill Build Sequence

Each animation request must progress through the following stages in exact order. The skill aborts or redirects if any stage fails.

### Stage 1: Frequency Gating — Should This Animate at All?

The first gate prevents unnecessary motion using a **frequency-tier table**:

| Trigger frequency | Animation decision |
|-------------------|------------------|
| Keyboard shortcuts | **No animation** — return static UI |
| Hover & list navigation | **Near-imperceptible** micro-motion |
| Modals, drawers, toasts | **Standard** motion |
| Onboarding, first-run | **Delight** — full animation allowed |

If the tier returns "no animation," the skill stops immediately. This protects against wasted render cycles and preempts `prefers-reduced-motion` violations.

### Stage 2: Purpose Definition — Why Does This Motion Exist?

Every animation must map to **exactly one purpose keyword**:

- **Feedback** — confirm user action completed
- **Spatial consistency** — maintain orientation during navigation
- **State indication** — signal mode change (enabled/disabled)
- **Preventing a jarring change** — soften abrupt layout shifts
- **Explanation** — teach interaction model
- **Delight** — reward or surprise (reserved for low-frequency moments)

If the requester cannot name a purpose, the skill aborts. This rule eliminates decorative animation that lacks user-centric justification.

### Stage 3: Tool Selection — Cheapest That Works

The skill enforces a **tool hierarchy** and selects the first satisfactory option:

1. **CSS `transition`** — for simple state changes
2. **CSS `@starting-style`** — for entry animations without JavaScript
3. **CSS `@keyframes` animation** — for multi-step or looping motion
4. **WAAPI (Web Animations API)** — for dynamic control, synchronization
5. **Motion library** — only for complex gesture-driven physics

This "cheapest that works" rule prevents heavy library imports for fades and slides.

### Stage 4: Property Constraints — GPU-Accelerated Only

Allowed properties are strictly limited:

| Property | Usage |
|----------|-------|
| `transform` | **Primary** — `translate()`, `scale()`, `rotate()` |
| `opacity` | **Secondary** — fades, layering |
| `clip-path` | **Exceptional** — special reveal effects only |

Specific rules from the specification:
- Use `scale(0.9–0.97)` combined with `opacity: 0` for entrance animations
- Set explicit `transform-origin` for asymmetric scaling
- Prefer **percentages** in `translate()` for responsiveness
- Use full `transform` strings when working with the Motion library

This constraint set guarantees **compositor-only** animations and eliminates layout thrashing.

### Stage 5: Easing and Duration — Curated Token System

The skill pulls from **predefined tables** rather than accepting arbitrary values:

**Easing curves:**
- `ease-out` — `cubic-bezier(0.23, 1, 0.32, 1)` for exits and feedback
- `ease-in-out` — for symmetric state toggles
- `ease` — sparingly, for subtle emphasis
- `linear` — only for opacity fades or infinite loops

**Duration matrix (selected examples):**
| Interaction | Duration range |
|-------------|---------------|
| Button press feedback | 100–160 ms |
| Dropdown/menu | 150–250 ms |
| Modal entrance/exit | 200–300 ms |
| Page transitions | 300–500 ms |

For gesture-driven or "alive" motion, the skill substitutes **spring physics** with configurable `stiffness` and `damping` instead of fixed durations.

### Stage 6: Interruption and Exit — Predictable Behavior

This stage defines behavior during **rapid retriggering** and **state reversal**:

| Scenario | Implementation |
|----------|---------------|
| Rapidly toggled elements | CSS transitions (interruptible mid-flight) |
| Gesture-driven motion | Springs (natural physics on release) |
| Standard exit | Symmetric timing to entrance |
| Hold-to-confirm patterns | Asymmetric — slow enter, instant exit |

Symmetric exits prevent visual "jumps" when dismissing elements. Asymmetric patterns reinforce deliberate action for destructive operations.

### Stage 7: Reduced-Motion and Pointer Gating — Accessibility Compliance

Final code must wrap motion in **conditional media queries**:

```css
@media (prefers-reduced-motion: reduce) {
  /* Eliminate or simplify motion */
}

@media (hover: hover) and (pointer: fine) {
  /* Enable hover-dependent motion only for fine pointers */
}

```

For JavaScript-driven animation, the skill emits `useReducedMotion()` hooks to respect system preferences dynamically.

## Complete Implementation Example

The following applies all seven stages to a button feedback animation:

```html
<button class="save-button">Save</button>

```

```css
:root {
  /* Stage 5: Curated tokens */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --duration-short: 120ms;
}

.save-button {
  /* Stage 3: CSS transition (cheapest tool) */
  /* Stage 4: transform + opacity only */
  transition: 
    opacity var(--duration-short) var(--ease-out),
    transform var(--duration-short) var(--ease-out);
  transform-origin: center center;
}

/* Stage 7: Reduced motion support */
@media (prefers-reduced-motion: reduce) {
  .save-button {
    transition: opacity 80ms var(--ease-out);
    transform: none !important;
  }
}

/* Stage 7: Pointer gating */
@media (hover: hover) and (pointer: fine) {
  .save-button:hover {
    /* Stages 4-5-6 combined */
    opacity: 0.9;
    transform: translateY(-2px);
  }
}

```

The JavaScript logic (abbreviated) that precedes this CSS:

```js
// Stage 1: Frequency check
if (interactionCount > 100) {
  return { motion: false, implementation: 'static' };
}

// Stage 2: Purpose validation
const PURPOSE_KEYWORDS = ['Feedback', 'Spatial consistency', 'State indication', 
                          'Preventing a jarring change', 'Explanation', 'Delight'];
const purpose = 'Feedback'; // Must match exactly

```

## Skill Output Format

Upon completing the seven stages, the `animate` skill emits:

1. **Implementation code** — the actual CSS/JS/WAAPI/Motion implementation
2. **Gate result summary** — which stages passed/failed and why
3. **Ingredients list** — tool, properties, easing, duration, and spring config used
4. **Feel-check guidance** — manual verification steps for the animation's perceived quality

## Key Files in the Animate Skill

| File | Purpose |
|------|---------|
| [[`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md)](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) | Complete specification with build sequence, hard rules, and output format |
| [[`skills/animate/RECIPES.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md)](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md) | Production-ready implementations for buttons, dropdowns, toasts, modals, and gestures |

## Summary

- The `animate` skill enforces a **fixed 7-stage pipeline**: frequency gating → purpose → tool → properties → easing/duration → interruption → accessibility gating
- **Construction-only operation**: the skill builds code but does not execute or preview animations
- **Strict abort conditions**: missing purpose, inappropriate frequency, or wrong property choices halt the pipeline
- **Cheapest-tool rule**: CSS transitions preferred over WAAPI; WAAPI preferred over Motion library
- **GPU-only properties**: `transform` and `opacity` (with `clip-path` exceptions) keep animations on the compositor
- **Mandatory accessibility**: `prefers-reduced-motion` and pointer-type media queries are non-optional outputs

## Frequently Asked Questions

### What happens if I try to use `top` or `left` instead of `transform` in the animate skill?

The skill rejects the request. According to [[`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md)](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md), only `transform` and `opacity` are permitted for standard animations. Using layout-triggering properties like `top`, `left`, `width`, or `height` forces recalculations and violates the compositor-only rule. The skill enforces `translate()` for position changes.

### Can I skip the purpose definition stage if the animation is obviously needed?

No. Stage 2 is mandatory and abort-on-failure. The skill requires one of six exact purpose keywords—`Feedback`, `Spatial consistency`, `State indication`, `Preventing a jarring change`, `Explanation`, or `Delight`. This prevents decorative motion without user-centric justification and ensures every animation can be traced to a specific design intent.

### How does the skill handle reduced motion preferences differently from pointer-type gating?

The skill treats these as **separate but mandatory** Stage 7 outputs. `prefers-reduced-motion: reduce` typically simplifies or eliminates transform-based motion while preserving opacity fades. The `hover: hover` and `pointer: fine` media query prevents hover-dependent transforms on touch devices where they feel broken. Both conditions wrap independent code blocks in the final CSS output.