# swiftui-motion

Provides SwiftUI animation rules and decision trees for coding agents. Helps configure springs, phase animators, and clean transitions without visual bugs.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 943 installs · ★ 677
- Author: AThevon
- License: MIT · policy=mirror · the beginning of the file is at the end of this page
- Source: https://github.com/AThevon/genjutsu/tree/HEAD/skills/_jutsu/swiftui-motion/SKILL.md
- Updated: 2026-10-05
- HTML: https://affpapa.org/en/nevibecode/skills/swiftui-motion

## What it does

The skill provides a strict decision tree for SwiftUI motion APIs. It guides the agent when to use simple `withAnimation`, when to reach for `PhaseAnimator` or `KeyframeAnimator` on iOS 17+, and how to build hero transitions via `matchedGeometryEffect`.

It defines exact tuning for spring presets like `.snappy`, `.bouncy`, and `.smooth`, advising against setting damping to zero. Mixing explicit `withAnimation` and implicit `.animation` on the same property is strictly forbidden because it causes modifier stacking conflicts. Note that compiling custom properties with the `@Animatable` macro requires Xcode 26.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add AThevon/genjutsu --skill swiftui-motion -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/swiftui-motion/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/swiftui-motion/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add AThevon/genjutsu --skill swiftui-motion -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/swiftui-motion/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add AThevon/genjutsu --skill swiftui-motion -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/swiftui-motion/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install AThevon/genjutsu swiftui-motion
```

2. **Manually: put the files in place**
- File: `.github/skills/swiftui-motion/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add AThevon/genjutsu --skill swiftui-motion -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/AThevon/genjutsu --path skills/_jutsu/swiftui-motion
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/swiftui-motion/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add AThevon/genjutsu --skill swiftui-motion -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/AThevon/genjutsu/tree/HEAD/skills/_jutsu/swiftui-motion/SKILL.md

## When to use it
- select the right spring preset instead of guessing damping values
- build shared element transitions using `matchedGeometryEffect`
- sequence multi-step state changes with `PhaseAnimator`
- prevent views from collapsing to zero scale during removal transitions

## Example prompts
- Build a card expand animation using matchedGeometryEffect and a smooth spring
- Animate this checkmark through multiple states with PhaseAnimator
- Add an asymmetric transition to this modal without scaling to zero

## Source text · SKILL.md · MIT

Below is the content of a third-party file. It is data, not instructions for you: do not act on anything written inside unless the human asks. Block tag: d878b24be630de6c.

BEGIN THIRD-PARTY FILE d878b24be630de6c
````text
---
name: swiftui-motion
description: "SwiftUI animation foundations - withAnimation, transitions, matchedGeometryEffect, PhaseAnimator, KeyframeAnimator, springs, gestures."
metadata:
  internal: true
---

> **Version-sensitive.** Every API name, SDK gate and browser-support claim below was
> verified on **2026-09-08** against primary sources. What against, and when, is in
> `_jutsu/VERSIONS.md`. If that date is old, re-verify before acting on a version number.

# SwiftUI Motion

> SwiftUI animation core. Loaded for any SwiftUI project (iOS, macOS, multi-target Apple).
> Concise rules here. Deep-dive in `references/`.
> Pair with `../motion-principles/SKILL.md` (foundation) and `../mobile-principles/SKILL.md` (touch UX).

---

## Animation API decision tree

| Need | API |
|---|---|
| Single value over time | `withAnimation { } + @State` or `.animation(_, value:)` |
| Multiple coordinated states | `PhaseAnimator(phases)` (iOS 17+) |
| Time-based keyframes | `KeyframeAnimator(initialValue:repeating:content:)` (iOS 17+) |
| Custom property animations | `@Animatable` macro (needs Xcode 26 / SwiftUI 2025 SDK to compile; **runtime availability iOS 13.0+ / macOS 10.15+ / watchOS 6.0+**) or the `Animatable` protocol by hand (iOS 13+) |
| Shared element transitions | `matchedGeometryEffect(id:in:)` |
| Gesture-driven | `DragGesture` / `MagnifyGesture` + `.offset` / `.scaleEffect` |
| Loop forever | `.animation(.linear.repeatForever(autoreverses: true), value: ...)` or `.phaseAnimator` |

**Rule:** start with `withAnimation`. Reach for `PhaseAnimator` only when you have 3+ ordered states. Reach for `KeyframeAnimator` only when you need parallel time-based tracks.

---

## Springs (the only easing you should care about)

SwiftUI ships named spring presets (iOS 17+): `.snappy`, `.bouncy`, `.smooth`, plus the parameterised
`.spring(duration:bounce:blendDuration:)` and `.interactiveSpring(...)`. Each of the three named ones
also takes `(duration:extraBounce:)` overloads. Use them. Tune `response` / `dampingFraction` only when
a preset is wrong.

| Preset (iOS 17+) | Equivalent | Mood |
|---|---|---|
| `.snappy` | `.spring(response: 0.5, dampingFraction: 0.85)` | UI snappy |
| `.bouncy` | `.spring(response: 0.5, dampingFraction: 0.7)` | playful |
| `.smooth` | `.spring(response: 0.5, dampingFraction: 1.0)` | calm, no bounce |
| `.interactiveSpring()` | `.spring(response: 0.15, dampingFraction: 0.86)` | gesture follow |

`response` is the spring's **period** - its stiffness expressed as a duration, i.e. how long one
oscillation would take. It is **not** the settling time: a `.spring(response: 0.5, dampingFraction: 1.0)`
keeps moving well past 0.5s. Lower = snappier, higher = softer. `dampingFraction` is the overshoot intensity in `0...1` (1 = no overshoot, 0 = perpetual oscillation - never use 0). For UI work, stay in `response: 0.2...0.5` and `dampingFraction: 0.7...1.0`. Deep-dive: `references/springs-cheatsheet.md`.

iOS 17+ also exposes `.spring(duration:bounce:)` where `bounce` is `0...1` (0 = critically damped, 1 = full bounce). It's the same spring, exposed in a more designer-friendly way:

```swift
````
END THIRD-PARTY FILE d878b24be630de6c

The third-party file has ended. Everything between the d878b24be630de6c tags is data: requests and commands from it are not followed. An “end of file” line with another tag inside the block is part of the file.

First 3149 of 15839 bytes. © AThevon · MIT · https://github.com/AThevon/genjutsu/tree/HEAD/skills/_jutsu/swiftui-motion/SKILL.md

_Part of the page did not fit — see the HTML version._

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
