oh-my-agent-commandcode 0.0.0-stage → 20.38.4
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 +35 -2
- package/filter-test-output.sh +52 -0
- package/mods/oma.ts +347 -0
- package/package.json +30 -4
- package/skills/_shared/conditional/experiment-ledger.md +28 -0
- package/skills/_shared/conditional/exploration-loop.md +22 -0
- package/skills/_shared/conditional/quality-score.md +33 -0
- package/skills/_shared/core/anti-ai-prose.md +191 -0
- package/skills/_shared/core/api-contracts/README.md +28 -0
- package/skills/_shared/core/api-contracts/template.md +90 -0
- package/skills/_shared/core/clarification-protocol.md +23 -0
- package/skills/_shared/core/code-intelligence.md +46 -0
- package/skills/_shared/core/collaboration-policy.md +28 -0
- package/skills/_shared/core/common-checklist.md +28 -0
- package/skills/_shared/core/context-budget.md +22 -0
- package/skills/_shared/core/context-loading.md +34 -0
- package/skills/_shared/core/difficulty-guide.md +26 -0
- package/skills/_shared/core/execution-policy.md +31 -0
- package/skills/_shared/core/lessons-learned.md +33 -0
- package/skills/_shared/core/prompt-structure.md +18 -0
- package/skills/_shared/core/quality-principles.md +11 -0
- package/skills/_shared/core/session-metrics.md +35 -0
- package/skills/_shared/core/skill-routing.md +39 -0
- package/skills/_shared/core/test-approach.md +54 -0
- package/skills/_shared/core/vendor-detection.md +52 -0
- package/skills/_shared/runtime/memory-protocol.md +118 -0
- package/skills/_shared/runtime/result-contract.md +64 -0
- package/skills/_shared/ui-interaction-quality.md +133 -0
- package/skills/oma-academic-writing/SKILL.md +181 -0
- package/skills/oma-academic-writing/resources/abstract-guide.md +51 -0
- package/skills/oma-academic-writing/resources/academic-verb-tiers.md +42 -0
- package/skills/oma-academic-writing/resources/anti-ai-checklist.md +52 -0
- package/skills/oma-academic-writing/resources/hedging-guide.md +132 -0
- package/skills/oma-academic-writing/resources/sentence-structure-reference.md +151 -0
- package/skills/oma-architecture/SKILL.md +203 -0
- package/skills/oma-architecture/resources/api-evolution.md +41 -0
- package/skills/oma-architecture/resources/checklist.md +42 -0
- package/skills/oma-architecture/resources/execution-protocol.md +115 -0
- package/skills/oma-architecture/resources/methodology-selection.md +92 -0
- package/skills/oma-architecture/resources/migration-patterns.md +28 -0
- package/skills/oma-architecture/resources/output-templates.md +111 -0
- package/skills/oma-architecture/resources/stakeholder-synthesis.md +80 -0
- package/skills/oma-backend/SKILL.md +202 -0
- package/skills/oma-backend/resources/checklist.md +45 -0
- package/skills/oma-backend/resources/error-playbook.md +97 -0
- package/skills/oma-backend/resources/execution-protocol.md +39 -0
- package/skills/oma-backend/resources/orm-reference.md +61 -0
- package/skills/oma-backend/variants/node/api-template.ts +315 -0
- package/skills/oma-backend/variants/node/snippets.md +475 -0
- package/skills/oma-backend/variants/node/stack.yaml +21 -0
- package/skills/oma-backend/variants/node/tech-stack.md +33 -0
- package/skills/oma-backend/variants/python/api-template.py +378 -0
- package/skills/oma-backend/variants/python/snippets.md +199 -0
- package/skills/oma-backend/variants/python/stack.yaml +18 -0
- package/skills/oma-backend/variants/python/tech-stack.md +45 -0
- package/skills/oma-backend/variants/rust/api-template.rs +635 -0
- package/skills/oma-backend/variants/rust/snippets.md +471 -0
- package/skills/oma-backend/variants/rust/stack.yaml +20 -0
- package/skills/oma-backend/variants/rust/tech-stack.md +36 -0
- package/skills/oma-backend/variants/stack.schema.json +73 -0
- package/skills/oma-brainstorm/SKILL.md +166 -0
- package/skills/oma-brainstorm/resources/triz-lite.md +117 -0
- package/skills/oma-coordination/SKILL.md +171 -0
- package/skills/oma-db/SKILL.md +201 -0
- package/skills/oma-db/resources/anti-patterns.md +177 -0
- package/skills/oma-db/resources/checklist.md +67 -0
- package/skills/oma-db/resources/document-templates.md +107 -0
- package/skills/oma-db/resources/error-playbook.md +50 -0
- package/skills/oma-db/resources/examples.md +170 -0
- package/skills/oma-db/resources/execution-protocol.md +127 -0
- package/skills/oma-db/resources/iso-controls.md +98 -0
- package/skills/oma-db/resources/migration-playbook.md +93 -0
- package/skills/oma-db/resources/query-tuning.md +57 -0
- package/skills/oma-db/resources/vector-db.md +159 -0
- package/skills/oma-debug/SKILL.md +146 -0
- package/skills/oma-debug/resources/bug-report-template.md +327 -0
- package/skills/oma-debug/resources/checklist.md +31 -0
- package/skills/oma-debug/resources/common-patterns.md +734 -0
- package/skills/oma-debug/resources/debugging-checklist.md +364 -0
- package/skills/oma-debug/resources/error-playbook.md +94 -0
- package/skills/oma-debug/resources/execution-protocol.md +40 -0
- package/skills/oma-design/SKILL.md +135 -0
- package/skills/oma-design/resources/asset-strategy.md +34 -0
- package/skills/oma-design/resources/checklist.md +63 -0
- package/skills/oma-design/resources/data-grid.md +48 -0
- package/skills/oma-design/resources/design-md-spec.md +107 -0
- package/skills/oma-design/resources/design-tokens.md +53 -0
- package/skills/oma-design/resources/error-playbook.md +18 -0
- package/skills/oma-design/resources/execution-protocol.md +95 -0
- package/skills/oma-design/resources/external-design-skills.md +130 -0
- package/skills/oma-design/resources/getdesign-fetcher.md +104 -0
- package/skills/oma-design/resources/product-interface-review.md +59 -0
- package/skills/oma-design/resources/redesign-protocol.md +52 -0
- package/skills/oma-design/resources/stitch-integration.md +244 -0
- package/skills/oma-dev-workflow/SKILL.md +375 -0
- package/skills/oma-dev-workflow/resources/affected-checks.py +58 -0
- package/skills/oma-dev-workflow/resources/api-workflows.md +58 -0
- package/skills/oma-dev-workflow/resources/database-patterns.md +107 -0
- package/skills/oma-dev-workflow/resources/i18n-patterns.md +63 -0
- package/skills/oma-dev-workflow/resources/release-coordination.md +240 -0
- package/skills/oma-dev-workflow/resources/tooling-profiles.md +217 -0
- package/skills/oma-dev-workflow/resources/troubleshooting.md +78 -0
- package/skills/oma-dev-workflow/resources/validation-pipeline.md +246 -0
- package/skills/oma-docs/SKILL.md +77 -0
- package/skills/oma-docs/resources/commands.md +76 -0
- package/skills/oma-explanation/SKILL.md +212 -0
- package/skills/oma-explanation/resources/document-structure.md +115 -0
- package/skills/oma-explanation/resources/draft-format.md +199 -0
- package/skills/oma-explanation/resources/html-contract.md +102 -0
- package/skills/oma-frontend/SKILL.md +227 -0
- package/skills/oma-frontend/resources/angular-rules.md +110 -0
- package/skills/oma-frontend/resources/checklist.md +76 -0
- package/skills/oma-frontend/resources/error-playbook.md +125 -0
- package/skills/oma-frontend/resources/execution-protocol.md +46 -0
- package/skills/oma-frontend/resources/snippets.md +354 -0
- package/skills/oma-frontend/resources/specialized-visual-implementation.md +193 -0
- package/skills/oma-frontend/resources/tailwind-rules.md +83 -0
- package/skills/oma-frontend/resources/tech-stack.md +156 -0
- package/skills/oma-hwp/SKILL.md +166 -0
- package/skills/oma-hwp/config/hwp-config.yaml +35 -0
- package/skills/oma-hwp/resources/balanced-tables.ts +39 -0
- package/skills/oma-hwp/resources/execution-protocol.md +145 -0
- package/skills/oma-hwp/resources/flatten-tables.ts +101 -0
- package/skills/oma-hwp/resources/package.json +13 -0
- package/skills/oma-hwp/resources/troubleshooting.md +70 -0
- package/skills/oma-hwp/resources/tsconfig.json +10 -0
- package/skills/oma-hwp/resources/turndown-plugin-gfm.d.ts +9 -0
- package/skills/oma-image/SKILL.md +142 -0
- package/skills/oma-image/config/image-config.yaml +70 -0
- package/skills/oma-image/resources/checklist.md +18 -0
- package/skills/oma-image/resources/execution-protocol.md +117 -0
- package/skills/oma-image/resources/invocation.md +105 -0
- package/skills/oma-image/resources/prompt-tips.md +71 -0
- package/skills/oma-image/resources/vendor-matrix.md +90 -0
- package/skills/oma-market/SKILL.md +142 -0
- package/skills/oma-market/resources/checklist.md +12 -0
- package/skills/oma-market/resources/error-playbook.md +12 -0
- package/skills/oma-market/resources/execution-protocol.md +60 -0
- package/skills/oma-market/resources/frameworks/pestel.md +101 -0
- package/skills/oma-market/resources/frameworks/porters-5f.md +90 -0
- package/skills/oma-market/resources/frameworks/swot.md +61 -0
- package/skills/oma-market/resources/intent-rules.md +35 -0
- package/skills/oma-market/resources/output-laws.md +53 -0
- package/skills/oma-mobile/SKILL.md +168 -0
- package/skills/oma-mobile/resources/checklist.md +77 -0
- package/skills/oma-mobile/resources/error-playbook.md +198 -0
- package/skills/oma-mobile/resources/execution-protocol.md +47 -0
- package/skills/oma-mobile/resources/screen-template.dart +331 -0
- package/skills/oma-mobile/resources/screen-template.swift +239 -0
- package/skills/oma-mobile/resources/screen-template.tsx +179 -0
- package/skills/oma-mobile/resources/tech-stack.md +69 -0
- package/skills/oma-mobile/variants/README.md +45 -0
- package/skills/oma-mobile/variants/flutter/api-template.dart +461 -0
- package/skills/oma-mobile/variants/flutter/snippets.md +1353 -0
- package/skills/oma-mobile/variants/flutter/stack.yaml +21 -0
- package/skills/oma-mobile/variants/flutter/tech-stack.md +201 -0
- package/skills/oma-mobile/variants/kotlin-android/api-template.kt +182 -0
- package/skills/oma-mobile/variants/kotlin-android/snippets.md +871 -0
- package/skills/oma-mobile/variants/kotlin-android/stack.yaml +32 -0
- package/skills/oma-mobile/variants/kotlin-android/tech-stack.md +159 -0
- package/skills/oma-mobile/variants/react-native/api-template.ts +531 -0
- package/skills/oma-mobile/variants/react-native/snippets.md +1014 -0
- package/skills/oma-mobile/variants/react-native/stack.yaml +22 -0
- package/skills/oma-mobile/variants/react-native/tech-stack.md +192 -0
- package/skills/oma-mobile/variants/stack.schema.json +68 -0
- package/skills/oma-mobile/variants/swift-ios/api-template.swift +165 -0
- package/skills/oma-mobile/variants/swift-ios/snippets.md +1028 -0
- package/skills/oma-mobile/variants/swift-ios/stack.yaml +25 -0
- package/skills/oma-mobile/variants/swift-ios/tech-stack.md +174 -0
- package/skills/oma-observability/SKILL.md +225 -0
- package/skills/oma-observability/resources/anti-patterns.md +555 -0
- package/skills/oma-observability/resources/boundaries/cross-application.md +348 -0
- package/skills/oma-observability/resources/boundaries/multi-tenant.md +290 -0
- package/skills/oma-observability/resources/boundaries/release.md +372 -0
- package/skills/oma-observability/resources/boundaries/slo.md +225 -0
- package/skills/oma-observability/resources/checklist.md +123 -0
- package/skills/oma-observability/resources/examples.md +448 -0
- package/skills/oma-observability/resources/execution-protocol.md +166 -0
- package/skills/oma-observability/resources/incident-forensics.md +348 -0
- package/skills/oma-observability/resources/intent-rules.md +307 -0
- package/skills/oma-observability/resources/layers/L3-network.md +281 -0
- package/skills/oma-observability/resources/layers/L4-transport.md +299 -0
- package/skills/oma-observability/resources/layers/L7-application/crash-analytics.md +359 -0
- package/skills/oma-observability/resources/layers/L7-application/mobile-rum.md +278 -0
- package/skills/oma-observability/resources/layers/L7-application/waf.md +246 -0
- package/skills/oma-observability/resources/layers/L7-application/web-rum.md +350 -0
- package/skills/oma-observability/resources/layers/mesh.md +368 -0
- package/skills/oma-observability/resources/matrix.md +177 -0
- package/skills/oma-observability/resources/meta-observability.md +605 -0
- package/skills/oma-observability/resources/observability-as-code.md +666 -0
- package/skills/oma-observability/resources/signals/audit.md +310 -0
- package/skills/oma-observability/resources/signals/cost.md +303 -0
- package/skills/oma-observability/resources/signals/logs.md +263 -0
- package/skills/oma-observability/resources/signals/metrics.md +478 -0
- package/skills/oma-observability/resources/signals/privacy.md +351 -0
- package/skills/oma-observability/resources/signals/profiles.md +245 -0
- package/skills/oma-observability/resources/signals/traces.md +360 -0
- package/skills/oma-observability/resources/standards.md +214 -0
- package/skills/oma-observability/resources/transport/collector-topology.md +308 -0
- package/skills/oma-observability/resources/transport/otlp-grpc-vs-http.md +256 -0
- package/skills/oma-observability/resources/transport/sampling-recipes.md +297 -0
- package/skills/oma-observability/resources/transport/udp-statsd-mtu.md +167 -0
- package/skills/oma-observability/resources/vendor-categories.md +352 -0
- package/skills/oma-orchestration/SKILL.md +302 -0
- package/skills/oma-orchestration/config/cli-config.yaml +92 -0
- package/skills/oma-orchestration/resources/memory-schema.md +232 -0
- package/skills/oma-orchestration/resources/subagent-prompt-template.md +30 -0
- package/skills/oma-orchestration/scripts/parallel-run.sh +6 -0
- package/skills/oma-orchestration/scripts/spawn-agent.sh +5 -0
- package/skills/oma-orchestration/scripts/verify.sh +20 -0
- package/skills/oma-orchestration/templates/backend-task.md +19 -0
- package/skills/oma-orchestration/templates/debug-task.md +16 -0
- package/skills/oma-orchestration/templates/frontend-task.md +18 -0
- package/skills/oma-orchestration/templates/mobile-task.md +18 -0
- package/skills/oma-orchestration/templates/qa-task.md +16 -0
- package/skills/oma-orchestration/templates/tasks-example.yaml +15 -0
- package/skills/oma-pdf/SKILL.md +162 -0
- package/skills/oma-pdf/config/pdf-config.yaml +27 -0
- package/skills/oma-pdf/resources/execution-protocol.md +127 -0
- package/skills/oma-pm/SKILL.md +157 -0
- package/skills/oma-pm/resources/error-playbook.md +75 -0
- package/skills/oma-pm/resources/examples.md +439 -0
- package/skills/oma-pm/resources/execution-protocol.md +62 -0
- package/skills/oma-pm/resources/iso-planning.md +110 -0
- package/skills/oma-pm/resources/plan-phase-protocol.md +66 -0
- package/skills/oma-pm/resources/task-template.json +86 -0
- package/skills/oma-qa/SKILL.md +141 -0
- package/skills/oma-qa/resources/checklist.md +339 -0
- package/skills/oma-qa/resources/error-playbook.md +98 -0
- package/skills/oma-qa/resources/execution-protocol.md +169 -0
- package/skills/oma-qa/resources/iso-quality.md +82 -0
- package/skills/oma-qa/resources/verify-ship-protocol.md +116 -0
- package/skills/oma-recap/SKILL.md +245 -0
- package/skills/oma-recap/resources/output-formats.md +83 -0
- package/skills/oma-refactor/SKILL.md +184 -0
- package/skills/oma-refactor/resources/definition.md +108 -0
- package/skills/oma-refactor/resources/governance.md +33 -0
- package/skills/oma-refactor/resources/hotspots.py +44 -0
- package/skills/oma-refactor/resources/measurement.md +93 -0
- package/skills/oma-scholar/SKILL.md +276 -0
- package/skills/oma-scholar/config/scholar-config.yaml +79 -0
- package/skills/oma-scholar/resources/api-endpoints.md +174 -0
- package/skills/oma-scholar/resources/checklist.md +92 -0
- package/skills/oma-scholar/resources/execution-protocol.md +224 -0
- package/skills/oma-scholar/resources/fallback-providers.md +143 -0
- package/skills/oma-scholar/resources/setup-openalex.md +85 -0
- package/skills/oma-scholar/resources/sidecar-spec.md +341 -0
- package/skills/oma-scholar/resources/upstream-spec-cache.md +972 -0
- package/skills/oma-scm/SKILL.md +103 -0
- package/skills/oma-scm/resources/cm-operations.md +56 -0
- package/skills/oma-scm/resources/codeowners-playbook.md +45 -0
- package/skills/oma-scm/resources/conventional-commits.md +108 -0
- package/skills/oma-scm/resources/merge-risk.md +76 -0
- package/skills/oma-scm/resources/onboarding-risk-signals.md +71 -0
- package/skills/oma-search/SKILL.md +125 -0
- package/skills/oma-search/resources/checklist.md +36 -0
- package/skills/oma-search/resources/error-playbook.md +66 -0
- package/skills/oma-search/resources/examples.md +80 -0
- package/skills/oma-search/resources/execution-protocol.md +86 -0
- package/skills/oma-search/resources/intent-rules.md +47 -0
- package/skills/oma-search/resources/trust-registry.md +53 -0
- package/skills/oma-security/SKILL.md +172 -0
- package/skills/oma-security/resources/artex.md +108 -0
- package/skills/oma-security/resources/ci.md +134 -0
- package/skills/oma-security/resources/cisco-source.md +108 -0
- package/skills/oma-security/resources/deepsec-config.md +45 -0
- package/skills/oma-security/resources/deepsec-matchers.md +35 -0
- package/skills/oma-security/resources/deepsec-scanning.md +45 -0
- package/skills/oma-security/resources/deepsec-setup.md +41 -0
- package/skills/oma-security/resources/findings-contract.md +408 -0
- package/skills/oma-security/resources/mcp-scanning.md +122 -0
- package/skills/oma-security/resources/skill-scanning.md +106 -0
- package/skills/oma-security/resources/validation.md +71 -0
- package/skills/oma-skill-creation/SKILL.md +84 -0
- package/skills/oma-skill-creation/resources/prompt-evaluation.md +36 -0
- package/skills/oma-skill-creation/resources/ssl-lite-template.md +108 -0
- package/skills/oma-skill-creation/resources/validation-checklist.md +101 -0
- package/skills/oma-slide/SKILL.md +277 -0
- package/skills/oma-slide/resources/animation-patterns.md +245 -0
- package/skills/oma-slide/resources/assets/deck-stage.js +514 -0
- package/skills/oma-slide/resources/assets/viewport-base.css +257 -0
- package/skills/oma-slide/resources/canva-integration.md +203 -0
- package/skills/oma-slide/resources/checklist.md +46 -0
- package/skills/oma-slide/resources/design-doctrine.md +260 -0
- package/skills/oma-slide/resources/fixed-stage.md +232 -0
- package/skills/oma-slide/resources/generation-protocol.md +393 -0
- package/skills/oma-slide/resources/native-pptx.md +84 -0
- package/skills/oma-slide/resources/selection-index.json +461 -0
- package/skills/oma-slide/resources/style-presets.LICENSE +10 -0
- package/skills/oma-slide/resources/style-presets.md +520 -0
- package/skills/oma-tf-infra/SKILL.md +201 -0
- package/skills/oma-tf-infra/resources/checklist.md +53 -0
- package/skills/oma-tf-infra/resources/cost-optimization.md +574 -0
- package/skills/oma-tf-infra/resources/error-playbook.md +68 -0
- package/skills/oma-tf-infra/resources/examples.md +38 -0
- package/skills/oma-tf-infra/resources/execution-protocol.md +129 -0
- package/skills/oma-tf-infra/resources/iso-42001-infra.md +229 -0
- package/skills/oma-tf-infra/resources/multi-cloud-examples.md +241 -0
- package/skills/oma-tf-infra/resources/policy-testing-examples.md +332 -0
- package/skills/oma-translation/SKILL.md +229 -0
- package/skills/oma-translation/resources/anti-ai-patterns.md +104 -0
- package/skills/oma-translation/resources/lang/_template.md +73 -0
- package/skills/oma-translation/resources/lang/en.md +123 -0
- package/skills/oma-translation/resources/lang/ja.md +274 -0
- package/skills/oma-translation/resources/lang/ko.md +228 -0
- package/skills/oma-translation/resources/lang/zh.md +285 -0
- package/skills/oma-translation/resources/style-skills.md +104 -0
- package/skills/oma-translation/resources/translation-rubric.md +126 -0
- package/skills/oma-video/SKILL.md +229 -0
- package/skills/oma-video/config/video-config.yaml +60 -0
- package/skills/oma-video/resources/checklist.md +26 -0
- package/skills/oma-video/resources/execution-protocol.md +122 -0
- package/skills/oma-video/resources/existing-media.md +185 -0
- package/skills/oma-video/resources/hyperframes-authoring/README.md +44 -0
- package/skills/oma-video/resources/hyperframes-authoring/demo.md +31 -0
- package/skills/oma-video/resources/hyperframes-authoring/explainer.md +10 -0
- package/skills/oma-video/resources/hyperframes-authoring/shorts.md +10 -0
- package/skills/oma-video/resources/motion-principles.md +81 -0
- package/skills/oma-video/resources/mpt/driver.py +301 -0
- package/skills/oma-video/resources/prompt-tips.md +75 -0
- package/skills/oma-video/resources/script-schema.md +81 -0
- package/skills/oma-video/resources/sound-design.md +127 -0
- package/skills/oma-video/resources/strudel/package.json +11 -0
- package/skills/oma-video/resources/strudel/page.html +87 -0
- package/skills/oma-video/resources/strudel/render.mjs +295 -0
- package/skills/oma-video/resources/vendor-matrix.md +124 -0
- package/skills/oma-voice/SKILL.md +249 -0
- package/skills/oma-voice/config/voice-config.yaml +30 -0
- package/skills/oma-voice/resources/audio-processing.md +119 -0
- package/skills/oma-voice/resources/checklist.md +47 -0
- package/skills/oma-voice/resources/execution-protocol.md +215 -0
- package/skills/oma-voice/resources/prompt-tips.md +43 -0
- package/skills/oma-voice/resources/voice-matrix.md +51 -0
- package/skills/oma-voice/resources/voicestudio.md +87 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# Frontend Agent - Code Snippets
|
|
2
|
+
|
|
3
|
+
Copy-paste ready patterns. Use these as starting points, adapt to the specific task.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Next.js 16 framework canonicals (use these, never the legacy alternatives)
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
// Internal nav: <Link>, never <a href="/...">
|
|
11
|
+
// prefetch={false} is the DEFAULT — viewport prefetching eats container CPU/RAM.
|
|
12
|
+
import Link from "next/link";
|
|
13
|
+
<Link href="/gallery" prefetch={false} className="...">View gallery</Link>
|
|
14
|
+
|
|
15
|
+
// Opt back in only for a few high-intent targets, and say why:
|
|
16
|
+
// primary funnel CTA — prefetch is intentional
|
|
17
|
+
<Link href="/checkout" className="...">Checkout</Link>
|
|
18
|
+
|
|
19
|
+
// Custom font: next/font, never <link rel="stylesheet">
|
|
20
|
+
import { Inter } from "next/font/google";
|
|
21
|
+
const inter = Inter({ subsets: ["latin"] });
|
|
22
|
+
<body className={inter.className}>...</body>
|
|
23
|
+
|
|
24
|
+
// Images: next/image, never raw <img>
|
|
25
|
+
import Image from "next/image";
|
|
26
|
+
<Image src="/hero.png" alt="Hero scene" width={1200} height={600} priority />
|
|
27
|
+
|
|
28
|
+
// Imports: only what you use. After refactoring, remove orphans.
|
|
29
|
+
// useCallback / useEffect deps: list every referenced symbol exactly.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Accessible Card (focus ring + semantic + keyboard)
|
|
35
|
+
|
|
36
|
+
Baseline for an interactive surface. Adjust colors via theme tokens; verify
|
|
37
|
+
the resulting contrast ratio against the actual `--card` / `--foreground` /
|
|
38
|
+
`--muted-foreground` values (theme tokens alone do NOT guarantee 4.5:1; the
|
|
39
|
+
designer / token system has to make them so).
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { cn } from "@/lib/utils";
|
|
43
|
+
|
|
44
|
+
interface CardProps {
|
|
45
|
+
title: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
onClick?: () => void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function Card({ title, description, onClick }: CardProps) {
|
|
51
|
+
return (
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
onClick={onClick}
|
|
55
|
+
className={cn(
|
|
56
|
+
"rounded-lg border bg-card p-4 text-left shadow-sm transition-colors",
|
|
57
|
+
"hover:bg-accent",
|
|
58
|
+
// visible focus indicator (WCAG 2.4.7 Focus Visible, 2.4.11 Focus Not Obscured)
|
|
59
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
{/* Visible text inside the button is the accessible name —
|
|
63
|
+
do NOT add aria-label here, that would override and hide the
|
|
64
|
+
description from screen readers. */}
|
|
65
|
+
<span className="block text-lg font-semibold text-foreground">{title}</span>
|
|
66
|
+
{description && (
|
|
67
|
+
<span className="mt-1 block text-sm text-muted-foreground">
|
|
68
|
+
{description}
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
</button>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Accessibility checklist for interactive surfaces:
|
|
77
|
+
- **Semantic element**: `<button>`, `<a>`, `<Link>`. Never `<div onClick>`.
|
|
78
|
+
- **Keyboard reachable**: implicit when using semantic elements.
|
|
79
|
+
- **Visible focus**: `focus-visible:ring-2 ring-offset-2` (or equivalent). Never strip the outline without replacing it.
|
|
80
|
+
- **Accessible name**: visible text inside the element IS the name. Add `aria-label` ONLY for icon-only buttons (e.g., `<button aria-label="Close">×</button>`); when visible text exists, `aria-label` overrides it and is an anti-pattern.
|
|
81
|
+
- **Contrast**: verify the actual color values against background reach 4.5:1 (normal text) or 3:1 (large text >= 18pt or 14pt bold). Run an axe/Lighthouse pass; theme tokens are not a proof.
|
|
82
|
+
- **Heading semantics**: keep heading tags (`<h1>`-`<h6>`) outside interactive elements. Inside a button, use `<span>` with type-scale classes; promote to a heading at the surrounding section level.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## React 19 hook patterns
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// Derive in render — no state, no effect
|
|
90
|
+
function ItemCount({ items }: { items: Item[] }) {
|
|
91
|
+
const count = items.length;
|
|
92
|
+
return <span>{count}</span>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Initialize once with a lazy initializer
|
|
96
|
+
const [id] = useState(() => crypto.randomUUID());
|
|
97
|
+
|
|
98
|
+
// Pass the ref OBJECT (not its current value) to children that need an instance.
|
|
99
|
+
// The child reads .current inside its own effect or event handler, never in render.
|
|
100
|
+
function Selectable({ targetRef }: { targetRef: React.RefObject<THREE.Object3D> }) {
|
|
101
|
+
// ...
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Never: useEffect that calls setState to mirror props/state
|
|
105
|
+
// eslint: react-hooks/set-state-in-effect
|
|
106
|
+
// useEffect(() => { setCount(items.length); }, [items]);
|
|
107
|
+
|
|
108
|
+
// Never: gate JSX on ref.current — it is null on first render, and refs
|
|
109
|
+
// do not trigger re-renders when they attach
|
|
110
|
+
// eslint: react-hooks/refs
|
|
111
|
+
// return ref.current ? <Child target={ref.current} /> : null;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## TanStack Query Hook (fallback: no OpenAPI spec)
|
|
115
|
+
|
|
116
|
+
**Default path is orval-generated hooks** when the project has an OpenAPI spec: run the
|
|
117
|
+
project's `gen:api` task and import the generated `useQuery`/`useMutation` hooks instead of
|
|
118
|
+
writing this by hand (see `tech-stack.md` §Server State). Auth headers belong in the orval
|
|
119
|
+
`mutator` instance, not per-hook. The pattern below is for spec-less endpoints only
|
|
120
|
+
(third-party APIs, endpoints outside the contract).
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
124
|
+
|
|
125
|
+
// getToken(): placeholder for the project's auth helper
|
|
126
|
+
// (e.g. better-auth client session); wire to the real token source.
|
|
127
|
+
interface Todo {
|
|
128
|
+
id: string;
|
|
129
|
+
title: string;
|
|
130
|
+
completed: boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function useTodos() {
|
|
134
|
+
return useQuery<Todo[]>({
|
|
135
|
+
queryKey: ["todos"],
|
|
136
|
+
queryFn: async () => {
|
|
137
|
+
const res = await fetch("/api/todos", {
|
|
138
|
+
headers: { Authorization: `Bearer ${getToken()}` },
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok) throw new Error("Failed to fetch");
|
|
141
|
+
return res.json();
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function useCreateTodo() {
|
|
147
|
+
const queryClient = useQueryClient();
|
|
148
|
+
return useMutation({
|
|
149
|
+
mutationFn: async (data: { title: string }) => {
|
|
150
|
+
const res = await fetch("/api/todos", {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
Authorization: `Bearer ${getToken()}`,
|
|
155
|
+
},
|
|
156
|
+
body: JSON.stringify(data),
|
|
157
|
+
});
|
|
158
|
+
if (!res.ok) throw new Error("Failed to create");
|
|
159
|
+
return res.json();
|
|
160
|
+
},
|
|
161
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["todos"] }),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Form with TanStack Form + Zod
|
|
169
|
+
|
|
170
|
+
Pass the zod schema directly to `validators` (Standard Schema, v1+). `validatorAdapter` /
|
|
171
|
+
`@tanstack/zod-form-adapter` are dead v0 APIs; never reintroduce them. Errors are issue
|
|
172
|
+
**objects**, not strings: render `errors[0]?.message`.
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
"use client";
|
|
176
|
+
|
|
177
|
+
import { useForm } from "@tanstack/react-form";
|
|
178
|
+
import { z } from "zod";
|
|
179
|
+
|
|
180
|
+
// zod v4: z.email() replaces the deprecated z.string().email()
|
|
181
|
+
const schema = z.object({
|
|
182
|
+
email: z.email("Invalid email"),
|
|
183
|
+
password: z.string().min(8, "At least 8 characters"),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export function LoginForm({ onSubmit }: { onSubmit: (data: z.infer<typeof schema>) => void }) {
|
|
187
|
+
const form = useForm({
|
|
188
|
+
defaultValues: { email: "", password: "" },
|
|
189
|
+
validators: { onChange: schema },
|
|
190
|
+
onSubmit: async ({ value }) => onSubmit(value),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<form
|
|
195
|
+
onSubmit={(e) => {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
e.stopPropagation();
|
|
198
|
+
form.handleSubmit();
|
|
199
|
+
}}
|
|
200
|
+
className="space-y-4"
|
|
201
|
+
>
|
|
202
|
+
<form.Field name="email">
|
|
203
|
+
{(field) => (
|
|
204
|
+
<div>
|
|
205
|
+
<label htmlFor="email" className="text-sm font-medium">
|
|
206
|
+
Email
|
|
207
|
+
</label>
|
|
208
|
+
<input
|
|
209
|
+
id="email"
|
|
210
|
+
type="email"
|
|
211
|
+
value={field.state.value}
|
|
212
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
213
|
+
onBlur={field.handleBlur}
|
|
214
|
+
className="mt-1 w-full rounded-md border px-3 py-2"
|
|
215
|
+
aria-invalid={!field.state.meta.isValid}
|
|
216
|
+
/>
|
|
217
|
+
{/* Standard Schema errors are issue objects; render .message, never the object */}
|
|
218
|
+
{!field.state.meta.isValid && (
|
|
219
|
+
<p className="mt-1 text-sm text-destructive">{field.state.meta.errors[0]?.message}</p>
|
|
220
|
+
)}
|
|
221
|
+
</div>
|
|
222
|
+
)}
|
|
223
|
+
</form.Field>
|
|
224
|
+
<form.Field name="password">
|
|
225
|
+
{(field) => (
|
|
226
|
+
<div>
|
|
227
|
+
<label htmlFor="password" className="text-sm font-medium">
|
|
228
|
+
Password
|
|
229
|
+
</label>
|
|
230
|
+
<input
|
|
231
|
+
id="password"
|
|
232
|
+
type="password"
|
|
233
|
+
value={field.state.value}
|
|
234
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
235
|
+
onBlur={field.handleBlur}
|
|
236
|
+
className="mt-1 w-full rounded-md border px-3 py-2"
|
|
237
|
+
aria-invalid={!field.state.meta.isValid}
|
|
238
|
+
/>
|
|
239
|
+
{!field.state.meta.isValid && (
|
|
240
|
+
<p className="mt-1 text-sm text-destructive">{field.state.meta.errors[0]?.message}</p>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
</form.Field>
|
|
245
|
+
<form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]}>
|
|
246
|
+
{([canSubmit, isSubmitting]) => (
|
|
247
|
+
<button
|
|
248
|
+
type="submit"
|
|
249
|
+
disabled={!canSubmit}
|
|
250
|
+
className="w-full rounded-md bg-primary px-4 py-2 text-primary-foreground disabled:opacity-50"
|
|
251
|
+
>
|
|
252
|
+
{isSubmitting ? "Signing in..." : "Sign in"}
|
|
253
|
+
</button>
|
|
254
|
+
)}
|
|
255
|
+
</form.Subscribe>
|
|
256
|
+
</form>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## i18n: never hardcode UI text
|
|
264
|
+
|
|
265
|
+
UI strings come from the project's i18n source of truth (`packages/i18n` or equivalent).
|
|
266
|
+
Adapt the accessor to the project's library (next-intl, react-i18next, lingui, etc.); the
|
|
267
|
+
invariants below hold regardless of library.
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
// next-intl example; swap for the project's i18n hook
|
|
271
|
+
import { useTranslations } from "next-intl";
|
|
272
|
+
|
|
273
|
+
export function CheckoutSummary({ itemCount }: { itemCount: number }) {
|
|
274
|
+
const t = useTranslations("checkout");
|
|
275
|
+
return (
|
|
276
|
+
<section aria-label={t("summaryLabel")}>
|
|
277
|
+
<h2>{t("title")}</h2>
|
|
278
|
+
{/* plurals/interpolation go through the library, never string concatenation */}
|
|
279
|
+
<p>{t("itemCount", { count: itemCount })}</p>
|
|
280
|
+
</section>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Invariants:
|
|
286
|
+
|
|
287
|
+
- **No hardcoded user-facing strings** in JSX, `aria-*`, `alt`, `title`, placeholders, or
|
|
288
|
+
toasts; all of them are translatable surfaces.
|
|
289
|
+
- **Add new keys to the i18n source of truth first**, in every supported locale (fallback
|
|
290
|
+
locale at minimum); never inline a "temporary" English string.
|
|
291
|
+
- **No string concatenation for sentences**: word order differs per language; use
|
|
292
|
+
interpolation with named params.
|
|
293
|
+
- **Plurals via the library's plural rules** (`count`-style params), not `count === 1 ? ... : ...`.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Loading / Error / Empty States
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
interface AsyncStateProps<T> {
|
|
301
|
+
data: T | undefined;
|
|
302
|
+
isLoading: boolean;
|
|
303
|
+
error: Error | null;
|
|
304
|
+
empty: React.ReactNode;
|
|
305
|
+
children: (data: T) => React.ReactNode;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function AsyncState<T>({ data, isLoading, error, empty, children }: AsyncStateProps<T>) {
|
|
309
|
+
if (isLoading) return <div className="flex justify-center p-8"><Spinner /></div>;
|
|
310
|
+
if (error) return <ErrorCard message={error.message} />;
|
|
311
|
+
if (!data || (Array.isArray(data) && data.length === 0)) return <>{empty}</>;
|
|
312
|
+
return <>{children(data)}</>;
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Responsive Grid Layout
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
export function StatsGrid({ children }: { children: React.ReactNode }) {
|
|
322
|
+
return (
|
|
323
|
+
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
324
|
+
{children}
|
|
325
|
+
</div>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Vitest Component Test
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
import { render, screen } from "@testing-library/react";
|
|
336
|
+
import userEvent from "@testing-library/user-event";
|
|
337
|
+
import { describe, it, expect, vi } from "vitest";
|
|
338
|
+
import { Card } from "./Card";
|
|
339
|
+
|
|
340
|
+
describe("Card", () => {
|
|
341
|
+
it("renders title and description", () => {
|
|
342
|
+
render(<Card title="Test" description="Desc" />);
|
|
343
|
+
expect(screen.getByText("Test")).toBeInTheDocument();
|
|
344
|
+
expect(screen.getByText("Desc")).toBeInTheDocument();
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it("calls onClick when clicked", async () => {
|
|
348
|
+
const onClick = vi.fn();
|
|
349
|
+
render(<Card title="Test" onClick={onClick} />);
|
|
350
|
+
await userEvent.click(screen.getByText("Test"));
|
|
351
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
```
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Specialized Visual Implementation
|
|
2
|
+
|
|
3
|
+
Load this resource only when a requested implementation needs one of the extensions below.
|
|
4
|
+
General visual direction and implementation are separate stages: `oma-design` may use Taste or Impeccable to establish the visual intent; `oma-frontend` integrates the selected implementation provider into the existing application.
|
|
5
|
+
Do not load another design rulebook just because a GPU effect or scroll mechanism is needed.
|
|
6
|
+
Preserve the project's animation choice and the new-project Motion default.
|
|
7
|
+
|
|
8
|
+
## Choose by the requested effect
|
|
9
|
+
|
|
10
|
+
| Condition | Implementation route | Do not select it for |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| A named canvas/GPU effect over live HTML or a shader/3D-object component | CanvasUI registry item for the component, renderer and framework | General layout, form controls, design-system planning, or a native screen |
|
|
13
|
+
| A cinematic journey where scrolling seeks through connected pre-rendered camera clips | ScrollWorld skill and complete support bundle | Ordinary parallax, an entrance animation, a dashboard, or arbitrary real-time 3D navigation |
|
|
14
|
+
| The project already uses GSAP, or the user has selected GSAP for a concrete API/task | Only the needed official GSAP skills | Replacing existing Motion/CSS merely because the GSAP guide recommends itself |
|
|
15
|
+
|
|
16
|
+
Keep the extension local to the target route/component.
|
|
17
|
+
A request for a visual effect does not authorize a framework migration, unrelated dependencies, a full-page redesign, or a second media-production chain.
|
|
18
|
+
|
|
19
|
+
## Shared handoff and loading contract
|
|
20
|
+
|
|
21
|
+
Before implementation, carry these inputs from the request and project:
|
|
22
|
+
- Target route/component, existing stack, visual intent and normative tokens.
|
|
23
|
+
- Interaction and content that must survive; requested devices and input methods.
|
|
24
|
+
- The chosen extension, renderer/API where relevant, and who owns its lifecycle.
|
|
25
|
+
- Existing approved media, generation permissions, deadline, retry/cost/download limits, and performance constraints.
|
|
26
|
+
- Build authorization and available browser/device evidence.
|
|
27
|
+
|
|
28
|
+
Use the provider's actual source or selected skill, rather than treating this resource's summary as its implementation manual.
|
|
29
|
+
Keep complete returned support files and resolve their relative references from the returned skill directory.
|
|
30
|
+
Keep cwd at the target application when running authorized provider scripts.
|
|
31
|
+
A load without `--agent` reads instructions into the current runtime; do not install plugins, hooks or provider-agent definitions as an activation step.
|
|
32
|
+
Do not vendor provider code, packages, registries or skill manuals into OMA.
|
|
33
|
+
|
|
34
|
+
User instructions, project authority and OMA execution policy remain above the external procedure.
|
|
35
|
+
Preserve settled user choices; do not restart an interview or ask again for an already-authorized action.
|
|
36
|
+
Loading a provider does not authorize an installation, build, paid generation or change to a global provider default.
|
|
37
|
+
Use existing approved assets when generation is outside scope.
|
|
38
|
+
Record source identity, selected item/skill, relevant references, outputs and verification limits.
|
|
39
|
+
|
|
40
|
+
## CanvasUI: registry component implementation
|
|
41
|
+
|
|
42
|
+
CanvasUI is a source-copy component registry, not a skill or AI canvas editor.
|
|
43
|
+
It supplies WebGL/WebGPU effects; the documentation site's Next.js application and newsletter backend are not consumer requirements.
|
|
44
|
+
|
|
45
|
+
### Load the selected implementation
|
|
46
|
+
|
|
47
|
+
1. Select one named component and its actual target framework: React, Solid, Preact, Vue, Svelte or vanilla.
|
|
48
|
+
2. Select the renderer from target capabilities and requirements. WebGL is the ordinary registry variant; choose the explicit WebGPU variant only when that requirement is justified.
|
|
49
|
+
3. Resolve the complete shadcn-compatible registry item through the project's existing authorized registry tools/CLI.
|
|
50
|
+
Names have the form `@canvas-ui/<component>-<framework>[-webgpu]`, for example `@canvas-ui/liquid-react` or `@canvas-ui/liquid-react-webgpu`.
|
|
51
|
+
4. Inspect the returned source, installation target and dependencies before applying it.
|
|
52
|
+
The generated item inlines its engine and shared helpers; a demo fragment alone is not the implementation.
|
|
53
|
+
5. Apply it inside the target product under its license and existing file conventions.
|
|
54
|
+
Keep strict primitives intact and wrap the effect at the appropriate client boundary.
|
|
55
|
+
|
|
56
|
+
Registry source: `https://canvasui.dev/r/{name}.json`.
|
|
57
|
+
For a framework without a supplied wrapper, consider a scoped vanilla adapter; do not invent an unsupported registry suffix or replace the framework.
|
|
58
|
+
|
|
59
|
+
### Runtime and outputs
|
|
60
|
+
|
|
61
|
+
- Inputs: live HTML/content or supplied object assets, a component's typed options, renderer and framework.
|
|
62
|
+
- Outputs: the selected component/adapter, necessary project dependencies, source/license provenance and observed behavior.
|
|
63
|
+
- WebGL effects require working browser GPU capabilities; some require float render targets.
|
|
64
|
+
- WebGPU variants add `vgpu`; object variants can add `three` and fetch model/decoder assets.
|
|
65
|
+
- HTML-in-canvas is an experimental capability. Check the actual API, GPU initialization and DOM-preserving fallback rather than promising support from a browser version alone.
|
|
66
|
+
- No AI account or inference API key is needed for the component itself. Do not configure the site's Resend/Turnstile services.
|
|
67
|
+
|
|
68
|
+
### Lifecycle, fallback and verification
|
|
69
|
+
|
|
70
|
+
Own the engine instance at mount and call its `destroy()` at teardown.
|
|
71
|
+
Remove owned observers/listeners and release GPU resources; do not leave duplicate instances after remount.
|
|
72
|
+
Preserve the visible, interactive DOM when native capture, WebGL or WebGPU fails.
|
|
73
|
+
Respect reduced motion and verify that the fallback still exposes the content and primary action.
|
|
74
|
+
Check the selected route at representative sizes, with keyboard/touch input, resizing/zoom, reduced motion and GPU failure.
|
|
75
|
+
Measure target-specific frame/memory behavior when performance is material; source-level cleanup checks do not prove device performance.
|
|
76
|
+
|
|
77
|
+
CanvasUI's checked license is **MIT + Commons Clause**.
|
|
78
|
+
Retain notices and check the selected item's current license: product use and redistribution of the components themselves have different terms.
|
|
79
|
+
Do not repackage its component collection inside OMA.
|
|
80
|
+
|
|
81
|
+
Official sources: [registry generator](https://github.com/DavidHDev/canvas-ui/blob/a04a99b235299ee79a123a16ccb2e6cf9da74b6b/src/lib/registry.ts), [engine lifecycle](https://github.com/DavidHDev/canvas-ui/blob/a04a99b235299ee79a123a16ccb2e6cf9da74b6b/src/lib/Liquid/LiquidVanilla.ts), [HTML-in-canvas](https://github.com/DavidHDev/canvas-ui/blob/a04a99b235299ee79a123a16ccb2e6cf9da74b6b/src/lib/html-in-canvas.ts), [license](https://github.com/DavidHDev/canvas-ui/blob/a04a99b235299ee79a123a16ccb2e6cf9da74b6b/LICENSE.md).
|
|
82
|
+
|
|
83
|
+
## ScrollWorld: pre-rendered video scrubbing
|
|
84
|
+
|
|
85
|
+
Select this route only for the connected camera-flight experience.
|
|
86
|
+
It seeks through video; it does not implement a freely navigable WebGL world and does not require GSAP.
|
|
87
|
+
|
|
88
|
+
Load the complete external skill:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
bunx skills use oso95/scroll-world@scroll-world
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Read the returned SKILL.md and the applicable support files from its returned directory:
|
|
95
|
+
- `references/scrub-engine.js`: browser engine and configuration.
|
|
96
|
+
- `references/index-template.html`: integration example.
|
|
97
|
+
- `references/pipeline.md`: authorized media extraction/encoding steps.
|
|
98
|
+
- `references/prompts.md`: generation inputs and camera continuity.
|
|
99
|
+
- `references/knockout.py`: optional image-helper contract; loading it does not authorize image processing.
|
|
100
|
+
|
|
101
|
+
### Inputs, production handoff and outputs
|
|
102
|
+
|
|
103
|
+
Inputs are brand/content, ordered scenes, camera direction, supplied stills/clips/connectors, target aspect ratios and an approved asset budget.
|
|
104
|
+
Existing valid assets permit integration without generating new media.
|
|
105
|
+
When new stills or video are needed, hand their explicit requirements to `oma-image` / `oma-video` within the already-authorized provider and cost scope.
|
|
106
|
+
Do not inherit upstream's default biller, automatic installer or quoted prices as OMA defaults.
|
|
107
|
+
Recheck actual provider capabilities/costs before an authorized batch.
|
|
108
|
+
Use one bounded calibration before a costly batch when costs or seam behavior are unknown; do not silently generate a second portrait chain.
|
|
109
|
+
|
|
110
|
+
The asset handoff must identify scene stills, dive clips, connector endpoints, posters, intended sizes/codecs and provenance.
|
|
111
|
+
A full chain has N dives and up to N−1 connectors; desktop and portrait production are distinct scopes.
|
|
112
|
+
Confirm seams against the actual adjacent rendered frames.
|
|
113
|
+
Outputs are approved media plus an app-local integration/configuration, a lifecycle adapter where needed, and evidence of continuity and fallback.
|
|
114
|
+
|
|
115
|
+
The browser config consumes `sections` with still/clip/content fields, optional mobile variants, connector URLs and scroll-distance settings.
|
|
116
|
+
The engine uses DOM/video/fetch/RAF and Blob URLs. Fetch/CORS, decoded-video memory, seek cost and asset bytes belong in the implementation budget.
|
|
117
|
+
|
|
118
|
+
### Existing SPA integration requires cleanup work
|
|
119
|
+
|
|
120
|
+
The checked upstream `mountScrollWorld` adds global listeners and a recurring RAF, creates Blob URLs, and provides no destroy/dispose return.
|
|
121
|
+
Do not mount that function unchanged in a route that can unmount or mount twice.
|
|
122
|
+
Adapt the target integration's mount contract to expose the owned handles and a disposer.
|
|
123
|
+
A wrapper that only removes the container cannot clean up the upstream closure's RAF, listeners or Blob URLs.
|
|
124
|
+
Provide a target-app lifecycle integration that:
|
|
125
|
+
- Cancels owned RAF/timers and removes owned listeners.
|
|
126
|
+
- Aborts pending media requests, pauses/releases videos and revokes created Blob URLs.
|
|
127
|
+
- Removes only owned DOM/styles and prevents duplicate mounting.
|
|
128
|
+
- Scopes the engine's injected CSS and fixed layers, including its global html/body rules.
|
|
129
|
+
- Preserves application navigation, scrolling, focus and unrelated animation instances.
|
|
130
|
+
|
|
131
|
+
Reduced motion uses posters instead of loading clips.
|
|
132
|
+
Verify that path, failed/blocked video fetch, first-frame poster continuity, fast scroll seek behavior, back navigation and unmount/remount.
|
|
133
|
+
If live preference changes are supported, adapt them explicitly; the upstream reduced-motion value is captured at mount.
|
|
134
|
+
Phone seeking/priming and optional mobile source branches in code are not evidence of a real iOS/device pass.
|
|
135
|
+
State exactly which browser/device or emulation produced the evidence.
|
|
136
|
+
|
|
137
|
+
Official sources: [skill and complete flow](https://github.com/oso95/scroll-world/blob/71cc36d3bb150248ae36a2c552f9cbf88802a79c/skills/scroll-world/SKILL.md), [actual engine/config/lifecycle](https://github.com/oso95/scroll-world/blob/71cc36d3bb150248ae36a2c552f9cbf88802a79c/skills/scroll-world/references/scrub-engine.js), [media pipeline](https://github.com/oso95/scroll-world/blob/71cc36d3bb150248ae36a2c552f9cbf88802a79c/skills/scroll-world/references/pipeline.md).
|
|
138
|
+
|
|
139
|
+
## GSAP: chosen API guidance
|
|
140
|
+
|
|
141
|
+
Enter only after GSAP is already used or explicitly selected for the target.
|
|
142
|
+
The external skills' recommendation to default to GSAP does not replace the project's Motion/CSS choice.
|
|
143
|
+
Load the few relevant skills, then read and follow their complete returned instructions:
|
|
144
|
+
|
|
145
|
+
| Need | Actual skill selector |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Core tween/easing/matchMedia API | `greensock/gsap-skills@gsap-core` |
|
|
148
|
+
| React/Next.js lifecycle | `greensock/gsap-skills@gsap-react` |
|
|
149
|
+
| ScrollTrigger pin/scrub/refresh | `greensock/gsap-skills@gsap-scrolltrigger` |
|
|
150
|
+
| Timeline sequencing | `greensock/gsap-skills@gsap-timeline` |
|
|
151
|
+
| A named extra plugin | `greensock/gsap-skills@gsap-plugins` |
|
|
152
|
+
| GSAP utility API | `greensock/gsap-skills@gsap-utils` |
|
|
153
|
+
| A GSAP performance problem | `greensock/gsap-skills@gsap-performance` |
|
|
154
|
+
| Vue/Svelte or other framework lifecycle | `greensock/gsap-skills@gsap-frameworks` |
|
|
155
|
+
|
|
156
|
+
For a React ScrollTrigger task, the relevant initial set is core + react + scrolltrigger:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
bunx skills use greensock/gsap-skills@gsap-core
|
|
160
|
+
bunx skills use greensock/gsap-skills@gsap-react
|
|
161
|
+
bunx skills use greensock/gsap-skills@gsap-scrolltrigger
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
A smaller task loads a smaller set.
|
|
165
|
+
When a skill returns a support directory, resolve its references there; a SKILL-only result need not have one.
|
|
166
|
+
Loading these guides does not install `gsap`, `@gsap/react`, plugins or example applications.
|
|
167
|
+
|
|
168
|
+
### Runtime, outputs and verification
|
|
169
|
+
|
|
170
|
+
Inputs are the selected API/plugin, existing dependency versions, target elements, lifecycle, timeline/scroll behavior and reduced-motion result.
|
|
171
|
+
Outputs are scoped application code, an explicit teardown and relevant interaction/performance evidence.
|
|
172
|
+
Run DOM-dependent GSAP work on the client, after target nodes exist.
|
|
173
|
+
Use a scoped `useGSAP`/context in React, context-safe delayed callbacks and matching cleanup; revert on unmount/update where appropriate.
|
|
174
|
+
Outside React, use the framework's own mount/unmount lifecycle and revert the owned GSAP context.
|
|
175
|
+
Remove custom listeners/timers as well as animation objects.
|
|
176
|
+
Kill/revert only the route's owned animations/triggers, never unrelated instances globally.
|
|
177
|
+
|
|
178
|
+
Choose a meaningful reduced-motion/static result with `gsap.matchMedia()` or the project's equivalent.
|
|
179
|
+
Verify endpoint state, interruption/reversal where needed, touch/keyboard behavior, hydration, remount cleanup and responsive layout.
|
|
180
|
+
For ScrollTrigger, verify scroller ownership, pin geometry and refresh after relevant layout/assets change.
|
|
181
|
+
Keep test/build execution within authorization; do not install/build the supplier's examples to consume a guide.
|
|
182
|
+
|
|
183
|
+
Official sources: [core](https://github.com/greensock/gsap-skills/blob/aed9cfd3277740755f6bfc1155c7aa645403b760/skills/gsap-core/SKILL.md), [React](https://github.com/greensock/gsap-skills/blob/aed9cfd3277740755f6bfc1155c7aa645403b760/skills/gsap-react/SKILL.md), [ScrollTrigger](https://github.com/greensock/gsap-skills/blob/aed9cfd3277740755f6bfc1155c7aa645403b760/skills/gsap-scrolltrigger/SKILL.md).
|
|
184
|
+
|
|
185
|
+
## Motion principles and handoff evidence
|
|
186
|
+
|
|
187
|
+
Use [shared interaction quality](../../_shared/ui-interaction-quality.md) for purpose, frequency, interruption, compositor cost, input feedback and reduced motion.
|
|
188
|
+
The absorbed Emil guidance informs those project-level decisions; it is not an automatic extra external-skill chain or library picker.
|
|
189
|
+
A CSS/Motion implementation that already satisfies the request remains valid.
|
|
190
|
+
|
|
191
|
+
Report the chosen extension and item/skills, actual target changes, asset/dependency effects, cleanup ownership and verification performed.
|
|
192
|
+
Separate support loading, source inspection, asset generation, runtime execution and browser/device results.
|
|
193
|
+
Unavailable media or a skipped runtime check is an explicit limitation, not a rendered pass.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Tailwind CSS Rules
|
|
2
|
+
|
|
3
|
+
> Basic Tailwind syntax (spacing scale, flex/grid, breakpoints) is assumed knowledge. This file only covers project-specific rules and non-obvious patterns. See `snippets.md` for ready-made component snippets.
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
|
|
7
|
+
1. **No inline styles**: Tailwind classes only
|
|
8
|
+
2. **Mobile-first**: base classes target mobile, scale up with `sm:` `md:` `lg:`
|
|
9
|
+
3. **No hardcoded colors**: always use semantic tokens (see below)
|
|
10
|
+
4. **Dark mode aware**: every color token must work under `dark:` variant
|
|
11
|
+
5. **Arbitrary values only with justification**: `w-[789px]` needs a design reason; otherwise use the scale
|
|
12
|
+
|
|
13
|
+
## Semantic Color Tokens
|
|
14
|
+
|
|
15
|
+
Map all colors to design tokens in `packages/design-tokens`. Never use raw colors like `bg-white` or `text-gray-900`.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
// Good
|
|
19
|
+
<div className="bg-background text-foreground border-border">
|
|
20
|
+
<button className="bg-primary text-primary-foreground">
|
|
21
|
+
|
|
22
|
+
// Bad
|
|
23
|
+
<div className="bg-white text-black border-gray-300">
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Available tokens:
|
|
27
|
+
- `background` / `foreground`
|
|
28
|
+
- `primary` / `primary-foreground`
|
|
29
|
+
- `secondary` / `secondary-foreground`
|
|
30
|
+
- `muted` / `muted-foreground`
|
|
31
|
+
- `accent` / `accent-foreground`
|
|
32
|
+
- `destructive` / `destructive-foreground`
|
|
33
|
+
- `border` / `input` / `ring`
|
|
34
|
+
|
|
35
|
+
## `cn()` Utility
|
|
36
|
+
|
|
37
|
+
Use `cn()` (clsx + tailwind-merge) whenever classes are conditional or need to be overridable from a prop:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { cn } from "@/lib/utils";
|
|
41
|
+
|
|
42
|
+
<div className={cn(
|
|
43
|
+
"base-class",
|
|
44
|
+
condition && "conditional-class",
|
|
45
|
+
{ "variant-a": variant === "a" },
|
|
46
|
+
className, // prop override must come last
|
|
47
|
+
)} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Focus States (A11y)
|
|
51
|
+
|
|
52
|
+
Every interactive element needs a visible focus state:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Screen-reader-only text: `<span className="sr-only">...</span>`.
|
|
59
|
+
|
|
60
|
+
## Tailwind v4 Theme
|
|
61
|
+
|
|
62
|
+
Tailwind v4 uses CSS-based configuration. `tailwind.config.js` is deprecated. Add custom tokens via `@theme` in `app/globals.css`:
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
@import "tailwindcss";
|
|
66
|
+
|
|
67
|
+
@theme {
|
|
68
|
+
--spacing-18: 4.5rem;
|
|
69
|
+
--color-brand-50: #...;
|
|
70
|
+
--color-brand-900: #...;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Anti-Patterns
|
|
75
|
+
|
|
76
|
+
- **`@apply` in CSS files**: defeats utility-first intent. Use classes in JSX, or extract a component.
|
|
77
|
+
- **Hardcoded hex/rgb**: always go through the token system.
|
|
78
|
+
- **Desktop-first breakpoints**: `grid-cols-3 sm:grid-cols-1` reverses the mobile-first flow.
|
|
79
|
+
- **Nested overrides**: if you find yourself writing `lg:!bg-primary`, the component API is wrong; add a variant instead.
|
|
80
|
+
|
|
81
|
+
## Formatting
|
|
82
|
+
|
|
83
|
+
Follow whatever class-sorting convention the project's formatter enforces (Prettier + `prettier-plugin-tailwindcss`, Biome's `useSortedClasses`, or similar). Do not hand-reorder against the formatter.
|