Troubleshooting Common Issues When Using emilkowalski/skills with AI Agents

AI agents fail the emilkowalski/skills animation standards by ignoring frequency gates, using CPU-heavy properties, and selecting incorrect easing curves, but strict adherence to the decision trees in skills/animate/SKILL.md and skills/review-animations/STANDARDS.md ensures compliant, performant motion.

The emilkowalski/skills repository encodes Emil Kowalski’s design-engineering philosophy into structured Markdown documents that prescribe strict decision-making processes for building and reviewing UI motion. When AI agents consume these skills without implementing their guardrails, they generate animation code that violates performance budgets and accessibility requirements. This guide maps the most frequent agent errors to their specific fixes in the source skills.

Decision Gate Violations: Animating High-Frequency Actions

The most common failure occurs when agents ignore the frequency-appropriate rule in skills/animate/SKILL.md. The skill explicitly forbids animation for actions occurring more than 100 times per day, such as keyboard shortcuts or command-palette toggles.

Agents often bypass the Should this animate? gate and add unnecessary transitions to high-frequency interactions. To fix this, implement the gate logic before generating CSS:

// Check frequency tier first
if (frequency > 100) {
  // No animation – return static style
  return <Button className="btn-static">Click</Button>;
}
// Otherwise apply motion

If the frequency tier is marked "No animation. Ever." in the skill tables, the agent must return static state changes instead of transition code.

Easing and Timing Mistakes

Using ease-in Instead of ease-out

The standards in skills/review-animations/STANDARDS.md require ease-out or custom cubic-bezier curves for UI entrances. The ease-in curve delays the moment the user sees movement, making interfaces feel sluggish.

Replace any ease-in with the strong custom curve from the easing.dev catalogue:

:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

.button {
  transition: transform 200ms var(--ease-out);
}

Oversized Durations Without Justification

UI animations must stay under 300 ms unless the element is rare or first-time, according to the duration tables in the standards. Agents frequently generate 500 ms–1000 ms transitions for common dropdowns.

Cut durations to the recommended range (e.g., dropdown 150–250 ms) or lower the motion budget to maintain responsiveness.

CSS Performance Anti-Patterns

Declaring transition: all

Using transition: all violates the GPU-only properties rule in skills/review-animations/STANDARDS.md and triggers Aggressive Escalation warnings. This animates layout-changing properties on the main thread, causing jank and recalculation storms.

Specify exact properties that leverage compositor threads:

/* Wrong */
.element {
  transition: all 300ms ease;
}

/* Correct */
.element {
  transition: transform 200ms var(--ease-out), 
              opacity 200ms var(--ease-out);
}

Valid GPU-accelerated properties include transform, opacity, and clip-path.

Keyframes on Rapidly-Triggered UI

Agents often implement @keyframes for interactive elements like toggles or dropdowns. However, keyframes restart from zero on each activation, breaking the Interruptibility rule.

Use CSS transitions or the Web Animations API (WAAPI) for rapid UI changes. Reserve keyframes exclusively for long-running decorative animations that do not respond to user input.

Framer Motion Shorthands Under Load

When using Framer Motion, agents rely on shorthand props like x, y, and scale. These bypass GPU acceleration and drop frames when the page is busy, violating the Performance section guidelines.

Animate with the full transform string to ensure hardware acceleration:

// Avoid during heavy load
<motion.div x={100} scale={1.2} />

// Prefer
<motion.div 
  transform="translateX(100px) scale(1.2)" 
/>

Visual Correctness and Transform Errors

Animating from scale(0)

Starting animations from scale(0) creates a "pop-in from nowhere" effect that feels artificial, violating the Never animate from scale(0) guideline.

Start from a subtle scale combined with opacity:

.tooltip {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 120ms var(--ease-out),
              transform 120ms var(--ease-out);
}

Wrong transform-origin on Popovers

Popovers must scale from their trigger point rather than the center. The origin & physical correctness rule requires using var(--transform-origin) for trigger-anchored components; keep centre origin only for modals.

.popover {
  transform-origin: var(--transform-origin);
}

Accessibility and Group Animation

Missing prefers-reduced-motion Handling

Accessibility requirements in the skills mandate gentler fallbacks for users who opt out of motion. Agents frequently omit the @media (prefers-reduced-motion: reduce) wrapper.

Wrap motion-heavy rules and keep only opacity or color transitions for the reduced case:

@media (prefers-reduced-motion: reduce) {
  .tooltip {
    transition: opacity 80ms ease;
    transform: none;
  }
}

Lack of Stagger for Groups

Animating entire lists simultaneously feels clunky. The Stagger Animations section prescribes a 30–80 ms delay between items.

Apply incremental delays based on child indices:

.item {
  opacity: 0;
  transform: translateY(8px);
  animation: fadeIn 300ms var(--ease-out) forwards;
}

.item:nth-child(1) { animation-delay: 0ms; }
.item:nth-child(2) { animation-delay: 40ms; }
.item:nth-child(3) { animation-delay: 80ms; }
/* … */

@keyframes fadeIn {
  to { opacity: 1; transform: translateY(0); }
}

Implementation Examples

Example 1: Correctly Gating an Animation

This TypeScript snippet implements the frequency gate from skills/animate/SKILL.md:

// AI‑generated snippet (simplified)
if (frequency > 100) {
  // No animation – return static style
  return <Button className="btn">Click</Button>;
}

// Otherwise, apply a subtle transition
return (
  <Button className="btn">
    Click
  </Button>
);
/* CSS respects GPU-only and origin rules */
.btn {
  transition: transform 150ms var(--ease-out);
  transform-origin: var(--transform-origin);
}

Example 2: Custom Easing with Reduced Motion Fallback

Using the official --ease-out variable from skills/animate/SKILL.md with accessibility wrapper:

:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

.tooltip {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 120ms var(--ease-out),
              transform 120ms var(--ease-out);
}

/* Reduced‑motion fallback */
@media (prefers-reduced-motion: reduce) {
  .tooltip {
    transition: opacity 80ms ease;
  }
}

Key Source Files

File Purpose
skills/animate/SKILL.md Primary build skill containing the decision flow and frequency gates
skills/review-animations/STANDARDS.md Catalog of easing curves, duration budgets, and GPU property rules
skills/review-animations/SKILL.md Review skill that validates motion against standards
skills/emil-design-eng/SKILL.md High-level philosophy underlying all animation decisions
README.md Repository overview and installation guidance

Summary

  • Check frequency gates first: Actions occurring >100 times daily must never animate, as specified in skills/animate/SKILL.md.
  • Use GPU-only properties: Animate transform, opacity, or clip-path only; never use transition: all.
  • Select correct easing: Replace ease-in with cubic-bezier(0.23, 1, 0.32, 1) or other ease-out variants from the standards.
  • Respect transform rules: Start scales from 0.95 not 0, and set transform-origin to var(--transform-origin) for popovers.
  • Handle accessibility: Wrap motion in prefers-reduced-motion media queries and provide opacity-only fallbacks.
  • Optimize performance: Avoid Framer Motion shorthands under load, use transitions (not keyframes) for rapid UI, and stagger group animations by 30–80 ms.

Frequently Asked Questions

Why does emilkowalski/skills forbid animation on high-frequency actions?

The frequency-appropriate rule in skills/animate/SKILL.md states that animations occurring more than 100 times per day create cognitive fatigue and performance overhead. Forcing static state changes on keyboard shortcuts and command-palette toggles preserves user focus and battery life while complying with the built-in review standards.

What is the correct replacement for transition: all?

Replace the shorthand with explicit property declarations targeting compositor-only layers. According to skills/review-animations/STANDARDS.md, valid declarations look like transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out), ensuring layout and paint calculations remain off the main thread to prevent jank.

How should AI agents handle staggered list animations?

Agents must apply incremental delays between 30–80 ms per item, calculated from the Stagger Animations section. Use nth-child selectors or inline styles with increasing delay values to create the cascading effect, ensuring the total sequence does not exceed the 300 ms budget for standard UI elements.

Where are the official easing curves defined?

The easing.dev catalogue and custom variables are defined in skills/review-animations/STANDARDS.md under the Responsive easing rules. The primary recommended curve is --ease-out: cubic-bezier(0.23, 1, 0.32, 1), which provides natural deceleration for UI entrances and is enforced by the review-animations skill.

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 →