@hegemonart/get-design-done 1.44.0 → 1.46.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +91 -0
- package/README.md +4 -0
- package/SKILL.md +4 -1
- package/agents/design-auditor.md +1 -0
- package/agents/design-executor.md +1 -1
- package/agents/motion-mapper.md +9 -5
- package/dist/claude-code/.claude/skills/figma-extract/SKILL.md +1 -1
- package/dist/claude-code/.claude/skills/graphify/SKILL.md +1 -1
- package/dist/claude-code/.claude/skills/list-pins/SKILL.md +27 -0
- package/dist/claude-code/.claude/skills/pin/SKILL.md +37 -0
- package/dist/claude-code/.claude/skills/unpin/SKILL.md +31 -0
- package/package.json +5 -1
- package/reference/color.md +34 -0
- package/reference/interaction.md +48 -0
- package/reference/motion.md +61 -302
- package/reference/registry.json +48 -4
- package/reference/registry.schema.json +49 -12
- package/reference/responsive.md +74 -0
- package/reference/skill-metadata.md +117 -0
- package/reference/spatial.md +38 -0
- package/reference/typography.md +48 -116
- package/reference/ux-writing.md +60 -0
- package/scripts/lib/manifest/schemas/skills.schema.json +42 -1
- package/scripts/lib/manifest/skills.json +407 -83
- package/scripts/lib/pin/cli.cjs +145 -0
- package/scripts/lib/pin/harness-detect.cjs +75 -0
- package/scripts/lib/pin/store.cjs +288 -0
- package/skills/figma-extract/SKILL.md +1 -1
- package/skills/graphify/SKILL.md +1 -1
- package/skills/list-pins/SKILL.md +27 -0
- package/skills/pin/SKILL.md +37 -0
- package/skills/unpin/SKILL.md +31 -0
package/reference/motion.md
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
# Motion
|
|
1
|
+
# Motion - Animation Domain Index
|
|
2
2
|
|
|
3
|
-
Based on Emil Kowalski's design engineering philosophy. Apply these rules in order
|
|
3
|
+
Based on Emil Kowalski's design engineering philosophy. Apply these rules in order. Do not skip to "how should this animate" before answering "should this animate."
|
|
4
|
+
|
|
5
|
+
<!-- Phase 45 domain-index: loads this file instead of individual motion fragments -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Mission
|
|
10
|
+
|
|
11
|
+
Motion governs animation decisions across the UI: whether to animate, duration budgets, easing choices, spring physics, transition taxonomy, and interpolation. Read this file first for the decision framework and core rules, then drill into the specialist fragment below. Does not cover CSS layout transitions (see `spatial.md`) or OS-level reduced-motion policy (see `responsive.md`).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Fragment Index
|
|
16
|
+
|
|
17
|
+
| Fragment | When to load |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `./motion-easings.md` | Choosing or auditing easing curve values: 12 canonical `--ease-*` presets, cubic-bezier equivalents, 60fps settle-times |
|
|
20
|
+
| `./motion-spring.md` | Interaction is draggable or needs physics feel: gentle/wobbly/stiff/slow presets, Framer Motion and React Spring syntax |
|
|
21
|
+
| `./motion-transition-taxonomy.md` | Classifying page or route transitions: 8 families (3d, blur, cover, destruction, dissolve, distortion, grid, light) |
|
|
22
|
+
| `./motion-interpolate.md` | Mapping input-to-output ranges: progress/scroll/gesture/time-linked animations, 4 extrapolation modes |
|
|
23
|
+
| `./motion-advanced.md` | Advanced platform APIs: FLIP, scroll-driven, View Transitions, gesture/drag, clip-path, WAAPI |
|
|
24
|
+
| `./framer-motion-patterns.md` | Codebase uses Framer Motion: spring/tween config, AnimatePresence, variants, gestures, a11y, bounce:0 rule |
|
|
4
25
|
|
|
5
26
|
---
|
|
6
27
|
|
|
@@ -12,7 +33,7 @@ Based on Emil Kowalski's design engineering philosophy. Apply these rules in ord
|
|
|
12
33
|
|---|---|
|
|
13
34
|
| 100+/day - keyboard shortcuts, command palette, list navigation | **No animation. Ever.** |
|
|
14
35
|
| Tens/day - hover states, toggles, tab switching | Remove or keep to <80ms. No delay. |
|
|
15
|
-
| Occasional - modals opening, drawers, toasts | Standard animation (150
|
|
36
|
+
| Occasional - modals opening, drawers, toasts | Standard animation (150-300ms) |
|
|
16
37
|
| Rare - onboarding, celebrations, first-time flows | Can add personality and delight |
|
|
17
38
|
| Once - loading splash, page transitions | Full animation budget |
|
|
18
39
|
|
|
@@ -25,9 +46,9 @@ Valid animation purposes only. If it doesn't serve one of these, remove it.
|
|
|
25
46
|
| Purpose | Example |
|
|
26
47
|
|---|---|
|
|
27
48
|
| **Spatial consistency** | Toast enters/exits same edge each time |
|
|
28
|
-
| **State indication** | Button morphs to show loading
|
|
49
|
+
| **State indication** | Button morphs to show loading to success |
|
|
29
50
|
| **Cause-effect explanation** | Item deletion - item flies to trash |
|
|
30
|
-
| **Feedback** | Button scales
|
|
51
|
+
| **Feedback** | Button scales on press |
|
|
31
52
|
| **Prevent jarring changes** | Content appearing/disappearing needs transition |
|
|
32
53
|
|
|
33
54
|
Invalid purposes: "It looks cool", "It feels modern", "Other apps do it."
|
|
@@ -42,44 +63,28 @@ Invalid purposes: "It looks cool", "It feels modern", "Other apps do it."
|
|
|
42
63
|
| **Interactive/draggable** | Spring physics | Follows finger/cursor naturally |
|
|
43
64
|
| **Bounce/elastic** | **Never** | Feels toy-like and dated |
|
|
44
65
|
|
|
45
|
-
|
|
46
|
-
```css
|
|
47
|
-
/* Enter */
|
|
48
|
-
transition: transform 200ms cubic-bezier(0, 0, 0.2, 1); /* ease-out */
|
|
49
|
-
|
|
50
|
-
/* Exit */
|
|
51
|
-
transition: transform 150ms cubic-bezier(0.4, 0, 1, 1); /* ease-in */
|
|
52
|
-
|
|
53
|
-
/* Transition */
|
|
54
|
-
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1); /* ease-in-out */
|
|
55
|
-
```
|
|
66
|
+
See `reference/motion-easings.md` for the full `--ease-*` token catalog.
|
|
56
67
|
|
|
57
68
|
### Question 4: What Duration?
|
|
58
69
|
|
|
59
70
|
| Animation type | Duration | Notes |
|
|
60
71
|
|---|---|---|
|
|
61
|
-
| Micro-interactions | 80
|
|
62
|
-
| Component enter/exit | 150
|
|
63
|
-
| Page transitions | 200
|
|
64
|
-
| Complex/orchestrated |
|
|
72
|
+
| Micro-interactions | 80-150ms | Hover, press, toggle |
|
|
73
|
+
| Component enter/exit | 150-250ms | Modals, drawers, dropdowns |
|
|
74
|
+
| Page transitions | 200-350ms | Route changes |
|
|
75
|
+
| Complex/orchestrated | <=400ms | Multi-step, staggered reveals |
|
|
65
76
|
| **Never exceed** | 400ms | Anything longer feels broken |
|
|
66
77
|
|
|
67
|
-
**Exit faster than enter**: Exit animations should run at **60
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
Enter: 250ms
|
|
71
|
-
Exit: 150ms (60% of 250)
|
|
72
|
-
```
|
|
78
|
+
**Exit faster than enter**: Exit animations should run at **60-70%** of the enter duration.
|
|
73
79
|
|
|
74
80
|
### Question 5: Only Animate `transform` and `opacity`
|
|
75
81
|
|
|
76
|
-
**Only these properties animate on the GPU:**
|
|
77
82
|
```css
|
|
78
|
-
/* SAFE */
|
|
83
|
+
/* SAFE - GPU-accelerated */
|
|
79
84
|
transform: translateX(), translateY(), scale(), rotate()
|
|
80
|
-
opacity: 0
|
|
85
|
+
opacity: 0 to 1
|
|
81
86
|
|
|
82
|
-
/* DANGEROUS
|
|
87
|
+
/* DANGEROUS - triggers layout/paint */
|
|
83
88
|
width, height, top, left, margin, padding, font-size
|
|
84
89
|
```
|
|
85
90
|
|
|
@@ -89,319 +94,73 @@ Exception: `filter` (blur) is GPU-accelerated in modern browsers but battery-exp
|
|
|
89
94
|
|
|
90
95
|
## Stagger Rules
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
- Direction: top-to-bottom OR left-to-right - never random
|
|
96
|
-
|
|
97
|
-
```css
|
|
98
|
-
.item:nth-child(1) { animation-delay: 0ms; }
|
|
99
|
-
.item:nth-child(2) { animation-delay: 40ms; }
|
|
100
|
-
.item:nth-child(3) { animation-delay: 80ms; }
|
|
101
|
-
/* etc. — cap at ~6 staggered items */
|
|
102
|
-
```
|
|
97
|
+
- Stagger delay: **30-50ms** per item
|
|
98
|
+
- Maximum stagger depth: **6-8 items** (items beyond that appear simultaneously)
|
|
99
|
+
- Direction: top-to-bottom OR left-to-right, never random
|
|
103
100
|
|
|
104
101
|
---
|
|
105
102
|
|
|
106
103
|
## Press Feedback
|
|
107
104
|
|
|
108
|
-
Every clickable element must give visual feedback within **100ms** of interaction.
|
|
105
|
+
Every clickable element must give visual feedback within **100ms** of interaction. The canonical scale value for press feedback is **`0.96`**.
|
|
106
|
+
|
|
107
|
+
- Never use `scale(0.95)` - too large, feels unresponsive
|
|
108
|
+
- Never use `scale(0.97)` or higher - imperceptible at high DPI
|
|
109
|
+
- `0.96` is the correct value for standard interactive elements
|
|
109
110
|
|
|
110
111
|
```css
|
|
111
112
|
button:active {
|
|
112
|
-
transform: scale(0.
|
|
113
|
+
transform: scale(0.96);
|
|
113
114
|
transition: transform 80ms ease-out;
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
/* On release */
|
|
117
|
-
button:not(:active) {
|
|
118
|
-
transform: scale(1);
|
|
119
|
-
transition: transform 150ms ease-out;
|
|
120
|
-
}
|
|
121
116
|
```
|
|
122
117
|
|
|
123
|
-
Scale range: **0.95–0.98** for buttons. **0.97** is the safest default.
|
|
124
|
-
Never scale below 0.90 - it looks broken.
|
|
125
|
-
|
|
126
118
|
---
|
|
127
119
|
|
|
128
120
|
## `prefers-reduced-motion`
|
|
129
121
|
|
|
130
|
-
Always respect this. It
|
|
122
|
+
Always respect this. It is not optional.
|
|
131
123
|
|
|
132
124
|
```css
|
|
133
125
|
@media (prefers-reduced-motion: reduce) {
|
|
134
|
-
*,
|
|
135
|
-
*::before,
|
|
136
|
-
*::after {
|
|
126
|
+
*, *::before, *::after {
|
|
137
127
|
animation-duration: 0.01ms !important;
|
|
138
|
-
animation-iteration-count: 1 !important;
|
|
139
128
|
transition-duration: 0.01ms !important;
|
|
140
129
|
scroll-behavior: auto !important;
|
|
141
130
|
}
|
|
142
131
|
}
|
|
143
132
|
```
|
|
144
133
|
|
|
145
|
-
Or in JavaScript:
|
|
146
|
-
```js
|
|
147
|
-
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
148
|
-
if (!prefersReduced) {
|
|
149
|
-
// Run animation
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## What Never To Animate
|
|
156
|
-
|
|
157
|
-
- Keyboard shortcuts and commands (too frequent)
|
|
158
|
-
- Tab switching within a page
|
|
159
|
-
- Filter/sort toggles on data tables
|
|
160
|
-
- Expanding/collapsing sidebar navigation items during heavy use
|
|
161
|
-
- Any interaction the user will perform 50+ times in a session
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## The Invisible Detail Rule
|
|
166
|
-
|
|
167
|
-
The best animations are ones users cannot describe but notice when absent. Signs of this:
|
|
168
|
-
- The interaction feels "snappy" or "responsive" without thinking about why
|
|
169
|
-
- Removing the animation makes the UI feel broken
|
|
170
|
-
- Users say "it feels premium" but can't point to any specific feature
|
|
171
|
-
|
|
172
|
-
This is the goal. Not "look at this animation" - "why does this feel so good to use?"
|
|
173
|
-
|
|
174
134
|
---
|
|
175
135
|
|
|
176
|
-
## Quick
|
|
136
|
+
## Quick Audit Checklist
|
|
177
137
|
|
|
178
138
|
- [ ] No animation on keyboard-triggered actions
|
|
179
|
-
- [ ] All durations
|
|
139
|
+
- [ ] All durations <=400ms
|
|
180
140
|
- [ ] Exit < enter duration
|
|
181
141
|
- [ ] Only `transform` and `opacity` for performance
|
|
182
142
|
- [ ] `prefers-reduced-motion` implemented
|
|
183
|
-
- [ ] Stagger
|
|
143
|
+
- [ ] Stagger <=50ms per item, capped at 6-8 items
|
|
184
144
|
- [ ] Press feedback on all interactive elements
|
|
185
145
|
- [ ] No bounce/elastic easing anywhere
|
|
186
146
|
- [ ] All animations have a defined purpose
|
|
187
147
|
|
|
188
148
|
---
|
|
189
149
|
|
|
190
|
-
##
|
|
191
|
-
|
|
192
|
-
Spring-based animation replaces duration-based tweening with physics parameters
|
|
193
|
-
(stiffness, damping, mass). Output feels more organic and adapts to interruption.
|
|
194
|
-
|
|
195
|
-
### React Spring
|
|
196
|
-
|
|
197
|
-
```jsx
|
|
198
|
-
import { useSpring, animated } from '@react-spring/web';
|
|
199
|
-
|
|
200
|
-
const styles = useSpring({
|
|
201
|
-
from: { opacity: 0, transform: 'translateY(20px)' },
|
|
202
|
-
to: { opacity: 1, transform: 'translateY(0px)' },
|
|
203
|
-
config: { tension: 170, friction: 26 } // default preset
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
React Spring presets:
|
|
208
|
-
|
|
209
|
-
| Preset | tension | friction | Character |
|
|
210
|
-
|--------|---------|----------|-----------|
|
|
211
|
-
| default | 170 | 26 | balanced |
|
|
212
|
-
| gentle | 120 | 14 | smooth, leisurely |
|
|
213
|
-
| wobbly | 180 | 12 | playful bounce |
|
|
214
|
-
| stiff | 210 | 20 | snappy |
|
|
215
|
-
| slow | 280 | 60 | slow and deliberate |
|
|
216
|
-
| molasses | 280 | 120 | very slow, no bounce |
|
|
217
|
-
|
|
218
|
-
### Framer Motion
|
|
219
|
-
|
|
220
|
-
```jsx
|
|
221
|
-
<motion.div
|
|
222
|
-
animate={{ x: 100 }}
|
|
223
|
-
transition={{ type: "spring", stiffness: 100, damping: 15, mass: 1 }}
|
|
224
|
-
/>
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Parameter guidance:
|
|
228
|
-
|
|
229
|
-
| Param | Range | Effect |
|
|
230
|
-
|-------|-------|--------|
|
|
231
|
-
| stiffness | 50–300 | higher = snappier arrival |
|
|
232
|
-
| damping | 10–40 | higher = less oscillation |
|
|
233
|
-
| mass | 0.5–2 | higher = more inertia, slower response |
|
|
234
|
-
|
|
235
|
-
Rule of thumb: for UI micro-interactions use stiffness 150–250, damping 20–30, mass 1.
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Scroll-Triggered Animations
|
|
240
|
-
|
|
241
|
-
Use IntersectionObserver for scroll-reveal effects - it replaces scroll-event
|
|
242
|
-
listeners with a throttled browser-native API.
|
|
243
|
-
|
|
244
|
-
### Basic pattern
|
|
245
|
-
|
|
246
|
-
```js
|
|
247
|
-
const observer = new IntersectionObserver((entries) => {
|
|
248
|
-
entries.forEach(entry => {
|
|
249
|
-
if (entry.isIntersecting) {
|
|
250
|
-
entry.target.classList.add('in-view');
|
|
251
|
-
// Optional: disconnect after first trigger
|
|
252
|
-
// observer.unobserve(entry.target);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
}, {
|
|
256
|
-
threshold: 0.1,
|
|
257
|
-
rootMargin: '0px 0px -100px 0px' // trigger 100px before entering viewport bottom
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Threshold guidance
|
|
264
|
-
|
|
265
|
-
| threshold | Meaning |
|
|
266
|
-
|-----------|---------|
|
|
267
|
-
| 0.0 | element enters viewport edge |
|
|
268
|
-
| 0.1–0.25 | element partially visible (most common for reveals) |
|
|
269
|
-
| 0.5 | element half-visible |
|
|
270
|
-
| 1.0 | element fully visible |
|
|
271
|
-
|
|
272
|
-
### Once vs repeat
|
|
273
|
-
|
|
274
|
-
- **Once** - call `observer.unobserve(entry.target)` after first intersection.
|
|
275
|
-
Use for: hero reveals, one-shot entrance animations, stat counters.
|
|
276
|
-
- **Repeat** - leave observer active. Use for: progress indicators, parallax effects,
|
|
277
|
-
sticky nav state changes.
|
|
278
|
-
|
|
279
|
-
### Performance rules
|
|
280
|
-
|
|
281
|
-
1. Animate only `transform` and `opacity` (GPU-accelerated). Avoid `top`, `left`, `width`, `height`.
|
|
282
|
-
2. No debounce/throttle needed - IntersectionObserver is already throttled by the browser.
|
|
283
|
-
3. For many elements, share a single observer instance and call `observe()` once per element.
|
|
284
|
-
4. Prefer CSS transitions triggered by a class toggle over requestAnimationFrame loops.
|
|
285
|
-
5. Use `will-change: transform, opacity` sparingly (only on elements that animate repeatedly).
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## MIFB Micro-Motion Extensions
|
|
290
|
-
Source: jakubkrehel/make-interfaces-feel-better (MIT) - motion.md
|
|
291
|
-
|
|
292
|
-
### Interruptible Animations
|
|
293
|
-
|
|
294
|
-
Use CSS transitions for interactive elements because transitions retarget mid-animation - when a user moves their cursor away before a hover animation completes, the transition reverses smoothly from wherever it currently is. Keyframe animations restart from the beginning, creating a jarring jump.
|
|
295
|
-
|
|
296
|
-
**Decision rule:**
|
|
297
|
-
- Interactive states (hover, focus, active, pressed): always CSS transitions
|
|
298
|
-
- Orchestrated sequences, entrance effects, data-driven animations: keyframe or JS animation
|
|
299
|
-
|
|
300
|
-
```css
|
|
301
|
-
/* Good — transition retargets smoothly */
|
|
302
|
-
.button { transition: background-color 150ms ease-out; }
|
|
303
|
-
|
|
304
|
-
/* Avoid for interactive — restarts on interruption */
|
|
305
|
-
.button:hover { animation: hover-bg 150ms ease-out forwards; }
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### Split-and-Stagger Enter/Exit
|
|
309
|
-
|
|
310
|
-
For multi-element entrances (card grids, lists, feature sections):
|
|
311
|
-
|
|
312
|
-
- Default stagger: 100ms between elements
|
|
313
|
-
- Heading words: 80ms per word
|
|
314
|
-
- Entrance transform: `opacity: 0 → 1` + `translateY(12px → 0)` + `blur(4px → 0)`
|
|
315
|
-
- Entrance duration: 300ms, `ease-out`
|
|
316
|
-
- Exit transform: `opacity: 1 → 0` + `translateY(0 → -12px)` (opposite direction, smaller offset)
|
|
317
|
-
- Exit duration: 150ms (half the entrance duration - exits should be faster)
|
|
318
|
-
|
|
319
|
-
The blur component adds a depth cue that makes entrances feel less flat. Keep blur modest (4px) - the goal is a subtle focus effect, not a visible blur.
|
|
320
|
-
|
|
321
|
-
### Contextual Icon Animations - Cross-Fade Pattern
|
|
322
|
-
|
|
323
|
-
When swapping two icons (e.g., play ↔ pause, chevron-up ↔ chevron-down, bookmark ↔ bookmarked), use this exact cross-fade spec:
|
|
324
|
-
|
|
325
|
-
**Framer Motion spring (preferred):**
|
|
326
|
-
- `scale: 0.25 → 1` (entering), `scale: 1 → 0.25` (exiting)
|
|
327
|
-
- `opacity: 0 → 1` (entering), `opacity: 1 → 0` (exiting)
|
|
328
|
-
- `filter: blur(4px) → blur(0)` (entering), `blur(0) → blur(4px)` (exiting)
|
|
329
|
-
- `transition: { type: "spring", duration: 0.3, bounce: 0 }` - **bounce MUST be 0**
|
|
150
|
+
## Rules of Thumb
|
|
330
151
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
-
|
|
335
|
-
|
|
336
|
-
The scale + blur combination creates a focus-snap effect that feels intentional rather than mechanical. The `bounce: 0` hard constraint exists because any bounce on a 0.25-scale origin point makes icons appear to "pop" invasively.
|
|
337
|
-
|
|
338
|
-
### Scale on Press - Canonical Value
|
|
339
|
-
|
|
340
|
-
The canonical scale value for press feedback is **`0.96`**.
|
|
341
|
-
|
|
342
|
-
Rules:
|
|
343
|
-
- Never use `scale(0.95)` - too large, feels unresponsive
|
|
344
|
-
- Never use `scale(0.97)` - too subtle at high DPI, not perceived as feedback
|
|
345
|
-
- Never use `scale(0.98)` or higher - imperceptible
|
|
346
|
-
- `0.96` is the ONLY correct value for standard interactive elements
|
|
347
|
-
|
|
348
|
-
Tailwind: `active:scale-[0.96]`
|
|
349
|
-
Framer: `whileTap={{ scale: 0.96 }}`
|
|
350
|
-
|
|
351
|
-
For primary CTAs where maximum tactility is needed (purchase, send, confirm):
|
|
352
|
-
use `0.96` with a shadow reduction: `box-shadow: none` during press.
|
|
353
|
-
|
|
354
|
-
Deprecation note: earlier versions of `reference/checklists.md` referenced `scale(0.97)`. That entry has been reconciled. **0.96 is the canonical value.**
|
|
355
|
-
|
|
356
|
-
### AnimatePresence initial={false}
|
|
357
|
-
|
|
358
|
-
When `AnimatePresence` wraps UI that exists in the DOM before it enters the animation scope (e.g., a tab panel that renders its first tab immediately, a dropdown that's already open on first load), use `initial={false}`:
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
<AnimatePresence initial={false}>
|
|
362
|
-
{isOpen && <motion.div key="panel" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} />}
|
|
363
|
-
</AnimatePresence>
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
Without `initial={false}`, Framer will animate the FIRST render of children - meaning UI that's immediately visible on page load will "fade in" unnecessarily. This creates a flash/flicker that signals poor craftsmanship.
|
|
367
|
-
|
|
368
|
-
**Rule:** Any `AnimatePresence` wrapping persistent UI should have `initial={false}`.
|
|
369
|
-
|
|
370
|
-
### will-change - GPU Property Table
|
|
371
|
-
|
|
372
|
-
Only add `will-change` when you observe first-frame stutter on lower-end hardware. Do NOT add it preemptively - it consumes GPU memory continuously for every element that has it.
|
|
373
|
-
|
|
374
|
-
GPU-compositable properties (safe with will-change):
|
|
375
|
-
| Property | will-change value |
|
|
376
|
-
|----------|------------------|
|
|
377
|
-
| transform (translate, scale, rotate) | `transform` |
|
|
378
|
-
| opacity | `opacity` |
|
|
379
|
-
| filter (blur, brightness, contrast) | `filter` |
|
|
380
|
-
| clip-path | `clip-path` |
|
|
381
|
-
|
|
382
|
-
Never use `will-change: all` or `will-change: contents` - this forces the entire element and its subtree onto a new compositor layer, thrashing memory.
|
|
383
|
-
|
|
384
|
-
Remove `will-change` after the animation completes if applied dynamically:
|
|
385
|
-
```js
|
|
386
|
-
element.addEventListener('transitionend', () => element.style.willChange = 'auto')
|
|
387
|
-
```
|
|
152
|
+
1. Keyboard-initiated actions (command palette, list navigation, shortcuts) must have zero animation. They repeat hundreds of times daily and every ms is felt.
|
|
153
|
+
2. Default to named spring presets (gentle/wobbly/stiff/slow) rather than raw stiffness/damping numbers; presets are tuned for 60fps settle-time and predictable feel.
|
|
154
|
+
3. Always use `--ease-*` CSS custom property tokens rather than inline `cubic-bezier()` strings; tokens keep easing consistent and respect `prefers-reduced-motion`.
|
|
155
|
+
4. OKLCH is the correct color space for animated color transitions; sRGB interpolation produces muddy mid-transition colors. See `reference/color-theory.md` for color interpolation in animation.
|
|
388
156
|
|
|
389
157
|
---
|
|
390
158
|
|
|
391
|
-
##
|
|
392
|
-
|
|
393
|
-
For spring physics, scroll-driven animation, FLIP, View Transitions API, gesture & drag mechanics, clip-path animation patterns, blur-to-mask crossfades, WAAPI, Framer Motion hardware-acceleration gotcha, motion cohesion & personality, and the next-day slow-motion review process, see:
|
|
394
|
-
|
|
395
|
-
→ **`reference/motion-advanced.md`** (Phase 18)
|
|
396
|
-
|
|
397
|
-
For the canonical easing catalog (`--ease-*` tokens, cubic-bezier equivalents, 60fps settle-times):
|
|
398
|
-
|
|
399
|
-
→ **`reference/motion-easings.md`** (Phase 18)
|
|
400
|
-
|
|
401
|
-
For spring parameter presets (gentle / wobbly / stiff / slow):
|
|
402
|
-
|
|
403
|
-
→ **`reference/motion-spring.md`** (Phase 18)
|
|
404
|
-
|
|
405
|
-
For transition family taxonomy (8 families: 3d / blur / cover / destruction / dissolve / distortion / grid / light):
|
|
159
|
+
## Cross-Domain See Also
|
|
406
160
|
|
|
407
|
-
|
|
161
|
+
- Color animation uses OKLCH path: `reference/color.md`
|
|
162
|
+
- Gesture semantics (velocity, pointer capture): `reference/interaction.md`
|
|
163
|
+
- OS-level reduced-motion: `reference/responsive.md`
|
|
164
|
+
- CSS layout transitions: `reference/spatial.md`
|
|
165
|
+
- Typography: `reference/typography.md`
|
|
166
|
+
- UX writing: `reference/ux-writing.md`
|
package/reference/registry.json
CHANGED
|
@@ -625,8 +625,9 @@
|
|
|
625
625
|
{
|
|
626
626
|
"name": "motion",
|
|
627
627
|
"path": "reference/motion.md",
|
|
628
|
-
"type": "
|
|
629
|
-
"description": "
|
|
628
|
+
"type": "domain-index",
|
|
629
|
+
"description": "Phase 45 domain-index: motion navigation - indexes easings, spring, transition-taxonomy, interpolate, advanced, framer-motion-patterns.",
|
|
630
|
+
"phase": 45
|
|
630
631
|
},
|
|
631
632
|
{
|
|
632
633
|
"name": "motion-advanced",
|
|
@@ -797,8 +798,9 @@
|
|
|
797
798
|
{
|
|
798
799
|
"name": "typography",
|
|
799
800
|
"path": "reference/typography.md",
|
|
800
|
-
"type": "
|
|
801
|
-
"description": "
|
|
801
|
+
"type": "domain-index",
|
|
802
|
+
"description": "Phase 45 domain-index: typography navigation - indexes type-scale heuristics, variable-fonts-loading, proportion-systems.",
|
|
803
|
+
"phase": 45
|
|
802
804
|
},
|
|
803
805
|
{
|
|
804
806
|
"name": "user-research",
|
|
@@ -847,6 +849,13 @@
|
|
|
847
849
|
"phase": 28.5,
|
|
848
850
|
"description": "Phase 28.5 skill-authoring contract — adapted from mattpocock/skills (MIT). SKILL.md <=100-line cap (warn >=100, block >=250 in CI), 1024-char description cap, <what>. Use when <triggers>. form (lax-mode default per Phase 33 A/B pending), frontmatter required fields, progressive-disclosure one-level-deep rule. Validator at scripts/validate-skill-length.cjs."
|
|
849
851
|
},
|
|
852
|
+
{
|
|
853
|
+
"name": "skill-metadata",
|
|
854
|
+
"path": "reference/skill-metadata.md",
|
|
855
|
+
"type": "meta-rules",
|
|
856
|
+
"phase": 46,
|
|
857
|
+
"description": "Phase 46 skill-metadata single source of truth: scripts/lib/manifest/skills.json record shape, the generate-skill-frontmatter.cjs forward/extract/check modes, the skills.json to generator to build:skills to skills/+dist build chain, the six managed frontmatter keys (canonical order, always-quoted strings) vs extra_frontmatter passthrough, the 20..1024 description budget (validate-skill-length.cjs + lint-agentskills-spec.cjs R4, lint:agentskills CI gate), and the pin metadata catalogue consumer."
|
|
858
|
+
},
|
|
850
859
|
{
|
|
851
860
|
"name": "capability-gap-stage-gate",
|
|
852
861
|
"path": "reference/capability-gap-stage-gate.md",
|
|
@@ -1049,6 +1058,41 @@
|
|
|
1049
1058
|
"type": "meta-rules",
|
|
1050
1059
|
"phase": 42,
|
|
1051
1060
|
"description": "Phase 42 multi-harness skill-placeholder catalogue: the four placeholders ({{command_prefix}}/{{model}}/{{config_file}}/{{ask_instruction}}) + per-harness substitution table + the \\{{...}} escape + the <!-- harness-only: a,b --> block rule. Skills authored once in source/skills/, compiled per-harness by scripts/build-skills.cjs via scripts/lib/build/factory.cjs reading scripts/lib/manifest/harnesses.json."
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
"name": "color",
|
|
1064
|
+
"path": "reference/color.md",
|
|
1065
|
+
"type": "domain-index",
|
|
1066
|
+
"phase": 45,
|
|
1067
|
+
"description": "Phase 45 domain-index: color + contrast navigation - color-theory, palette-catalog, contrast-advanced, style-vocabulary."
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
"name": "spatial",
|
|
1071
|
+
"path": "reference/spatial.md",
|
|
1072
|
+
"type": "domain-index",
|
|
1073
|
+
"phase": 45,
|
|
1074
|
+
"description": "Phase 45 domain-index: layout/spacing/composition - composition, proportion-systems, css-grid-layout, visual-hierarchy-layout, gestalt, image-optimization, data-visualization, surfaces."
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
"name": "interaction",
|
|
1078
|
+
"path": "reference/interaction.md",
|
|
1079
|
+
"type": "domain-index",
|
|
1080
|
+
"phase": 45,
|
|
1081
|
+
"description": "Phase 45 domain-index: interaction + a11y + components - accessibility, component-authoring, form-patterns, information-architecture, onboarding-progressive-disclosure, emotional-design, components/."
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
"name": "responsive",
|
|
1085
|
+
"path": "reference/responsive.md",
|
|
1086
|
+
"type": "domain-index",
|
|
1087
|
+
"phase": 45,
|
|
1088
|
+
"description": "Phase 45 domain-index: responsive + i18n + platforms - i18n, rtl-cjk-cultural, platforms, native-platforms, performance, css-grid-layout."
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
"name": "ux-writing",
|
|
1092
|
+
"path": "reference/ux-writing.md",
|
|
1093
|
+
"type": "domain-index",
|
|
1094
|
+
"phase": 45,
|
|
1095
|
+
"description": "Phase 45 domain-index: UX-writing + voice - brand-voice, style-vocabulary, anti-patterns."
|
|
1052
1096
|
}
|
|
1053
1097
|
]
|
|
1054
1098
|
}
|
|
@@ -4,19 +4,41 @@
|
|
|
4
4
|
"title": "Reference Registry",
|
|
5
5
|
"description": "Typed index of every reference/*.md (and reference/*.json default) in the plugin. Enables agents to query by type instead of grep-hunting import strings. Round-trip enforced: every reference/*.md must appear in entries[], every entry must resolve to an existing file.",
|
|
6
6
|
"type": "object",
|
|
7
|
-
"required": [
|
|
7
|
+
"required": [
|
|
8
|
+
"version",
|
|
9
|
+
"generated_at",
|
|
10
|
+
"entries"
|
|
11
|
+
],
|
|
8
12
|
"properties": {
|
|
9
|
-
"$schema": {
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
"$schema": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
16
|
+
"version": {
|
|
17
|
+
"const": 1
|
|
18
|
+
},
|
|
19
|
+
"generated_at": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"format": "date-time"
|
|
22
|
+
},
|
|
12
23
|
"entries": {
|
|
13
24
|
"type": "array",
|
|
14
25
|
"items": {
|
|
15
26
|
"type": "object",
|
|
16
|
-
"required": [
|
|
27
|
+
"required": [
|
|
28
|
+
"name",
|
|
29
|
+
"path",
|
|
30
|
+
"type"
|
|
31
|
+
],
|
|
17
32
|
"properties": {
|
|
18
|
-
"name": {
|
|
19
|
-
|
|
33
|
+
"name": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"minLength": 1,
|
|
36
|
+
"pattern": "^[a-z0-9][a-z0-9-._]*$"
|
|
37
|
+
},
|
|
38
|
+
"path": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1
|
|
41
|
+
},
|
|
20
42
|
"type": {
|
|
21
43
|
"type": "string",
|
|
22
44
|
"enum": [
|
|
@@ -41,13 +63,28 @@
|
|
|
41
63
|
"typography",
|
|
42
64
|
"layout",
|
|
43
65
|
"performance",
|
|
44
|
-
"component-spec"
|
|
66
|
+
"component-spec",
|
|
67
|
+
"domain-index"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"tier": {
|
|
71
|
+
"enum": [
|
|
72
|
+
"L0",
|
|
73
|
+
"L1",
|
|
74
|
+
"L2"
|
|
45
75
|
]
|
|
46
76
|
},
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
"phase": {
|
|
78
|
+
"type": "number",
|
|
79
|
+
"description": "Phase that introduced this entry. Numbers are allowed (e.g., 19.6, 27.5, 27.6, 27.7, 28.5) — decimal phases are valid per the long-standing precedent established by Phases 19.6 / 27.5 / 27.6 / 27.7 / 28.5."
|
|
80
|
+
},
|
|
81
|
+
"description": {
|
|
82
|
+
"type": "string"
|
|
83
|
+
},
|
|
84
|
+
"registered_at": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"format": "date-time"
|
|
87
|
+
}
|
|
51
88
|
},
|
|
52
89
|
"additionalProperties": false
|
|
53
90
|
}
|