feat(animation): auto-install motion lib + detection across init/onboard/advisor
Add lib/animation-lib-check.sh with detect_anim_eligibility, is_anim_lib_installed and recommend_anim_install_cmd helpers. Wire it into the framework: - init-project STEP 5e: silent auto-install after scaffold validated - onboard STEP 2.5: propose + wait for user confirmation (opt-in on existing projects) - plugin-advisor PHASE 1/2/3: read-only detection only, never installs - scaffolder PHASE 4: clarifies boundary (orchestrator owns motion install) - design-gate filesystem signals: motion / motion-v / framer-motion / gsap / lottie-react / react-spring / popmotion / auto-animate Recommends `motion` (rebranded from framer-motion in Nov 2024) for React-family and Svelte stacks, `motion-v` for Vue 3 / Nuxt. Excludes React Native (use react-native-reanimated), backend, embedded, Flutter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d513ea39a0
commit
f80f83ee77
@ -68,6 +68,27 @@ Subtasks :
|
||||
- [x] Mettre à jour `skills/seo/SKILL.md` — cross-ref /validate pour W3C/WCAG
|
||||
- [x] Grep cohérence : refs /validate correctes, skill détecté par la harness
|
||||
|
||||
## Animation lib (`motion`) — install + détection
|
||||
|
||||
Problème : `motion` (ex-`framer-motion`, rebrandé nov 2024) n'est ni installé par les scripts ni détecté par plugin-advisor / design-gate. Ajouter détection + install conditionnel.
|
||||
|
||||
Décisions :
|
||||
- **Package** : `motion` (npm `motion`, import `motion/react`). `motion-v` pour Vue 3 (package séparé). Svelte/vanilla → `motion`.
|
||||
- **Éligibilité** : tout projet qui peut consommer l'API. ✅ React/Next/Remix/Astro+React, Vue3/Nuxt, Svelte. ❌ Backend, CLI, embedded, Flutter, WordPress/Drupal/Strapi, RN (réservé `react-native-reanimated`).
|
||||
- **init-project** STEP 5 : auto-install si éligible + absent (l'utilisateur a déjà validé scaffold).
|
||||
- **onboard** STEP 2.5 : propose + attendre OK (projet existant, opt-in).
|
||||
- **plugin-advisor** : read-only — détecte + reporte ("✅ motion installed" ou "ℹ️ eligible but absent — run /onboard").
|
||||
- **design-gate** : ajouter motion/motion-v/framer-motion (legacy) dans filesystem signals.
|
||||
|
||||
Subtasks :
|
||||
- [x] Créer `lib/animation-lib-check.sh` — fonctions `detect_anim_eligibility()` + `is_anim_lib_installed()` + `recommend_anim_install_cmd()`
|
||||
- [x] Patcher `agents/scaffolder.md` PHASE 4 — note (le scaffolder n'installe PAS, l'orchestrateur init-project STEP 5e gère)
|
||||
- [x] Patcher `skills/init-project/SKILL.md` — STEP 5e ANIMATION LIB (auto-install si éligible)
|
||||
- [x] Patcher `skills/onboard/SKILL.md` — STEP 2.5 ANIMATION LIB (propose + attendre yes/skip)
|
||||
- [x] Patcher `agents/plugin-advisor.md` PHASE 1 (sourcing du helper) + PHASE 2 (signaux `anim-lib-eligible`/`anim-lib-installed`) + PHASE 3 (section ANIMATION LIB read-only)
|
||||
- [x] Patcher `lib/design-gate.md` — ajouter motion/motion-v/framer-motion + autres anim-libs dans filesystem signals
|
||||
- [x] Tester : shellcheck OK ; matrix React/Vue/RN/backend/with-motion/no-package/pnpm tous corrects
|
||||
|
||||
## Helper `--help` / `help` sur tous les skills (option C)
|
||||
Problème : aucun skill ne gère `--help` aujourd'hui. `argument-hint` affiche juste la syntaxe en autocomplétion, pas de description/exemples. L'utilisateur doit lire le SKILL.md ou deviner.
|
||||
|
||||
|
||||
@ -35,6 +35,13 @@ ls package.json pyproject.toml Cargo.toml go.mod 2>/dev/null | head -5
|
||||
grep -rl "next\|react\|vue\|prisma\|supabase" package.json 2>/dev/null | head -3 || true
|
||||
find . -name "*.tsx" -o -name "*.jsx" 2>/dev/null | head -3 | wc -l
|
||||
find . -name "docker-compose*" -o -name "Dockerfile" 2>/dev/null | head -3 | wc -l
|
||||
|
||||
# Animation lib status (motion / motion-v) — read-only detection
|
||||
if [ -f "$HOME/.claude/lib/animation-lib-check.sh" ]; then
|
||||
source "$HOME/.claude/lib/animation-lib-check.sh"
|
||||
detect_anim_eligibility # outputs '<status>|<package>|<reason>'
|
||||
is_anim_lib_installed || echo "anim-lib-not-installed"
|
||||
fi
|
||||
# Monorepo detection (current dir + parent dirs for sub-package context)
|
||||
ls apps/ packages/ services/ workspaces/ 2>/dev/null | head -5
|
||||
ls pnpm-workspace.yaml turbo.json nx.json lerna.json 2>/dev/null
|
||||
@ -70,6 +77,8 @@ Detect signals from the project description and filesystem scan:
|
||||
| `skill-creation` | "create a skill", "new skill", "custom skill", `/plugin-dev:create-plugin` in description |
|
||||
| `embedded` | "firmware", "bare-metal", "microcontroller", "STM32", "ESP32", "RTOS", "driver", "kernel", "bootloader" in description; **or** `platformio.ini` present; **or** linker script (`*.ld`, `*.lds`) present; **or** `Makefile` + `src/*.c` + no `package.json`/`Cargo.toml`/`go.mod`/`setup.py`/`pyproject.toml` (C project without standard ecosystems). Note: `.c` files with a Rust/Node/Go manifest = FFI binding, NOT embedded. |
|
||||
| `simple` | single file, hotfix, quick script, no frontend, no deploy |
|
||||
| `anim-lib-eligible` | output of `detect_anim_eligibility` starts with `eligible|` (React/Vue/Svelte stack) |
|
||||
| `anim-lib-installed` | `is_anim_lib_installed` returns 0 (any of motion / motion-v / framer-motion / gsap / lottie-react / react-spring / popmotion / auto-animate present) |
|
||||
|
||||
---
|
||||
|
||||
@ -117,11 +126,20 @@ RECOMMENDATIONS:
|
||||
ℹ️ OPTIONAL: [plugin] — [marginal benefit, low priority]
|
||||
🖥️ CLI : [gsd v2] — [run 'gsd' in terminal if multi-session]
|
||||
|
||||
ANIMATION LIB:
|
||||
✅ <lib> installed (anim-lib-installed)
|
||||
ℹ️ eligible (<reason>) — install via /onboard or /init (eligible, not installed)
|
||||
— not eligible (<reason>) (no UI framework / RN / backend)
|
||||
|
||||
CONFLICTS: [plugin A ↔ plugin B — overlap on X] or none
|
||||
BLOCKING: [issues] or none
|
||||
ACTION REQUIRED? YES / NO
|
||||
```
|
||||
|
||||
> ANIMATION LIB is **read-only** in this report. The advisor never installs
|
||||
> packages itself — it just states the status. Installation happens in
|
||||
> `/init-project` STEP 5e (auto) or `/onboard` STEP 2.5 (opt-in).
|
||||
|
||||
## PHASE 4 — AUTO-ACTIVATION (when called from /init-project or /ship-feature)
|
||||
|
||||
After presenting RECOMMENDATIONS, if any plugin has ⚡ ENABLE status:
|
||||
|
||||
@ -89,6 +89,10 @@ Add `COMPOSE_PROJECT_NAME=<slug>` to `.env.example`.
|
||||
On failure: read error → fix config → retry once → if still failing: report and stop.
|
||||
If DOCKER_RELEVANT: `docker --version && docker compose version` — failure is warning, not blocker.
|
||||
|
||||
> **Note**: do NOT install `motion` / `motion-v` / animation libs here.
|
||||
> The init-project orchestrator handles that in STEP 5e via
|
||||
> `lib/animation-lib-check.sh`. Scaffolder stays language-agnostic.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5 — VERIFY BUILD
|
||||
|
||||
117
lib/animation-lib-check.sh
Executable file
117
lib/animation-lib-check.sh
Executable file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# lib/animation-lib-check.sh — Animation library detection
|
||||
# Sourced by: skills/init-project, skills/onboard, agents/plugin-advisor.
|
||||
#
|
||||
# Recommends `motion` (ex-`framer-motion`, rebranded Nov 2024) for
|
||||
# React-family / Svelte stacks, and `motion-v` for Vue 3 / Nuxt.
|
||||
#
|
||||
# Override the project root with: ANIM_PROJECT_ROOT=/path before sourcing.
|
||||
# ============================================================
|
||||
|
||||
ANIM_PROJECT_ROOT="${ANIM_PROJECT_ROOT:-$PWD}"
|
||||
|
||||
# Match a literal dep key in package.json (deps + devDeps + peerDeps).
|
||||
# Args: $1 = exact dep name. Returns 0 if found, 1 otherwise. No output.
|
||||
_anim_has_dep() {
|
||||
local pkg_json="$ANIM_PROJECT_ROOT/package.json"
|
||||
[ -f "$pkg_json" ] || return 1
|
||||
# The closing escaped quote anchors the match so "react" does not
|
||||
# collide with "react-native" or "react-dom".
|
||||
grep -Eq "\"$1\"[[:space:]]*:" "$pkg_json"
|
||||
}
|
||||
|
||||
# Decide whether the project can consume the motion library.
|
||||
# Outputs on stdout: '<status>|<package>|<reason>'
|
||||
# status : eligible | no
|
||||
# package : motion | motion-v | -
|
||||
# reason : short human-readable note
|
||||
# Returns 0 if eligible, 1 if not.
|
||||
detect_anim_eligibility() {
|
||||
local pkg_json="$ANIM_PROJECT_ROOT/package.json"
|
||||
|
||||
if [ ! -f "$pkg_json" ]; then
|
||||
echo "no|-|no package.json (not a Node project)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# React Native / Expo are excluded: motion targets the DOM, RN apps
|
||||
# should use react-native-reanimated instead.
|
||||
if _anim_has_dep "react-native" || _anim_has_dep "expo"; then
|
||||
echo "no|-|React Native stack — use react-native-reanimated"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _anim_has_dep "react" || _anim_has_dep "next" \
|
||||
|| _anim_has_dep "@remix-run/react" || _anim_has_dep "@astrojs/react"; then
|
||||
echo "eligible|motion|React-family stack"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if _anim_has_dep "vue" || _anim_has_dep "nuxt"; then
|
||||
echo "eligible|motion-v|Vue 3 / Nuxt stack"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if _anim_has_dep "svelte" || _anim_has_dep "@sveltejs/kit"; then
|
||||
echo "eligible|motion|Svelte stack"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if _anim_has_dep "astro"; then
|
||||
echo "no|-|Astro without a React/Vue/Svelte integration"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "no|-|no supported UI framework detected"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Look for any installed animation library.
|
||||
# Outputs the detected package name on stdout (empty if none).
|
||||
# Returns 0 if found, 1 otherwise.
|
||||
is_anim_lib_installed() {
|
||||
local pkg_json="$ANIM_PROJECT_ROOT/package.json"
|
||||
[ -f "$pkg_json" ] || return 1
|
||||
|
||||
local libs=(
|
||||
motion
|
||||
motion-v
|
||||
framer-motion
|
||||
gsap
|
||||
"@gsap/react"
|
||||
lottie-react
|
||||
react-spring
|
||||
"@react-spring/web"
|
||||
popmotion
|
||||
"@formkit/auto-animate"
|
||||
)
|
||||
|
||||
local lib
|
||||
for lib in "${libs[@]}"; do
|
||||
if _anim_has_dep "$lib"; then
|
||||
echo "$lib"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Build the install command for the recommended package.
|
||||
# Args: $1 = package name (motion | motion-v).
|
||||
# Outputs the command on stdout. Returns 1 on missing arg.
|
||||
recommend_anim_install_cmd() {
|
||||
local pkg="$1"
|
||||
[ -z "$pkg" ] && return 1
|
||||
local root="$ANIM_PROJECT_ROOT"
|
||||
|
||||
if [ -f "$root/pnpm-lock.yaml" ]; then
|
||||
echo "pnpm add $pkg"
|
||||
elif [ -f "$root/yarn.lock" ]; then
|
||||
echo "yarn add $pkg"
|
||||
elif [ -f "$root/bun.lockb" ] || [ -f "$root/bun.lock" ]; then
|
||||
echo "bun add $pkg"
|
||||
else
|
||||
echo "npm install $pkg"
|
||||
fi
|
||||
}
|
||||
@ -21,6 +21,7 @@ Check BOTH the task description AND the filesystem:
|
||||
- `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: `motion`, `motion-v`, `framer-motion` (legacy), `gsap`, `@gsap/react`, `lottie-react`, `react-spring`, `popmotion`, `@formkit/auto-animate`
|
||||
|
||||
## DECISION
|
||||
|
||||
|
||||
@ -87,6 +87,33 @@ If `graphify` CLI is installed AND complexity >= 30%:
|
||||
3. Print: `🔗 Scaffold graph generated at graphify-out/`
|
||||
If `graphify` not installed or complexity < 30% → skip silently.
|
||||
|
||||
## STEP 5e — ANIMATION LIB (auto-install)
|
||||
Install `motion` (ex-`framer-motion`, rebranded Nov 2024) when the stack supports it.
|
||||
The scaffold has just been validated by the user, so install proceeds silently.
|
||||
|
||||
```bash
|
||||
source "$HOME/.claude/lib/animation-lib-check.sh"
|
||||
if result=$(detect_anim_eligibility); then
|
||||
pkg=$(echo "$result" | cut -d'|' -f2)
|
||||
if ! is_anim_lib_installed >/dev/null; then
|
||||
cmd=$(recommend_anim_install_cmd "$pkg")
|
||||
echo "🎬 Installing animation lib: $cmd"
|
||||
eval "$cmd"
|
||||
else
|
||||
installed=$(is_anim_lib_installed)
|
||||
echo "🎬 Animation lib already present: $installed — skipping install"
|
||||
fi
|
||||
else
|
||||
echo "🎬 Animation lib: stack not eligible — skipping ($(echo "$result" | cut -d'|' -f3))"
|
||||
fi
|
||||
```
|
||||
|
||||
Rules:
|
||||
- `motion` for React-family / Svelte / vanilla JS stacks.
|
||||
- `motion-v` for Vue 3 / Nuxt.
|
||||
- React Native, Flutter, backend, embedded, static HTML → skipped.
|
||||
- If another animation lib (gsap, lottie-react, react-spring, …) is already present → skipped.
|
||||
|
||||
## STEP 6 — PLAN
|
||||
Invoke `superpowers:writing-plans` with BRIEF + skeleton.
|
||||
Granular tasks (2-5 min each), exact file paths, TDD: tests before code.
|
||||
|
||||
@ -103,6 +103,38 @@ Si `CLAUDE.md` existe déjà : lire son contenu, ne PAS écraser — fusionner a
|
||||
|
||||
---
|
||||
|
||||
## STEP 2.5 — ANIMATION LIB (propose, opt-in)
|
||||
Vérifier si le stack peut consommer `motion` (ex-`framer-motion`, rebranded nov 2024)
|
||||
et proposer l'install si absent. **Aucun install sans confirmation utilisateur** —
|
||||
on ajoute une dep à un projet existant.
|
||||
|
||||
```bash
|
||||
source "$HOME/.claude/lib/animation-lib-check.sh"
|
||||
result=$(detect_anim_eligibility)
|
||||
status=$(echo "$result" | cut -d'|' -f1)
|
||||
pkg=$(echo "$result" | cut -d'|' -f2)
|
||||
reason=$(echo "$result" | cut -d'|' -f3)
|
||||
```
|
||||
|
||||
Cas :
|
||||
- **`status=eligible` AND aucune lib anim détectée** → proposer :
|
||||
```
|
||||
🎬 ANIMATION LIB
|
||||
Stack: <reason>. Aucune lib d'animation détectée.
|
||||
Install `<cmd>` ? (yes / skip)
|
||||
```
|
||||
Sur `yes` → exécuter `recommend_anim_install_cmd "$pkg"` puis confirmer.
|
||||
Sur `skip` → continuer silencieusement.
|
||||
|
||||
- **`status=eligible` AND une lib anim déjà présente** (motion, framer-motion, gsap, lottie, react-spring, popmotion, auto-animate) → log info uniquement :
|
||||
```
|
||||
🎬 Animation lib déjà présente : <lib> — pas d'action.
|
||||
```
|
||||
|
||||
- **`status=no`** → skip silencieusement (raison loggée seulement en mode verbose).
|
||||
|
||||
---
|
||||
|
||||
## STEP 3 — DEEP INTERVIEW
|
||||
|
||||
L'orchestrateur pilote directement l'interview (l'agent `interviewer.md` est laissé pour `/init-project` où le BRIEF format est attendu ; ici on reste en markdown libre dans la CLAUDE.md).
|
||||
|
||||
Loading…
Reference in New Issue
Block a user