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, orclip-pathonly; never usetransition: all. - Select correct easing: Replace
ease-inwithcubic-bezier(0.23, 1, 0.32, 1)or otherease-outvariants from the standards. - Respect transform rules: Start scales from
0.95not0, and settransform-origintovar(--transform-origin)for popovers. - Handle accessibility: Wrap motion in
prefers-reduced-motionmedia 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →