Files
claude_mac/lib/design-gate.md
T
bastien ba14b5ea03 feat(skills): site-motion, site-level scroll and transition choreography
Personal skill distilling the MengTo motion pack invariants (LRN-141):
gates first (reduced motion renders final states, content visible without
JS, compositor-only, offscreen pause), one smooth-scroll engine with the
Lenis/ScrollTrigger sync, Astro ClientRouter lifecycle, numbered recipes
(reveal, scrub, sticky stack, video and image scrub, TreeWalker split,
progressive blur, marquee, WebGL budgets), upstream pitfalls, checklist.
Routed into the Build UI chain of CLAUDE.global.md and lib/design-gate.md.
2026-09-28 01:40:01 +02:00

10 KiB

DESIGN GATE — Auto-detect design tasks, ensure the design toolchain is active

Inline snippet. Include in any agent STEP 0 that may touch UI/design.

WHEN TO RUN

Run this gate when the task description OR target files match design signals.

DETECTION

Check BOTH the task description AND the filesystem:

Task description signals (case-insensitive match on $ARGUMENTS):

  • UI keywords: component, button, card, modal, dialog, tooltip, dropdown, sidebar, navbar, header, footer, layout, grid, form, input, table
  • Style keywords: css, style, theme, color, font, spacing, margin, padding, border, shadow, animation, transition, hover, motion, animate, responsive, dark mode, light mode
  • Design keywords: design, ui, ux, visual, polish, pixel, figma, mockup, wireframe, prototype
  • Framework UI: tailwind, styled-component, emotion, chakra, radix, shadcn, headless

Filesystem signals (quick check, no deep scan):

  • Target files have .tsx, .jsx, .vue, .svelte, .astro, .css, .scss, .less, or .module.css extension
  • tailwind.config or postcss.config present in project root
  • tokens/, theme/, or design-system/ directory exists
  • Storybook config (.storybook/) present
  • Animation lib in package.json deps: any package is_anim_lib_installed recognizes (lib/animation-lib-check.sh, the single source)

DECISION

Source of truth for activation is the profile system — never an atomic per-tool toggle. The gate's whole job: confirm the design toolchain is active, and if not, point at ONE command — /profile design.

1. Tier — does the gate even apply?

  • Trivial (≤2 files, single cosmetic value, one CSS tweak — same scope as /hotfix) → no design tools required. Skip the gate, proceed.
  • Build UI / design system / review-audit → toolchain required, continue.
  • In doubt (trivial tweak vs real UI change) → do NOT silently skip: ask the user, or default to the Build tier.

Tier does NOT change WHAT gets checked. Every non-trivial design tier draws from the one design profile — so the gate checks that profile's design-core tools (the # GATE-BLOCK: allowlist in design.profile: ui-ux-pro-max, frontend-design, emil-design-eng, design-motion-principles, design-html, design-review, design-consultation, the 21st CLI and 21st-ui-build — the canary for the whole 21st skill pack). The profile also bundles browser/plan/shotgun tooling and graphify for convenience; those never trip the gate. Motion (design-motion-principles) and static-HTML (design-html) are already in the core set — checked regardless; their CLAUDE.md "+motion / +static" notes say which tool you'll lean on, not a separate activation step. site-motion (personal skill, site-level scroll/page choreography) rides the same Build chain but isn't on the GATE-BLOCK list: it ships with the repo, nothing to install or verify.

2. State — run the deterministic check

bash "$HOME/.claude/lib/design-tool-gate.sh"

It reads the design-core tools (# GATE-BLOCK: in design.profile) plus their types (profile.sh show design --plain) and checks each on its own channel — skill symlink, claude plugin list, claude mcp list, command -v. It never reads disabledMcpServers (unreliable for bi-modal servers like context7). The core set lives in design.profile, not in the script or here — single source.

Exit codes: 0 = ready · 11 = ready-but-unverified (proceed, but surface it) · 10 = incomplete (gate trips) · 2 = error.

3. Branch on the result

  • 0 / READY → proceed silently. Toolchain is active.

  • 10 / INCOMPLETE → STOP. The script reports up to three groups; relay them and the remedy to the user:

    🎨 DESIGN DETECTED — the design toolchain isn't fully active.
    activate with /profile design:        <skills / ui-ux-pro-max>
    required + manual step:                <e.g. 21st — needs the CLI>
    → run  /profile design  to activate it, then continue.
    
    • activate with /profile design → skills + the plugin; /profile design turns them on directly.
    • required + manual step → required tools the profile can't flip silently. the 21st CLI lands here: it TRIPS the gate (it's required for Build), it is NOT a silent "optional". /profile design symlinks the 21st skills, but the CLI they shell out to is a global npm install: tell the user to run npm i -g @21st-dev/cli then 21st login (no API key, no MCP).
    • Do NOT hand-activate individual tools. The profile is the unit of activation.
  • 11 / READY BUT UNVERIFIED → claude was unreachable, so the design plugin (ui-ux-pro-max) could NOT be checked. Do NOT report a plain "ready": proceed only after telling the user that N tool(s) went unverified and having them confirm with claude plugin list. Fail-visible, not fail-silent.

4. Animation library — suggest-only (fires only on a real motion signal)

Orthogonal to the toolchain check above: §2-3 are about Claude's design TOOLS; this is about the PROJECT's runtime dep. Evaluate it only once the toolchain is resolved and you're actually proceeding with the build (READY, or after the user ran /profile design). Never on the INCOMPLETE stop path — that path has one action only (/profile design); don't stack an optional note on it.

Fires only when ALL THREE hold — drop any one → no suggestion, stay silent:

  1. Motion signal — the task matched a motion keyword from §DETECTION: animation, transition, hover, motion, or animate. A static button / card / layout with no motion signal needs no anim lib → skip.
  2. Stack eligible — detect_anim_eligibility returns eligible|….
  3. No anim lib yet — is_anim_lib_installed finds none.

Only if condition 1 holds, run the helper for 2 and 3 — do NOT re-list packages here; the helper's is_anim_lib_installed is the single source of which libs count:

source "$HOME/.claude/lib/animation-lib-check.sh"
result=$(detect_anim_eligibility)            # '<status>|<package>|<reason>'
status=$(echo "$result" | cut -d'|' -f1)
pkg=$(echo "$result"    | cut -d'|' -f2)
reason=$(echo "$result" | cut -d'|' -f3)
if [ "$status" = "eligible" ] && ! is_anim_lib_installed >/dev/null; then
  cmd=$(recommend_anim_install_cmd "$pkg")   # pnpm/yarn/bun/npm per lockfile
  # → surface the one-line suggestion below. Do NOT run $cmd.
fi

Surface — always this single line (non-blocking, suggest-only):

🎬 Stack motion-eligible (<reason>), no anim lib — `<cmd>`? (optional; say the word, I'll add it)

Rules:

  • Suggest-only, never auto-install. Run <cmd> ONLY on explicit user consent. BDR-005: mid-session + existing package.json = consent required — same contract as /onboard STEP 2.5, opposite of /init-project STEP 5e (auto-install on a just-validated fresh scaffold).
  • Non-blocking. Never halts the build; NOT a second gate. The toolchain stop (§3, exit 10) is the only STOP. Surface the line, keep going.
  • Stateless dedup, by construction. The suggestion is ALWAYS the single line above — no first-time-block / later-short split. That split would need session state the gate doesn't have, and a file marker would persist forever (per project, not per session). Determinism here comes from having nothing to remember, not from a behavioral "the agent recalls it" guard. Re-fire is one ignorable line, on a narrow population: condition 3 (is_anim_lib_installed, 10 libs incl gsap / react-spring / lottie) kills it the instant any anim lib lands, so only "eligible + pure-CSS + actively declined" ever sees it twice.
  • Two "motion"s (agent-facing). The lib motion (npm dep, this step) ≠ the skill design-motion-principles (# GATE-BLOCK: core set, §2-3). The toolchain check handles the skill; this step handles the lib. Don't conflate them when talking to the user.

5. Impeccable design context — suggest-only (one check, one line)

Same class as §4: a PROJECT-side prerequisite, not a tool. impeccable installs globally, but every one of its verbs reads a per-project PRODUCT.md that only /impeccable init writes. Without it the skill runs on invented context, which is worse than not running it — and nothing else in the process says so, because init has to happen in the agent chat, not in an installer.

Fires when BOTH hold — else stay silent:

  1. impeccable symlink present under skills/ (non-blocking external — not on the # GATE-BLOCK: list, so §3 never checks it).
  2. The project has no PRODUCT.md at its root.

Evaluate it on the same path as §4: after the toolchain resolves, never on the INCOMPLETE stop path. One line, non-blocking:

🧭 impeccable has no project context here (no PRODUCT.md) — run `/impeccable init` first? (optional)

Rules:

  • Non-blocking, and never run init unprompted: it interviews the user about the product, so it needs their attention, not their absence.
  • One line per session at most. A refusal is an answer; do not re-ask inside the same task.
  • Skip entirely for a review/audit of a single component and for any non-UI work. This is for Build and design-system tiers.

Other toolchains

The script defaults to the design profile. A task needing another profile's toolchain passes it: design-tool-gate.sh <profile>. Scope comes from that profile's # GATE-BLOCK: line (absent → every skill/plugin/mcp entry). The remedy is always /profile <that> — a profile, never a lone tool.

IMPORTANT

  • Remedy is ALWAYS a profile (/profile design), never an atomic tool toggle — the profile system is the single source of truth for what's active.
  • the 21st CLI is REQUIRED (it trips the gate) and /profile design cannot install it — the gate names the two commands; surface them to the user.
  • The design-core set (what trips the gate) is declared in design.profile on the # GATE-BLOCK: line(s) — edit there to add/remove a blocking design tool, not in the script.
  • The state check shells out to claude (plugin/mcp list): a few seconds. Trivial / non-design tasks skip it entirely (no signal, or trivial tier).
  • design-tool-gate.sh's per-type state checks MIRROR profile.sh:skill_status() — change one, sync the other.
  • Do NOT run this gate on pure backend/API/CLI tasks (no signals = no gate).