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

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 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) (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).

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:

@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:

<button class="save-button">Save</button>
: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:

// 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) 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) 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), 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →