@minhduydev/mdpi 0.4.1 → 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 +35 -7
- package/dist/template/.pi/prompts/INDEX.md +3 -9
- package/dist/template/.pi/skills/INDEX.md +39 -8
- package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
- package/dist/template/.pi/skills/frontend-design/SKILL.md +1 -1
- 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/nextjs-app-router/SKILL.md +334 -0
- package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -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/v0/SKILL.md +264 -0
- package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
- 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/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { mkdir, readdir } from "node:fs/promises";
|
|
12
12
|
//#region package.json
|
|
13
|
-
var version = "0.
|
|
13
|
+
var version = "0.5.0";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/utils/manifest.ts
|
|
16
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.5.0
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Templates Injector Extension
|
|
3
3
|
*
|
|
4
|
-
* Auto-injects project context files into system prompt.
|
|
5
4
|
* Auto-injects project context files into system prompt via pi's before_agent_start hook.
|
|
6
5
|
*
|
|
7
6
|
* Resolution: prefer the LIVE file at `.pi/{name}` (filled by /init, the project's
|
|
@@ -9,21 +8,40 @@
|
|
|
9
8
|
* when no live file exists. This keeps templates/ pristine as deliverables while
|
|
10
9
|
* ensuring real project state is what the agent actually sees.
|
|
11
10
|
*
|
|
12
|
-
* Auto-injected (always, whichever resolves):
|
|
11
|
+
* Auto-injected (always, whichever resolves) — but ONLY when not placeholder-heavy:
|
|
13
12
|
* - project.md
|
|
14
13
|
* - tech-stack.md
|
|
15
14
|
* - state.md ← the "you are here" marker; live version injected once /init fills it
|
|
16
15
|
*
|
|
17
|
-
*
|
|
16
|
+
* Placeholder-skip: at before_agent_start, blank seed templates (still full of
|
|
17
|
+
* `[Criterion]`/`[URL]`/`<!-- ... -->` markers) are skipped so they don't tax the
|
|
18
|
+
* first message. A live file with real content (few markers) still injects.
|
|
19
|
+
*
|
|
20
|
+
* DESIGN.md is NOT auto-injected — load it on demand via `/inject-template DESIGN.md`
|
|
21
|
+
* (e.g. when starting UI work).
|
|
22
|
+
*
|
|
23
|
+
* User can opt-in to inject more via /inject-template command (placeholder-skip
|
|
24
|
+
* does not apply to explicit on-demand injection).
|
|
18
25
|
*/
|
|
19
26
|
|
|
20
27
|
import * as fs from "node:fs";
|
|
21
28
|
import * as path from "node:path";
|
|
22
29
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
23
30
|
|
|
24
|
-
const ALWAYS_INJECT = ["project.md", "tech-stack.md", "state.md"
|
|
31
|
+
const ALWAYS_INJECT = ["project.md", "tech-stack.md", "state.md"];
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
// Placeholder markers that indicate a template is still a blank seed (not filled).
|
|
34
|
+
// Counted to decide whether an auto-injected file would just add noise to the
|
|
35
|
+
// first message. Threshold is intentionally low (>5) so a genuinely filled live
|
|
36
|
+
// file (a handful of incidental bracket occurrences) still injects.
|
|
37
|
+
const PLACEHOLDER_MARKER_RE = /\[(?:e\.g\.|Criterion|URL|Title|Date|slug)[^\]]*\]|<slug>|<!-- /g;
|
|
38
|
+
const PLACEHOLDER_MARKER_THRESHOLD = 5;
|
|
39
|
+
|
|
40
|
+
function readTemplate(
|
|
41
|
+
cwd: string,
|
|
42
|
+
name: string,
|
|
43
|
+
skipPlaceholders = false,
|
|
44
|
+
): string | null {
|
|
27
45
|
// Prefer live file at .pi/{name} (filled by /init — real project state);
|
|
28
46
|
// fall back to blank seed at .pi/templates/{name} when no live file exists.
|
|
29
47
|
const livePath = path.join(cwd, ".pi", name);
|
|
@@ -33,7 +51,17 @@ function readTemplate(cwd: string, name: string): string | null {
|
|
|
33
51
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
34
52
|
// Strip frontmatter for injection
|
|
35
53
|
const fmMatch = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
36
|
-
|
|
54
|
+
const body = (fmMatch ? fmMatch[1] : content).trim();
|
|
55
|
+
// Auto-inject only: skip placeholder-heavy files so unfilled templates don't
|
|
56
|
+
// tax the first message. On-demand /inject-template bypasses this (default).
|
|
57
|
+
// Anchored to a closing `]` so real markdown links like `[Vercel](...)` don't
|
|
58
|
+
// count; only placeholder-shaped tokens (`[URL]`, `[Criterion 1]`, `[e.g., ...]`,
|
|
59
|
+
// `<slug>`, `<!-- `) do.
|
|
60
|
+
if (skipPlaceholders) {
|
|
61
|
+
const markers = body.match(PLACEHOLDER_MARKER_RE);
|
|
62
|
+
if (markers && markers.length > PLACEHOLDER_MARKER_THRESHOLD) return null;
|
|
63
|
+
}
|
|
64
|
+
return body;
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
export default function templatesInjector(pi: ExtensionAPI) {
|
|
@@ -41,7 +69,7 @@ export default function templatesInjector(pi: ExtensionAPI) {
|
|
|
41
69
|
const injected: string[] = [];
|
|
42
70
|
|
|
43
71
|
for (const name of ALWAYS_INJECT) {
|
|
44
|
-
const content = readTemplate(ctx.cwd, name);
|
|
72
|
+
const content = readTemplate(ctx.cwd, name, /* skipPlaceholders */ true);
|
|
45
73
|
if (content && content.length > 0) {
|
|
46
74
|
injected.push(`### ${name}\n\n${content}`);
|
|
47
75
|
}
|
|
@@ -4,7 +4,7 @@ purpose: Index of slash commands with purpose, when-to-use, and lifecycle positi
|
|
|
4
4
|
|
|
5
5
|
# Prompts Index
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
11 slash commands. Lifecycle is canonical; utilities attach at any phase.
|
|
8
8
|
|
|
9
9
|
## Canonical Lifecycle
|
|
10
10
|
|
|
@@ -39,9 +39,6 @@ Status: /status
|
|
|
39
39
|
| `/gc` | Fallow analysis + quality grades + optional cleanup PRs | Maintenance cadence; not during active feature work | `[--dry-run] [--apply] [--scope <dir>]` | Maintenance |
|
|
40
40
|
| `/status` | Show active feature, progress tail, blockers | Orient at session start or when unsure | `[--full]` | Any (read-only) |
|
|
41
41
|
| `/close` | Finalize active feature, clear `.active` | Feature done/blocked/abandoned, or recover dangling `.active` | `[--done\|--blocked\|--abandoned] [--note <text>]` | Ship/Recovery |
|
|
42
|
-
| `/loop-check` | NO-GO qualification gate — refuse-list + 2-condition test + 30s checklist | Before scheduling a task as an unattended loop | `<task description> [--help]` | Define |
|
|
43
|
-
| `/loop-init` | Scaffold `.pi/loops/<name>/` from templates (VISION/STATE/SKILL) | Once a task passes /loop-check | `<name> [--help]` | Define |
|
|
44
|
-
| `/loop-review` | Maker/checker gate — verifier subagent runs the gate, emits ACCEPT/REJECT | After a maker run, before ship | `<loop-name> [--help]` | Review |
|
|
45
42
|
|
|
46
43
|
## When to use what
|
|
47
44
|
|
|
@@ -57,9 +54,6 @@ Status: /status
|
|
|
57
54
|
| "Where am I / what's the state" | `/status` |
|
|
58
55
|
| Feature done but `/ship` left `.active` dangling | `/close --done` |
|
|
59
56
|
| Maintenance / dead code sweep | `/gc --dry-run` |
|
|
60
|
-
| Qualify a task as an unattended loop (refuse-list + 2-condition test) | `/loop-check "<task>"` (Define) |
|
|
61
|
-
| Scaffold a loop after /loop-check returns GO | `/loop-init <name>` (Define) |
|
|
62
|
-
| Maker/checker gate on a loop run before shipping | `/loop-review <name>` (Review) |
|
|
63
57
|
|
|
64
58
|
## Conventions (shared across commands)
|
|
65
59
|
|
|
@@ -73,6 +67,6 @@ Status: /status
|
|
|
73
67
|
|
|
74
68
|
## Related
|
|
75
69
|
|
|
76
|
-
- `skills/INDEX.md` — task → skill routing (
|
|
70
|
+
- `skills/INDEX.md` — task → skill routing (67 skills)
|
|
77
71
|
- `workflows/INDEX.md` — 6 DAG workflows invoked by commands
|
|
78
|
-
- `templates/` —
|
|
72
|
+
- `templates/` — 12 template files (PRD, plan body, state, roadmap, etc.)
|
|
@@ -17,17 +17,22 @@ When the agent edits files matching these patterns, the listed skills auto-load.
|
|
|
17
17
|
|
|
18
18
|
| File pattern | Auto-load skill(s) | Why |
|
|
19
19
|
|-------------|-------------------|-----|
|
|
20
|
-
| `*.ts,*.tsx,*.jsx` | `react-best-practices`, `deep-module-design` | TypeScript/React best practices + structural quality |
|
|
20
|
+
| `*.ts,*.tsx,*.jsx` | `react-best-practices`, `deep-module-design`, `react-compiler` | TypeScript/React best practices + structural quality |
|
|
21
|
+
| `**/actions.ts`, `**/actions/**` | `react-server-actions` | Server Actions + useActionState patterns |
|
|
22
|
+
| `**/app/**/page.tsx`, `**/app/**/layout.tsx` | `nextjs-app-router`, `nextjs-cache` | App Router conventions + caching |
|
|
23
|
+
| `**/stores/**`, `**/store.ts` | `zustand` | Zustand state management patterns |
|
|
24
|
+
| `**/hooks/use-query*.ts`, `**/queries/**` | `tanstack-query` | TanStack Query hooks and patterns |
|
|
25
|
+
| `**/forms/**` with `useForm`, `zodResolver` | `react-hook-form` | React Hook Form + Zod patterns |
|
|
21
26
|
| `*.swift,*.swiftui` | `swift-concurrency`, `swiftui-expert-skill` | Swift patterns + concurrency safety |
|
|
22
27
|
| `*.test.*,*.spec.*,__tests__/**` | `test-driven-development`, `testing-anti-patterns` | Test-first discipline + mock hygiene |
|
|
23
28
|
| `*.sql,migrations/**` | `supabase-postgres-best-practices` | Query performance + RLS |
|
|
24
29
|
| `.github/workflows/**,Dockerfile,docker-compose*.yml` | `ci-cd-and-automation` | Pipeline design + caching |
|
|
25
30
|
| `.pi/skills/*/SKILL.md` | `writing-skills` | Skill authoring best practices |
|
|
26
|
-
|
|
31
|
+
|
|
27
32
|
| `*.css,*.scss,*.less` | `baseline-ui`, `frontend-design`, `design-taste-frontend` | Deslop pass + design system consistency |
|
|
28
33
|
| `*.tsx,*.jsx` | `baseline-ui`, `frontend-ui-engineering` | Deslop pass + production-quality UI standards |
|
|
29
34
|
| `*.md,docs/**,ADR*.md` | `documentation-and-adrs` | Doc structure + ADR format |
|
|
30
|
-
| `.pi/**/DESIGN.md` | `frontend-design`, `design-taste-frontend` | Project design identity — load aesthetic skills when DESIGN.md is edited |
|
|
35
|
+
| `.pi/**/DESIGN.md` | `frontend-design`, `design-taste-frontend` | Project design identity — load aesthetic skills when DESIGN.md is edited. NOTE: DESIGN.md is no longer auto-injected; load it into context on demand via `/inject-template DESIGN.md` when starting UI work. |
|
|
31
36
|
|
|
32
37
|
---
|
|
33
38
|
|
|
@@ -65,10 +70,19 @@ When the user's prompt contains these keywords (case-insensitive), the listed sk
|
|
|
65
70
|
| payment, subscription, license, billing, checkout | `polar` |
|
|
66
71
|
| Figma, design token, mockup, screenshot to code | `figma`, `mockup-to-code` |
|
|
67
72
|
| Jira, Confluence, Atlassian, issue, ticket | `jira` |
|
|
73
|
+
| v0, v0.sh, v0.dev, AI UI generator, Vercel v0, v0 component, v0 generate | `v0` |
|
|
74
|
+
| shadcn, shadcn/ui, shadcn-ui, shadcn ui, shadcn component, shadcn add | `shadcn-ui` |
|
|
75
|
+
| Server Actions, useActionState, useOptimistic, useFormStatus, 'use server', form action, progressive enhancement | `react-server-actions` |
|
|
76
|
+
| App Router, layout.tsx, page.tsx, parallel routes, intercepting routes, route groups, async params, template.tsx, loading.tsx | `nextjs-app-router` |
|
|
77
|
+
| use cache, cacheLife, cacheTag, revalidateTag, revalidatePath, Next.js cache, connection() | `nextjs-cache` |
|
|
78
|
+
| React Compiler, auto-memoize, babel-plugin-react-compiler, useMemo, useCallback, memoization | `react-compiler` |
|
|
79
|
+
| TanStack Query, React Query, useQuery, useMutation, optimistic update, infinite query, prefetch | `tanstack-query` |
|
|
80
|
+
| Zustand, state management, global state, create store, useShallow, immer, persist, devtools | `zustand` |
|
|
81
|
+
| React Hook Form, useForm, zodResolver, Controller, useFieldArray, form validation, conditional fields | `react-hook-form` |
|
|
68
82
|
| browser, e2e, screenshot, playwright, chrome | `playwright`, `chrome-devtools`, `browser-testing-with-devtools` |
|
|
69
83
|
| dependency, package, library, npm, PyPI, source | `opensrc` |
|
|
70
84
|
| scrape, crawl, webclaw, bot protection, 403, webfetch fail, extract web content, web scraping | `webclaw` |
|
|
71
|
-
|
|
85
|
+
|
|
72
86
|
| Swift, iOS, macOS, actor, async/await, Sendable | `swift-concurrency`, `swiftui-expert-skill`, `core-data-expert` |
|
|
73
87
|
|
|
74
88
|
---
|
|
@@ -111,9 +125,7 @@ When the user's prompt contains these keywords (case-insensitive), the listed sk
|
|
|
111
125
|
| `dcp-hygiene` | At command/phase closure — compress closed exploratory work-streams via pi-dcp when `compress` is available; no-ops if DCP absent | All | Low |
|
|
112
126
|
| `memory-system` | Understanding/leveraging pi-hermes-memory — auto-flywheel, tools, commands, when to use memory_search vs vcc_recall | All | Low |
|
|
113
127
|
| `doubt-driven-development` | In-flight adversarial review of non-trivial decisions before they stand | Build | Medium |
|
|
114
|
-
|
|
115
|
-
| `loop-audit` | Scoring a project's loop-readiness 0-100 + L0/L1/L2/L3; L3 gated on proven run | Review | Low |
|
|
116
|
-
| `loop-cost` | Estimating tokens/day + daily cap + early-exit flag before approving a loop budget | Plan | Low |
|
|
128
|
+
|
|
117
129
|
|
|
118
130
|
### Implementation
|
|
119
131
|
|
|
@@ -155,7 +167,14 @@ When the user's prompt contains these keywords (case-insensitive), the listed sk
|
|
|
155
167
|
| `mockup-to-code` | Converting UI mockups, screenshots, Figma/Sketch designs into code | Build | Medium |
|
|
156
168
|
| `oklch-color-workflow` | Complete OKLCH color system — syntax, palette generation, contrast, Tailwind v4 | Build | Low |
|
|
157
169
|
| `production-hardening` | Production hardening — i18n, error states, edge cases, cross-browser | Ship | High |
|
|
158
|
-
| `react-best-practices` | Writing, reviewing, or refactoring React/Next.js code for performance | Build | Medium |
|
|
170
|
+
| `react-best-practices` | Writing, reviewing, or refactoring React 19 / Next.js 16 code for performance | Build | Medium |
|
|
171
|
+
| `react-server-actions` | Building forms, mutations, data writes with React 19 Server Actions | Build | Medium |
|
|
172
|
+
| `nextjs-app-router` | Building Next.js App Router pages — layouts, routes, RSC boundaries | Build | Medium |
|
|
173
|
+
| `nextjs-cache` | Next.js 16 caching — `use cache`, cacheLife, cacheTag, revalidation | Build | Medium |
|
|
174
|
+
| `react-compiler` | Enabling, debugging, optimizing with the React Compiler | Build | Low |
|
|
175
|
+
| `tanstack-query` | Data fetching, caching, mutations with TanStack Query v5 | Build | Medium |
|
|
176
|
+
| `zustand` | Global/shared state management with Zustand v5 | Build | Medium |
|
|
177
|
+
| `react-hook-form` | Building forms with React Hook Form v7 + Zod v3 | Build | Medium |
|
|
159
178
|
| `redesign-existing-projects` | Upgrading an existing website or app's visual design | Build | High |
|
|
160
179
|
| `ui-craft-principles` | 16 craft principles — concentric radius, optical alignment, interruptible animations | Build | Low |
|
|
161
180
|
| `ui-quality-audit` | 5-dimension UI quality scoring (0-4) with P0-P3 severity tags | Review | Medium |
|
|
@@ -197,6 +216,8 @@ When the user's prompt contains these keywords (case-insensitive), the listed sk
|
|
|
197
216
|
| `opensrc` | Understanding how a library works internally, debugging dependency issues | Build | Low |
|
|
198
217
|
| `pdf-extract` | Extracting text, images, tables, or metadata from PDF files | Build | Low |
|
|
199
218
|
| `webclaw` | When webfetch returns 403 or bot protection errors | Build | Low |
|
|
219
|
+
| `v0` | Using v0 (v0.app by Vercel) for AI-powered UI generation, prompt engineering, CLI/SDK integration | Build | Medium |
|
|
220
|
+
| `shadcn-ui` | Setting up, configuring, or adding shadcn/ui components — CLI v4, presets, skills, registries | Build | Medium |
|
|
200
221
|
| `gemini-large-context` | Analyzing large codebases, comparing multiple files exceeding typical context limits | Plan | Low |
|
|
201
222
|
| `fallow` | Codebase intelligence — quality, dead code, duplication, complexity hotspots | Review | Low |
|
|
202
223
|
|
|
@@ -227,8 +248,18 @@ Maps user intent to skill(s). `→` = sequential pipeline (execute in order). `+
|
|
|
227
248
|
| "I'm stuck" / "not sure what to do" | `behavioral-kernel` + `using-agent-skills` | All | Low |
|
|
228
249
|
| "which skill to use" / "what skill for" | `using-agent-skills` | Define | Low |
|
|
229
250
|
| "create UI" / "build component" / "design page" | `frontend-design` + `design-taste-frontend` | Build | Medium |
|
|
251
|
+
| "generate with v0" / "v0 component" / "v0 prompt" / "AI generate UI" | `v0` + `frontend-design` | Build | Medium |
|
|
252
|
+
| "add shadcn components" / "shadcn init" / "setup shadcn" / "shadcn/ui setup" | `shadcn-ui` + `frontend-design` | Build | Medium |
|
|
253
|
+
| "Server Action" / "useActionState" / "useOptimistic" / "'use server'" | `react-server-actions` + `nextjs-app-router` | Build | Medium |
|
|
254
|
+
| "App Router" / "layout.tsx" / "parallel route" / "intercepting route" | `nextjs-app-router` + `react-best-practices` | Build | Medium |
|
|
255
|
+
| "use cache" / "revalidateTag" / "cacheLife" / "Next.js cache" | `nextjs-cache` + `nextjs-app-router` | Build | Medium |
|
|
256
|
+
| "React Compiler" / "auto-memoize" / "useMemo unnecessary" | `react-compiler` + `react-best-practices` | Build | Low |
|
|
257
|
+
| "useQuery" / "useMutation" / "TanStack Query" / "optimistic update" | `tanstack-query` + `zustand` | Build | Medium |
|
|
258
|
+
| "Zustand" / "create store" / "useShallow" / "global state" | `zustand` + `tanstack-query` | Build | Medium |
|
|
259
|
+
| "React Hook Form" / "useForm" / "zodResolver" / "useFieldArray" | `react-hook-form` + `react-server-actions` | Build | Medium |
|
|
230
260
|
| "deploy to Cloudflare" | `cloudflare` | Ship | High |
|
|
231
261
|
| "deploy to Vercel" | `vercel-deploy-claimable` | Ship | High |
|
|
262
|
+
| "animate" / "animation" / "motion" / "framer" / "transition" | `frontend-design` (references/animation/) | Build | Low |
|
|
232
263
|
| "set up database" / "Supabase" | `supabase` + `supabase-postgres-best-practices` | Build | High |
|
|
233
264
|
| "add logging" / "monitoring" / "observability" | `observability-and-instrumentation` | Ship | Medium |
|
|
234
265
|
| "optimize context" / "agent quality degraded" / "too many tokens" | `context-engineering` | All | Low |
|
|
@@ -16,7 +16,7 @@ description: "Use at command/phase closure points to compress closed exploratory
|
|
|
16
16
|
- The `compress` tool is not registered (DCP extension not installed, or `compress.permission: "deny"`) — see No-op clause below.
|
|
17
17
|
- The work-stream is still in-flight or spans your most recent turn — DCP turn protection (last 3 turns) already refuses these; don't try.
|
|
18
18
|
- The user just asked about the content you'd be compressing — they still need it verbatim.
|
|
19
|
-
- The command is read-only/scaffold and produced almost no tool output (`/status`, `/close
|
|
19
|
+
- The command is read-only/scaffold and produced almost no tool output (`/status`, `/close`) — compressing near-empty streams wastes more tokens than it saves.
|
|
20
20
|
- Inside orchestrator workflows' phase prompts — subagents carry their own context; only the orchestrator's accumulated summaries matter, and those are bounded by "Keep under N words" per prompt.
|
|
21
21
|
|
|
22
22
|
## Core Principle
|
|
@@ -43,7 +43,7 @@ description: MUST load when building any web UI with React-based frameworks —
|
|
|
43
43
|
|
|
44
44
|
Search: `@theme`, `@container`, `OKLCH`, `mask-`, `text-shadow`
|
|
45
45
|
|
|
46
|
-
### shadcn/ui (CLI
|
|
46
|
+
### shadcn/ui (CLI v4.11)
|
|
47
47
|
|
|
48
48
|
- `./references/shadcn/setup.md` - Installation, visual styles, component list
|
|
49
49
|
- `./references/shadcn/core-components.md` - Button, Card, Dialog, Select, Tabs, Toast
|
|
@@ -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/`
|