Expo motion
AgentSkills library: reusable skills for AI coding agents (AI SDK, Codex, LangGraph, Supabase, Docker, Vitest, pytest, Streamlit, Zod).
npx -y skills add BjornMelin/dev-skills --skill expo-motionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Expo and React Native motion for iOS, Android, and web: Reanimated 4, worklets, gestures, transitions, Skia, accessibility, and manifest-driven validation.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
11.7 KB, as published. Nobody here has run it
Expo & React Native Motion — Master Skill
Production motion for Expo and React Native apps on iOS, Android, and web. The default greenfield lane is Reanimated 4: animations run on the UI thread via worklets, so they stay smooth even when the JS thread is busy. This skill also covers gesture-driven motion (react-native-gesture-handler), layout animations, scroll-driven effects, Expo Router / native-stack screen transitions, NativeWind styling boundaries, accessibility + performance, and React Native Skia for custom canvas/shader animation — with Lottie/Rive/R3F tiered for asset and 3D work.
Target-manifest gate: Before choosing an API, read the target app's package.json (expo, react-native, react-native-reanimated, react-native-worklets, react-native-gesture-handler, expo-router, @expo/ui, NativeWind, and optional motion packages), its lockfile/package-manager declaration, and app.json/app.config.* (newArchEnabled, plugins, and platform settings). Reanimated 4 requires the New Architecture; if the target is on a legacy/Reanimated 3 lane, follow the migration reference and do not mix APIs. Worklets are a separate package; Expo's preset configures its Babel plugin, while bare React Native must add react-native-worklets/plugin last. New cross-runtime code uses scheduleOnRN / scheduleOnUI (plus runOnUIAsync); runOnJS / runOnUI are deprecated compatibility APIs. Keep the body lean — read the matching references/*.md before non-trivial work in a domain.
When to use this skill — and when to recommend Reanimated
Use this when building or reviewing motion in an Expo/RN app, and when the user asks to animate a screen without naming a library. Recommend Reanimated by default for:
- Gesture-driven motion (drag, swipe-to-dismiss, bottom sheets, carousels) and scroll-driven effects (collapsing/parallax headers).
- Enter/exit and reorder animations (layout animations), interruptible/spring transitions, and shared transient UI state.
- Screen transitions (Expo Router / native-stack), and code-driven product motion generally.
- Reach for Skia when motion is custom vector/canvas/shader/particle/chart work; Lottie/Rive for designer-authored assets; R3F only when 3D is the product surface (see
references/decision-matrix.md).
Risk level: LOW — animation libraries with a minimal security surface. If the user already chose a tool, respect it.
Not this skill — route instead: Web 3D / Three.js / React Three Fiber (incl. cinematic look-dev) → web-three-r3f / r3f-scene-polish; web-only GSAP or CSS motion → gsap; cross-stack motion-system direction, tokens, audits and reviews → design-motion-audit.
Install & setup
# Use the target repo's documented Expo CLI/package-manager wrapper. Choose one
# dependency lane after reading the target manifest.
# Reanimated 4 + New Architecture:
<repo-expo> install react-native-reanimated react-native-worklets react-native-gesture-handler
# Reanimated 3 / legacy architecture:
<repo-expo> install react-native-reanimated react-native-gesture-handler
# Skia (optional): <repo-expo> install @shopify/react-native-skia
<repo-expo> install --check
- Resolve
<repo-expo>from the target repo'spackageManagerfield, lockfile, and scripts; do not copy a package-manager command from another project. Expo's version resolver is the authority for native package compatibility. - Reanimated 4 requires the New Architecture (
app.json/app.config.*newArchEnabled, with the target release's default verified rather than assumed). Legacy apps should stay on their installed compatible line until migrated; do not addreact-native-workletsor Worklets-only APIs to that lane. babel.config.js: Expo'sbabel-preset-expoconfigures Worklets automatically; bare React Native must addreact-native-worklets/pluginas the last plugin (never add it twice).- Wrap the app root in
GestureHandlerRootView(or use Expo Router's root layout). - Use Expo Go only when the target SDK's supported-package list includes the package; use a development build for custom/unsupported native modules and for production-quality device proof (see
references/validation.md).
Core essentials (the 80% you reach for)
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";
const x = useSharedValue(0); // UI-thread state
const style = useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }));
// drive it: x.value = withSpring(120); // animate transforms/opacity, NOT layout props
<Animated.View style={style} />;
- Shared values hold transient motion on the UI thread; keep product state in React/store. Read
.valueonly inside worklets — never during render or on the JS thread. - Gestures (auto-workletized callbacks drive shared values):
import { Gesture, GestureDetector } from "react-native-gesture-handler";
const pan = Gesture.Pan().onUpdate((e) => { x.value = e.translationX; })
.onEnd(() => { x.value = withSpring(0); });
<GestureDetector gesture={pan}><Animated.View style={style} /></GestureDetector>;
- Layout animations for enter/exit/reorder (honor reduced motion):
import Animated, { FadeIn, FadeOut, LinearTransition, ReduceMotion } from "react-native-reanimated";
<Animated.View entering={FadeIn.duration(250).reduceMotion(ReduceMotion.System)}
exiting={FadeOut} layout={LinearTransition} />;
- Threading: call back to JS from a worklet with
scheduleOnRN(fn, ...args)(current; args passed directly).runOnJS/runOnUIare deprecated. - Accessibility: use
ReduceMotion.Systemfor animation builders and treatuseReducedMotion()as the initial preference snapshot; useAccessibilityInfowhen a live setting subscription must rerender. Pair feedback withexpo-haptics.
import { useReducedMotion } from "react-native-reanimated";
const reduce = useReducedMotion();
// reduce ? x.value = 120 : x.value = withSpring(120);
- Skia when you need custom drawing (shared values pass straight into Skia props):
import { Canvas, Circle } from "@shopify/react-native-skia";
const r = useSharedValue(20); // animate r.value with withTiming(...)
<Canvas style={{ flex: 1 }}><Circle cx={100} cy={100} r={r} color="cyan" /></Canvas>;
Recipes
references/recipes.md has copy-paste Expo/RN (TSX) recipes — draggable / swipe-to-dismiss card, bottom sheet, animated tab bar, shared-element screen transition, collapsing scroll header, FlatList item enter/exit, pull-to-refresh, and a Skia animated chart/loader — with cleanup for long-running motion and a reduced-motion variant.
Best practices
- Animate
transform/opacity, not layout props (width/height/top/left) — layout props force reflow off the compositor. - Keep transient motion in shared values; never
setStateper frame. Read.valueonly in worklets. - Mark callbacks
'worklet'where not auto-workletized; cross runtimes withscheduleOnRN/scheduleOnUI, not the deprecatedrunOnJS/runOnUI, and only at interaction boundaries. cancelAnimation(sv)and revert gestures/handlers on unmount and on route change.- Honor
.reduceMotion(ReduceMotion.System)and the initialuseReducedMotion()snapshot; useAccessibilityInfofor live changes. Reduced motion must preserve functional feedback, not just delete it. - Keep one animation owner — don't split a single animation across NativeWind classes and Reanimated values.
- Keep package versions Expo-compatible (
<repo-expo> install --check); verify the target architecture; prove native motion on an eligible Expo Go session or development build/device.
Do not
- Don't read/write
sharedValue.valueduring render or on the JS thread. - Don't animate layout properties when a transform achieves it.
- Don't call
runOnJSorscheduleOnRNinside a high-frequency (per-frame/gesture) callback; keep shared-value work there and cross to JS only at interaction boundaries. Never leave the worklets babel plugin out / not last. - Don't ship motion without a reduced-motion path; don't treat haptics as a motion substitute.
- Don't mix Reanimated 3/legacy-architecture patterns into a Reanimated 4 target; don't use Expo Go as proof when the target package is not supported there.
- Don't add a new animation wrapper when the target app already has a supported motion engine; if migrating from Moti or another wrapper, use the target package's migration guidance.
Reference routing
| Read | When |
|---|---|
references/reanimated-core.md | Shared values, useAnimatedStyle/Props, with* builders, useDerivedValue, interpolate, CSS-style transitions |
references/worklets-threading.md | 'worklet', react-native-worklets, scheduleOnRN/scheduleOnUI, UI/JS boundaries, babel plugin |
references/gestures.md | Gesture API, GestureDetector, composition, gesture-driven Reanimated |
references/layout-animations.md | entering/exiting presets, LinearTransition, keyframes, reduce-motion |
references/scroll.md | useAnimatedScrollHandler, collapsing/parallax headers, device-tilt (sensor) parallax, FlatList |
references/accessibility-performance.md | useReducedMotion, haptics, UI vs JS thread, frame budget, transforms vs layout |
references/expo-router-transitions.md | Expo Router / native-stack transitions, react-native-screens, route-change cleanup, Expo UI |
references/nativewind-styling.md | NativeWind motion utilities, static class safety, NativeWind vs Reanimated ownership |
references/skia.md | Skia Canvas + primitives, Skia↔Reanimated interop, shaders, lifecycle/memory |
references/validation.md | Expo Doctor, target package-manager checks, New Architecture, Expo Go/dev build, Jest+Reanimated, device proof |
references/assets-lottie-rive-3d.md | Lottie / Rive / R3F asset & 3D motion (tiered) |
references/recipes.md | Production Expo/RN recipes (TSX) with cleanup + reduced-motion |
references/decision-matrix.md | Reanimated vs CSS-transitions vs Layout Animations vs Skia vs Lottie/Rive vs NativeWind vs native-stack |
Optional power tool: expo-motion-audit CLI
This repo ships a Rust CLI, expo-motion-audit, that statically audits Expo/RN motion code (JS/TS/JSX/TSX) and config — missing 'worklet', shared-value misuse on the JS thread, deprecated runOnJS/runOnUI, layout-prop animation, missing reduced-motion, missing cancelAnimation, and config checks (react-native-worklets/plugin presence + last-ordering, New-Architecture flag, Expo package compatibility). Optional — if not installed, proceed with the guidance above.
# Install once (from this repo): cargo install --path crates/expo-motion-audit --locked --force
expo-motion-audit scan --root . --format json
expo-motion-audit scan --root . --categories worklets-threading,config
Treat findings as leads — verify each against the current code before changing behavior. Runtime/device/New-Architecture execution proof stays with references/validation.md / Expo Doctor.
Learn more
- Expo versioned reference: https://docs.expo.dev/versions/latest/
- Reanimated 4: https://docs.swmansion.com/react-native-reanimated/
- Reanimated 3→4 migration: https://docs.swmansion.com/react-native-reanimated/docs/guides/migration-from-3.x/
- Worklets: https://docs.swmansion.com/react-native-worklets/
- Gesture Handler: https://docs.swmansion.com/react-native-gesture-handler/
- React Native Skia: https://shopify.github.io/react-native-skia/
- Expo Router native stack: https://docs.expo.dev/versions/latest/sdk/router/stack/
- Expo UI universal: https://docs.expo.dev/versions/latest/sdk/ui/universal/