Motion Design Principles skill for Codex

UI motion that explains, then gets out of the way. Codex gives every animation a purpose or removes it, then applies a small set of duration and easing tokens scaled by distance, with faster ease-in exits and ease-out entrances. Choreography follows one focal motion with capped staggers and directional meaning, springs handle gestures, only transform and opacity animate, and reduced-motion users get fades that keep the meaning.

  • Design & UX
  • $motion-design-principles
  • 171 lines
  • 2 files
  • ~1,950 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- motion-design-principles

Installs to ~/.agents/skills/motion-design-principles/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $motion-design-principles, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Sets the motion language for a product UI - when to animate at all, duration and easing tokens by distance and element size, enter and exit asymmetry, choreography and stagger, spatial continuity between states, spring parameters, and reduced-motion alternatives that keep meaning. Library-agnostic with CSS, Web Animations API and Motion examples. Use when defining motion tokens, reviewing animations that feel slow, janky or random, choreographing page or modal transitions, or making animation accessible.

Use it when

  • Defining duration and easing tokens for a product
  • Animations feel slow, janky, inconsistent or decorative
  • Choreographing modal, page, list or shared-element transitions
  • Making motion accessible for reduced-motion users

Use something else when

How to check the result

Recordings slowed in the DevTools Animations panel match the motion spec, a 4x CPU-throttled trace shows no long frames, and reduced-motion emulation keeps every state change perceivable.

The mistake it prevents

Using the same slow ease-in-out for everything, so entrances feel sluggish and exits linger when users repeat an action.

~/.agents/skills/motion-design-principles/SKILL.md

--- name: motion-design-principles description: Sets the motion language for a product UI - when to animate at all, duration and easing tokens by distance and element size, enter and exit… license: MIT ---

Good UI motion explains something: where an element came from, what changed, what to look at next. It is fast enough that nobody waits for it, consistent enough to feel like one product, and optional for people who turn it off. If an animation explains nothing, remove it.

When to animate

PurposeExampleAnimate?
Feedback that an action registeredButton press, toggle, checkboxYes, 100-150 ms
Spatial relationshipSheet slides from the button that opened it; list item expands into detailYes
State change that could be missedItem added to cart, inline save confirmationYes, brief
Attention to something newNew message badgeOnce, never looping
Continuity during loadingSkeleton shimmer, progressSubtle, or static under reduced motion
DecorationParallax, floating blobs, entrance animation on every scroll sectionRarely; never on task-focused screens

Duration tokens

TokenDurationUse
--dur-instant100 msPress states, color and opacity changes, small toggles
--dur-fast150-200 msTooltips, dropdowns, small reveals, exits
--dur-base250 msModals, cards expanding, sheets on phones
--dur-slow350-400 msLarge surfaces moving far, page-level transitions on big screens
(never)> 500 msAnything users trigger repeatedly

Scale duration with distance and size: a 40px move needs less time than a full-screen sheet. Desktop and large screens can use slightly longer durations than phones for the same component because distances are larger; wearables shorter.

Easing tokens

:root {
  --ease-out:    cubic-bezier(0.2, 0, 0, 1);      /* entering, responding: fast start, gentle stop */
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);      /* leaving the screen: gentle start, fast end */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);    /* moving between two on-screen positions */
  --ease-emphasis: cubic-bezier(0.05, 0.7, 0.1, 1); /* hero moments, large surfaces arriving */
  --dur-instant: 100ms; --dur-fast: 180ms; --dur-base: 250ms; --dur-slow: 380ms;
}
MovementEasing
Element enters or appearsease-out (decelerate): arrives quickly, settles
Element exitsease-in (accelerate), and about 20-30% shorter than its entrance
Element moves or resizes on screenease-in-out
Color, opacity onlylinear or ease-out; short
Physical, interruptible gestures (drag release, sheet fling)Spring

Never use linear for movement (feels mechanical) or the CSS keyword ease as a house default (its fast middle looks generic).

Springs

Use springs where the user’s gesture hands off to animation, or where interruption is common. Describe by feel and map to the library:

FeelMotion (type: "spring")Notes
Snappy UI, no overshootbounce: 0, duration: 0.3Default for most UI springs
Slight lifebounce: 0.15, duration: 0.35Cards, toasts
Playfulbounce: 0.3Rarely; consumer and celebratory moments
<motion.div layout transition={{ type: "spring", bounce: 0, duration: 0.3 }} />

CSS can approximate a spring with linear() easing generated from a spring curve; keep it to decorative cases since it is not interruptible like a JS spring.

Choreography

  • One focal motion at a time. When several things change, the most important one moves; others fade or simply appear.
  • Stagger lists by 20-40 ms per item and cap the total (for example, only the first 6-8 items stagger, the rest appear with the last one). Total sequence under ~400 ms.
  • Direction carries meaning. Forward navigation slides in from the trailing edge, back from the leading edge (mirror in RTL). Sheets come from the edge they live on.
  • Continuity. When an element transforms into another (card to detail), animate the shared element (FLIP, layoutId, View Transitions) rather than fading out and in.
  • Exit before enter, or crossfade overlapping by about half; do not run two full sequences back to back.
  • Small distances. Entrances move 8-24px, not from off-screen, unless it is a sheet or page.

Performance rules

  • Animate transform and opacity. Animating width, height, top, left, margin or box-shadow triggers layout or paint each frame; use FLIP or transform: scale and a pseudo-element shadow with opacity instead.
  • will-change: transform only on elements about to animate, removed afterwards.
  • Hold 60 fps on a mid-range phone. Profile with the Performance panel (CPU 4x slowdown).
  • Never block input for an animation; interactions must stay responsive mid-transition, and a second click should redirect, not queue.

Reduced motion

prefers-reduced-motion: reduce means remove movement, not meaning.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important;
  }
  .toast { transition: opacity var(--dur-fast) linear !important; } /* keep a gentle fade */
}
const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
el.animate(reduce ? [{ opacity: 0 }, { opacity: 1 }]
                  : [{ opacity: 0, transform: "translateY(12px)" }, { opacity: 1, transform: "none" }],
           { duration: reduce ? 120 : 250, easing: "cubic-bezier(0.2, 0, 0, 1)", fill: "both" });
  • Replace slides, zooms and parallax with fades or instant changes.
  • Stop autoplaying loops; anything moving for more than 5 seconds needs a pause control (WCAG 2.2.2).
  • Nothing flashes more than three times per second (WCAG 2.3.1).
  • In Motion for React, <MotionConfig reducedMotion="user"> disables transform and layout animations while keeping opacity.

Review workflow

  • Inventory every animation: rg -n "transition|animation|@keyframes|animate\(|motion\.|gsap\." src.
  • For each, write its purpose in one phrase. No purpose: remove it.
  • Replace raw values with duration and easing tokens.
  • Check enter/exit asymmetry and direction consistency.
  • Check performance (properties animated, frame rate under CPU throttling).
  • Check reduced motion keeps meaning.

Gotchas

  • Durations feel slower on repeated use. Tune by doing the action ten times in a row.
  • Spinners for actions under about 300-400 ms create flicker; delay showing them.
  • transition: all animates properties you did not intend (including layout ones) and makes theme switches crawl. List properties explicitly.
  • Animating from display: none needs @starting-style and transition-behavior: allow-discrete in CSS, or a JS library; otherwise the entrance never plays.
  • Exit animations need the element to stay mounted (Motion’s AnimatePresence, or waiting for animationend) or they are skipped.

Verification

  • Record the interaction (screen recording at 60 fps, or the DevTools Animations panel at 10% speed) and check easing and stagger match the spec.
  • Toggle reduced motion in DevTools Rendering; every state change is still perceivable.
  • Performance trace with 4x CPU slowdown shows no long frames during transitions.

Output: motion spec

| Interaction | Property | Duration | Easing | Reduced motion |
|---|---|---|---|---|
| Modal open | opacity 0->1, translateY 16->0 | base 250 | ease-out | opacity only, 120 |
| Modal close | opacity, translateY 0->8 | fast 180 | ease-in | instant |
| List insert | height via FLIP, opacity | base 250 | ease-in-out | instant |

Related: small feedback states in $micro-interactions; implementation in $css-animations, $motion-animations or $view-transitions.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Motion Design Principles"
  short_description: "UI motion that explains, then gets out of the way"
  default_prompt: "$motion-design-principles Define motion tokens for our design system and replace the random durations"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem