@minhduydev/mdpi 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/template/.pi/VERSION +1 -1
- package/dist/template/.pi/extensions/templates-injector.ts +34 -6
- package/dist/template/.pi/prompts/INDEX.md +3 -9
- package/dist/template/.pi/skills/INDEX.md +81 -19
- package/dist/template/.pi/skills/accessibility-audit/SKILL.md +8 -2
- package/dist/template/.pi/skills/baseline-ui/SKILL.md +211 -0
- package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
- package/dist/template/.pi/skills/design-taste-frontend/SKILL.md +53 -42
- package/dist/template/.pi/skills/fixing-accessibility/SKILL.md +509 -0
- package/dist/template/.pi/skills/frontend-design/SKILL.md +60 -47
- package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +88 -15
- package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +148 -13
- package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +127 -20
- package/dist/template/.pi/skills/frontend-ui-engineering/SKILL.md +21 -27
- package/dist/template/.pi/skills/nextjs-app-router/SKILL.md +334 -0
- package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -0
- package/dist/template/.pi/skills/oklch-color-workflow/SKILL.md +426 -0
- package/dist/template/.pi/skills/production-hardening/SKILL.md +652 -0
- package/dist/template/.pi/skills/react-best-practices/SKILL.md +79 -1
- package/dist/template/.pi/skills/react-compiler/SKILL.md +237 -0
- package/dist/template/.pi/skills/react-hook-form/SKILL.md +374 -0
- package/dist/template/.pi/skills/react-server-actions/SKILL.md +299 -0
- package/dist/template/.pi/skills/shadcn-ui/SKILL.md +404 -0
- package/dist/template/.pi/skills/tanstack-query/SKILL.md +330 -0
- package/dist/template/.pi/skills/ui-craft-principles/SKILL.md +564 -0
- package/dist/template/.pi/skills/ui-quality-audit/SKILL.md +329 -0
- package/dist/template/.pi/skills/v0/SKILL.md +264 -0
- package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
- package/dist/template/.pi/templates/DESIGN.md +76 -0
- package/dist/template/.pi/workflows/INDEX.md +2 -1
- package/dist/template/.pi/workflows/frontend-feature-workflow.md +343 -0
- package/dist/template/.pi/workflows/quality-loop.md +1 -1
- package/package.json +1 -1
- package/dist/template/.pi/prompts/loop-check.md +0 -87
- package/dist/template/.pi/prompts/loop-init.md +0 -157
- package/dist/template/.pi/prompts/loop-review.md +0 -90
- package/dist/template/.pi/skills/loop-audit/SKILL.md +0 -141
- package/dist/template/.pi/skills/loop-cost/SKILL.md +0 -130
- package/dist/template/.pi/skills/loop-engineering/SKILL.md +0 -175
- package/dist/template/.pi/templates/loop-github-action.yml +0 -162
- package/dist/template/.pi/templates/loop-orchestrator.sh +0 -514
- package/dist/template/.pi/templates/loop-orchestrator.test.ts +0 -332
- package/dist/template/.pi/templates/loop-orchestrator.ts +0 -936
- package/dist/template/.pi/templates/loop-state.json +0 -24
- package/dist/template/.pi/templates/loop-state.md +0 -98
- package/dist/template/.pi/templates/loop-vision.md +0 -110
- /package/dist/template/.pi/templates/{design.md → feature-design.md} +0 -0
|
@@ -3,6 +3,8 @@ name: frontend-design
|
|
|
3
3
|
description: MUST load when building any web UI with React-based frameworks — components, pages, or full applications. Covers Tailwind CSS v4, shadcn/ui, Motion animations. Base UI implementation skill; combine with aesthetic overlays (minimalist-ui, high-end-visual-design) for specific styles.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**Aesthetic Context:** Your implementation must reflect the project `.pi/DESIGN.md` identity. Before writing any component, internalize the Overview & Mood, Colors, and Typography sections. All code output should feel like it belongs to the same intentional design system.
|
|
7
|
+
|
|
6
8
|
# Frontend Design
|
|
7
9
|
|
|
8
10
|
## When to Use
|
|
@@ -18,6 +20,17 @@ description: MUST load when building any web UI with React-based frameworks —
|
|
|
18
20
|
|
|
19
21
|
- Backend-only tasks or minimal UI with no visual design requirements.
|
|
20
22
|
|
|
23
|
+
## Relationship to Other Skills
|
|
24
|
+
|
|
25
|
+
| Skill | Role |
|
|
26
|
+
|-------|------|
|
|
27
|
+
| `design-taste-frontend` | Upstream — sets aesthetic baseline and anti-AI-slops. Load BEFORE this skill. |
|
|
28
|
+
| `frontend-ui-engineering` | Sibling — handles component implementation, accessibility, and state patterns. |
|
|
29
|
+
| `react-best-practices` | Complement — React/Next.js performance patterns. |
|
|
30
|
+
| `baseline-ui` | Quick deslop pass for automatic fixes (spacing, typography). |
|
|
31
|
+
|
|
32
|
+
**Pipeline:** `design-taste-frontend` → `frontend-design` → `frontend-ui-engineering`
|
|
33
|
+
|
|
21
34
|
## Reference Documentation
|
|
22
35
|
|
|
23
36
|
### Tailwind CSS v4.1
|
|
@@ -30,7 +43,7 @@ description: MUST load when building any web UI with React-based frameworks —
|
|
|
30
43
|
|
|
31
44
|
Search: `@theme`, `@container`, `OKLCH`, `mask-`, `text-shadow`
|
|
32
45
|
|
|
33
|
-
### shadcn/ui (CLI
|
|
46
|
+
### shadcn/ui (CLI v4.11)
|
|
34
47
|
|
|
35
48
|
- `./references/shadcn/setup.md` - Installation, visual styles, component list
|
|
36
49
|
- `./references/shadcn/core-components.md` - Button, Card, Dialog, Select, Tabs, Toast
|
|
@@ -67,7 +80,7 @@ For sophisticated compositions: posters, brand materials, design systems.
|
|
|
67
80
|
- `./references/design/interaction.md` - State models, focus, dialogs/popovers, loading patterns
|
|
68
81
|
- `./references/design/ux-writing.md` - Button copy, error structure, empty states, i18n
|
|
69
82
|
|
|
70
|
-
Search: `
|
|
83
|
+
Search: `tinted neutrals`, `focus-visible`, `verb + object`, `65ch`
|
|
71
84
|
|
|
72
85
|
## Design Thinking
|
|
73
86
|
|
|
@@ -79,49 +92,56 @@ Before coding, commit to BOLD aesthetic direction:
|
|
|
79
92
|
|
|
80
93
|
Bold maximalism and refined minimalism both work. Key is intentionality.
|
|
81
94
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
These patterns immediately signal "AI made this." Avoid them all.
|
|
95
|
+
## Don't
|
|
85
96
|
|
|
86
97
|
### Typography
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
99
|
+
| Pattern | Replacement | Because |
|
|
100
|
+
|---------|-------------|---------|
|
|
101
|
+
| Inter, Roboto, Arial as display fonts | Distinctive display fonts (Instrument Sans, Outfit, Fraunces) | Overused fonts signal generic design |
|
|
102
|
+
| Monospace used as "developer aesthetic" shorthand | Purposeful type choice; mono only for code/data | Mono-as-aesthetic reads as placeholder design |
|
|
103
|
+
| Big icons centered above every heading | Integrated icon + heading lockup, or icon inline | Giant centered icons feel template-generated |
|
|
104
|
+
| Using `px` for body text | `rem`/`em` to respect user font-size preferences | `px` ignores accessibility and user settings |
|
|
92
105
|
|
|
93
106
|
### Color
|
|
94
107
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
| Pattern | Replacement | Because |
|
|
109
|
+
|---------|-------------|---------|
|
|
110
|
+
| Gray text on colored backgrounds | Darker shade of the background color | Gray-on-color fails contrast and looks muddy |
|
|
111
|
+
| Pure `#000` or `#fff` | Tinted near-black or near-white | Pure black/white don't exist in natural light |
|
|
112
|
+
| Gradient text on headings or metrics | Solid, well-chosen heading color | Gradient text is a design crutch |
|
|
113
|
+
| `rgba()` / heavy alpha transparency as primary palette | Explicit, named color values | Heavy alpha stacking creates unpredictable colors |
|
|
100
114
|
|
|
101
115
|
### Layout
|
|
102
116
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
| Pattern | Replacement | Because |
|
|
118
|
+
|---------|-------------|---------|
|
|
119
|
+
| Cards nested inside cards | Typography, spacing, dividers for hierarchy | Nested cards create visual noise without purpose |
|
|
120
|
+
| Identical card grids (icon + heading + text ×3-6) | Varied layout with purposeful asymmetry | Repeated identical cards is the #1 AI tell |
|
|
121
|
+
| Hero metric template (big number + small label + gradient accent) | Contextual data display — number embedded in prose or card | Generic hero metrics are the startup-template cliché |
|
|
122
|
+
| Center-aligning everything | Left-align content blocks; reserve center for short hero headlines | Center-aligned body text is hard to scan |
|
|
123
|
+
| Same spacing everywhere (no visual rhythm) | Use proximity to group related items; vary spacing to create sections | Uniform spacing flattens hierarchy |
|
|
108
124
|
|
|
109
125
|
### Visual
|
|
110
126
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
| Pattern | Replacement | Because |
|
|
128
|
+
|---------|-------------|---------|
|
|
129
|
+
| Glassmorphism used decoratively | Flat surfaces or layered shadows | Glassmorphism needs a functional reason for depth |
|
|
130
|
+
| Thick colored border on one side of rounded rectangles | Subtle border or shadow on entire element | One-sided colored borders are a dated pattern |
|
|
131
|
+
| Sparklines as decoration (not connected to real data) | Real sparklines from actual data, or omit entirely | Decorative sparklines are fake data theater |
|
|
132
|
+
| Generic drop shadows on everything | Intentional shadow hierarchy — only where depth communicates meaning | Shadow-everywhere flattens the depth language |
|
|
133
|
+
| Rounded rectangles as the only shape language | Mix shapes: sharp corners, soft corners, circles, organic shapes | Single-shape designs feel templated |
|
|
116
134
|
|
|
117
135
|
### Motion
|
|
118
136
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
137
|
+
| Pattern | Replacement | Because |
|
|
138
|
+
|---------|-------------|---------|
|
|
139
|
+
| Bounce or elastic easing on UI | Exponential easing `cubic-bezier(0.16, 1, 0.3, 1)` | Real objects decelerate smoothly, not bounce |
|
|
140
|
+
| Animating `height`, `width`, `padding`, `margin` | Animate only `transform` and `opacity` | Layout animations cause expensive repaints |
|
|
141
|
+
| Default `ease` | Exponential easing curves tuned to animation purpose | Default `ease` is a compromise rarely optimal |
|
|
142
|
+
| Missing `prefers-reduced-motion` handling | Always respect reduced motion preferences | ~35% of adults over 40 prefer reduced motion |
|
|
123
143
|
|
|
124
|
-
> **The
|
|
144
|
+
> **The Slop Test:** If you showed this interface to someone and said "AI made this," would they believe you immediately? If yes, that's the problem.
|
|
125
145
|
|
|
126
146
|
## Best Practices
|
|
127
147
|
|
|
@@ -235,28 +255,21 @@ Create atmosphere: gradient meshes, noise textures, geometric patterns, layered
|
|
|
235
255
|
|
|
236
256
|
| Rationalization | Reality |
|
|
237
257
|
|---|---|
|
|
238
|
-
| "The
|
|
258
|
+
| "The default look is fine for now" | Default styles signal low quality. Use the design system from the start. |
|
|
239
259
|
| "I'll make it responsive later" | Retrofitting responsive design is 3x harder than building it mobile-first. |
|
|
240
260
|
| "Accessibility is a nice-to-have" | It's a legal requirement in many jurisdictions and an engineering quality standard. |
|
|
241
261
|
| "This is just a prototype" | Prototypes become production code. Build the foundation right from the start. |
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- Components exceeding 200 lines (split them)
|
|
246
|
-
- Inline styles or arbitrary pixel values
|
|
247
|
-
- Missing error states, loading states, or empty states
|
|
248
|
-
- No keyboard navigation testing
|
|
249
|
-
- Color as the sole indicator of state (red/green without text or icons)
|
|
250
|
-
- Generic "AI look" (purple gradients, oversized cards, stock layouts)
|
|
262
|
+
| "Typography doesn't matter for functionality" | Typography is 95% of web design. Bad type ruins even good layouts. |
|
|
263
|
+
| "Users won't notice the details" | Users may not articulate it, but they feel quality. Details accumulate into perception. |
|
|
251
264
|
|
|
252
265
|
## Verification
|
|
253
266
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
- [ ]
|
|
257
|
-
- [ ]
|
|
258
|
-
- [ ]
|
|
267
|
+
- [ ] Design tokens defined: primitives + semantic layer, with dark mode variants
|
|
268
|
+
- [ ] Typography: distinctive font pairing, fluid sizing with `clamp()`, `max-width: 65ch` on body text
|
|
269
|
+
- [ ] Color: OKLCH tokens, tinted neutrals (chroma 0.01-0.02), sufficient contrast (4.5:1 min)
|
|
270
|
+
- [ ] Motion: exponential easing only, `prefers-reduced-motion` handled, only `transform` + `opacity` animated
|
|
271
|
+
- [ ] Spacing: consistent 4pt scale, `gap` over margins, self-adjusting grids
|
|
259
272
|
- [ ] Responsive: works at 320px, 768px, 1024px, 1440px
|
|
260
|
-
- [ ]
|
|
261
|
-
- [ ]
|
|
262
|
-
- [ ] No
|
|
273
|
+
- [ ] Interaction: all 8 states designed, `:focus-visible` used, skeletons over spinners
|
|
274
|
+
- [ ] UX Writing: verb + object buttons, error = what + why + fix, empty states are onboarding
|
|
275
|
+
- [ ] No banned fonts, no gray-on-color text, no pure black/white
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Motion Advanced
|
|
2
2
|
|
|
3
|
-
Scroll, orchestration, TypeScript, performance.
|
|
3
|
+
Scroll, orchestration, TypeScript, AnimateView, performance.
|
|
4
4
|
|
|
5
5
|
## Scroll Animations
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
8
|
import { motion, useScroll, useTransform } from 'motion/react';
|
|
9
9
|
|
|
10
|
-
// Scroll progress
|
|
10
|
+
// Scroll progress (GPU-accelerated via ScrollTimeline API since v12.32)
|
|
11
11
|
const { scrollYProgress } = useScroll();
|
|
12
12
|
const opacity = useTransform(scrollYProgress, [0, 1], [1, 0]);
|
|
13
13
|
|
|
@@ -36,7 +36,7 @@ const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8]);
|
|
|
36
36
|
## AnimatePresence Modes
|
|
37
37
|
|
|
38
38
|
```tsx
|
|
39
|
-
// Wait for exit before enter
|
|
39
|
+
// Wait for exit before enter (recommended for page transitions)
|
|
40
40
|
<AnimatePresence mode="wait">
|
|
41
41
|
<motion.div key={currentPage} />
|
|
42
42
|
</AnimatePresence>
|
|
@@ -50,6 +50,37 @@ const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8]);
|
|
|
50
50
|
<AnimatePresence mode="sync" />
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## AnimateView (New — Motion+ Early Access)
|
|
54
|
+
|
|
55
|
+
View Transitions wrapper for React. Enter/exit/update/share animations for page transitions:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { AnimateView } from 'motion/react'
|
|
59
|
+
|
|
60
|
+
<AnimateView>
|
|
61
|
+
<motion.div
|
|
62
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
63
|
+
initial={{ opacity: 0, scale: 0.95 }}
|
|
64
|
+
/>
|
|
65
|
+
</AnimateView>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Built on React 19.2 `ViewTransition` component. Works alongside Next.js 16 `experimental.viewTransition`.
|
|
69
|
+
|
|
70
|
+
## arc() — Curved Motion Paths (v12.40+)
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { arc } from 'motion/react'
|
|
74
|
+
|
|
75
|
+
<motion.div
|
|
76
|
+
animate={{
|
|
77
|
+
x: 200,
|
|
78
|
+
y: -120,
|
|
79
|
+
transition: { path: arc() }
|
|
80
|
+
}}
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
53
84
|
## Orchestration
|
|
54
85
|
|
|
55
86
|
```tsx
|
|
@@ -157,6 +188,24 @@ const prefersReduced = useReducedMotion();
|
|
|
157
188
|
|
|
158
189
|
// Use layoutRoot to isolate layout calculations
|
|
159
190
|
<motion.div layoutRoot />
|
|
191
|
+
|
|
192
|
+
// Axis-locked layout (v12.35+) — cheaper than full layout
|
|
193
|
+
<motion.div layout="x" />
|
|
194
|
+
|
|
195
|
+
// Custom anchor point (v12.38+)
|
|
196
|
+
<motion.div layoutAnchor={{ x: 0.5, y: 0.5 }} />
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## CSS Color Support (v12.35+)
|
|
200
|
+
|
|
201
|
+
Motion now supports modern CSS color formats:
|
|
202
|
+
- `oklch()`, `oklab()`, `lab()`, `lch()`
|
|
203
|
+
- `color-mix()`, `light-dark()`
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<motion.div
|
|
207
|
+
animate={{ backgroundColor: 'oklch(0.65 0.22 250)' }}
|
|
208
|
+
/>
|
|
160
209
|
```
|
|
161
210
|
|
|
162
211
|
## Common Patterns
|
|
@@ -171,18 +220,28 @@ const prefersReduced = useReducedMotion();
|
|
|
171
220
|
/>
|
|
172
221
|
```
|
|
173
222
|
|
|
174
|
-
### Page transitions
|
|
223
|
+
### Page transitions (Next.js App Router)
|
|
175
224
|
```tsx
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
225
|
+
// app/template.tsx
|
|
226
|
+
'use client'
|
|
227
|
+
import { AnimatePresence, motion } from 'motion/react'
|
|
228
|
+
import { usePathname } from 'next/navigation'
|
|
229
|
+
|
|
230
|
+
export default function Template({ children }) {
|
|
231
|
+
const pathname = usePathname()
|
|
232
|
+
return (
|
|
233
|
+
<AnimatePresence mode="wait" initial={false}>
|
|
234
|
+
<motion.main
|
|
235
|
+
key={pathname}
|
|
236
|
+
initial={{ opacity: 0, x: 20 }}
|
|
237
|
+
animate={{ opacity: 1, x: 0 }}
|
|
238
|
+
exit={{ opacity: 0, x: -20 }}
|
|
239
|
+
>
|
|
240
|
+
{children}
|
|
241
|
+
</motion.main>
|
|
242
|
+
</AnimatePresence>
|
|
243
|
+
)
|
|
244
|
+
}
|
|
186
245
|
```
|
|
187
246
|
|
|
188
247
|
### Expandable card
|
|
@@ -212,13 +271,27 @@ anime.js v4 still appropriate for:
|
|
|
212
271
|
- Non-React projects
|
|
213
272
|
|
|
214
273
|
```javascript
|
|
215
|
-
// anime.js for SVG morphing
|
|
216
274
|
import { animate, svg } from 'animejs';
|
|
217
275
|
animate('#path1', { d: svg.morphTo('#path2'), duration: 1 });
|
|
218
276
|
```
|
|
219
277
|
|
|
278
|
+
## Library Comparison (2026)
|
|
279
|
+
|
|
280
|
+
| Library | Bundle | React DX | Scroll | Gestures | Layout Anim |
|
|
281
|
+
|---------|--------|----------|--------|----------|-------------|
|
|
282
|
+
| **Motion** | ~85KB | 🏆 Best | Built-in | Built-in | Built-in |
|
|
283
|
+
| GSAP | ~78KB | Imperative | ScrollTrigger | Draggable | Flip plugin |
|
|
284
|
+
| React Spring | ~45KB | Good | External | ❌ | ❌ |
|
|
285
|
+
| Anime.js | ~52KB | Imperative | External | ❌ | ❌ |
|
|
286
|
+
| TailwindCSS Motion | ~5KB | Good | Built-in | ❌ | ❌ |
|
|
287
|
+
|
|
288
|
+
**Verdict**: Motion for React-first projects with complex interactions. GSAP for marketing sites with complex timelines. React Spring for physics-driven natural motion. Anime.js for SVG path animations.
|
|
289
|
+
|
|
220
290
|
## Installation
|
|
221
291
|
|
|
222
292
|
```bash
|
|
223
293
|
npm install motion
|
|
294
|
+
# or migrate from framer-motion:
|
|
295
|
+
npm uninstall framer-motion && npm install motion
|
|
296
|
+
# swap imports: "framer-motion" → "motion/react"
|
|
224
297
|
```
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Motion Core (motion/react)
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Package**: `motion` (v12.40.0). Formerly "framer-motion".
|
|
4
|
+
**Import**: `import { motion, AnimatePresence, useScroll, useTransform } from 'motion/react'`
|
|
5
|
+
|
|
6
|
+
Framer Motion rebranded to **Motion** in November 2024. Both `motion` and `framer-motion` packages published in lockstep. New projects use `motion`. No breaking changes in v12 for React.
|
|
4
7
|
|
|
5
8
|
## Motion Principles
|
|
6
9
|
|
|
@@ -8,6 +11,8 @@
|
|
|
8
11
|
- Use motion to explain state change and hierarchy
|
|
9
12
|
- Prefer subtle distance (`8-16px`) and opacity shifts
|
|
10
13
|
- Use consistent timing/easing system across the app
|
|
14
|
+
- Let Tailwind handle static styles; Motion handles behavior
|
|
15
|
+
- **Remove `transition-*` Tailwind classes from motion elements** — they conflict
|
|
11
16
|
|
|
12
17
|
## Timing System
|
|
13
18
|
|
|
@@ -19,6 +24,7 @@
|
|
|
19
24
|
| Large entrances | 500-800ms |
|
|
20
25
|
|
|
21
26
|
**Rule**: exit duration = ~75% of enter duration.
|
|
27
|
+
**Never exceed 600ms for UI responsiveness.**
|
|
22
28
|
|
|
23
29
|
## Easing System
|
|
24
30
|
|
|
@@ -29,20 +35,20 @@ const EASING_ENTER = [0.16, 1, 0.3, 1];
|
|
|
29
35
|
const EASING_EXIT = [0.4, 0, 1, 1];
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
Avoid bounce/elastic easings for product UI.
|
|
38
|
+
Avoid bounce/elastic easings for product UI. Motion's hybrid engine runs animations natively via Web Animations API (WAAPI) and ScrollTimeline for 120fps GPU performance, falling back to JS only for spring physics and gestures.
|
|
33
39
|
|
|
34
40
|
## Performance Rules
|
|
35
41
|
|
|
36
42
|
Animate only compositor-friendly properties:
|
|
37
43
|
|
|
38
|
-
- `transform`
|
|
44
|
+
- `transform` (x, y, scale, rotate, skew)
|
|
39
45
|
- `opacity`
|
|
40
46
|
|
|
41
47
|
Avoid animating:
|
|
42
48
|
|
|
43
|
-
- `width`, `height`
|
|
44
|
-
- `top`, `left`
|
|
45
|
-
- `margin`, `padding`
|
|
49
|
+
- `width`, `height` — triggers layout recalculation
|
|
50
|
+
- `top`, `left` — use `x`/`y` instead
|
|
51
|
+
- `margin`, `padding`, `border`
|
|
46
52
|
|
|
47
53
|
## Basic Pattern
|
|
48
54
|
|
|
@@ -54,6 +60,101 @@ Avoid animating:
|
|
|
54
60
|
/>
|
|
55
61
|
```
|
|
56
62
|
|
|
63
|
+
## React 19 + Next.js 15/16
|
|
64
|
+
|
|
65
|
+
### Page Transitions (App Router)
|
|
66
|
+
|
|
67
|
+
**Critical**: Use `template.tsx`, NOT `layout.tsx`. Layout persists across routes and never remounts.
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// app/template.tsx
|
|
71
|
+
'use client'
|
|
72
|
+
|
|
73
|
+
import { AnimatePresence, motion } from 'motion/react'
|
|
74
|
+
import { usePathname } from 'next/navigation'
|
|
75
|
+
|
|
76
|
+
export default function Template({ children }: { children: React.ReactNode }) {
|
|
77
|
+
const pathname = usePathname()
|
|
78
|
+
return (
|
|
79
|
+
<AnimatePresence mode="wait" initial={false}>
|
|
80
|
+
<motion.div
|
|
81
|
+
key={pathname}
|
|
82
|
+
initial={{ opacity: 0, y: 8 }}
|
|
83
|
+
animate={{ opacity: 1, y: 0 }}
|
|
84
|
+
exit={{ opacity: 0, y: -8 }}
|
|
85
|
+
transition={{ duration: 0.18, ease: 'easeInOut' }}
|
|
86
|
+
style={{ minHeight: 'var(--page-min-height, 100dvh)' }}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
</motion.div>
|
|
90
|
+
</AnimatePresence>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Dynamic Import (Performance)
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import dynamic from 'next/dynamic'
|
|
99
|
+
|
|
100
|
+
const AnimatedWrapper = dynamic(() => import('@/components/animated-wrapper'), {
|
|
101
|
+
ssr: false,
|
|
102
|
+
loading: ({ children }) => <>{children}</>,
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### React 19.2 View Transitions
|
|
107
|
+
|
|
108
|
+
Next.js 16 + React 19.2 support native View Transitions via `experimental.viewTransition: true`. Motion's `AnimateView` (premium) builds on this.
|
|
109
|
+
|
|
110
|
+
## Integration with shadcn/ui
|
|
111
|
+
|
|
112
|
+
**Architecture**: shadcn/ui = structure + accessibility. Motion = behavior + animation. Wrap/extend shadcn components — don't replace.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
src/
|
|
116
|
+
├── components/
|
|
117
|
+
│ ├── ui/ # shadcn generated (untouched)
|
|
118
|
+
│ └── animated/ # Motion-wrapped shadcn components
|
|
119
|
+
│ ├── AnimatedButton.tsx
|
|
120
|
+
│ ├── AnimatedDialog.tsx
|
|
121
|
+
│ └── ...
|
|
122
|
+
└── lib/
|
|
123
|
+
└── animations.ts # Shared variants & transition configs
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Shared Variants Pattern
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// lib/animations.ts
|
|
130
|
+
import type { Variants, Transition } from 'motion/react'
|
|
131
|
+
|
|
132
|
+
export const fadeIn: Variants = {
|
|
133
|
+
initial: { opacity: 0 },
|
|
134
|
+
animate: { opacity: 1 },
|
|
135
|
+
exit: { opacity: 0 },
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const slideUp: Variants = {
|
|
139
|
+
initial: { opacity: 0, y: 20 },
|
|
140
|
+
animate: { opacity: 1, y: 0 },
|
|
141
|
+
exit: { opacity: 0, y: 20 },
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const spring: Transition = {
|
|
145
|
+
type: 'spring',
|
|
146
|
+
stiffness: 300,
|
|
147
|
+
damping: 25,
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Installation Order
|
|
152
|
+
|
|
153
|
+
1. `npx shadcn init` + add components
|
|
154
|
+
2. `npm install motion`
|
|
155
|
+
3. Create `lib/animations.ts` for shared variants
|
|
156
|
+
4. Create `components/animated/` directory for wrapped components
|
|
157
|
+
|
|
57
158
|
## Variants Pattern (Recommended)
|
|
58
159
|
|
|
59
160
|
```tsx
|
|
@@ -69,8 +170,6 @@ const card = {
|
|
|
69
170
|
<motion.div variants={card} initial="hidden" animate="visible" />
|
|
70
171
|
```
|
|
71
172
|
|
|
72
|
-
Use variants for shared timing and maintainability.
|
|
73
|
-
|
|
74
173
|
## Exit Animations (AnimatePresence)
|
|
75
174
|
|
|
76
175
|
```tsx
|
|
@@ -87,7 +186,7 @@ Use variants for shared timing and maintainability.
|
|
|
87
186
|
</AnimatePresence>
|
|
88
187
|
```
|
|
89
188
|
|
|
90
|
-
Always provide stable `key` values
|
|
189
|
+
Always provide stable `key` values. Use `mode="wait"` to prevent overlapping DOM elements.
|
|
91
190
|
|
|
92
191
|
## Stagger Patterns
|
|
93
192
|
|
|
@@ -123,6 +222,9 @@ Use `layout` for reordering and size changes. Add spring only when needed:
|
|
|
123
222
|
<motion.div layout transition={{ type: 'spring', stiffness: 320, damping: 28 }} />
|
|
124
223
|
```
|
|
125
224
|
|
|
225
|
+
**New (v12.35+)**: Axis-locked layout: `layout="x"` or `layout="y"`.
|
|
226
|
+
**New (v12.38+)**: Custom anchor: `layoutAnchor={{ x: 0.5, y: 0.5 }}`.
|
|
227
|
+
|
|
126
228
|
## Gestures
|
|
127
229
|
|
|
128
230
|
```tsx
|
|
@@ -133,7 +235,7 @@ Use `layout` for reordering and size changes. Add spring only when needed:
|
|
|
133
235
|
/>
|
|
134
236
|
```
|
|
135
237
|
|
|
136
|
-
Keep gesture amplitudes subtle (`0.98-1.03`).
|
|
238
|
+
Keep gesture amplitudes subtle (`0.98-1.03`). Available: `whileHover`, `whileTap`, `whileFocus`, `whileDrag`, `whileInView`.
|
|
137
239
|
|
|
138
240
|
## Height Expand/Collapse (No height animation)
|
|
139
241
|
|
|
@@ -168,14 +270,47 @@ Use CSS grid technique:
|
|
|
168
270
|
}
|
|
169
271
|
```
|
|
170
272
|
|
|
171
|
-
For motion/react,
|
|
273
|
+
For motion/react, use `useReducedMotion()`:
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
import { useReducedMotion } from 'motion/react'
|
|
277
|
+
|
|
278
|
+
const prefersReduced = useReducedMotion()
|
|
279
|
+
|
|
280
|
+
<motion.div
|
|
281
|
+
animate={prefersReduced ? {} : { scale: 1.1 }}
|
|
282
|
+
/>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Motion AI Kit
|
|
286
|
+
|
|
287
|
+
Official Motion AI tools (premium, Motion+ required):
|
|
288
|
+
```bash
|
|
289
|
+
npx motion-ai # Install MCP server + skills for Claude Code, Cursor, Windsurf, etc.
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Provides: 400+ premium examples, MotionScore runtime profiling, CSS spring generation, transition editing.
|
|
293
|
+
|
|
294
|
+
## Common Pitfalls
|
|
295
|
+
|
|
296
|
+
| Pitfall | Fix |
|
|
297
|
+
|---------|-----|
|
|
298
|
+
| `layout.tsx` for AnimatePresence (CLS) | Use `template.tsx` with `mode="wait"` |
|
|
299
|
+
| `transition-*` classes on motion elements | Remove Tailwind transition classes |
|
|
300
|
+
| Animating `width`/`height` | Use `scaleX`/`scaleY` or grid technique |
|
|
301
|
+
| Missing `use client` in Next.js | Extract animation to client component |
|
|
302
|
+
| `mode="sync"` with page transitions | Use `mode="wait"` to prevent overlap |
|
|
303
|
+
| Duration > 600ms for UI | Cap at 600ms; reserve long durations for storytelling |
|
|
172
304
|
|
|
173
305
|
## Quick Checklist
|
|
174
306
|
|
|
175
|
-
- [ ] Uses `motion/react` import
|
|
307
|
+
- [ ] Uses `motion/react` import (not `framer-motion`)
|
|
176
308
|
- [ ] Timing follows 100/300/500ms system
|
|
177
309
|
- [ ] Exponential easing, no bounce/elastic
|
|
178
310
|
- [ ] Animates only `transform` and `opacity`
|
|
179
311
|
- [ ] Uses `AnimatePresence` for exit states
|
|
180
|
-
- [ ] Includes reduced motion support
|
|
312
|
+
- [ ] Includes reduced motion support (CSS + `useReducedMotion()`)
|
|
181
313
|
- [ ] Stagger windows stay under 500ms
|
|
314
|
+
- [ ] Next.js: uses `template.tsx` not `layout.tsx`
|
|
315
|
+
- [ ] No `transition-*` classes on motion elements
|
|
316
|
+
- [ ] shadcn/ui: animated components in `components/animated/`
|