agemon 0.1.0 → 6.3.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/README.md +983 -30
- package/assets/skills/architecture/agemon-architecture/LICENSE +21 -0
- package/assets/skills/architecture/agemon-architecture/NOTICE.md +9 -0
- package/assets/skills/architecture/agemon-architecture/SKILL.md +275 -0
- package/assets/skills/code-quality/agemon-clean-code/LICENSE +21 -0
- package/assets/skills/code-quality/agemon-clean-code/NOTICE.md +9 -0
- package/assets/skills/code-quality/agemon-clean-code/SKILL.md +78 -0
- package/assets/skills/code-quality/agemon-house-rules/SKILL.md +103 -0
- package/assets/skills/commit/agemon-commit/SKILL.md +87 -0
- package/assets/skills/design/agemon-design/LICENSE +21 -0
- package/assets/skills/design/agemon-design/NOTICE.md +43 -0
- package/assets/skills/design/agemon-design/SKILL.md +128 -0
- package/assets/skills/design/agemon-design/references/accessibility.md +182 -0
- package/assets/skills/design/agemon-design/references/actions.md +215 -0
- package/assets/skills/design/agemon-design/references/ai-chat.md +158 -0
- package/assets/skills/design/agemon-design/references/brief.md +190 -0
- package/assets/skills/design/agemon-design/references/color.md +216 -0
- package/assets/skills/design/agemon-design/references/components.md +91 -0
- package/assets/skills/design/agemon-design/references/copy.md +300 -0
- package/assets/skills/design/agemon-design/references/core-rules.md +166 -0
- package/assets/skills/design/agemon-design/references/craft-intent.md +162 -0
- package/assets/skills/design/agemon-design/references/dashboard.md +131 -0
- package/assets/skills/design/agemon-design/references/dataviz.md +197 -0
- package/assets/skills/design/agemon-design/references/finish-bar.md +243 -0
- package/assets/skills/design/agemon-design/references/forms.md +192 -0
- package/assets/skills/design/agemon-design/references/heuristics.md +319 -0
- package/assets/skills/design/agemon-design/references/inspiration.md +287 -0
- package/assets/skills/design/agemon-design/references/layout.md +236 -0
- package/assets/skills/design/agemon-design/references/loops.md +155 -0
- package/assets/skills/design/agemon-design/references/metadata.md +98 -0
- package/assets/skills/design/agemon-design/references/modern-css.md +448 -0
- package/assets/skills/design/agemon-design/references/motion.md +434 -0
- package/assets/skills/design/agemon-design/references/personas.md +206 -0
- package/assets/skills/design/agemon-design/references/preset-dashboard.md +109 -0
- package/assets/skills/design/agemon-design/references/preset-editorial.md +94 -0
- package/assets/skills/design/agemon-design/references/preset-minimal.md +93 -0
- package/assets/skills/design/agemon-design/references/principles-catalog.md +299 -0
- package/assets/skills/design/agemon-design/references/recipe-auth.md +88 -0
- package/assets/skills/design/agemon-design/references/recipe-dashboard.md +130 -0
- package/assets/skills/design/agemon-design/references/recipe-landing.md +120 -0
- package/assets/skills/design/agemon-design/references/responsive.md +168 -0
- package/assets/skills/design/agemon-design/references/review.md +340 -0
- package/assets/skills/design/agemon-design/references/routing.md +143 -0
- package/assets/skills/design/agemon-design/references/sound.md +150 -0
- package/assets/skills/design/agemon-design/references/spec.md +123 -0
- package/assets/skills/design/agemon-design/references/stack.md +522 -0
- package/assets/skills/design/agemon-design/references/stage-assets.md +106 -0
- package/assets/skills/design/agemon-design/references/stage-build.md +46 -0
- package/assets/skills/design/agemon-design/references/stage-critique.md +34 -0
- package/assets/skills/design/agemon-design/references/stage-directions.md +44 -0
- package/assets/skills/design/agemon-design/references/stage-intake.md +34 -0
- package/assets/skills/design/agemon-design/references/stage-verify.md +44 -0
- package/assets/skills/design/agemon-design/references/state-design.md +188 -0
- package/assets/skills/design/agemon-design/references/tells-2026-11.md +32 -0
- package/assets/skills/design/agemon-design/references/themes.md +233 -0
- package/assets/skills/design/agemon-design/references/third-party-licenses.md +323 -0
- package/assets/skills/design/agemon-design/references/tokens.md +350 -0
- package/assets/skills/design/agemon-design/references/typography.md +248 -0
- package/assets/skills/design/agemon-design/scripts/audit-page.js +532 -0
- package/assets/skills/design/agemon-design/scripts/check-source.mjs +358 -0
- package/assets/skills/design/agemon-design/scripts/deal.mjs +231 -0
- package/assets/skills/design/agemon-design/scripts/inventory.mjs +676 -0
- package/assets/skills/essentials/web-design-guidelines/LICENSE +21 -0
- package/assets/skills/essentials/web-design-guidelines/NOTICE.md +14 -0
- package/assets/skills/essentials/web-design-guidelines/SKILL.md +18 -0
- package/assets/skills/essentials/web-design-guidelines/references/guidelines.md +184 -0
- package/assets/skills/essentials/writing-guidelines/LICENSE +21 -0
- package/assets/skills/essentials/writing-guidelines/NOTICE.md +14 -0
- package/assets/skills/essentials/writing-guidelines/SKILL.md +18 -0
- package/assets/skills/essentials/writing-guidelines/references/guidelines.md +250 -0
- package/assets/skills/founder/agemon-founder-board/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-board/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-board/SKILL.md +111 -0
- package/assets/skills/founder/agemon-founder-board/lenses.md +84 -0
- package/assets/skills/founder/agemon-founder-brand/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-brand/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-brand/SKILL.md +77 -0
- package/assets/skills/founder/agemon-founder-cfo/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-cfo/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-cfo/SKILL.md +109 -0
- package/assets/skills/founder/agemon-founder-cfo/example.json +27 -0
- package/assets/skills/founder/agemon-founder-cfo/unit_economics.py +270 -0
- package/assets/skills/founder/agemon-founder-competitors/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-competitors/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-competitors/SKILL.md +84 -0
- package/assets/skills/founder/agemon-founder-consumer/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-consumer/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-consumer/SKILL.md +126 -0
- package/assets/skills/founder/agemon-founder-consumer/customer.example.json +34 -0
- package/assets/skills/founder/agemon-founder-consumer/panel.py +424 -0
- package/assets/skills/founder/agemon-founder-consumer/pitch.example.md +3 -0
- package/assets/skills/founder/agemon-founder-launch/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-launch/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-launch/SKILL.md +65 -0
- package/assets/skills/founder/agemon-founder-marketing/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-marketing/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-marketing/SKILL.md +80 -0
- package/assets/skills/founder/agemon-founder-offer/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-offer/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-offer/SKILL.md +75 -0
- package/assets/skills/founder/agemon-founder-ops/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-ops/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-ops/SKILL.md +77 -0
- package/assets/skills/founder/agemon-founder-plan/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-plan/NOTICE.md +11 -0
- package/assets/skills/founder/agemon-founder-plan/SKILL.md +88 -0
- package/assets/skills/founder/agemon-founder-plan/compile.py +178 -0
- package/assets/skills/founder/agemon-founder-pricing/LICENSE +21 -0
- package/assets/skills/founder/agemon-founder-pricing/NOTICE.md +12 -0
- package/assets/skills/founder/agemon-founder-pricing/SKILL.md +92 -0
- package/assets/skills/founder/agemon-founder-pricing/van_westendorp.py +172 -0
- package/assets/skills/geo-seo/geo/LICENSE +21 -0
- package/assets/skills/geo-seo/geo/NOTICE.md +18 -0
- package/assets/skills/geo-seo/geo/SKILL.md +145 -0
- package/assets/skills/geo-seo/geo-audit/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-audit/NOTICE.md +17 -0
- package/assets/skills/geo-seo/geo-audit/SKILL.md +371 -0
- package/assets/skills/geo-seo/geo-audit/references/ai-visibility.md +233 -0
- package/assets/skills/geo-seo/geo-audit/references/content.md +329 -0
- package/assets/skills/geo-seo/geo-audit/references/platform-analysis.md +294 -0
- package/assets/skills/geo-seo/geo-audit/references/schema.md +383 -0
- package/assets/skills/geo-seo/geo-audit/references/technical.md +368 -0
- package/assets/skills/geo-seo/geo-brand-mentions/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-brand-mentions/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-brand-mentions/SKILL.md +459 -0
- package/assets/skills/geo-seo/geo-citability/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-citability/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-citability/SKILL.md +320 -0
- package/assets/skills/geo-seo/geo-content/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-content/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-content/SKILL.md +352 -0
- package/assets/skills/geo-seo/geo-crawlers/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-crawlers/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-crawlers/SKILL.md +388 -0
- package/assets/skills/geo-seo/geo-llmstxt/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-llmstxt/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-llmstxt/SKILL.md +433 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-platform-optimizer/SKILL.md +282 -0
- package/assets/skills/geo-seo/geo-report/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-report/NOTICE.md +14 -0
- package/assets/skills/geo-seo/geo-report/SKILL.md +406 -0
- package/assets/skills/geo-seo/geo-report-pdf/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-report-pdf/NOTICE.md +20 -0
- package/assets/skills/geo-seo/geo-report-pdf/SKILL.md +153 -0
- package/assets/skills/geo-seo/geo-report-pdf/templates/geo-report-template.html +548 -0
- package/assets/skills/geo-seo/geo-schema/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-schema/NOTICE.md +16 -0
- package/assets/skills/geo-seo/geo-schema/SKILL.md +396 -0
- package/assets/skills/geo-seo/geo-technical/LICENSE +21 -0
- package/assets/skills/geo-seo/geo-technical/NOTICE.md +15 -0
- package/assets/skills/geo-seo/geo-technical/SKILL.md +566 -0
- package/assets/skills/output-style/agemon-adhd/LICENSE +21 -0
- package/assets/skills/output-style/agemon-adhd/NOTICE.md +13 -0
- package/assets/skills/output-style/agemon-adhd/SKILL.md +138 -0
- package/assets/skills/performance/agemon-performance/NOTICE.md +1 -0
- package/assets/skills/performance/agemon-performance/SKILL.md +76 -0
- package/assets/skills/security/agemon-security/LICENSE +21 -0
- package/assets/skills/security/agemon-security/NOTICE.md +8 -0
- package/assets/skills/security/agemon-security/SKILL.md +356 -0
- package/assets/skills/security/agemon-security-audit/AI-AND-LLM.md +83 -0
- package/assets/skills/security/agemon-security-audit/ATTACK-CLASSES.md +130 -0
- package/assets/skills/security/agemon-security-audit/CLIENT-SIDE.md +83 -0
- package/assets/skills/security/agemon-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
- package/assets/skills/security/agemon-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
- package/assets/skills/security/agemon-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
- package/assets/skills/security/agemon-security-audit/HUNTING.md +251 -0
- package/assets/skills/security/agemon-security-audit/LICENSE +21 -0
- package/assets/skills/security/agemon-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
- package/assets/skills/security/agemon-security-audit/NOTICE.md +12 -0
- package/assets/skills/security/agemon-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
- package/assets/skills/security/agemon-security-audit/RECONNAISSANCE.md +156 -0
- package/assets/skills/security/agemon-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
- package/assets/skills/security/agemon-security-audit/SKILL.md +192 -0
- package/assets/skills/security/agemon-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
- package/assets/skills/security/agemon-security-audit/VALIDATION-AND-REPORTING.md +186 -0
- package/assets/skills/security/agemon-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
- package/assets/skills/security/agemon-security-audit/report-schema.json +461 -0
- package/assets/skills/security/agemon-security-audit/validate-coverage-ledger.cjs +872 -0
- package/assets/skills/security/agemon-security-audit/validate-findings.cjs +773 -0
- package/assets/skills/self-review/agemon-review-intake/LICENSE +21 -0
- package/assets/skills/self-review/agemon-review-intake/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-review-intake/SKILL.md +205 -0
- package/assets/skills/self-review/agemon-review-request/LICENSE +21 -0
- package/assets/skills/self-review/agemon-review-request/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-review-request/SKILL.md +104 -0
- package/assets/skills/self-review/agemon-review-request/code-reviewer.md +188 -0
- package/assets/skills/self-review/agemon-root-cause/LICENSE +21 -0
- package/assets/skills/self-review/agemon-root-cause/NOTICE.md +10 -0
- package/assets/skills/self-review/agemon-root-cause/SKILL.md +283 -0
- package/assets/skills/self-review/agemon-root-cause/condition-based-waiting-example.ts +158 -0
- package/assets/skills/self-review/agemon-root-cause/condition-based-waiting.md +115 -0
- package/assets/skills/self-review/agemon-root-cause/defense-in-depth.md +122 -0
- package/assets/skills/self-review/agemon-root-cause/find-polluter.sh +72 -0
- package/assets/skills/self-review/agemon-root-cause/root-cause-tracing.md +169 -0
- package/assets/skills/self-review/agemon-root-cause/test-academic.md +14 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-1.md +58 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-2.md +68 -0
- package/assets/skills/self-review/agemon-root-cause/test-pressure-3.md +69 -0
- package/assets/skills/self-review/agemon-verify-before-done/LICENSE +21 -0
- package/assets/skills/self-review/agemon-verify-before-done/NOTICE.md +9 -0
- package/assets/skills/self-review/agemon-verify-before-done/SKILL.md +120 -0
- package/assets/skills/team-lead/agemon-plan-rfc/SKILL.md +317 -0
- package/assets/skills/team-lead/prd-generator/SKILL.md +437 -0
- package/assets/skills/team-lead/skill-headofit-audit/SKILL.md +72 -0
- package/assets/skills/team-lead/skill-incident-rca/SKILL.md +66 -0
- package/assets/skills/team-lead/skill-meeting-lifecycle/SKILL.md +63 -0
- package/assets/skills/team-lead/skill-obsidian-vault-sync/SKILL.md +69 -0
- package/assets/skills/team-lead/skill-prd-decomposer/SKILL.md +71 -0
- package/assets/skills/team-lead/skill-sec-check/SKILL.md +70 -0
- package/assets/skills/team-lead/skill-task-extractor/SKILL.md +79 -0
- package/assets/skills/team-lead/skill-tech-spike/SKILL.md +57 -0
- package/assets/skills/team-lead/skill-techlead-reviewer/SKILL.md +81 -0
- package/assets/skills/workflow/agemon-brainstorming/LICENSE +21 -0
- package/assets/skills/workflow/agemon-brainstorming/NOTICE.md +14 -0
- package/assets/skills/workflow/agemon-brainstorming/SKILL.md +287 -0
- package/assets/skills/workflow/agemon-brainstorming/builder-check-prompt.md +23 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/LICENSE +21 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-dispatching-parallel-agents/SKILL.md +167 -0
- package/assets/skills/workflow/agemon-executing-plans/LICENSE +21 -0
- package/assets/skills/workflow/agemon-executing-plans/NOTICE.md +15 -0
- package/assets/skills/workflow/agemon-executing-plans/SKILL.md +322 -0
- package/assets/skills/workflow/agemon-executing-plans/scripts/task-done +55 -0
- package/assets/skills/workflow/agemon-executing-plans/scripts/task-start +32 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/LICENSE +21 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-finishing-a-development-branch/SKILL.md +225 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/LICENSE +21 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/NOTICE.md +15 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/SKILL.md +339 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/code-reviewer.md +198 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/implementer-prompt.md +154 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/re-review-prompt.md +116 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/batching.md +11 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/cannot-verify.md +10 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/final-review.md +49 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/fix-loop.md +77 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/handling-reports.md +15 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/preflight.md +26 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/resuming.md +12 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/role-scout.md +18 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/references/role-worker.md +19 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/review-package +64 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/sdd-repo +54 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/sdd-workspace +110 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/scripts/task-brief +108 -0
- package/assets/skills/workflow/agemon-subagent-driven-development/task-reviewer-prompt.md +209 -0
- package/assets/skills/workflow/agemon-test-driven-development/LICENSE +21 -0
- package/assets/skills/workflow/agemon-test-driven-development/NOTICE.md +14 -0
- package/assets/skills/workflow/agemon-test-driven-development/SKILL.md +330 -0
- package/assets/skills/workflow/agemon-test-driven-development/writing-good-tests.md +198 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/LICENSE +21 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-using-git-worktrees/SKILL.md +167 -0
- package/assets/skills/workflow/agemon-writing-plans/LICENSE +21 -0
- package/assets/skills/workflow/agemon-writing-plans/NOTICE.md +13 -0
- package/assets/skills/workflow/agemon-writing-plans/SKILL.md +204 -0
- package/assets/tools/code-review-graph-constraints.txt +1418 -0
- package/assets/tools/package-lock.json +111 -0
- package/assets/tools/package.json +6 -0
- package/dist/chunk-ZZBF3GOV.js +3451 -0
- package/dist/chunk-ZZBF3GOV.js.map +1 -0
- package/dist/fake-subprocess-IV4ML77S.js +636 -0
- package/dist/fake-subprocess-IV4ML77S.js.map +1 -0
- package/dist/index.js +23836 -1945
- package/dist/index.js.map +1 -1
- package/package.json +37 -17
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Composition Spec
|
|
2
|
+
|
|
3
|
+
Defines `.design/spec.md` — the durable "what" between brief (why) and build (how). Consumed by `/agemon-design build`. Sits beside `brief.md` in `.design/` and is committed to the repo. An older `.ui-craft/spec.md` is read, not rewritten.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## The Spec Format
|
|
8
|
+
|
|
9
|
+
One file. Per-surface `## Surface: <name>` sections. Append-mostly — new surfaces add a new section; existing sections are only edited when a composition decision changes. No JSX, no component code — this is a design document, not implementation.
|
|
10
|
+
|
|
11
|
+
Multiple surfaces coexist in a single file, just as a brief covers one project with multiple concerns in one place.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Per-Surface Template
|
|
16
|
+
|
|
17
|
+
Copy this block for each new surface. Fill every subsection — leave none empty or the acceptance bar is undefined.
|
|
18
|
+
|
|
19
|
+
```markdown
|
|
20
|
+
## Surface: <name>
|
|
21
|
+
|
|
22
|
+
### Composition
|
|
23
|
+
|
|
24
|
+
**Recipe:** `recipe-<type>.md` → <Variant name>
|
|
25
|
+
**Why:** <one line citing the brief principle or constraint that drove this choice>
|
|
26
|
+
|
|
27
|
+
### Layout skeleton
|
|
28
|
+
|
|
29
|
+
Desktop
|
|
30
|
+
┌──────────────────────────────────────────────┐
|
|
31
|
+
│ [region] [region] [region] │
|
|
32
|
+
├──────────────────────────────────────────────┤
|
|
33
|
+
│ ┌────────────────┐ ┌───────────────────┐ │
|
|
34
|
+
│ │ <content area> │ │ <content area> │ │
|
|
35
|
+
│ └────────────────┘ └───────────────────┘ │
|
|
36
|
+
└──────────────────────────────────────────────┘
|
|
37
|
+
|
|
38
|
+
Mobile
|
|
39
|
+
┌──────────────────┐
|
|
40
|
+
│ [region] [☰] │
|
|
41
|
+
├──────────────────┤
|
|
42
|
+
│ <content area> │
|
|
43
|
+
└──────────────────┘
|
|
44
|
+
|
|
45
|
+
### Component inventory
|
|
46
|
+
|
|
47
|
+
| Region | Component | Contract ref |
|
|
48
|
+
|--------|-----------|--------------|
|
|
49
|
+
| header | Nav bar | components.md → Nav bar |
|
|
50
|
+
| hero | Headline + CTA | components.md → Buttons |
|
|
51
|
+
| … | … | … |
|
|
52
|
+
|
|
53
|
+
### State lattice
|
|
54
|
+
|
|
55
|
+
| State | Required / Optional / N-A | Notes |
|
|
56
|
+
|-------|--------------------------|-------|
|
|
57
|
+
| idle | Required | default, data present |
|
|
58
|
+
| loading | Required | skeletons mirror final layout |
|
|
59
|
+
| empty | Required | first-run or no data |
|
|
60
|
+
| error | Required | cause + recovery action |
|
|
61
|
+
| partial | Optional — only if widgets can fail independently | |
|
|
62
|
+
| conflict | N-A | no collaborative editing on this surface |
|
|
63
|
+
| offline | Optional — only if writes are queued | |
|
|
64
|
+
| success | Required | confirmation after primary action |
|
|
65
|
+
|
|
66
|
+
See [state-design.md](state-design.md) for state contracts and CRAFT_LEVEL thresholds.
|
|
67
|
+
|
|
68
|
+
### Acceptance bar
|
|
69
|
+
|
|
70
|
+
Drawn from the recipe's acceptance criteria. All items must be green before build reports done.
|
|
71
|
+
|
|
72
|
+
- [ ] <recipe checklist item 1>
|
|
73
|
+
- [ ] <recipe checklist item 2>
|
|
74
|
+
- [ ] <recipe checklist item 3>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## How the Spec Gets Used
|
|
80
|
+
|
|
81
|
+
**Intake** — read `.design/spec.md` after `brief.md`. If the surface already has a spec section, it is the composition ground truth; do not re-derive from scratch.
|
|
82
|
+
|
|
83
|
+
**Build phase** — `/agemon-design build <surface>` builds against the acceptance bar in the surface's spec section. Every item in the acceptance bar must be green before the build reports done.
|
|
84
|
+
|
|
85
|
+
**Finalize phase** — the finishing pass verifies against the acceptance bar and the brief's learned constraints (§6). The acceptance bar is the surface-level definition of done; the brief's §6 constraints are the project-level floor.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## When to Update
|
|
90
|
+
|
|
91
|
+
Update a spec section when any of these change:
|
|
92
|
+
|
|
93
|
+
- **Composition changes** — different recipe variant selected.
|
|
94
|
+
- **New surface** — append a new `## Surface: <name>` section. Never overwrite an existing section.
|
|
95
|
+
- **Recipe swap** — the recipe file changed and the acceptance bar items shift.
|
|
96
|
+
- **Learned constraint overrides a composition choice** — note it in the Composition subsection, citing the brief §6 entry.
|
|
97
|
+
|
|
98
|
+
Append-mostly. When deprecating a composition choice within a surface, mark the old entry as:
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
~~**Recipe:** [recipe-landing.md](recipe-landing.md) → Product-forward~~ — deprecated 2026-06-24, swapped to Message-forward per brief §6 constraint (no hero visuals).
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Never delete past composition records — the spec is a log, not a config file.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## File Location and Git
|
|
109
|
+
|
|
110
|
+
Commit `.design/spec.md` to the repo. It belongs in version control alongside the code it governs — losing it between sessions means losing the composition rationale.
|
|
111
|
+
|
|
112
|
+
The `.design/` directory is the project's design decision store:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
.design/
|
|
116
|
+
├── brief.md # why — principles, user, success metric
|
|
117
|
+
├── spec.md # what — chosen composition, layout, inventory, acceptance bar
|
|
118
|
+
└── (tokens live in the project's own token files)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`brief.md` and `spec.md` are companions: the brief anchors principles; the spec records how those principles translated into a specific surface composition. When they conflict, the brief wins — a spec choice that violates a brief §6 constraint must be updated to comply.
|
|
122
|
+
|
|
123
|
+
See `../SKILL.md` for routing.
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# Stack: Motion / GSAP / Three.js
|
|
2
|
+
|
|
3
|
+
Load this reference **only when the user opts in during intake**. Every rule in `motion.md` still applies — this file covers the library-specific how.
|
|
4
|
+
|
|
5
|
+
## Decision tree — which library?
|
|
6
|
+
|
|
7
|
+
| Need | Pick |
|
|
8
|
+
|------|------|
|
|
9
|
+
| Single hover, fade, or enter | **CSS transition / `@keyframes`** (0KB, always wins) |
|
|
10
|
+
| Modern CSS scroll-linked reveal | **`animation-timeline: view()`** before any JS library |
|
|
11
|
+
| React layout/exit animations, gestures, scroll progress tied to state | **Motion** |
|
|
12
|
+
| Complex timelines with labels/overlaps, ScrollTrigger pin+scrub, SplitText, SVG paths, non-React | **GSAP** |
|
|
13
|
+
| 3D scenes, shaders, product viewers, particle fields | **Three.js + R3F** |
|
|
14
|
+
|
|
15
|
+
**Never install two animation libraries that animate the same property** — they will fight and one will silently lose. Pick one per surface.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Motion (framer-motion)
|
|
20
|
+
|
|
21
|
+
Package renamed to `motion` on npm (legacy `framer-motion` still works).
|
|
22
|
+
|
|
23
|
+
### When to reach for it
|
|
24
|
+
- React component needs **exit** animation — `AnimatePresence` is the only clean way to animate unmounts.
|
|
25
|
+
- **Shared element transition** (tabs underline, modal-from-card) — `layoutId`.
|
|
26
|
+
- **Scroll-linked** progress bars, parallax tied to component state — `useScroll` + `useTransform`.
|
|
27
|
+
- **Gesture-driven** interactions (drag, pan).
|
|
28
|
+
|
|
29
|
+
### When NOT
|
|
30
|
+
- A single hover/fade/enter — CSS wins, no library needed.
|
|
31
|
+
- A one-off `@keyframes` spinner or loader.
|
|
32
|
+
- Non-React surfaces — use GSAP.
|
|
33
|
+
|
|
34
|
+
### Install
|
|
35
|
+
```bash
|
|
36
|
+
npm install motion
|
|
37
|
+
```
|
|
38
|
+
```tsx
|
|
39
|
+
import {
|
|
40
|
+
motion,
|
|
41
|
+
AnimatePresence,
|
|
42
|
+
useScroll,
|
|
43
|
+
useTransform,
|
|
44
|
+
useReducedMotion,
|
|
45
|
+
MotionConfig,
|
|
46
|
+
LazyMotion,
|
|
47
|
+
domAnimation,
|
|
48
|
+
} from "motion/react"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Top patterns
|
|
52
|
+
|
|
53
|
+
**1. Exit animation with `AnimatePresence`**
|
|
54
|
+
```tsx
|
|
55
|
+
<AnimatePresence>
|
|
56
|
+
{open && (
|
|
57
|
+
<motion.div
|
|
58
|
+
key="modal"
|
|
59
|
+
initial={{ opacity: 0, y: 8 }}
|
|
60
|
+
animate={{ opacity: 1, y: 0 }}
|
|
61
|
+
exit={{ opacity: 0, y: 4 }}
|
|
62
|
+
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
|
|
63
|
+
/>
|
|
64
|
+
)}
|
|
65
|
+
</AnimatePresence>
|
|
66
|
+
```
|
|
67
|
+
Every child needs a unique `key`. Without `AnimatePresence`, `exit` is silently ignored.
|
|
68
|
+
|
|
69
|
+
**2. Shared element transition with `layoutId`**
|
|
70
|
+
```tsx
|
|
71
|
+
{tabs.map((tab) => (
|
|
72
|
+
<button key={tab.id} onClick={() => setActive(tab.id)}>
|
|
73
|
+
{tab.label}
|
|
74
|
+
{active === tab.id && (
|
|
75
|
+
<motion.div layoutId="tab-underline" className="underline" />
|
|
76
|
+
)}
|
|
77
|
+
</button>
|
|
78
|
+
))}
|
|
79
|
+
```
|
|
80
|
+
Animates position between elements sharing the same `layoutId`. FLIP-based, GPU-safe.
|
|
81
|
+
|
|
82
|
+
**3. Scroll progress (smoothed with `useSpring`)**
|
|
83
|
+
```tsx
|
|
84
|
+
const { scrollYProgress } = useScroll()
|
|
85
|
+
const smooth = useSpring(scrollYProgress, { stiffness: 120, damping: 30, mass: 0.3 })
|
|
86
|
+
return (
|
|
87
|
+
<motion.div
|
|
88
|
+
style={{ scaleX: smooth, transformOrigin: "0%" }}
|
|
89
|
+
className="fixed top-0 inset-x-0 h-[2px] bg-foreground"
|
|
90
|
+
/>
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
Always bind scroll-linked values via `style`, **never** via `animate` (would trigger React renders per frame). `useSpring` smooths without a RAF loop.
|
|
94
|
+
|
|
95
|
+
**3b. Viewport-triggered reveal**
|
|
96
|
+
```tsx
|
|
97
|
+
<motion.section
|
|
98
|
+
initial={{ opacity: 0, y: 24 }}
|
|
99
|
+
whileInView={{ opacity: 1, y: 0 }}
|
|
100
|
+
viewport={{ once: true, margin: "-80px" }}
|
|
101
|
+
transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
`once: true` prevents re-triggering on scroll back. Negative `margin` fires before the element is fully in view — feels natural, not delayed.
|
|
105
|
+
|
|
106
|
+
**4. Spring vs tween — pick ONE per project**
|
|
107
|
+
```tsx
|
|
108
|
+
// Spring (Motion default — physical, no fixed duration)
|
|
109
|
+
transition={{ type: "spring", bounce: 0.25, visualDuration: 0.3 }}
|
|
110
|
+
|
|
111
|
+
// Tween (deterministic, matches our 200–300ms rule)
|
|
112
|
+
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
|
|
113
|
+
```
|
|
114
|
+
Mixing both within the same app reads as inconsistent. Document the choice.
|
|
115
|
+
|
|
116
|
+
**5. Reduced-motion, once for the whole app**
|
|
117
|
+
```tsx
|
|
118
|
+
<MotionConfig reducedMotion="user">
|
|
119
|
+
<App />
|
|
120
|
+
</MotionConfig>
|
|
121
|
+
```
|
|
122
|
+
Or per-component with `useReducedMotion()` and branch the animation.
|
|
123
|
+
|
|
124
|
+
### Clashes with ui-craft rules
|
|
125
|
+
|
|
126
|
+
- Motion defaults to spring (good) but specs often call `{ duration, ease }`. **Pick lane per project**, don't mix.
|
|
127
|
+
- Springs have no fixed duration → our 200–300ms budget doesn't apply directly; constrain via `bounce ≤ 0.25` and `visualDuration`.
|
|
128
|
+
- `layout` animates via `transform` only → matches "GPU-accelerated transforms only".
|
|
129
|
+
- `whileHover={{ scale: 1.05 }}` on clickable cards feels toy-like — keep ≤ 1.02 for functional UI.
|
|
130
|
+
|
|
131
|
+
### Perf gotchas
|
|
132
|
+
|
|
133
|
+
- Full `motion` import ≈ 50KB gz. On marketing pages use **`LazyMotion` + `domAnimation`** for code-split:
|
|
134
|
+
```tsx
|
|
135
|
+
<LazyMotion features={domAnimation}>
|
|
136
|
+
<m.div animate={{ opacity: 1 }} />
|
|
137
|
+
</LazyMotion>
|
|
138
|
+
```
|
|
139
|
+
- `layout` without stable `key`/`layoutId` on list items → every item reflows on any change. Use `layoutId` or `LayoutGroup`.
|
|
140
|
+
- Animating `width`/`height`/`top` triggers layout. Use `scale`, `x`, `y`.
|
|
141
|
+
- `useScroll({ container })` with `trackContentSize: true` has cost — only enable when content genuinely resizes.
|
|
142
|
+
- **Next.js App Router**: any file using `motion` hooks (`useScroll`, `useTransform`, `useSpring`, `useReducedMotion`) must be `'use client'`. Silent hydration mismatches otherwise.
|
|
143
|
+
- Inline `style={{ … }}` objects on `motion.div` create a new object every render → memoization busted. Hoist or `useMemo`.
|
|
144
|
+
- **Motion v12 animates `oklch()` / `oklab()` / `color-mix()` directly** — useful for dynamic theming. Example: `animate={{ backgroundColor: "oklch(70% 0.15 250)" }}`. Hardware-accelerated, no RGB interpolation artifacts.
|
|
145
|
+
|
|
146
|
+
### Anti-patterns (flag in review)
|
|
147
|
+
|
|
148
|
+
- `motion.div` wrapping every element "just in case" — each one adds an observer.
|
|
149
|
+
- `exit` prop without `AnimatePresence` — silently does nothing.
|
|
150
|
+
- `whileHover={{ scale: 1.08 }}` on buttons — fine for cards, too much for CTAs.
|
|
151
|
+
- `layout` on virtualized lists — kills FPS.
|
|
152
|
+
- `transition={{ duration: 2 }}` on functional UI — 300ms ceiling; longer only for decorative.
|
|
153
|
+
- Binding `scrollYProgress` to `animate={{ … }}` instead of `style={{ … }}` — one causes per-frame React renders, the other runs on the compositor.
|
|
154
|
+
- Permanent `style={{ willChange: "transform" }}` on motion elements — leaks compositor layers. Only just-in-time, via `whileHover` / `whileTap` or transient state.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## GSAP
|
|
159
|
+
|
|
160
|
+
All GSAP plugins (including ScrollTrigger, SplitText, MorphSVG) are MIT since late 2024.
|
|
161
|
+
|
|
162
|
+
### When to reach for it
|
|
163
|
+
- **Timelines with labels/overlaps** — sequence shots, re-use, rewind.
|
|
164
|
+
- **ScrollTrigger** — pin sections, scrub cinematic scenes, snap to waypoints.
|
|
165
|
+
- **SplitText** — per-line/word/char reveal on headlines.
|
|
166
|
+
- **SVG morphing/drawing** — `MorphSVG`, `DrawSVG`.
|
|
167
|
+
- **Non-React surfaces** — vanilla, canvas/WebGL tweening.
|
|
168
|
+
|
|
169
|
+
### When NOT
|
|
170
|
+
- A hover state or enter animation in React — Motion is more ergonomic.
|
|
171
|
+
- Anything CSS `animation-timeline: view()` can do natively in evergreens.
|
|
172
|
+
- Text splitting on body copy — huge DOM cost + a11y risk. Headlines only.
|
|
173
|
+
|
|
174
|
+
### Install
|
|
175
|
+
```bash
|
|
176
|
+
npm install gsap @gsap/react
|
|
177
|
+
```
|
|
178
|
+
```ts
|
|
179
|
+
import gsap from "gsap"
|
|
180
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger"
|
|
181
|
+
import { SplitText } from "gsap/SplitText"
|
|
182
|
+
import { useGSAP } from "@gsap/react"
|
|
183
|
+
|
|
184
|
+
gsap.registerPlugin(ScrollTrigger, SplitText, useGSAP)
|
|
185
|
+
```
|
|
186
|
+
Always `registerPlugin()` — in production bundlers will otherwise tree-shake plugins to nothing (silent failure).
|
|
187
|
+
|
|
188
|
+
### Top patterns
|
|
189
|
+
|
|
190
|
+
**1. `useGSAP` hook (React) — auto-cleanup, StrictMode safe**
|
|
191
|
+
```tsx
|
|
192
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
193
|
+
useGSAP(
|
|
194
|
+
() => {
|
|
195
|
+
gsap.from(".card", { y: 40, opacity: 0, stagger: 0.08, duration: 0.3 })
|
|
196
|
+
},
|
|
197
|
+
{ scope: ref }
|
|
198
|
+
)
|
|
199
|
+
return <div ref={ref}>…</div>
|
|
200
|
+
```
|
|
201
|
+
Wraps `gsap.context()` so everything reverts on unmount. Never use raw `useEffect` for GSAP in React.
|
|
202
|
+
|
|
203
|
+
**2. Timeline with labels**
|
|
204
|
+
```ts
|
|
205
|
+
const tl = gsap.timeline({
|
|
206
|
+
defaults: { ease: "power2.out", duration: 0.3 },
|
|
207
|
+
})
|
|
208
|
+
tl.from(".title", { y: 40, opacity: 0 })
|
|
209
|
+
.from(".sub", { opacity: 0 }, "-=0.2") // overlap 200ms
|
|
210
|
+
.addLabel("hero-done")
|
|
211
|
+
```
|
|
212
|
+
Overlap with relative offsets keeps sequences tight.
|
|
213
|
+
|
|
214
|
+
**3. ScrollTrigger pin + scrub**
|
|
215
|
+
```ts
|
|
216
|
+
gsap.to(".panel", {
|
|
217
|
+
xPercent: -300,
|
|
218
|
+
scrollTrigger: {
|
|
219
|
+
trigger: ".panels",
|
|
220
|
+
pin: true,
|
|
221
|
+
scrub: 1, // smooth with 1s catch-up, never `true`
|
|
222
|
+
end: "+=2000",
|
|
223
|
+
invalidateOnRefresh: true,
|
|
224
|
+
},
|
|
225
|
+
})
|
|
226
|
+
```
|
|
227
|
+
Use `scrub: 1` (or higher), not `true` — `true` welds the animation to the wheel and jitters.
|
|
228
|
+
|
|
229
|
+
**3a. Sticky-stack (cards pin and stack on scroll) — canonical skeleton**
|
|
230
|
+
|
|
231
|
+
The #1 sticky-stack bug: the trigger fires halfway down the viewport instead of pinning at the top. The fix is always `start: "top top"`.
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
useGSAP(() => {
|
|
235
|
+
const cards = gsap.utils.toArray<HTMLElement>(".stack-card")
|
|
236
|
+
cards.forEach((card, i) => {
|
|
237
|
+
if (i === cards.length - 1) return
|
|
238
|
+
ScrollTrigger.create({
|
|
239
|
+
trigger: card,
|
|
240
|
+
start: "top top", // pin at viewport top — never "top center"
|
|
241
|
+
endTrigger: cards[cards.length - 1],
|
|
242
|
+
end: "top top",
|
|
243
|
+
pin: true,
|
|
244
|
+
pinSpacing: false,
|
|
245
|
+
})
|
|
246
|
+
// previous card recedes as the NEXT card arrives
|
|
247
|
+
gsap.to(card, {
|
|
248
|
+
scale: 0.94, autoAlpha: 0.6, ease: "none",
|
|
249
|
+
scrollTrigger: { trigger: cards[i + 1], start: "top bottom", end: "top top", scrub: 1 },
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
}, { scope: ref })
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Every card except the last is pinned; the recede tween is driven by the *next* card's trigger. Cards themselves are `min-height: 100dvh` flex-centered wrappers.
|
|
256
|
+
|
|
257
|
+
**3b. Horizontal pan (vertical scroll drives horizontal travel) — canonical skeleton**
|
|
258
|
+
|
|
259
|
+
The #1 horizontal-pan bug: the pan starts before the section is pinned, so the user sees half a slide. Same fix: `start: "top top"`, pin the wrapper, scrub the inner track.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
useGSAP(() => {
|
|
263
|
+
const distance = track.current!.scrollWidth - window.innerWidth
|
|
264
|
+
gsap.to(track.current, {
|
|
265
|
+
x: -distance, ease: "none",
|
|
266
|
+
scrollTrigger: {
|
|
267
|
+
trigger: wrap.current,
|
|
268
|
+
start: "top top",
|
|
269
|
+
end: () => `+=${distance}`, // scroll length = horizontal travel
|
|
270
|
+
pin: true,
|
|
271
|
+
scrub: 1,
|
|
272
|
+
invalidateOnRefresh: true,
|
|
273
|
+
},
|
|
274
|
+
})
|
|
275
|
+
}, { scope: wrap })
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Wrapper is `overflow: hidden`; the track is a `100dvh` flex row. Both skeletons collapse to plain stacked sections under `prefers-reduced-motion` (wrap in `gsap.matchMedia`, pattern 5 below).
|
|
279
|
+
|
|
280
|
+
**4. SplitText (headlines only)**
|
|
281
|
+
```ts
|
|
282
|
+
const split = SplitText.create(".headline", { type: "lines,words" })
|
|
283
|
+
gsap.from(split.words, {
|
|
284
|
+
y: 24,
|
|
285
|
+
opacity: 0,
|
|
286
|
+
stagger: 0.02,
|
|
287
|
+
duration: 0.4,
|
|
288
|
+
ease: "power3.out",
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
Revert with `split.revert()` in cleanup. `@gsap/react` handles it if scoped.
|
|
292
|
+
|
|
293
|
+
**5. `matchMedia` for responsive + reduced-motion**
|
|
294
|
+
```ts
|
|
295
|
+
const mm = gsap.matchMedia()
|
|
296
|
+
mm.add("(prefers-reduced-motion: no-preference)", () => {
|
|
297
|
+
// animations here
|
|
298
|
+
})
|
|
299
|
+
mm.add("(min-width: 768px)", () => {
|
|
300
|
+
// desktop-only pins
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
This is the only sane way to handle reduced-motion and breakpoints together in GSAP.
|
|
304
|
+
|
|
305
|
+
**6. `quickTo` for high-frequency updates (mouse follower, pointer-linked)**
|
|
306
|
+
```ts
|
|
307
|
+
const xTo = gsap.quickTo("#dot", "x", { duration: 0.4, ease: "power3" })
|
|
308
|
+
const yTo = gsap.quickTo("#dot", "y", { duration: 0.4, ease: "power3" })
|
|
309
|
+
window.addEventListener("pointermove", (e) => { xTo(e.clientX); yTo(e.clientY) })
|
|
310
|
+
```
|
|
311
|
+
Reuses one tween instead of creating a new tween per event — crucial for pointer/scroll handlers that fire 60+ times/sec. Never `gsap.to()` inside a frequent event handler.
|
|
312
|
+
|
|
313
|
+
**7. `autoAlpha` over `opacity`**
|
|
314
|
+
```ts
|
|
315
|
+
gsap.to(".menu", { autoAlpha: 0, duration: 0.2 })
|
|
316
|
+
```
|
|
317
|
+
`autoAlpha` animates opacity **and** toggles `visibility: hidden` at 0 — hidden elements stop catching pointer events and get skipped by screen readers. `opacity: 0` alone does neither.
|
|
318
|
+
|
|
319
|
+
### Clashes with ui-craft rules
|
|
320
|
+
|
|
321
|
+
- Default ease is `power1.out` — flat. For UI use `power2.out` or `power3.out`; for springiness `back.out(1.4)` sparingly. **Avoid `elastic` / `bounce` on functional UI** — reads as demo.
|
|
322
|
+
- Default `duration: 0.5` — trim to **0.2–0.3 for UI**; keep 0.5–1.2 for hero scroll scenes only.
|
|
323
|
+
- GSAP animates any property — easy to accidentally animate `left` / `top` / `width` (layout thrash). Stick to `x`, `y`, `scale`, `rotation`, `opacity`, `autoAlpha`.
|
|
324
|
+
- No default reduced-motion — wrap in `gsap.matchMedia` or early-return on `matchMedia("(prefers-reduced-motion: reduce)").matches`.
|
|
325
|
+
|
|
326
|
+
### Perf gotchas
|
|
327
|
+
|
|
328
|
+
- Core ≈ 25KB gz, +7KB ScrollTrigger, +11KB SplitText. Import named plugins only.
|
|
329
|
+
- Forgetting `registerPlugin()` → tree-shaken in production → silent failure.
|
|
330
|
+
- Timelines not killed on unmount (outside `useGSAP`) → orphan RAF ticks. Always `ctx.revert()` in cleanup.
|
|
331
|
+
- More than ~50 independent `ScrollTrigger`s with `scrub` → RAF stalls. Batch into one timeline.
|
|
332
|
+
- **`immediateRender` trap**: a second `from()` / `fromTo()` targeting the same property on the same element will snap to its start value immediately, overwriting earlier tweens. Pass `immediateRender: false` on all but the first.
|
|
333
|
+
- `ScrollTrigger.refresh()` is expensive — don't call it on every `resize`. Debounce, or only on orientation change / content load. `invalidateOnRefresh: true` on the trigger handles most recalcs automatically.
|
|
334
|
+
- Use `clearProps: "all"` at the end of a tween to remove the inline styles GSAP wrote, preventing conflicts with CSS states (hover, `:active`) afterwards.
|
|
335
|
+
- **Pause animations off-screen with `IntersectionObserver`**. On long pages with multiple timelines, idle sections still burn RAF cycles. Pause them:
|
|
336
|
+
```ts
|
|
337
|
+
const io = new IntersectionObserver(([entry]) => {
|
|
338
|
+
if (entry.isIntersecting) tl.play()
|
|
339
|
+
else tl.pause()
|
|
340
|
+
})
|
|
341
|
+
io.observe(container)
|
|
342
|
+
```
|
|
343
|
+
Or use ScrollTrigger's `toggleActions: "play pause resume pause"` which handles this natively.
|
|
344
|
+
|
|
345
|
+
### Anti-patterns
|
|
346
|
+
|
|
347
|
+
- Reaching for GSAP for what one `transition: transform 200ms ease-out` would do.
|
|
348
|
+
- Pinning every section — "scroll jacking". Pin 1-2 hero sections, max.
|
|
349
|
+
- `scrub: true` — jittery. Use `scrub: 1`.
|
|
350
|
+
- SplitText on body copy — huge DOM cost, a11y nightmare. Headlines only.
|
|
351
|
+
- Mixing `gsap.to` with Motion or CSS transitions on the same property — they fight.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Three.js + React Three Fiber
|
|
356
|
+
|
|
357
|
+
R3F v9 pairs with React 19; v8 with React 18. `drei` is the swiss-army helper set — always install alongside.
|
|
358
|
+
|
|
359
|
+
### When to reach for it
|
|
360
|
+
- **3D product viewers** the user rotates.
|
|
361
|
+
- **Interactive hero scenes** where the scene reacts to scroll or cursor.
|
|
362
|
+
- **Data viz in 3D** (rare — prefer 2D unless the extra dimension is load-bearing).
|
|
363
|
+
- **Shaders** tied to React state.
|
|
364
|
+
|
|
365
|
+
### When NOT
|
|
366
|
+
- A marketing page that could be a **WebP/MP4** — users on phones pay 400KB + GPU for nothing.
|
|
367
|
+
- Static logo rotation — CSS 3D transforms.
|
|
368
|
+
- Decorative 2D canvas — `<canvas>` + Motion.
|
|
369
|
+
|
|
370
|
+
### Install
|
|
371
|
+
```bash
|
|
372
|
+
npm install three @react-three/fiber @react-three/drei
|
|
373
|
+
```
|
|
374
|
+
```tsx
|
|
375
|
+
import { Canvas, useFrame, useThree } from "@react-three/fiber"
|
|
376
|
+
import {
|
|
377
|
+
Environment,
|
|
378
|
+
OrbitControls,
|
|
379
|
+
useGLTF,
|
|
380
|
+
PerformanceMonitor,
|
|
381
|
+
} from "@react-three/drei"
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Top patterns
|
|
385
|
+
|
|
386
|
+
**1. Canvas with perf caps (always)**
|
|
387
|
+
```tsx
|
|
388
|
+
<Canvas
|
|
389
|
+
dpr={[1, 2]} // cap retina cost
|
|
390
|
+
frameloop="demand" // render only when props change
|
|
391
|
+
camera={{ position: [0, 0, 5], fov: 45 }}
|
|
392
|
+
gl={{ antialias: true, powerPreference: "high-performance" }}
|
|
393
|
+
>
|
|
394
|
+
<ambientLight intensity={0.5} />
|
|
395
|
+
<Environment preset="city" />
|
|
396
|
+
<Model />
|
|
397
|
+
</Canvas>
|
|
398
|
+
```
|
|
399
|
+
`dpr={[1, 2]}` + `frameloop="demand"` is the responsible default. Most "heavy" R3F demos are heavy because they omit these.
|
|
400
|
+
|
|
401
|
+
**2. `useFrame` with delta, never fixed increments**
|
|
402
|
+
```tsx
|
|
403
|
+
useFrame((_, dt) => {
|
|
404
|
+
ref.current.rotation.y += dt * 0.5 // speed in rad/sec, framerate-independent
|
|
405
|
+
})
|
|
406
|
+
```
|
|
407
|
+
Never `+= 0.01` — ties speed to framerate (feels fast on 120Hz, slow on 60Hz).
|
|
408
|
+
|
|
409
|
+
**3. `<Environment />` + `<Lightformer />` for lighting**
|
|
410
|
+
```tsx
|
|
411
|
+
<Environment preset="studio" />
|
|
412
|
+
```
|
|
413
|
+
Presets (`studio`, `city`, `sunset`, `warehouse`, `apartment`) cover 90% of cases. Beats five hand-placed lights.
|
|
414
|
+
|
|
415
|
+
**4. Instancing for repeats**
|
|
416
|
+
```tsx
|
|
417
|
+
<instancedMesh args={[null, null, 10000]}>
|
|
418
|
+
<boxGeometry args={[0.1, 0.1, 0.1]} />
|
|
419
|
+
<meshStandardMaterial />
|
|
420
|
+
</instancedMesh>
|
|
421
|
+
```
|
|
422
|
+
One draw call for 10k objects. Use when the same mesh repeats more than ~50 times.
|
|
423
|
+
|
|
424
|
+
**5. Auto-degrade with `PerformanceMonitor` (drei)**
|
|
425
|
+
```tsx
|
|
426
|
+
const [dpr, setDpr] = useState(1.5)
|
|
427
|
+
return (
|
|
428
|
+
<Canvas dpr={dpr}>
|
|
429
|
+
<PerformanceMonitor
|
|
430
|
+
onDecline={() => setDpr(1)}
|
|
431
|
+
onIncline={() => setDpr(2)}
|
|
432
|
+
/>
|
|
433
|
+
…
|
|
434
|
+
</Canvas>
|
|
435
|
+
)
|
|
436
|
+
```
|
|
437
|
+
Drops `dpr` automatically on low FPS. Ship this on any production scene.
|
|
438
|
+
|
|
439
|
+
**6. `<Suspense>` with nested progressive loading**
|
|
440
|
+
```tsx
|
|
441
|
+
<Canvas>
|
|
442
|
+
<Suspense fallback={<Model url="/model-low.glb" />}>
|
|
443
|
+
<Model url="/model-high.glb" />
|
|
444
|
+
</Suspense>
|
|
445
|
+
</Canvas>
|
|
446
|
+
```
|
|
447
|
+
Every `useLoader` / `useGLTF` / `useTexture` **must** live under a Suspense boundary. Nesting lets you show a low-res placeholder while the high-res loads, then swap — zero blank frames.
|
|
448
|
+
|
|
449
|
+
**6b. DOM overlays inside the scene with `<Html>` (drei)**
|
|
450
|
+
```tsx
|
|
451
|
+
import { Html } from "@react-three/drei"
|
|
452
|
+
|
|
453
|
+
<mesh position={[0, 1, 0]}>
|
|
454
|
+
<Html distanceFactor={8} occlude="blending">
|
|
455
|
+
<div className="rounded-md bg-background/90 px-2 py-1 text-xs">Label</div>
|
|
456
|
+
</Html>
|
|
457
|
+
</mesh>
|
|
458
|
+
```
|
|
459
|
+
`distanceFactor` scales with camera distance (so labels don't balloon on zoom). `occlude` hides the overlay when geometry blocks it — respects depth without feeling cheap.
|
|
460
|
+
|
|
461
|
+
**6c. Axis-specific prop notation**
|
|
462
|
+
```tsx
|
|
463
|
+
// Instead of <mesh position={[x, 0, 0]}> on every render:
|
|
464
|
+
<mesh position-x={x} />
|
|
465
|
+
```
|
|
466
|
+
Avoids recreating the `[x, y, z]` tuple each frame and reads cleaner when animating a single axis via state/ref.
|
|
467
|
+
|
|
468
|
+
**7. Auto-fit camera with `<Bounds>` + `<Center>`**
|
|
469
|
+
```tsx
|
|
470
|
+
import { Bounds, Center } from "@react-three/drei"
|
|
471
|
+
|
|
472
|
+
<Canvas>
|
|
473
|
+
<Bounds fit clip observe margin={1.2}>
|
|
474
|
+
<Center><Model /></Center>
|
|
475
|
+
</Bounds>
|
|
476
|
+
</Canvas>
|
|
477
|
+
```
|
|
478
|
+
Stops the "model invisible because the camera is inside it" footgun. `observe` re-fits on model change.
|
|
479
|
+
|
|
480
|
+
### Clashes with ui-craft rules
|
|
481
|
+
|
|
482
|
+
- Three.js runs **its own RAF** — independent of CSS `prefers-reduced-motion`. Read it in React and cut autorotate / camera drift:
|
|
483
|
+
```tsx
|
|
484
|
+
const reduced = useReducedMotion()
|
|
485
|
+
useFrame((_, dt) => {
|
|
486
|
+
if (!reduced) ref.current.rotation.y += dt * 0.2
|
|
487
|
+
})
|
|
488
|
+
```
|
|
489
|
+
- Heavy lighting/shadows violate the spirit of "GPU-accelerated transforms only" by burning GPU on everything. Budget draw calls and shadow resolution.
|
|
490
|
+
- Default `Canvas` runs 60fps forever — battery killer. **`frameloop="demand"` is the default**, not the optimization.
|
|
491
|
+
|
|
492
|
+
### Perf gotchas
|
|
493
|
+
|
|
494
|
+
- **No `dpr` cap** → 3× pixel cost on retina. Always `dpr={[1, 2]}`.
|
|
495
|
+
- Mutating position/rotation via React state → re-render per frame. Mutate via `ref` inside `useFrame`.
|
|
496
|
+
- Loading `.glb` in component body → re-fetches on remount. Use `useGLTF("/model.glb")` (cached) + `useGLTF.preload("/model.glb")` at module scope.
|
|
497
|
+
- **Compress assets**: GLB via DRACO (`useGLTF("/model.glb", "/draco/")`) + textures via KTX2 (`useKTX2Loader`). Routine 60-80% size reduction. Uncompressed GLBs are the #1 cause of "my 3D page is 8MB".
|
|
498
|
+
- `frameloop="demand"` + external state change (window resize, parent re-render) → scene goes stale. Call `invalidate()` from `useThree()` to trigger one render frame manually.
|
|
499
|
+
- Draw-call budget: **~200 meshes mobile, ~1000 desktop**. Beyond → instance, merge, or LOD (`<Detailed />` from drei).
|
|
500
|
+
- Custom shaders / textures need explicit `.dispose()` on unmount — R3F handles standard cases but external refs leak.
|
|
501
|
+
|
|
502
|
+
### Anti-patterns
|
|
503
|
+
|
|
504
|
+
- `<Canvas>` with no `dpr` cap and `frameloop="always"` on a mostly-static hero.
|
|
505
|
+
- `new THREE.Vector3()` / `new THREE.Color()` inside `useFrame` — GC pressure every frame. Hoist to `useMemo` or module scope.
|
|
506
|
+
- `OrbitControls` on a marketing page — confuses users. `autoRotate` only, or omit.
|
|
507
|
+
- 10k individual `<mesh>` instead of `<instancedMesh>`.
|
|
508
|
+
- Post-processing stack (bloom + DoF + SSAO) shipped to phones — feature-flag by device or user preference.
|
|
509
|
+
- A scene that would be a 60KB WebP rendered server-side.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Cross-stack rules
|
|
514
|
+
|
|
515
|
+
1. **One library per property.** Never let Motion and GSAP animate the same `transform`. Never let Three.js drive DOM transforms that CSS is also animating.
|
|
516
|
+
2. **Reduced-motion is non-negotiable across all three.** Motion: `MotionConfig reducedMotion="user"`. GSAP: `matchMedia("(prefers-reduced-motion: no-preference)")`. Three.js: read `useReducedMotion()` and cut autorotate / idle drift.
|
|
517
|
+
3. **Spring vs tween is a project-level choice**, not a per-component one. Document it.
|
|
518
|
+
4. **GPU-accelerated transforms only.** Motion's `layout` and GSAP's `x`/`y`/`scale` honor this; animating `width`/`top` does not. Three.js runs on the GPU, but lighting/shadows/post-processing are their own budget.
|
|
519
|
+
5. **Budget, then build.** Bundle: Motion ≈ 50KB, GSAP core ≈ 25KB, Three.js ≈ 150KB, R3F + drei another 30-80KB. If you're shipping all three to one page, stop — one of them is wrong.
|
|
520
|
+
6. **`will-change` discipline.** Set `will-change: transform` only **just before** the animation fires (e.g. on `:hover`, in a `whileHover`, before a `gsap.to` call) and remove it after. Persistent `will-change` leaks compositor layers and eats GPU memory. Never set it globally on `*`.
|
|
521
|
+
7. **No smooth-scroll libraries (Lenis, Locomotive, ScrollSmoother) unless the design absolutely demands it.** They hijack native scroll, break touch momentum on iOS, fight `prefers-reduced-motion`, and make Cmd-F scroll-to-match janky. Prefer native scroll + `scroll-behavior: smooth` on specific anchors + `animation-timeline: scroll()` for reveal effects.
|
|
522
|
+
8. **Strip debug artifacts before ship.** GSAP `ScrollTrigger` `markers: true`, R3F `<Stats />`, drei `<Perf />`, `<OrbitControls />` on marketing pages, Leva panels, `console.log` in `useFrame`. Grep the diff before merging.
|