@polymorphism-tech/morph-spec 4.10.7 → 4.10.8
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.md +3 -3
- package/LICENSE +71 -71
- package/README.md +379 -379
- package/bin/morph-spec.js +1 -1
- package/claude-plugin.json +14 -14
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +206 -206
- package/framework/agents/README.md +14 -14
- package/framework/agents/architecture/standards-architect.md +159 -159
- package/framework/agents/frontend/blazor-builder.md +13 -0
- package/framework/agents/frontend/css-specialist.md +87 -0
- package/framework/agents/frontend/nextjs-expert.md +13 -0
- package/framework/agents/frontend/nextjs-ui-specialist.md +218 -0
- package/framework/agents/frontend/ui-ux-designer.md +80 -10
- package/framework/agents/infrastructure/azure-architect.md +149 -149
- package/framework/agents/infrastructure/infra-architect.md +48 -48
- package/framework/agents.json +2268 -2204
- package/framework/hooks/README.md +204 -204
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +10 -24
- package/framework/hooks/shared/phase-utils.js +139 -139
- package/framework/hooks/shared/worktree-helpers.js +30 -8
- package/framework/rules/csharp-standards.md +13 -13
- package/framework/rules/frontend-standards.md +13 -13
- package/framework/rules/infrastructure-standards.md +16 -16
- package/framework/rules/testing-standards.md +14 -14
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +12 -0
- package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +254 -254
- package/framework/skills/level-0-meta/morph-init/SKILL.md +88 -3
- package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +247 -247
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +270 -270
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +515 -499
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +508 -500
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +12 -1
- package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +272 -262
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +317 -311
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +424 -323
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +2040 -2040
- package/framework/standards/frontend/nextjs/motion-patterns.md +321 -0
- package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -17
- package/framework/templates/README.md +814 -814
- package/framework/templates/code/dotnet/contracts/Commands.cs +74 -74
- package/framework/templates/code/dotnet/contracts/Entities.cs +25 -25
- package/framework/templates/code/dotnet/contracts/Queries.cs +74 -74
- package/framework/templates/code/dotnet/contracts/README.md +74 -74
- package/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -173
- package/framework/templates/code/dotnet/frontend/component.razor +239 -239
- package/framework/templates/code/dotnet/jobs/agent.cs +163 -163
- package/framework/templates/code/dotnet/jobs/job.cs +171 -171
- package/framework/templates/code/dotnet/test.cs +239 -239
- package/framework/templates/code/sql/rls-policy.sql +57 -57
- package/framework/templates/code/sql/supabase-migration.sql +100 -100
- package/framework/templates/code/sql/supabase-migration.template.sql +113 -113
- package/framework/templates/code/typescript/contracts.ts +168 -168
- package/framework/templates/context/CONTEXT.md +181 -181
- package/framework/templates/context/design-system.md +211 -0
- package/framework/templates/docs/proposal.md +182 -182
- package/framework/templates/docs/user-stories.md +34 -34
- package/framework/templates/examples/design-system-examples.md +357 -357
- package/framework/templates/examples/spec-examples.md +90 -90
- package/framework/templates/feature/decisions.md +187 -187
- package/framework/templates/feature/recap.md +146 -146
- package/framework/templates/feature/tasks.md +199 -199
- package/framework/templates/infrastructure/azure/README.md +286 -286
- package/framework/templates/infrastructure/azure/deploy-checklist.md +426 -426
- package/framework/templates/infrastructure/azure/parameters.dev.json +29 -29
- package/framework/templates/infrastructure/azure/parameters.prod.json +29 -29
- package/framework/templates/infrastructure/azure/parameters.staging.json +29 -29
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -67
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/docker/easypanel.template.json +54 -54
- package/package.json +82 -82
- package/src/commands/agents/index.js +13 -13
- package/src/commands/project/install-plugin-cmd.js +28 -28
- package/src/commands/project/setup-infra-cmd.js +12 -12
- package/src/commands/project/worktree.js +58 -2
- package/src/commands/tasks/index.js +4 -4
- package/src/commands/templates/index.js +5 -5
- package/src/commands/utils/index.js +3 -3
- package/src/commands/validation/index.js +4 -4
- package/src/core/state/phase-state-machine.js +217 -217
- package/src/lib/generators/design-system-generator.js +298 -298
- package/src/lib/generators/index.js +10 -10
- package/src/lib/generators/metadata-extractor.js +387 -387
- package/src/lib/stack-filter.js +65 -65
- package/src/lib/standards/index.js +7 -7
- package/src/lib/standards/standards-context-injector.js +302 -302
- package/src/lib/validators/architecture/architecture-validator.js +387 -387
- package/src/lib/validators/architecture/index.js +7 -7
- package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +316 -316
- package/src/lib/validators/blazor/blazor-state-validator.js +279 -279
- package/src/lib/validators/blazor/blazor-validator.js +369 -369
- package/src/lib/validators/blazor/index.js +9 -9
- package/src/lib/validators/content/content-validator.js +287 -287
- package/src/lib/validators/content/index.js +7 -7
- package/src/lib/validators/contracts/index.js +7 -7
- package/src/lib/validators/css/css-validator.js +352 -352
- package/src/lib/validators/css/index.js +7 -7
- package/src/lib/validators/design-system/design-system-validator.js +231 -231
- package/src/lib/validators/design-system/index.js +7 -7
- package/src/lib/validators/nextjs/index.js +6 -6
- package/src/lib/validators/nextjs/next-component-validator.js +183 -183
- package/src/lib/validators/packages/index.js +7 -7
- package/src/lib/validators/packages/package-validator.js +360 -360
- package/src/lib/validators/shared/index.js +12 -12
- package/src/lib/validators/shared/issue-counter.js +18 -18
- package/src/lib/validators/shared/result-formatter.js +124 -124
- package/src/lib/validators/ui/index.js +7 -7
- package/src/lib/validators/ui/ui-contrast-validator.js +422 -422
- package/src/scripts/global-install.js +58 -58
- package/src/scripts/install-plugin.js +126 -126
- package/src/utils/claude-md-injector.js +90 -90
- package/src/utils/file-copier.js +200 -196
- package/src/utils/hooks-installer.js +556 -494
- package/src/utils/logger.js +32 -32
- package/src/utils/skills-installer.js +178 -178
- package/src/utils/version-checker.js +175 -175
- package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +0 -38
- package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +0 -14
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
---
|
|
2
|
+
scope: frontend-nextjs-ui
|
|
3
|
+
layer: 3
|
|
4
|
+
keywords: framer-motion, animation, motion, transition, variants, gesture, scroll
|
|
5
|
+
load_when: nextjs-ui-specialist active
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Motion Patterns — Framer Motion
|
|
9
|
+
|
|
10
|
+
Reference guide for implementing animations and transitions in Next.js projects using Framer Motion. Covers the canonical variants library, design token bridge, scroll and gesture patterns, loading states, and mandatory WCAG accessibility compliance.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Section 1: Core Variants Library
|
|
15
|
+
|
|
16
|
+
Place this file at `motion/variants.ts` in your Next.js project root.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Variants } from 'framer-motion';
|
|
20
|
+
import { durations, easings } from '@/lib/design-tokens'; // maps to design-system.md motion tokens
|
|
21
|
+
|
|
22
|
+
// Fade
|
|
23
|
+
export const fadeIn: Variants = {
|
|
24
|
+
hidden: { opacity: 0 },
|
|
25
|
+
visible: { opacity: 1, transition: { duration: durations.base, ease: easings.standard } },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Slide variations
|
|
29
|
+
export const slideInUp: Variants = {
|
|
30
|
+
hidden: { opacity: 0, y: 24 },
|
|
31
|
+
visible: { opacity: 1, y: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
32
|
+
};
|
|
33
|
+
export const slideInDown: Variants = {
|
|
34
|
+
hidden: { opacity: 0, y: -24 },
|
|
35
|
+
visible: { opacity: 1, y: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
36
|
+
};
|
|
37
|
+
export const slideInLeft: Variants = {
|
|
38
|
+
hidden: { opacity: 0, x: -24 },
|
|
39
|
+
visible: { opacity: 1, x: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
40
|
+
};
|
|
41
|
+
export const slideInRight: Variants = {
|
|
42
|
+
hidden: { opacity: 0, x: 24 },
|
|
43
|
+
visible: { opacity: 1, x: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Scale
|
|
47
|
+
export const scaleIn: Variants = {
|
|
48
|
+
hidden: { opacity: 0, scale: 0.92 },
|
|
49
|
+
visible: { opacity: 1, scale: 1, transition: { duration: durations.fast, ease: easings.bounce } },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Stagger container + child
|
|
53
|
+
export const staggerContainer: Variants = {
|
|
54
|
+
hidden: {},
|
|
55
|
+
visible: {
|
|
56
|
+
transition: {
|
|
57
|
+
staggerChildren: 0.08,
|
|
58
|
+
delayChildren: 0.1,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
export const staggerItem: Variants = {
|
|
63
|
+
hidden: { opacity: 0, y: 16 },
|
|
64
|
+
visible: { opacity: 1, y: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Page transition (for AnimatePresence in layout.tsx)
|
|
68
|
+
export const pageTransition: Variants = {
|
|
69
|
+
hidden: { opacity: 0, y: 8 },
|
|
70
|
+
visible: { opacity: 1, y: 0, transition: { duration: durations.base, ease: easings.decelerate } },
|
|
71
|
+
exit: { opacity: 0, y: -8, transition: { duration: durations.fast, ease: easings.accelerate } },
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Section 2: Design Token Bridge
|
|
78
|
+
|
|
79
|
+
This file bridges the CSS variables defined in `.morph/context/design-system.md` to JavaScript values consumed by Framer Motion. Place at `lib/design-tokens.ts`.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// lib/design-tokens.ts
|
|
83
|
+
// Maps CSS variables from .morph/context/design-system.md to JS values for Framer Motion
|
|
84
|
+
export const durations = {
|
|
85
|
+
instant: 0.05,
|
|
86
|
+
fast: 0.15,
|
|
87
|
+
base: 0.3,
|
|
88
|
+
slow: 0.5,
|
|
89
|
+
slower: 0.8,
|
|
90
|
+
} as const;
|
|
91
|
+
|
|
92
|
+
export const easings = {
|
|
93
|
+
standard: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
|
94
|
+
decelerate: [0, 0, 0.2, 1] as [number, number, number, number],
|
|
95
|
+
accelerate: [0.4, 0, 1, 1] as [number, number, number, number],
|
|
96
|
+
bounce: [0.34, 1.56, 0.64, 1] as [number, number, number, number],
|
|
97
|
+
spring: [0.68, -0.55, 0.265, 1.55] as [number, number, number, number],
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **Rule**: Never hardcode duration numbers or easing arrays in component files. Always import from `@/lib/design-tokens`.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Section 3: Scroll Animations
|
|
106
|
+
|
|
107
|
+
Two approaches for triggering animations when elements enter the viewport:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
'use client';
|
|
111
|
+
import { motion, useInView } from 'framer-motion';
|
|
112
|
+
import { useRef } from 'react';
|
|
113
|
+
import { fadeIn, slideInUp } from '@/motion/variants';
|
|
114
|
+
|
|
115
|
+
// Option A: whileInView (simpler, one-shot)
|
|
116
|
+
<motion.div
|
|
117
|
+
variants={slideInUp}
|
|
118
|
+
initial="hidden"
|
|
119
|
+
whileInView="visible"
|
|
120
|
+
viewport={{ once: true, margin: '-50px' }}
|
|
121
|
+
>
|
|
122
|
+
|
|
123
|
+
// Option B: useInView hook (more control)
|
|
124
|
+
function AnimatedSection({ children }: { children: React.ReactNode }) {
|
|
125
|
+
const ref = useRef(null);
|
|
126
|
+
const isInView = useInView(ref, { once: true, margin: '-100px' });
|
|
127
|
+
return (
|
|
128
|
+
<motion.div ref={ref} variants={fadeIn} initial="hidden" animate={isInView ? 'visible' : 'hidden'}>
|
|
129
|
+
{children}
|
|
130
|
+
</motion.div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- Use `once: true` for content sections — animations should not replay on scroll up.
|
|
136
|
+
- Adjust `margin` to fire slightly before the element fully enters the viewport.
|
|
137
|
+
- Prefer `whileInView` for simple cases; use `useInView` when you need imperative control or conditional logic.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Section 4: Gesture Interactions
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
import { durations, easings } from '@/lib/design-tokens';
|
|
145
|
+
|
|
146
|
+
// Hover + tap on cards
|
|
147
|
+
<motion.div
|
|
148
|
+
whileHover={{ y: -4, boxShadow: 'var(--shadow-lift)' }}
|
|
149
|
+
whileTap={{ scale: 0.98 }}
|
|
150
|
+
transition={{ duration: durations.fast, ease: easings.standard }}
|
|
151
|
+
>
|
|
152
|
+
|
|
153
|
+
// Drag interaction
|
|
154
|
+
<motion.div
|
|
155
|
+
drag
|
|
156
|
+
dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
|
|
157
|
+
dragElastic={0.1}
|
|
158
|
+
whileDrag={{ scale: 1.05, cursor: 'grabbing' }}
|
|
159
|
+
>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- `whileHover` and `whileTap` are inline — they do not need variant definitions for simple state changes.
|
|
163
|
+
- Use `var(--shadow-lift)` from the design system rather than hardcoded box-shadow values.
|
|
164
|
+
- `dragElastic={0.1}` gives a subtle rubber-band feel without being distracting.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Section 5: AnimatePresence (Page Transitions)
|
|
169
|
+
|
|
170
|
+
Integrate `AnimatePresence` at the layout level to animate between routes:
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
// app/layout.tsx
|
|
174
|
+
'use client';
|
|
175
|
+
import { AnimatePresence, motion } from 'framer-motion';
|
|
176
|
+
import { usePathname } from 'next/navigation';
|
|
177
|
+
import { pageTransition } from '@/motion/variants';
|
|
178
|
+
|
|
179
|
+
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
180
|
+
const pathname = usePathname();
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<html>
|
|
184
|
+
<body>
|
|
185
|
+
<AnimatePresence mode="wait">
|
|
186
|
+
<motion.main
|
|
187
|
+
key={pathname}
|
|
188
|
+
variants={pageTransition}
|
|
189
|
+
initial="hidden"
|
|
190
|
+
animate="visible"
|
|
191
|
+
exit="exit"
|
|
192
|
+
>
|
|
193
|
+
{children}
|
|
194
|
+
</motion.main>
|
|
195
|
+
</AnimatePresence>
|
|
196
|
+
</body>
|
|
197
|
+
</html>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- `mode="wait"` ensures the exit animation completes before the entering page renders.
|
|
203
|
+
- The `key` prop must change on navigation — use `usePathname()` from `next/navigation`.
|
|
204
|
+
- Keep page transitions subtle (`y: 8`, fast duration) — aggressive transitions hurt perceived performance.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Section 6: Loading Patterns
|
|
209
|
+
|
|
210
|
+
Prefer CSS `animate-pulse` for skeleton loaders over Framer Motion — CSS animations run off the main thread and have lower performance overhead.
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
// components/skeleton.tsx
|
|
214
|
+
import { cn } from '@/lib/utils';
|
|
215
|
+
|
|
216
|
+
function Skeleton({ className }: { className?: string }) {
|
|
217
|
+
return (
|
|
218
|
+
<div
|
|
219
|
+
className={cn(
|
|
220
|
+
'animate-pulse rounded-[var(--radius-md)] bg-[var(--color-neutral-200)]',
|
|
221
|
+
className
|
|
222
|
+
)}
|
|
223
|
+
/>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Skeleton card example
|
|
228
|
+
function SkeletonCard() {
|
|
229
|
+
return (
|
|
230
|
+
<div className="p-[var(--space-6)] space-y-[var(--space-4)]">
|
|
231
|
+
<Skeleton className="h-4 w-3/4" />
|
|
232
|
+
<Skeleton className="h-4 w-1/2" />
|
|
233
|
+
<Skeleton className="h-20 w-full" />
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
- Use design token CSS variables (`--radius-md`, `--color-neutral-200`, `--space-*`) — never hardcode dimensions or colors.
|
|
240
|
+
- Skeleton shapes should mirror the actual content layout to minimize layout shift on load.
|
|
241
|
+
- For spinner/progress indicators that need JS control, use a simple Framer Motion `animate={{ rotate: 360 }}` with `repeat: Infinity`.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Section 7: WCAG Accessibility (MANDATORY)
|
|
246
|
+
|
|
247
|
+
> **This section is non-negotiable.** All animated components must respect `prefers-reduced-motion`.
|
|
248
|
+
|
|
249
|
+
### Hook pattern — wrap all animated components
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
'use client';
|
|
253
|
+
import { motion, useReducedMotion } from 'framer-motion';
|
|
254
|
+
import { slideInUp } from '@/motion/variants';
|
|
255
|
+
|
|
256
|
+
function AnimatedCard({ children }: { children: React.ReactNode }) {
|
|
257
|
+
const shouldReduceMotion = useReducedMotion();
|
|
258
|
+
|
|
259
|
+
const variants = shouldReduceMotion
|
|
260
|
+
? { hidden: { opacity: 0 }, visible: { opacity: 1 } } // instant, no movement
|
|
261
|
+
: slideInUp;
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<motion.div variants={variants} initial="hidden" animate="visible">
|
|
265
|
+
{children}
|
|
266
|
+
</motion.div>
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
When `shouldReduceMotion` is `true`:
|
|
272
|
+
- Remove all `x`, `y`, `scale` transforms.
|
|
273
|
+
- Keep opacity transitions (they do not cause vestibular issues).
|
|
274
|
+
- Do not set `transition: { duration: 0 }` — a very short fade is acceptable and less jarring than an instant pop-in.
|
|
275
|
+
|
|
276
|
+
### CSS fallback (add to global stylesheet)
|
|
277
|
+
|
|
278
|
+
```css
|
|
279
|
+
@media (prefers-reduced-motion: reduce) {
|
|
280
|
+
*, *::before, *::after {
|
|
281
|
+
animation-duration: 0.01ms !important;
|
|
282
|
+
transition-duration: 0.01ms !important;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
This CSS fallback catches animations outside Framer Motion (Tailwind `animate-*`, third-party components, CSS keyframes).
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Section 8: Anti-patterns
|
|
292
|
+
|
|
293
|
+
| Anti-pattern | Correct approach |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `duration: 0.8` for UI interactions | `duration: durations.fast` (0.15) for micro-interactions |
|
|
296
|
+
| Hardcoded easing `[0.4, 0, 0.2, 1]` | `ease: easings.standard` (from design-tokens) |
|
|
297
|
+
| No `useReducedMotion()` check | Always check or use CSS media query |
|
|
298
|
+
| Animating everything on the page | Reserve motion for 3-5 meaningful moments per page |
|
|
299
|
+
| Forgetting `animation-fill-mode: backwards` in stagger | Will cause a flash before the animation starts |
|
|
300
|
+
| `AnimatePresence` without `key` changes | Exit animations will never fire |
|
|
301
|
+
| Using `framer-motion` for skeleton loaders | Use CSS `animate-pulse` — lower performance cost |
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Section 9: Installation
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npm install framer-motion
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
> If using **shadcn/ui**, framer-motion is already included as a dependency — no additional install needed.
|
|
312
|
+
|
|
313
|
+
Verify the installed version supports the features used here (requires framer-motion >= 10):
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
npm list framer-motion
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -196,20 +196,20 @@ Components are copied to `components/ui/` -- NOT an npm dependency, your code to
|
|
|
196
196
|
| `useEffect` for data fetching | React Query `useQuery` | No caching, race conditions |
|
|
197
197
|
| Form validation on submit only | Zod resolver + react-hook-form | Delayed error feedback |
|
|
198
198
|
| shadcn as npm package | `npx shadcn@latest add` | Copy-paste system, not a dependency |
|
|
199
|
-
|
|
200
|
-
## TypeScript Strict Mode (Required)
|
|
201
|
-
|
|
202
|
-
Always enable `"strict": true` in `tsconfig.json`. This is non-negotiable for
|
|
203
|
-
agent-assisted development because agents rely on compiler errors to self-correct.
|
|
204
|
-
Without strict mode, type/null errors only surface at runtime where agents cannot observe them.
|
|
205
|
-
|
|
206
|
-
```json
|
|
207
|
-
{
|
|
208
|
-
"compilerOptions": {
|
|
209
|
-
"strict": true,
|
|
210
|
-
"noUncheckedIndexedAccess": true
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
Strict mode enables: `strictNullChecks`, `noImplicitAny`, `strictFunctionTypes`, `strictPropertyInitialization`.
|
|
199
|
+
|
|
200
|
+
## TypeScript Strict Mode (Required)
|
|
201
|
+
|
|
202
|
+
Always enable `"strict": true` in `tsconfig.json`. This is non-negotiable for
|
|
203
|
+
agent-assisted development because agents rely on compiler errors to self-correct.
|
|
204
|
+
Without strict mode, type/null errors only surface at runtime where agents cannot observe them.
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"compilerOptions": {
|
|
209
|
+
"strict": true,
|
|
210
|
+
"noUncheckedIndexedAccess": true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Strict mode enables: `strictNullChecks`, `noImplicitAny`, `strictFunctionTypes`, `strictPropertyInitialization`.
|