@kensaurus/skills 0.0.0-stage → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +53 -0
- package/.claude-plugin/plugin.json +40 -0
- package/.cursor-plugin/plugin.json +38 -0
- package/.mcp.json +28 -0
- package/CHANGELOG.md +1761 -0
- package/LICENSE +21 -0
- package/NOTICE +13 -0
- package/README.md +820 -2
- package/SECURITY.md +55 -0
- package/agents/code-reviewer.md +60 -0
- package/agents/completion-judge.md +89 -0
- package/agents/db-migrator.md +125 -0
- package/agents/debugger.md +47 -0
- package/agents/deploy-checker.md +100 -0
- package/agents/perf-monitor.md +74 -0
- package/assets/favicon.png +0 -0
- package/assets/logo-light.png +0 -0
- package/assets/logo.png +0 -0
- package/assets/logo.svg +6 -0
- package/assets/og.png +0 -0
- package/bin/install.mjs +1127 -0
- package/bin/kenji.js +2 -0
- package/commands/adr.md +17 -0
- package/commands/aeo-plan.md +18 -0
- package/commands/arch-boundaries.md +17 -0
- package/commands/aso-plan.md +18 -0
- package/commands/auth-flows.md +19 -0
- package/commands/backup-plan.md +17 -0
- package/commands/burndown-full.md +25 -0
- package/commands/capacitor-plan.md +18 -0
- package/commands/codemod-safety.md +22 -0
- package/commands/commit.md +18 -0
- package/commands/complete-everything.md +40 -0
- package/commands/cost-plan.md +19 -0
- package/commands/deadcode-plan.md +26 -0
- package/commands/deadcode.md +32 -0
- package/commands/debug-issue.md +17 -0
- package/commands/deps-plan.md +18 -0
- package/commands/docs-plan.md +17 -0
- package/commands/doctrine.md +19 -0
- package/commands/error-plan.md +19 -0
- package/commands/feedback-to-closure.md +36 -0
- package/commands/fix-issue.md +76 -0
- package/commands/gate-logic.md +26 -0
- package/commands/green-repo.md +36 -0
- package/commands/grill-me.md +19 -0
- package/commands/gtm-plan.md +21 -0
- package/commands/gtm-weekly.md +17 -0
- package/commands/gtm.md +22 -0
- package/commands/handoff.md +15 -0
- package/commands/housekeep-backlog.md +18 -0
- package/commands/housekeep-files.md +22 -0
- package/commands/housekeep-gates.md +18 -0
- package/commands/instant-nav.md +11 -0
- package/commands/integrity-plan.md +19 -0
- package/commands/launch-kit.md +16 -0
- package/commands/mcp-guide.md +40 -0
- package/commands/mobile-plan.md +19 -0
- package/commands/native-rn-monorepo/README.md +78 -0
- package/commands/native-rn-monorepo/android-build.md +26 -0
- package/commands/native-rn-monorepo/android-install.md +32 -0
- package/commands/native-rn-monorepo/android-logcat.md +37 -0
- package/commands/native-rn-monorepo/ios-ci-logs.md +56 -0
- package/commands/native-rn-monorepo/ios-ci-status.md +52 -0
- package/commands/native-rn-monorepo/ios-ci-trigger.md +59 -0
- package/commands/native-rn-monorepo/rn-reset.md +50 -0
- package/commands/native-rn-monorepo/rn-ship-ios.md +67 -0
- package/commands/native-rn-monorepo/rn-verify.md +53 -0
- package/commands/perf-plan.md +18 -0
- package/commands/plan-mode.md +74 -0
- package/commands/pr.md +16 -0
- package/commands/pricing-plan.md +20 -0
- package/commands/privacy-plan.md +18 -0
- package/commands/readability.md +12 -0
- package/commands/readme.md +15 -0
- package/commands/refactor.md +15 -0
- package/commands/release-prep.md +17 -0
- package/commands/research.md +25 -0
- package/commands/responsive-audit.md +21 -0
- package/commands/review-code.md +18 -0
- package/commands/rls-plan.md +18 -0
- package/commands/secrets-plan.md +18 -0
- package/commands/security-plan.md +19 -0
- package/commands/ship-and-observe.md +36 -0
- package/commands/skill-conflicts.md +19 -0
- package/commands/slop-plan.md +18 -0
- package/commands/stub-plan.md +18 -0
- package/commands/test-mutation.md +16 -0
- package/commands/test-plan.md +17 -0
- package/commands/test.md +29 -0
- package/commands/thirdparty-web-interface-guidelines.md +185 -0
- package/commands/uiux-plan.md +18 -0
- package/commands/uiux.md +45 -0
- package/commands/update-deps.md +21 -0
- package/commands/validation-plan.md +19 -0
- package/commands-portable/fix-issue.md +72 -0
- package/commands-portable/plan-mode.md +92 -0
- package/commands-portable/research.md +91 -0
- package/docs/screenshots/README.md +5 -0
- package/docs/screenshots/audit-dark.png +0 -0
- package/docs/screenshots/build-dark.png +0 -0
- package/docs/screenshots/grill-dark.png +0 -0
- package/docs/screenshots/hero-dark.png +0 -0
- package/docs/screenshots/hero-light.png +0 -0
- package/docs/screenshots/ship-dark.png +0 -0
- package/docs/screenshots/src/showcase.html +320 -0
- package/hooks/completion-gate.mjs +258 -0
- package/hooks/cursor-hooks.json +13 -0
- package/hooks/hooks.json +15 -0
- package/install.sh +21 -0
- package/llms.txt +40 -0
- package/mcp/README.md +266 -0
- package/mcp/VERSIONS.md +41 -0
- package/mcp/mcp-full.json.template +124 -0
- package/mcp/mcp.json.template +29 -0
- package/mcp/pinned-versions.json +27 -0
- package/package.json +93 -4
- package/rules/approved-plan-execution.mdc +65 -0
- package/rules/full-stack-ship-discipline.mdc +37 -0
- package/rules/native-rn-monorepo/README.md +63 -0
- package/rules/native-rn-monorepo/_project.mdc +69 -0
- package/rules/native-rn-monorepo/native-android.mdc +72 -0
- package/rules/native-rn-monorepo/native-ios.mdc +61 -0
- package/rules/native-rn-monorepo/react-native-js.mdc +78 -0
- package/rules/native-rn-monorepo/web.mdc +60 -0
- package/rules/project-starter/components.mdc +54 -0
- package/rules/project-starter/data-fetching.mdc +77 -0
- package/rules/project-starter/git.mdc +41 -0
- package/rules/project-starter/supabase.mdc +37 -0
- package/rules/project-starter/tailwind.mdc +48 -0
- package/rules/project-starter/typescript.mdc +36 -0
- package/rules/project-starter/web-performance.mdc +42 -0
- package/rules/senior-engineer.mdc +30 -0
- package/rules/shell-first-search.mdc +19 -0
- package/rules/skill-workflows.mdc +35 -0
- package/rules/verification-before-completion.mdc +57 -0
- package/skills/audit-accessibility/SKILL.md +441 -0
- package/skills/audit-agent-speed/SKILL.md +181 -0
- package/skills/audit-agent-speed/scripts/stop-typecheck.mjs +151 -0
- package/skills/audit-analytics/SKILL.md +138 -0
- package/skills/audit-auth-flows/SKILL.md +267 -0
- package/skills/audit-backend-architecture/SKILL.md +266 -0
- package/skills/audit-backend-architecture/references/patterns.md +386 -0
- package/skills/audit-bundle-size/SKILL.md +296 -0
- package/skills/audit-cicd/SKILL.md +218 -0
- package/skills/audit-code-quality/SKILL.md +314 -0
- package/skills/audit-code-review/SKILL.md +289 -0
- package/skills/audit-codemod-safety/SKILL.md +159 -0
- package/skills/audit-db-schema/SKILL.md +465 -0
- package/skills/audit-db-schema/references/details.md +110 -0
- package/skills/audit-doctrine/SKILL.md +189 -0
- package/skills/audit-env-parity/SKILL.md +133 -0
- package/skills/audit-fe-api/SKILL.md +458 -0
- package/skills/audit-gate-logic/SKILL.md +219 -0
- package/skills/audit-i18n/SKILL.md +339 -0
- package/skills/audit-infra-cost/SKILL.md +142 -0
- package/skills/audit-langfuse-llm/SKILL.md +468 -0
- package/skills/audit-langfuse-llm/references/details.md +226 -0
- package/skills/audit-llm-security/SKILL.md +147 -0
- package/skills/audit-monetization-iap/SKILL.md +137 -0
- package/skills/audit-payment-system/SKILL.md +268 -0
- package/skills/audit-payment-system/references/checklist.md +283 -0
- package/skills/audit-performance/SKILL.md +383 -0
- package/skills/audit-performance/references/loading-priority-2026.md +81 -0
- package/skills/audit-realworld/SKILL.md +287 -0
- package/skills/audit-registry-listing/SKILL.md +122 -0
- package/skills/audit-resilience/SKILL.md +154 -0
- package/skills/audit-responsive/SKILL.md +221 -0
- package/skills/audit-responsive/references/checklist.md +166 -0
- package/skills/audit-security/SKILL.md +289 -0
- package/skills/audit-skill-conflicts/SKILL.md +178 -0
- package/skills/audit-ui-states/SKILL.md +146 -0
- package/skills/audit-uiux-design-system/SKILL.md +475 -0
- package/skills/audit-uiux-design-system/references/details.md +71 -0
- package/skills/audit-ux/SKILL.md +379 -0
- package/skills/audit-ux/references/details.md +245 -0
- package/skills/audit-ux-journeys/SKILL.md +215 -0
- package/skills/audit-ux-journeys/references/checklist.md +179 -0
- package/skills/backend-db-performance/SKILL.md +441 -0
- package/skills/backend-error-handling/SKILL.md +489 -0
- package/skills/backend-error-handling/references/details.md +58 -0
- package/skills/backend-observability/SKILL.md +88 -0
- package/skills/backend-patterns/SKILL.md +499 -0
- package/skills/backend-patterns/references/architecture-patterns.md +298 -0
- package/skills/backend-realtime/SKILL.md +403 -0
- package/skills/backend-realtime/references/patterns.md +74 -0
- package/skills/burndown-full/SKILL.md +174 -0
- package/skills/complete-everything/SKILL.md +295 -0
- package/skills/data-pipeline/SKILL.md +109 -0
- package/skills/data-visualization/SKILL.md +488 -0
- package/skills/debug-error/SKILL.md +322 -0
- package/skills/debug-fe-be-integration/SKILL.md +459 -0
- package/skills/debug-sentry-monitor/SKILL.md +497 -0
- package/skills/debug-sentry-monitor/references/details.md +165 -0
- package/skills/deploy-npm/SKILL.md +394 -0
- package/skills/deploy-npm/references/example-mushi-mushi.md +52 -0
- package/skills/deploy-verify/SKILL.md +489 -0
- package/skills/design-api/SKILL.md +379 -0
- package/skills/design-canvas/SKILL.md +155 -0
- package/skills/design-email/SKILL.md +370 -0
- package/skills/design-frontend/SKILL.md +143 -0
- package/skills/design-generative-art/SKILL.md +474 -0
- package/skills/design-mobile-first/SKILL.md +506 -0
- package/skills/design-motion/SKILL.md +333 -0
- package/skills/design-motion/references/delight-interactions.md +191 -0
- package/skills/design-prd/SKILL.md +443 -0
- package/skills/design-system/SKILL.md +457 -0
- package/skills/design-theme/SKILL.md +226 -0
- package/skills/design-theme/themes/tsumagoi-ranch.md +150 -0
- package/skills/docs-adr/SKILL.md +168 -0
- package/skills/docs-coauthor/SKILL.md +368 -0
- package/skills/docs-comparison-pages/SKILL.md +117 -0
- package/skills/docs-domain-modeling/SKILL.md +97 -0
- package/skills/docs-launch-kit/SKILL.md +139 -0
- package/skills/docs-writer/SKILL.md +469 -0
- package/skills/enhance-agent-guardrails/SKILL.md +164 -0
- package/skills/enhance-arch-boundaries/SKILL.md +154 -0
- package/skills/enhance-capacitor-ui/SKILL.md +463 -0
- package/skills/enhance-capacitor-ui/references/details.md +750 -0
- package/skills/enhance-email-deliverability/SKILL.md +143 -0
- package/skills/enhance-growth-loops/SKILL.md +122 -0
- package/skills/enhance-lifecycle-email/SKILL.md +130 -0
- package/skills/enhance-motion/SKILL.md +193 -0
- package/skills/enhance-onboarding/SKILL.md +148 -0
- package/skills/enhance-pwa/SKILL.md +304 -0
- package/skills/enhance-readability/SKILL.md +146 -0
- package/skills/enhance-readme/SKILL.md +496 -0
- package/skills/enhance-readme/package-lock.json +187 -0
- package/skills/enhance-readme/package.json +17 -0
- package/skills/enhance-readme/scripts/generate-readme-blocks.mjs +199 -0
- package/skills/enhance-readme/scripts/record-readme-tour.mjs +442 -0
- package/skills/enhance-skill-prompts/SKILL.md +167 -0
- package/skills/enhance-skill-prompts/references/exemplar-audit-auth-flows.md +311 -0
- package/skills/enhance-web-conversion/SKILL.md +155 -0
- package/skills/enhance-web-forms/SKILL.md +154 -0
- package/skills/enhance-web-instant-nav/SKILL.md +138 -0
- package/skills/enhance-web-instant-nav/references/bfcache-blockers.md +23 -0
- package/skills/enhance-web-instant-nav/references/early-hints.md +33 -0
- package/skills/enhance-web-instant-nav/references/speculation-rules.md +44 -0
- package/skills/enhance-web-landing/SKILL.md +459 -0
- package/skills/enhance-web-landing/references/details.md +773 -0
- package/skills/enhance-web-redesign/SKILL.md +228 -0
- package/skills/enhance-web-seo/SKILL.md +276 -0
- package/skills/enhance-web-ui/SKILL.md +473 -0
- package/skills/enhance-web-ui/references/details.md +674 -0
- package/skills/enhance-web-ux/HEURISTICS.md +242 -0
- package/skills/enhance-web-ux/PATTERNS.md +375 -0
- package/skills/enhance-web-ux/SKILL.md +464 -0
- package/skills/enhance-web-ux/examples.md +222 -0
- package/skills/enhance-web-ux/references/details.md +406 -0
- package/skills/enhance-web-web3d/SKILL.md +397 -0
- package/skills/enhance-web-web3d/references/css-canvas-effects.md +180 -0
- package/skills/handoff/SKILL.md +66 -0
- package/skills/housekeep-backlog/SKILL.md +149 -0
- package/skills/housekeep-dead-code/SKILL.md +387 -0
- package/skills/housekeep-dead-code/references/ratchet-ci.md +205 -0
- package/skills/housekeep-dead-code/references/supabase-hygiene.md +152 -0
- package/skills/housekeep-design/SKILL.md +207 -0
- package/skills/housekeep-files/SKILL.md +220 -0
- package/skills/housekeep-files/references/naming-and-catalog.md +86 -0
- package/skills/housekeep-files/scripts/housekeep-files.ps1 +360 -0
- package/skills/housekeep-files/scripts/housekeep-files.sh +238 -0
- package/skills/housekeep-gates/SKILL.md +174 -0
- package/skills/iterate-agent-harness/SKILL.md +137 -0
- package/skills/iterate-gtm-weekly/SKILL.md +103 -0
- package/skills/iterate-post-launch/SKILL.md +292 -0
- package/skills/meta-mcp-builder/SKILL.md +313 -0
- package/skills/meta-skill-creator/SKILL.md +304 -0
- package/skills/mobile-capacitor-platform/SKILL.md +104 -0
- package/skills/mobile-emulator-start/SKILL.md +296 -0
- package/skills/mobile-emulator-test/SKILL.md +491 -0
- package/skills/mobile-emulator-test/references/details.md +478 -0
- package/skills/mobile-rn-performance/SKILL.md +107 -0
- package/skills/mobile-rn-screen/SKILL.md +476 -0
- package/skills/mobile-rn-screen/references/details.md +785 -0
- package/skills/mushi-health/SKILL.md +206 -0
- package/skills/mushi-integration/SKILL.md +257 -0
- package/skills/plan-aeo-readiness/SKILL.md +166 -0
- package/skills/plan-antislop/SKILL.md +281 -0
- package/skills/plan-aso/SKILL.md +149 -0
- package/skills/plan-backup-dr/SKILL.md +131 -0
- package/skills/plan-capacitor-hardening/SKILL.md +217 -0
- package/skills/plan-data-integrity/SKILL.md +187 -0
- package/skills/plan-dead-code/SKILL.md +386 -0
- package/skills/plan-dead-code/references/knip-config.md +214 -0
- package/skills/plan-dead-code/references/output-templates.md +133 -0
- package/skills/plan-dead-code/references/preservation-contract.md +50 -0
- package/skills/plan-dead-code/references/residue-greps.md +84 -0
- package/skills/plan-dependency-provenance/SKILL.md +200 -0
- package/skills/plan-docs-sync/SKILL.md +143 -0
- package/skills/plan-docs-sync/references/drift-taxonomy.md +43 -0
- package/skills/plan-docs-sync/references/output-templates.md +33 -0
- package/skills/plan-docs-sync/references/preservation-contract.md +17 -0
- package/skills/plan-error-handling/SKILL.md +205 -0
- package/skills/plan-gtm/SKILL.md +276 -0
- package/skills/plan-gtm/references/benchmarks-2026.md +183 -0
- package/skills/plan-input-validation/SKILL.md +179 -0
- package/skills/plan-llm-cost-guardrails/SKILL.md +176 -0
- package/skills/plan-mobile-readiness/SKILL.md +171 -0
- package/skills/plan-perf-audit/SKILL.md +145 -0
- package/skills/plan-perf-audit/references/audit-scope.md +51 -0
- package/skills/plan-perf-audit/references/output-templates.md +33 -0
- package/skills/plan-perf-audit/references/preservation-contract.md +13 -0
- package/skills/plan-pricing/SKILL.md +173 -0
- package/skills/plan-privacy-compliance/SKILL.md +148 -0
- package/skills/plan-rls-audit/SKILL.md +231 -0
- package/skills/plan-secrets-audit/SKILL.md +181 -0
- package/skills/plan-security-audit/SKILL.md +168 -0
- package/skills/plan-security-audit/references/output-templates.md +36 -0
- package/skills/plan-security-audit/references/owasp-supabase-scope.md +55 -0
- package/skills/plan-security-audit/references/preservation-contract.md +18 -0
- package/skills/plan-stub-checker/SKILL.md +216 -0
- package/skills/plan-stub-checker/references/detection-methodology.md +75 -0
- package/skills/plan-stub-checker/references/detection-taxonomy.md +34 -0
- package/skills/plan-stub-checker/references/output-templates.md +63 -0
- package/skills/plan-stub-checker/references/preservation-contract.md +24 -0
- package/skills/plan-test-coverage/SKILL.md +170 -0
- package/skills/plan-test-coverage/references/methodology.md +54 -0
- package/skills/plan-test-coverage/references/output-templates.md +34 -0
- package/skills/plan-test-coverage/references/preservation-contract.md +15 -0
- package/skills/plan-uiux-unification/SKILL.md +230 -0
- package/skills/plan-uiux-unification/references/output-templates.md +67 -0
- package/skills/plan-uiux-unification/references/phase-workbook.md +85 -0
- package/skills/plan-uiux-unification/references/preservation-contract.md +24 -0
- package/skills/protocol-browser-anti-stall/SKILL.md +211 -0
- package/skills/protocol-browser-anti-stall/references/mcp-to-cli-map.md +113 -0
- package/skills/protocol-browser-anti-stall/references/playwright-session-coordination.md +170 -0
- package/skills/research/SKILL.md +422 -0
- package/skills/test-exploratory/SKILL.md +165 -0
- package/skills/test-exploratory/references/charter-template.md +29 -0
- package/skills/test-load/SKILL.md +126 -0
- package/skills/test-mutation/SKILL.md +160 -0
- package/skills/test-playwright/SKILL.md +354 -0
- package/skills/test-qa/SKILL.md +364 -0
- package/skills/test-qa/references/details.md +268 -0
- package/skills/test-red-team/SKILL.md +387 -0
- package/skills/test-red-team/references/owasp-attack-checklist.md +193 -0
- package/skills/test-unit/SKILL.md +259 -0
- package/skills/test-unit/references/details.md +267 -0
- package/skills/test-visual-regression/SKILL.md +132 -0
- package/skills/thirdparty-emil-design-eng/ATTRIBUTION.md +20 -0
- package/skills/thirdparty-emil-design-eng/SKILL.md +21 -0
- package/skills/thirdparty-emil-design-eng/references/emil-design-eng.md +676 -0
- package/skills/thirdparty-ui-ux-pro-max/ATTRIBUTION.md +22 -0
- package/skills/thirdparty-ui-ux-pro-max/SKILL.md +304 -0
- package/skills/thirdparty-ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/thirdparty-ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/thirdparty-ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/thirdparty-ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/thirdparty-ui-ux-pro-max/data/products.csv +97 -0
- package/skills/thirdparty-ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/thirdparty-ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/thirdparty-ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/thirdparty-ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/thirdparty-ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/thirdparty-ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/thirdparty-ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/thirdparty-ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/thirdparty-ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/thirdparty-ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/thirdparty-web-interface-guidelines/ATTRIBUTION.md +23 -0
- package/skills/thirdparty-web-interface-guidelines/SKILL.md +190 -0
- package/skills/workflow-build-feature/SKILL.md +118 -0
- package/skills/workflow-coding-discipline/SKILL.md +140 -0
- package/skills/workflow-environment-ready/SKILL.md +128 -0
- package/skills/workflow-feature-flag/SKILL.md +262 -0
- package/skills/workflow-feedback-to-closure/SKILL.md +165 -0
- package/skills/workflow-fix-and-ship/SKILL.md +136 -0
- package/skills/workflow-git-commit/SKILL.md +200 -0
- package/skills/workflow-green-repo/SKILL.md +166 -0
- package/skills/workflow-grilling/SKILL.md +73 -0
- package/skills/workflow-gtm/SKILL.md +153 -0
- package/skills/workflow-housekeep/SKILL.md +453 -0
- package/skills/workflow-housekeep/references/templates.md +109 -0
- package/skills/workflow-launch-ready/SKILL.md +145 -0
- package/skills/workflow-merge-conflicts/SKILL.md +62 -0
- package/skills/workflow-onboard/SKILL.md +99 -0
- package/skills/workflow-parallel-agents/SKILL.md +164 -0
- package/skills/workflow-pr/SKILL.md +197 -0
- package/skills/workflow-quality-gate/SKILL.md +147 -0
- package/skills/workflow-refactor/SKILL.md +274 -0
- package/skills/workflow-release-prep/SKILL.md +207 -0
- package/skills/workflow-ship-and-observe/SKILL.md +164 -0
- package/skills/workflow-spec-tdd/SKILL.md +141 -0
- package/skills/workflow-spec-tdd/references/spec-template.md +126 -0
- package/skills/workflow-spec-tdd/references/tdd-patterns.md +167 -0
- package/skills-cursor/babysit/SKILL.md +17 -0
- package/skills-cursor/canvas/SKILL.md +142 -0
- package/skills-cursor/canvas/sdk/canvas-tokens.d.ts +235 -0
- package/skills-cursor/canvas/sdk/chart-primitives.d.ts +200 -0
- package/skills-cursor/canvas/sdk/dag-layout.d.ts +102 -0
- package/skills-cursor/canvas/sdk/diff-view.d.ts +130 -0
- package/skills-cursor/canvas/sdk/form-primitives.d.ts +194 -0
- package/skills-cursor/canvas/sdk/hooks.d.ts +117 -0
- package/skills-cursor/canvas/sdk/index.d.ts +47 -0
- package/skills-cursor/canvas/sdk/theme.d.ts +61 -0
- package/skills-cursor/canvas/sdk/todo-list.d.ts +49 -0
- package/skills-cursor/canvas/sdk/ui-primitives.d.ts +549 -0
- package/skills-cursor/canvas/sdk/ui-primitives.test.d.ts +2 -0
- package/skills-cursor/create-hook/SKILL.md +238 -0
- package/skills-cursor/create-rule/SKILL.md +185 -0
- package/skills-cursor/create-skill/SKILL.md +269 -0
- package/skills-cursor/create-skill/references/authoring-guide.md +182 -0
- package/skills-cursor/create-subagent/SKILL.md +228 -0
- package/skills-cursor/migrate-to-skills/SKILL.md +121 -0
- package/skills-cursor/shell/SKILL.md +22 -0
- package/skills-cursor/split-to-prs/SKILL.md +47 -0
- package/skills-cursor/statusline/SKILL.md +193 -0
- package/skills-cursor/update-cli-config/SKILL.md +85 -0
- package/skills-cursor/update-cursor-settings/SKILL.md +137 -0
- package/skills.sh.json +296 -0
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
### M5. `(hover: hover)` media queries copy-pasted across components
|
|
2
|
+
|
|
3
|
+
**Symptom:** Hover states on touch shells (the hover paint sticks
|
|
4
|
+
because there's no `pointerleave` after a tap on iOS WebView).
|
|
5
|
+
|
|
6
|
+
**Detection:** `rg -n '@media \(hover|hover\):not\(:active' --type css`
|
|
7
|
+
in component-scope CSS, or bare `hover:` in primitives without a
|
|
8
|
+
pointer-axis gate.
|
|
9
|
+
|
|
10
|
+
**Fix shape:** Define a single `@custom-variant can-hover` (Tailwind 4)
|
|
11
|
+
or add a `hover-only` plugin (Tailwind 3) gated on the `data-can-hover`
|
|
12
|
+
attribute, then convert primitives:
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
/* Tailwind 4 */
|
|
16
|
+
@custom-variant can-hover (&:where(html[data-can-hover="true"] *));
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
// before — paints on tap on iOS WebView
|
|
21
|
+
<button className="hover:bg-muted">…</button>
|
|
22
|
+
|
|
23
|
+
// after — only paints on devices that actually hover
|
|
24
|
+
<button className="can-hover:hover:bg-muted">…</button>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Same applies to `group-hover:opacity-100` row actions: gate behind
|
|
28
|
+
`can-hover:` and provide a tap fallback (long-press menu, always-visible
|
|
29
|
+
on coarse pointer) — see `enhance-web-ui` H7.
|
|
30
|
+
|
|
31
|
+
### M6. Capacitor split-screen / iPad landscape / fold ignored
|
|
32
|
+
|
|
33
|
+
**Symptom:** On iPad landscape, the app renders as a stretched phone:
|
|
34
|
+
bottom dock 1024 px wide, side rail missing, content max-width
|
|
35
|
+
640 px floating in the middle of a 1024 px viewport.
|
|
36
|
+
|
|
37
|
+
**Detection:** Open the app on an iPad simulator (or Chrome DevTools
|
|
38
|
+
`iPad Pro (12.9") landscape` preset). Compare the rendered chrome to
|
|
39
|
+
the desktop chrome. If they don't match (modulo platform-mode tokens),
|
|
40
|
+
form factor is being computed from `Capacitor.isNativePlatform()` and
|
|
41
|
+
not from the actual viewport.
|
|
42
|
+
|
|
43
|
+
**Fix shape:** Form factor must be computed from `matchMedia` against
|
|
44
|
+
the viewport, **not** from `isNativePlatform()`. Native is a *platform*,
|
|
45
|
+
not a *form factor*. iPad landscape is `expanded` form factor on the
|
|
46
|
+
`ios` platform — both axes apply, separately:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// the context hook
|
|
50
|
+
const compactMql = matchMedia("(max-width: 767.98px)");
|
|
51
|
+
const mediumMql = matchMedia("(min-width: 768px) and (max-width: 1023.98px)");
|
|
52
|
+
const expandedMql = matchMedia("(min-width: 1024px)");
|
|
53
|
+
|
|
54
|
+
function resolveFormFactor() {
|
|
55
|
+
if (compactMql.matches) return "compact"; // phone
|
|
56
|
+
if (mediumMql.matches) return "medium"; // small tablet, foldable folded
|
|
57
|
+
if (expandedMql.matches) return "expanded"; // iPad landscape, desktop
|
|
58
|
+
return "compact";
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The breakpoints align with Material Design 3 *Window Size Classes* and
|
|
63
|
+
match Tailwind's `md:` / `lg:` so the chrome allow-list and the context
|
|
64
|
+
hook never disagree.
|
|
65
|
+
|
|
66
|
+
### M7. SSR mismatch from form-factor switch in render
|
|
67
|
+
|
|
68
|
+
**Symptom:** Hydration warning in console; first-paint shows desktop
|
|
69
|
+
chrome for 200 ms then snaps to mobile chrome (or vice versa).
|
|
70
|
+
|
|
71
|
+
**Detection:** Open the app on a phone, view-source — what chrome is
|
|
72
|
+
in the SSR HTML? If it's wrong, your render path is reading
|
|
73
|
+
`window.matchMedia` (which doesn't exist on the server).
|
|
74
|
+
|
|
75
|
+
**Fix shape:** Two patterns, pick one:
|
|
76
|
+
|
|
77
|
+
1. **Dual-mount + CSS gate.** Always render *both* chrome variants
|
|
78
|
+
on the server; gate their visibility with `md:hidden` / `hidden md:flex`
|
|
79
|
+
so CSS resolves the visibility synchronously at first paint, no JS
|
|
80
|
+
needed. The context hook still runs for *axis tweaks* (token
|
|
81
|
+
overrides, axis-aware variants) but chrome visibility is CSS-only.
|
|
82
|
+
2. **Server-known form factor.** If your framework supports it
|
|
83
|
+
(Next.js with a `Sec-CH-UA-Platform` / `Viewport-Width` header,
|
|
84
|
+
Remix loaders, etc.), resolve the form factor server-side and write
|
|
85
|
+
`<html data-form-factor>` directly into SSR HTML. CSS reads it
|
|
86
|
+
without JS.
|
|
87
|
+
|
|
88
|
+
Either pattern eliminates the FOUC. The dual-mount + CSS gate is
|
|
89
|
+
simpler and works on any stack.
|
|
90
|
+
|
|
91
|
+
### M8. Token saturation single-tier across surfaces (see M2)
|
|
92
|
+
|
|
93
|
+
Already covered in M2 — restated here for the catalogue. The fix is
|
|
94
|
+
*per-form-factor* token overrides at the `:root[data-form-factor]`
|
|
95
|
+
selector, not per-component conditionals.
|
|
96
|
+
|
|
97
|
+
### M9. Hover-only affordance shipped to native shells
|
|
98
|
+
|
|
99
|
+
**Symptom:** A row delete button only appears on `:hover`; it ships
|
|
100
|
+
to iOS / Android WebViews where the user has no hover capability and
|
|
101
|
+
the button is invisible. Silent because users don't report features
|
|
102
|
+
they don't know exist.
|
|
103
|
+
|
|
104
|
+
**Detection:** `rg -n 'group-hover:opacity-100|opacity-0 hover:opacity-100' --type tsx`
|
|
105
|
+
inside primitives or feature components.
|
|
106
|
+
|
|
107
|
+
**Fix shape:** Same as M5 — gate hover-reveal behind `can-hover:` and
|
|
108
|
+
provide an always-visible affordance (or long-press / swipe menu) on
|
|
109
|
+
coarse-pointer devices:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// before — invisible on touch
|
|
113
|
+
<RowAction className="opacity-0 group-hover:opacity-100">…</RowAction>
|
|
114
|
+
|
|
115
|
+
// after — always visible on touch, hover-revealed on pointer
|
|
116
|
+
<RowAction className="can-hover:opacity-0 can-hover:group-hover:opacity-100 focus-within:opacity-100">…</RowAction>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### M10. Chrome dimensions hardcoded as `md:pl-[72px]` literals
|
|
120
|
+
|
|
121
|
+
**Symptom:** Side rail width changes from 72 to 80 px → 47 component
|
|
122
|
+
files need editing. Or: a feature dialog forgets to add `md:pl-[72px]`
|
|
123
|
+
and overlaps the side rail.
|
|
124
|
+
|
|
125
|
+
**Detection:** `rg -n 'md:pl-\[72px\]|md:ml-\[72px\]|pl-\[var\(--side-rail' --type tsx`.
|
|
126
|
+
If > 3 hits, the chrome dimension has leaked.
|
|
127
|
+
|
|
128
|
+
**Fix shape:** Promote the dimension to a CSS variable in your `@theme`
|
|
129
|
+
or `:root` block:
|
|
130
|
+
|
|
131
|
+
```css
|
|
132
|
+
@theme {
|
|
133
|
+
--side-rail-width: 0px; /* default; compact has no rail */
|
|
134
|
+
}
|
|
135
|
+
:root[data-form-factor="compact"] { --side-rail-width: 0px; }
|
|
136
|
+
:root[data-form-factor="medium"],
|
|
137
|
+
:root[data-form-factor="expanded"] { --side-rail-width: 72px; }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Then in app-shell, exactly one consumer:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<div className="pl-[var(--side-rail-width)]">…</div>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Resize the rail in one place; every layout follows.
|
|
147
|
+
|
|
148
|
+
### M11. Form-factor switch via `pathname.startsWith("/desktop")`
|
|
149
|
+
|
|
150
|
+
**Symptom:** Some routes look mobile, others look desktop, regardless
|
|
151
|
+
of actual viewport. Codebase has `/m/*` and `/d/*` route prefixes (or
|
|
152
|
+
similar) baked into the URL.
|
|
153
|
+
|
|
154
|
+
**Detection:** `rg -n 'pathname.*startsWith.*"/d"|pathname.*startsWith.*"/m"' --type tsx`.
|
|
155
|
+
|
|
156
|
+
**Fix shape:** Form factor is a *runtime* property of the current
|
|
157
|
+
window, not a property of the URL. Delete the URL-based branches; use
|
|
158
|
+
`useViewportContext().formFactor`. If the URL prefix exists for SEO /
|
|
159
|
+
analytics reasons, keep it but stop reading it for layout decisions.
|
|
160
|
+
|
|
161
|
+
### M12. `safe-area-inset-*` ignored or hardcoded
|
|
162
|
+
|
|
163
|
+
**Symptom:** On iPhone with the Dynamic Island, top content is hidden
|
|
164
|
+
under the status bar. Or: the bottom dock sits on top of the home
|
|
165
|
+
indicator. Or: the keyboard appears and the input scrolls off-screen.
|
|
166
|
+
|
|
167
|
+
**Detection:** Open the iOS Capacitor build, view a page with a
|
|
168
|
+
top-anchored element. Is it visible below the Dynamic Island? Then
|
|
169
|
+
view a page with the keyboard open — does the focused input remain
|
|
170
|
+
visible?
|
|
171
|
+
|
|
172
|
+
**Fix shape:** Use `env(safe-area-inset-*)` in the app shell + provide
|
|
173
|
+
fallback:
|
|
174
|
+
|
|
175
|
+
```css
|
|
176
|
+
@theme {
|
|
177
|
+
--safe-area-top: env(safe-area-inset-top, 0px);
|
|
178
|
+
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
<header style={{ paddingTop: "var(--safe-area-top)" }}>…</header>
|
|
184
|
+
<nav style={{ paddingBottom: "var(--safe-area-bottom)" }}>…</nav>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Keyboard handling: register a `Keyboard.addListener("keyboardWillShow", …)`
|
|
188
|
+
in your Capacitor init module, write a `--keyboard-height` CSS variable
|
|
189
|
+
to `<html>`, scroll the focused input into view. Capacitor 6+ ships
|
|
190
|
+
this as the `@capacitor/keyboard` plugin — wire it once in
|
|
191
|
+
`capacitor-init.ts`, not per-page.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Three-Layer Architecture (the deliverable shape)
|
|
196
|
+
|
|
197
|
+
Every cross-surface separation lands in three layers, in this order.
|
|
198
|
+
Skipping any layer is the source of the regressions catalogued above.
|
|
199
|
+
|
|
200
|
+
### Layer 1 — Context Primitive (the source of truth)
|
|
201
|
+
|
|
202
|
+
A single hook that owns axis detection. SSR-safe defaults; subscribes
|
|
203
|
+
to `matchMedia` change events; writes `<html data-*>` once on mount;
|
|
204
|
+
exposes a typed snapshot to React.
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
// hooks/use-viewport-context.ts (generic shape)
|
|
208
|
+
export type FormFactor = "compact" | "medium" | "expanded";
|
|
209
|
+
export type Platform = "web" | "ios" | "android";
|
|
210
|
+
|
|
211
|
+
export interface ViewportContext {
|
|
212
|
+
formFactor: FormFactor;
|
|
213
|
+
platform: Platform;
|
|
214
|
+
canHover: boolean;
|
|
215
|
+
isNative: boolean; // convenience: platform !== "web"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function useViewportContext(): ViewportContext;
|
|
219
|
+
export function useViewportContextEffects(): void; // mount once in app-shell
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`useViewportContext` reads the shared snapshot; `useViewportContextEffects`
|
|
223
|
+
attaches the matchMedia listeners and writes `<html data-*>`. Mount the
|
|
224
|
+
effects exactly once near the root.
|
|
225
|
+
|
|
226
|
+
### Layer 2 — Mode Tokens (CSS variables, no JSX)
|
|
227
|
+
|
|
228
|
+
Every visual difference between platforms / form factors lives as a CSS
|
|
229
|
+
variable override at the `:root[data-platform=…]` or
|
|
230
|
+
`:root[data-form-factor=…]` selector. Components consume `var(--token)`;
|
|
231
|
+
the platform / form factor decides which value paints.
|
|
232
|
+
|
|
233
|
+
```css
|
|
234
|
+
@theme {
|
|
235
|
+
--press-scale: 0.97;
|
|
236
|
+
--overlay-radius: 1.125rem;
|
|
237
|
+
--tap-highlight: transparent;
|
|
238
|
+
--side-rail-width: 0px;
|
|
239
|
+
--active-dock-height: var(--dock-height);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
:root[data-platform="ios"] { --press-scale: 0.96; --overlay-radius: 1.25rem; }
|
|
243
|
+
:root[data-platform="android"] { --press-scale: 1; --overlay-radius: 1.75rem;
|
|
244
|
+
-webkit-tap-highlight-color: rgba(0,0,0,0.08); }
|
|
245
|
+
:root[data-form-factor="compact"] { --side-rail-width: 0px; }
|
|
246
|
+
:root[data-form-factor="medium"],
|
|
247
|
+
:root[data-form-factor="expanded"] { --side-rail-width: 72px;
|
|
248
|
+
--active-dock-height: 0px; }
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Layer 3 — Axis-Aware Variants + Container-Query Primitives
|
|
252
|
+
|
|
253
|
+
Custom Tailwind variants make axis-specific styling discoverable in
|
|
254
|
+
component code without leaking the implementation:
|
|
255
|
+
|
|
256
|
+
```css
|
|
257
|
+
/* Tailwind 4 */
|
|
258
|
+
@custom-variant ff-compact (&:where(html[data-form-factor="compact"] *));
|
|
259
|
+
@custom-variant ff-medium (&:where(html[data-form-factor="medium"] *));
|
|
260
|
+
@custom-variant ff-expanded (&:where(html[data-form-factor="expanded"] *));
|
|
261
|
+
@custom-variant platform-ios (&:where(html[data-platform="ios"] *));
|
|
262
|
+
@custom-variant platform-android (&:where(html[data-platform="android"] *));
|
|
263
|
+
@custom-variant platform-native (&:where(html[data-platform="ios"] *,
|
|
264
|
+
html[data-platform="android"] *));
|
|
265
|
+
@custom-variant can-hover (&:where(html[data-can-hover="true"] *));
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Primitives become `@container` roots and use `@md:` / `@lg:`:
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
export function Card({ children, className }) {
|
|
272
|
+
return (
|
|
273
|
+
<div className={cn(
|
|
274
|
+
"@container rounded-[var(--radius-card)] p-3",
|
|
275
|
+
className,
|
|
276
|
+
)}>
|
|
277
|
+
{children}
|
|
278
|
+
</div>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
export function EditorialHero({ media, children }) {
|
|
285
|
+
return (
|
|
286
|
+
<div className={cn(
|
|
287
|
+
"grid gap-5",
|
|
288
|
+
media && "@4xl:grid-cols-[1.18fr_0.82fr] @4xl:items-center",
|
|
289
|
+
)}>
|
|
290
|
+
{children}
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
The hero now adapts to its slot. Drop it in the main column on desktop:
|
|
297
|
+
two-column. Drop it in a side panel: single-column. Drop it on mobile:
|
|
298
|
+
single-column. No viewport branch anywhere.
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Six-Step Rollout (the implementation sequence)
|
|
303
|
+
|
|
304
|
+
Apply in order. Each step is independently shippable and reversible.
|
|
305
|
+
Land step N + 1 only after step N is verified across the six-cell
|
|
306
|
+
matrix.
|
|
307
|
+
|
|
308
|
+
| # | Step | What lands | Risk | Verifies |
|
|
309
|
+
|---|------|------------|------|----------|
|
|
310
|
+
| 1 | Context primitive | `useViewportContext` + effects | low | `<html data-*>` populated at first paint |
|
|
311
|
+
| 2 | Platform mode tokens | `:root[data-platform=…]` overrides for radius / press / tap-highlight | low | iOS / Android visual differences without JS forks |
|
|
312
|
+
| 3 | Form-factor token gates + chrome dual-mount | `--side-rail-width`, `--active-dock-height`, dual-mount BottomNav/SideRail/SideNav with CSS visibility gate | low | No FOUC at first paint; iPad landscape gets the rail |
|
|
313
|
+
| 4 | Container-query primitives | Card / List / Hero / OptionCard become `@container`; convert `lg:` → `@4xl:` | medium | Same primitive in main column vs side panel renders correctly in both |
|
|
314
|
+
| 5 | Per-form-factor heuristic guide | `design-system/HEURISTICS.md` documenting the squint test per form factor + tier per surface | low (docs) | Future enhancers know which heuristic applies to which axis |
|
|
315
|
+
| 6 | Guardrail | ESLint `no-restricted-syntax` against bare `md:`/`lg:` in primitives + Cursor / AGENTS rule | low | Lint catches axis violations in PRs |
|
|
316
|
+
|
|
317
|
+
If you can only land 3 steps, land 1, 3, and 6 — context, dual-mount,
|
|
318
|
+
guardrail. The rest can come incrementally without regressions.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Squint-Test Matrix (the verification grid)
|
|
323
|
+
|
|
324
|
+
After each enhancement, view the surface at every cell. Any cell that
|
|
325
|
+
"just looks templated" is a missed axis. Mark each cell pass / fail.
|
|
326
|
+
|
|
327
|
+
| | Compact (≤640) | Medium (768–1023) | Expanded (≥1024) |
|
|
328
|
+
|--------------|----------------|-------------------|------------------|
|
|
329
|
+
| **Web** | | | |
|
|
330
|
+
| **iOS** | | (iPad portrait) | (iPad landscape) |
|
|
331
|
+
| **Android** | | (small tablet) | (large tablet / Chromebook) |
|
|
332
|
+
|
|
333
|
+
Per-cell checks:
|
|
334
|
+
|
|
335
|
+
- **Chrome** — correct nav pattern? (compact: bottom dock; medium:
|
|
336
|
+
side rail; expanded: persistent sidebar). Active state is a
|
|
337
|
+
micro-indicator, not a full-cell wash (see `enhance-web-ui` H1).
|
|
338
|
+
- **Hierarchy squint** — primary content obvious in 0.5 s? (see
|
|
339
|
+
`enhance-web-ui` § 3a)
|
|
340
|
+
- **Category squint** — color tier matches the form factor? (compact
|
|
341
|
+
vibrant for tier-A apps; expanded calmer)
|
|
342
|
+
- **Hit targets** — touch targets ≥ 44 px on coarse-pointer cells; no
|
|
343
|
+
hover-only affordances on touch
|
|
344
|
+
- **Safe area** — no content under status bar / Dynamic Island /
|
|
345
|
+
home indicator
|
|
346
|
+
- **First-paint** — no FOUC; both chrome variants ship in SSR HTML;
|
|
347
|
+
CSS resolves visibility before JS
|
|
348
|
+
|
|
349
|
+
A passed matrix is a *prerequisite* for declaring the work done — not
|
|
350
|
+
a stretch goal.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Pattern Library
|
|
355
|
+
|
|
356
|
+
### Context hook (Tailwind 4 + React 18+)
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
"use client";
|
|
360
|
+
import { useEffect, useSyncExternalStore } from "react";
|
|
361
|
+
|
|
362
|
+
export type FormFactor = "compact" | "medium" | "expanded";
|
|
363
|
+
export type Platform = "web" | "ios" | "android";
|
|
364
|
+
|
|
365
|
+
const COMPACT_QUERY = "(max-width: 767.98px)";
|
|
366
|
+
const MEDIUM_QUERY = "(min-width: 768px) and (max-width: 1023.98px)";
|
|
367
|
+
const EXPANDED_QUERY = "(min-width: 1024px)";
|
|
368
|
+
const HOVER_QUERY = "(hover: hover) and (pointer: fine)";
|
|
369
|
+
|
|
370
|
+
let snapshot: ViewportContext = {
|
|
371
|
+
formFactor: "compact",
|
|
372
|
+
platform: "web",
|
|
373
|
+
canHover: false,
|
|
374
|
+
isNative: false,
|
|
375
|
+
};
|
|
376
|
+
const subscribers = new Set<() => void>();
|
|
377
|
+
const subscribe = (fn: () => void) => { subscribers.add(fn); return () => subscribers.delete(fn); };
|
|
378
|
+
const getSnapshot = () => snapshot;
|
|
379
|
+
const getServerSnapshot = () => snapshot;
|
|
380
|
+
const emit = () => subscribers.forEach((fn) => fn());
|
|
381
|
+
|
|
382
|
+
function getPlatform(): Platform {
|
|
383
|
+
if (typeof window === "undefined") return "web";
|
|
384
|
+
// Replace with your stack's detection: Capacitor.getPlatform(), expo-constants, etc.
|
|
385
|
+
// @ts-expect-error injected by Capacitor
|
|
386
|
+
const cap = window.Capacitor?.getPlatform?.();
|
|
387
|
+
if (cap === "ios" || cap === "android") return cap;
|
|
388
|
+
return "web";
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function useViewportContext(): ViewportContext {
|
|
392
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function useViewportContextEffects(): void {
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
if (typeof window === "undefined") return;
|
|
398
|
+
const root = document.documentElement;
|
|
399
|
+
const platform = getPlatform();
|
|
400
|
+
const isNative = platform !== "web";
|
|
401
|
+
|
|
402
|
+
const compactMql = matchMedia(COMPACT_QUERY);
|
|
403
|
+
const mediumMql = matchMedia(MEDIUM_QUERY);
|
|
404
|
+
const expandedMql = matchMedia(EXPANDED_QUERY);
|
|
405
|
+
const hoverMql = matchMedia(HOVER_QUERY);
|
|
406
|
+
|
|
407
|
+
const resolveFormFactor = (): FormFactor => {
|
|
408
|
+
if (compactMql.matches) return "compact";
|
|
409
|
+
if (mediumMql.matches) return "medium";
|
|
410
|
+
if (expandedMql.matches) return "expanded";
|
|
411
|
+
return "compact";
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const update = () => {
|
|
415
|
+
const next: ViewportContext = {
|
|
416
|
+
formFactor: resolveFormFactor(),
|
|
417
|
+
platform,
|
|
418
|
+
canHover: hoverMql.matches,
|
|
419
|
+
isNative,
|
|
420
|
+
};
|
|
421
|
+
if (
|
|
422
|
+
next.formFactor === snapshot.formFactor &&
|
|
423
|
+
next.platform === snapshot.platform &&
|
|
424
|
+
next.canHover === snapshot.canHover &&
|
|
425
|
+
next.isNative === snapshot.isNative
|
|
426
|
+
) return;
|
|
427
|
+
snapshot = next;
|
|
428
|
+
root.dataset.formFactor = next.formFactor;
|
|
429
|
+
root.dataset.platform = next.platform;
|
|
430
|
+
root.dataset.canHover = next.canHover ? "true" : "false";
|
|
431
|
+
emit();
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
update();
|
|
435
|
+
[compactMql, mediumMql, expandedMql, hoverMql].forEach(m =>
|
|
436
|
+
m.addEventListener("change", update));
|
|
437
|
+
return () => {
|
|
438
|
+
[compactMql, mediumMql, expandedMql, hoverMql].forEach(m =>
|
|
439
|
+
m.removeEventListener("change", update));
|
|
440
|
+
};
|
|
441
|
+
}, []);
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Platform mode tokens (CSS variables only)
|
|
446
|
+
|
|
447
|
+
See M3 fix shape above. Default tokens in `@theme`; overrides per
|
|
448
|
+
`:root[data-platform=…]` block. Components reference `var(--token)`;
|
|
449
|
+
zero JSX branches.
|
|
450
|
+
|
|
451
|
+
### Form-factor token gates + chrome dual-mount
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
// app-shell.tsx
|
|
455
|
+
export function AppShell({ children }: PropsWithChildren) {
|
|
456
|
+
useViewportContextEffects();
|
|
457
|
+
return (
|
|
458
|
+
<div className="min-h-dvh">
|
|
459
|
+
{/* Both chrome variants ship in SSR; CSS gate resolves at first paint */}
|
|
460
|
+
<DesktopSideNav className="hidden md:flex" />
|
|
461
|
+
<main className="md:pl-[var(--side-rail-width)]">{children}</main>
|
|
462
|
+
<BottomNav className="md:hidden" />
|
|
463
|
+
</div>
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Container-query primitive
|
|
469
|
+
|
|
470
|
+
See *Layer 3* above — `@container` on the root, `@md:` / `@lg:` /
|
|
471
|
+
`@4xl:` for slot-aware micro-layout. Pick the threshold by the slot's
|
|
472
|
+
typical width, not the viewport.
|
|
473
|
+
|
|
474
|
+
### Per-form-factor heuristic guide (`design-system/HEURISTICS.md`)
|
|
475
|
+
|
|
476
|
+
A short markdown file the team treats as canon. Sections:
|
|
477
|
+
|
|
478
|
+
- **Compact form factor** — vibrant tier, bottom dock, thumb targets,
|
|
479
|
+
one-handed reach map, full-bleed media, sheet over popover, haptics on.
|
|
480
|
+
- **Medium form factor** — side rail, two-pane where it adds clarity,
|
|
481
|
+
hover affordances allowed only with `can-hover:`, sheet remains
|
|
482
|
+
default for transient surfaces.
|
|
483
|
+
- **Expanded form factor** — persistent sidebar, hover-reveal allowed,
|
|
484
|
+
popover preferred over sheet, calmer tier, denser data tables ok,
|
|
485
|
+
keyboard shortcuts surfaced.
|
|
486
|
+
- **Platform iOS** — overlay radius `1.25rem`, press-scale `0.96`,
|
|
487
|
+
no tap-highlight, system font fallback `-apple-system`.
|
|
488
|
+
- **Platform Android** — overlay radius `1.75rem` (M3 corner-XL),
|
|
489
|
+
ripple via `-webkit-tap-highlight-color`, no press-scale, Roboto
|
|
490
|
+
fallback.
|
|
491
|
+
- **Squint-test protocol** — six-cell matrix, what to look for per cell,
|
|
492
|
+
what counts as pass.
|
|
493
|
+
- **Adoption checklist** — "before adding a new primitive, can it use
|
|
494
|
+
`@container`? Before adding `lg:` to a primitive, are you sure
|
|
495
|
+
it's chrome?".
|
|
496
|
+
|
|
497
|
+
Keep it under 250 lines. The file's value is being read, not being
|
|
498
|
+
exhaustive.
|
|
499
|
+
|
|
500
|
+
### Guardrail (ESLint `no-restricted-syntax` + Cursor rule)
|
|
501
|
+
|
|
502
|
+
```js
|
|
503
|
+
// eslint.config.mjs
|
|
504
|
+
{
|
|
505
|
+
files: ["design-system/primitives/**", "features/**/components/**"],
|
|
506
|
+
rules: {
|
|
507
|
+
"no-restricted-syntax": ["warn",
|
|
508
|
+
{
|
|
509
|
+
selector: "Literal[value=/(?:^|\\s)(?:md|lg|xl|2xl):/]",
|
|
510
|
+
message: "Bare md:/lg:/xl:/2xl: viewport prefixes are reserved for app-level chrome (app-shell, bottom-nav, side-rail, desktop-side-nav). Primitives must adapt to their slot, not the viewport — use @md:/@lg:/@xl: (container query) for component micro-layout, ff-medium:/ff-expanded: for form-factor decisions, or platform-ios:/platform-android:/can-hover: for axis-specific behaviour. See design-system/HEURISTICS.md.",
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
selector: "TemplateElement[value.raw=/(?:^|\\s)(?:md|lg|xl|2xl):/]",
|
|
514
|
+
message: "Bare md:/lg:/xl:/2xl: viewport prefixes are reserved for app-level chrome — see design-system/HEURISTICS.md.",
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
```mdc
|
|
522
|
+
---
|
|
523
|
+
description: Responsive design uses three orthogonal axes — viewport prefixes (md:/lg:) reserved for chrome.
|
|
524
|
+
globs: ["design-system/**", "features/**/components/**", "components/**"]
|
|
525
|
+
alwaysApply: true
|
|
526
|
+
---
|
|
527
|
+
# Responsive Design Axes
|
|
528
|
+
|
|
529
|
+
Use the right axis for the right question:
|
|
530
|
+
|
|
531
|
+
- **Container queries (`@md:`/`@lg:`/`@4xl:`)** — component micro-layout. The
|
|
532
|
+
primitive doesn't know the viewport; it knows its slot.
|
|
533
|
+
- **Form-factor variants (`ff-compact:`/`ff-medium:`/`ff-expanded:`)** — when
|
|
534
|
+
the design heuristic genuinely depends on form factor, not slot width.
|
|
535
|
+
- **Platform variants (`platform-ios:`/`platform-android:`)** — visual
|
|
536
|
+
differences mandated by OS guidelines (radius, press, tap-highlight).
|
|
537
|
+
- **Pointer variants (`can-hover:`)** — hover affordances only.
|
|
538
|
+
- **Bare viewport prefixes (`md:`/`lg:`)** — only in the chrome allow-list:
|
|
539
|
+
`app-shell`, `bottom-nav`, `side-rail`, `desktop-side-nav`, `app/layout.tsx`.
|
|
540
|
+
|
|
541
|
+
See design-system/HEURISTICS.md for the squint-test protocol and per-axis
|
|
542
|
+
adoption checklist.
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Implementation Rules
|
|
548
|
+
|
|
549
|
+
1. **Detect axes once, write `<html data-*>`, never branch in JSX.** Every
|
|
550
|
+
per-platform / per-form-factor / per-pointer JSX branch is a bug
|
|
551
|
+
waiting to fork.
|
|
552
|
+
2. **Tokens are the contract; primitives are the consumer.** A primitive
|
|
553
|
+
that hardcodes `rounded-2xl` for iOS and `rounded-md` for Android is
|
|
554
|
+
broken; it should render `rounded-[var(--radius-card)]` and let the
|
|
555
|
+
token decide.
|
|
556
|
+
3. **Container queries for slot, viewport queries for chrome.** Memorise
|
|
557
|
+
this. Every other rule follows from it.
|
|
558
|
+
4. **Dual-mount chrome on the server, gate visibility with CSS.** Avoids
|
|
559
|
+
FOUC; works without JS; passes hydration checks on every framework.
|
|
560
|
+
5. **SSR-safe defaults at every boundary.** Default `formFactor:
|
|
561
|
+
"compact"`, `platform: "web"`, `canHover: false` — the most
|
|
562
|
+
restrictive answer in each axis. The client snaps to the actual
|
|
563
|
+
value once mounted.
|
|
564
|
+
6. **No new colour / radius / spacing values invented.** Add a token to
|
|
565
|
+
`@theme`, override per `:root[data-…]`, consume `var(--token)`.
|
|
566
|
+
7. **Test on a real native shell, not just Chrome DevTools toggle.**
|
|
567
|
+
The differences between Chrome's "iPhone 14 Pro" preset and an
|
|
568
|
+
actual iOS WebView (font rendering, scroll inertia, tap-highlight,
|
|
569
|
+
safe area) are exactly the bugs this skill prevents.
|
|
570
|
+
8. **Run the six-cell matrix before declaring done.** Three viewports
|
|
571
|
+
× at least PWA + one native shell. Five cells passing is not done.
|
|
572
|
+
9. **Patch the primitive, not the call site.** Same rule as
|
|
573
|
+
`enhance-web-ui` *Primitive-First Patch Rule* — if a `lg:` shows up
|
|
574
|
+
in three feature components, the bug is that the underlying
|
|
575
|
+
primitive isn't a `@container`.
|
|
576
|
+
10. **Document the why of every axis decision.** A comment on the
|
|
577
|
+
`data-platform="ios"` block saying "iOS overlay radius is `1.25rem`
|
|
578
|
+
per HIG, vs Android M3 `corner-extra-large` `1.75rem`" prevents the
|
|
579
|
+
next enhancer from "harmonising" the values back to a single
|
|
580
|
+
radius and breaking both platforms.
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Quick Sanity Checks Before You Stop
|
|
585
|
+
|
|
586
|
+
- [ ] **Source of truth**: a single `useViewportContext()` (or equivalent)
|
|
587
|
+
hook owns all three axes; no `useMatchMedia` / `getPlatform()`
|
|
588
|
+
branches scattered in components.
|
|
589
|
+
- [ ] **`<html data-*>` populated at first paint** in every shell
|
|
590
|
+
(PWA, iOS WebView, Android WebView). No `(not set)` cells.
|
|
591
|
+
- [ ] **Chrome allow-list enforced**: `md:`/`lg:` only in app-shell,
|
|
592
|
+
bottom-nav, side-rail, desktop-side-nav, layout root. ESLint rule
|
|
593
|
+
catches new violations.
|
|
594
|
+
- [ ] **Container queries on primitives**: every reused card / list
|
|
595
|
+
row / hero / option-card declares `@container` and uses `@md:` /
|
|
596
|
+
`@lg:` / `@4xl:` for internal layout. Drop a primitive in a 320 px
|
|
597
|
+
side panel on a 1920 px monitor → it looks like the compact
|
|
598
|
+
variant, not the desktop variant.
|
|
599
|
+
- [ ] **Mode tokens for platform differences**: every `if (platform === …)`
|
|
600
|
+
JSX branch replaced by a CSS variable defaulted in `@theme` and
|
|
601
|
+
overridden in `:root[data-platform=…]`.
|
|
602
|
+
- [ ] **Mode tokens for form-factor chrome**: `--side-rail-width`,
|
|
603
|
+
`--active-dock-height` (and any other chrome dimension) live as
|
|
604
|
+
CSS variables, gated per `:root[data-form-factor=…]`. No
|
|
605
|
+
`md:pl-[72px]` literal duplicated across files.
|
|
606
|
+
- [ ] **Hover gated on `can-hover:`**: no bare `hover:` paint or
|
|
607
|
+
`group-hover:opacity-100` row action that ships to native shells
|
|
608
|
+
without a touch fallback.
|
|
609
|
+
- [ ] **Safe area handled**: `env(safe-area-inset-*)` consumed in app
|
|
610
|
+
shell; no content under Dynamic Island or home indicator on iOS.
|
|
611
|
+
- [ ] **Dual-mount chrome with CSS gate**: both `BottomNav` and
|
|
612
|
+
`DesktopSideNav` render in SSR HTML; visibility resolved by
|
|
613
|
+
`md:hidden` / `hidden md:flex`, not by JS. No FOUC.
|
|
614
|
+
- [ ] **Per-form-factor tier documented**: `design-system/HEURISTICS.md`
|
|
615
|
+
names the saturation tier per form factor (e.g. compact = tier-A
|
|
616
|
+
vibrant, expanded = tier-C calm) and per platform.
|
|
617
|
+
- [ ] **Six-cell matrix passed**: 3 form factors × at least PWA + iOS
|
|
618
|
+
WebView + Android WebView. Each cell screenshot reviewed with
|
|
619
|
+
the squint test from `enhance-web-ui` § 3a.
|
|
620
|
+
- [ ] **Guardrail in place**: ESLint `no-restricted-syntax` + Cursor /
|
|
621
|
+
AGENTS rule (`responsive-design-axes.mdc`) live in the repo so
|
|
622
|
+
the next enhancer can't reintroduce axis conflation.
|
|
623
|
+
|
|
624
|
+
### Cross-surface failure-mode audit (the difficult-to-spot ones)
|
|
625
|
+
- [ ] **M1 axis conflation**: every `useIsMobile` call site re-examined;
|
|
626
|
+
replaced with explicit form-factor / platform / pointer answers.
|
|
627
|
+
- [ ] **M2 single-tier across surfaces**: per-form-factor tier explicitly
|
|
628
|
+
chosen and documented; no tier-D `/8` tints painting a tier-A
|
|
629
|
+
consumer surface on compact.
|
|
630
|
+
- [ ] **M3 platform JSX forks**: zero `if (platform === "ios")` JSX
|
|
631
|
+
branches outside the context hook itself.
|
|
632
|
+
- [ ] **M4 viewport-coupled primitives**: zero bare `md:`/`lg:` inside
|
|
633
|
+
`design-system/primitives/**`.
|
|
634
|
+
- [ ] **M5 ungated hover**: zero bare `hover:` in primitives without
|
|
635
|
+
`can-hover:` gate (or always-visible touch fallback).
|
|
636
|
+
- [ ] **M6 iPad landscape ignored**: form factor on iPad landscape =
|
|
637
|
+
`expanded`; side rail / sidebar render as on desktop.
|
|
638
|
+
- [ ] **M7 SSR mismatch**: view-source on a phone returns the right
|
|
639
|
+
chrome HTML; no React hydration warnings for axis-related markup.
|
|
640
|
+
- [ ] **M9 hover-only on native**: every `group-hover:` / `opacity-0
|
|
641
|
+
hover:opacity-100` has either `can-hover:` gate or always-visible
|
|
642
|
+
touch fallback.
|
|
643
|
+
- [ ] **M10 chrome literals**: zero `md:pl-[72px]` literal duplicated;
|
|
644
|
+
single `var(--side-rail-width)` token consumed everywhere.
|
|
645
|
+
- [ ] **M11 URL-coupled form factor**: zero
|
|
646
|
+
`pathname.startsWith("/desktop")` reads for layout decisions.
|
|
647
|
+
- [ ] **M12 safe area + keyboard**: top / bottom safe-area insets
|
|
648
|
+
consumed; keyboard plugin wired in capacitor-init.
|
|
649
|
+
|
|
650
|
+
### Repo health
|
|
651
|
+
- [ ] Lint passes on every modified file
|
|
652
|
+
- [ ] Six-cell matrix screenshots show no FOUC, no overlap, no wrap,
|
|
653
|
+
no platform-mode mismatch
|
|
654
|
+
- [ ] `HEURISTICS.md` updated; `responsive-design-axes.mdc` rule lives
|
|
655
|
+
in `.cursor/rules/` (or `AGENTS.md` for non-Cursor projects)
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## When Not To Use This Skill
|
|
660
|
+
|
|
661
|
+
- Single-surface visual polish (web only or iOS only) → use
|
|
662
|
+
`enhance-web-ui` directly; this skill is the *prerequisite
|
|
663
|
+
architecture* but isn't needed if you only ship one surface.
|
|
664
|
+
- Pure heuristic audit (no code changes) → use `audit-uiux-design-system`
|
|
665
|
+
or `audit-ux`.
|
|
666
|
+
- Brand-new app from scratch → use `design-frontend` and *bake the
|
|
667
|
+
three-axis architecture in from day one* — this skill catalogues the
|
|
668
|
+
remediation path, not the greenfield design.
|
|
669
|
+
- React Native / pure native (no web shell) → the axis taxonomy still
|
|
670
|
+
applies but the implementation layer (CSS variables, container
|
|
671
|
+
queries) doesn't; use a stack-native equivalent (NativeWind tokens,
|
|
672
|
+
Reanimated, etc.).
|
|
673
|
+
- Pure backend / data-correctness work → out of scope.
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## Companion / Sibling Skills
|
|
678
|
+
|
|
679
|
+
- [`enhance-web-ui`](../../enhance-web-ui/SKILL.md) — single-surface
|
|
680
|
+
artistic / composition skill. Read after this one when you're polishing
|
|
681
|
+
*one cell* of the matrix; the H1–H16 hidden failure modes there
|
|
682
|
+
catalogue *within-surface* bugs (active-state mass, chrome tautology,
|
|
683
|
+
brand-color competition, wrapper-collapsed tiles, etc.) that this
|
|
684
|
+
skill assumes are handled separately per surface.
|
|
685
|
+
- [`enhance-web-ux`](../../enhance-web-ux/SKILL.md) — task-flow / data-
|
|
686
|
+
correctness companion. Use *before* this skill to fix the *what*
|
|
687
|
+
(pain → heuristic → primitive); use *this* skill to make the *how*
|
|
688
|
+
(per surface) safe.
|
|
689
|
+
- [`audit-uiux-design-system`](../../audit-uiux-design-system/SKILL.md) —
|
|
690
|
+
pure-audit companion. Run after the six-step rollout to verify
|
|
691
|
+
no design-token drift was introduced.
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
## Research Anchors
|
|
696
|
+
|
|
697
|
+
- **Material Design 3 — Window Size Classes** — canonical breakpoints
|
|
698
|
+
for compact (≤600 dp) / medium (600–840 dp) / expanded (≥840 dp)
|
|
699
|
+
form factors and the navigation pattern (bottom bar / nav rail /
|
|
700
|
+
nav drawer) that maps to each. Aligned with Tailwind's `md:`/`lg:`
|
|
701
|
+
and the breakpoints used in *Layer 1*.
|
|
702
|
+
<https://m3.material.io/foundations/layout/applying-layout/window-size-classes>
|
|
703
|
+
- **Material Design 3 — NavigationBar / NavigationRail / NavigationDrawer** —
|
|
704
|
+
per-form-factor navigation pattern; spec for active-indicator pill
|
|
705
|
+
(32×16 wrapping the icon) referenced in `enhance-web-ui` H1.
|
|
706
|
+
<https://m3.material.io/components/navigation-bar/overview>
|
|
707
|
+
<https://m3.material.io/components/navigation-rail/overview>
|
|
708
|
+
- **Apple Human Interface Guidelines — Adaptive Layouts** — iOS form
|
|
709
|
+
factor heuristics; reference for safe-area math, sheet vs popover,
|
|
710
|
+
multitasking / split-view behaviour on iPad.
|
|
711
|
+
<https://developer.apple.com/design/human-interface-guidelines/layout>
|
|
712
|
+
- **Ionic — Modes** — canonical "platform tokens, not platform JSX"
|
|
713
|
+
pattern. Ionic ships separate iOS-mode and Android-mode CSS variable
|
|
714
|
+
sets; components consume the variable. Reference for *Layer 2* and
|
|
715
|
+
Hidden Failure Mode M3.
|
|
716
|
+
<https://ionicframework.com/docs/theming/platform-styles>
|
|
717
|
+
- **Konsta UI — Mobile-first React with iOS / Material Design themes** —
|
|
718
|
+
React-native rendering of the Ionic mode pattern; useful as a
|
|
719
|
+
reference implementation when Ionic itself is too heavy.
|
|
720
|
+
<https://konstaui.com/react/>
|
|
721
|
+
- **Tailwind CSS 4 — Container Queries** — built-in `@container` /
|
|
722
|
+
`@md:` / `@lg:` utilities (no plugin needed in v4). Reference for
|
|
723
|
+
*Layer 3* and Hidden Failure Mode M4.
|
|
724
|
+
<https://tailwindcss.com/docs/responsive-design#container-queries>
|
|
725
|
+
- **MDN — `@media (hover)` and `@media (pointer)`** — pointer-axis
|
|
726
|
+
detection. Reference for *Pointer capability* axis and the
|
|
727
|
+
`can-hover:` variant.
|
|
728
|
+
<https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover>
|
|
729
|
+
<https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer>
|
|
730
|
+
- **MDN — `env(safe-area-inset-*)` + `viewport-fit=cover`** — canonical
|
|
731
|
+
safe-area handling on iOS / Android WebViews. Reference for Hidden
|
|
732
|
+
Failure Mode M12.
|
|
733
|
+
<https://developer.mozilla.org/en-US/docs/Web/CSS/env>
|
|
734
|
+
- **Capacitor — Plugins / Keyboard / StatusBar / SafeArea** — runtime
|
|
735
|
+
primitives for native-shell wiring. Reference for capacitor-init
|
|
736
|
+
patterns mentioned in Hidden Failure Mode M12.
|
|
737
|
+
<https://capacitorjs.com/docs/plugins>
|
|
738
|
+
- **Sec-CH-UA-Form-Factors / Sec-CH-UA-Platform** — Client Hints headers
|
|
739
|
+
that allow server-side form-factor / platform resolution; reference
|
|
740
|
+
for Hidden Failure Mode M7 fix shape #2.
|
|
741
|
+
<https://wicg.github.io/client-hints-infrastructure/>
|
|
742
|
+
- **Linear — A calmer interface for a product in motion (2025)** —
|
|
743
|
+
reference for chrome-as-recess across form factors; same principle
|
|
744
|
+
applies whether the chrome is a desktop sidebar or a mobile dock.
|
|
745
|
+
<https://linear.app/now/behind-the-latest-design-refresh>
|
|
746
|
+
- **NN/g — Responsive Design and Adaptive Design** — distinguishes
|
|
747
|
+
responsive (one layout that flexes) from adaptive (different layouts
|
|
748
|
+
per breakpoint); this skill argues hybrid apps need *adaptive* chrome
|
|
749
|
+
+ *responsive* content, with axes orthogonal.
|
|
750
|
+
<https://www.nngroup.com/articles/responsive-design/>
|