| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #!/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
- }
|