agents-inc/skills/src/skills/mobile-animation-gesture-handler/SKILL.md
mobile-animation-gesture-handler
React Native Gesture Handler - gesture types, GestureDetector, gesture composition, state machine, platform-specific gestures, swipeable rows, hover gestures
- Source repository stars
- 23
- Declared platforms
- 0
- Static risk flags
- 0
- Last source update
- 2026-08-09
- Source checked
- 2026-08-28
Decision brief
What it does: where it fits
Quick Guide: Use Gesture Handler's v2 builder API (Gesture.Pan(), Gesture.Tap(), etc.) with GestureDetector for all touch interactions. Wrap your app root in GestureHandlerRootView. Compose gestures with Gesture.Simultaneous(), Gesture.Race(), and Gesture.Exclusive(). Use onChan…
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-animation-gesture-handler"Inspect the Agent Skill "mobile-animation-gesture-handler" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/mobile-animation-gesture-handler/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Pattern 1: GestureHandlerRootView Setup
Every app using Gesture Handler must wrap its root in GestureHandlerRootView. Without it, gestures silently fail -- no errors, just no recognition.
Every app using Gesture Handler must wrap its root in GestureHandlerRootView. Without it, gestures silently fail -- no errors, just no recognition.Why good: single root wrapper, flex: 1 ensures full-screen coverageGotcha (Android modals): React Native Modals on Android create a separate native view hierarchy. Wrap Modal content in its own GestureHandlerRootView -- gestures inside a Modal won't work otherwise. - 02
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
Adding pan, pinch, tap, rotation, long-press, fling, or hover gestures to React Native viewsComposing multiple gestures on the same view (pinch-to-zoom + drag)Building swipeable list rows with reveal actions - 03
Philosophy
React Native Gesture Handler replaces the built-in Gesture Responder System with native-driven gesture recognition. The key advantage is that gestures are processed on the native thread, not JS -- so they remain responsive even when JS is busy.
Native-first -- Gesture recognition runs natively; callbacks optionally run as worklets on the UI threadDeclarative composition -- Define gestures as objects, compose them with Simultaneous, Race, ExclusiveState machine driven -- Every gesture follows UNDETERMINED - BEGAN - ACTIVE - END/FAILED/CANCELLED - 04
Core Patterns
Every app using Gesture Handler must wrap its root in GestureHandlerRootView. Without it, gestures silently fail -- no errors, just no recognition.
Every app using Gesture Handler must wrap its root in GestureHandlerRootView. Without it, gestures silently fail -- no errors, just no recognition.Why good: single root wrapper, flex: 1 ensures full-screen coverageGotcha (Android modals): React Native Modals on Android create a separate native view hierarchy. Wrap Modal content in its own GestureHandlerRootView -- gestures inside a Modal won't work otherwise. - 05
Pattern 2: Pan Gesture with Shared Values
The most common pattern: drag an element by tracking translation deltas.
The most common pattern: drag an element by tracking translation deltas.Why onChange over onUpdate: onChange provides changeX/changeY (delta since last event) -- add it to an offset. onUpdate provides translationX/translationY (cumulative since gesture start) -- use it as an absolute positi…See examples/core.md for complete pan, tap, pinch, and rotation examples.
Permission review
Static risk signals and limitations
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 23 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- agents-inc/skills
- Skill path
- src/skills/mobile-animation-gesture-handler/SKILL.md
- Commit
- 81d43a51211aca12c85dcc16085fa99014ec548e
- License
- MIT
- Collected
- 2026-08-28
- Default branch
- main
View the original SKILL.md
React Native Gesture Handler Patterns
Quick Guide: Use Gesture Handler's v2 builder API (
Gesture.Pan(),Gesture.Tap(), etc.) withGestureDetectorfor all touch interactions. Wrap your app root inGestureHandlerRootView. Compose gestures withGesture.Simultaneous(),Gesture.Race(), andGesture.Exclusive(). UseonChange(notonUpdate) when working with animation shared values --onChangeprovides deltas (changeX),onUpdateprovides cumulative values (translationX). Gesture callbacks are automatically workletized when your animation library is installed.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST wrap the app root in GestureHandlerRootView -- gestures will silently fail without it)
(You MUST use GestureDetector with the builder API (Gesture.Pan(), etc.) -- NOT the legacy PanGestureHandler components)
(You MUST use onChange for incremental shared value updates and onUpdate for cumulative values -- mixing them causes drift)
(You MUST use Gesture.Simultaneous() for multi-touch interactions (pinch + pan) -- without it, only one gesture activates)
(You MUST NOT nest GestureDetector components using different API styles (hooks vs builder) under the same root -- this causes undefined behavior)
</critical_requirements>
Auto-detection: react-native-gesture-handler, GestureDetector, GestureHandlerRootView, Gesture.Pan, Gesture.Tap, Gesture.Pinch, Gesture.Rotation, Gesture.LongPress, Gesture.Fling, Gesture.Hover, Gesture.Simultaneous, Gesture.Race, Gesture.Exclusive, Swipeable, ReanimatedSwipeable, onBegin, onStart, onChange, onUpdate, onEnd, onFinalize
When to use:
- Adding pan, pinch, tap, rotation, long-press, fling, or hover gestures to React Native views
- Composing multiple gestures on the same view (pinch-to-zoom + drag)
- Building swipeable list rows with reveal actions
- Replacing React Native's built-in Gesture Responder System (PanResponder)
- Implementing gesture-driven animations with shared values
- Adding hover interactions for iPad trackpad, desktop, or web targets
Key patterns covered:
- GestureDetector + builder API for all gesture types
- Gesture composition: Simultaneous, Race, Exclusive
- Gesture state machine and lifecycle callbacks
- Shared value integration in gesture callbacks (onChange vs onUpdate)
- ReanimatedSwipeable for swipeable list rows
- Hover gesture for pointer devices (iPad trackpad, mouse, stylus)
- Platform-specific gesture configuration (Android ripple, iOS haptics)
- Cross-component gesture relations (requireToFail, simultaneousWith, block)
When NOT to use:
- Simple button taps (use
PressableorTouchableOpacityfrom React Native core) - Scroll-only interactions (use
ScrollVieworFlatListdirectly) - Web-only applications without React Native
Detailed Resources:
- examples/core.md - GestureDetector setup, pan, tap, pinch, rotation gestures with shared values
- examples/composition.md - Simultaneous, Race, Exclusive composition, cross-component relations
- examples/swipeable.md - ReanimatedSwipeable rows, FlatList integration, action panels
- examples/advanced.md - Hover gesture, manual gesture control, platform-specific config
- reference.md - Decision frameworks, gesture type reference, state machine diagram
Philosophy
React Native Gesture Handler replaces the built-in Gesture Responder System with native-driven gesture recognition. The key advantage is that gestures are processed on the native thread, not JS -- so they remain responsive even when JS is busy.
Core principles:
- Native-first -- Gesture recognition runs natively; callbacks optionally run as worklets on the UI thread
- Declarative composition -- Define gestures as objects, compose them with
Simultaneous,Race,Exclusive - State machine driven -- Every gesture follows UNDETERMINED -> BEGAN -> ACTIVE -> END/FAILED/CANCELLED
- Builder API -- Chain configuration methods:
Gesture.Pan().minDistance(10).onUpdate(handler) - One GestureDetector per gesture (or composed gesture) -- Don't attach multiple unrelated gestures via separate nested detectors
Mental model: Think of each gesture as a state machine that competes with other gestures for activation. Composition methods (Simultaneous, Race, Exclusive) define the competition rules. The gesture that wins transitions to ACTIVE; the rest FAIL or get CANCELLED.
v3 hooks API (beta): RNGH v3 introduces a hooks-based API (usePanGesture, useSimultaneousGestures, etc.) that is cleaner but still in beta. The v2 builder API (Gesture.Pan(), GestureDetector) is the stable production API documented here.
Core Patterns
Pattern 1: GestureHandlerRootView Setup
Every app using Gesture Handler must wrap its root in GestureHandlerRootView. Without it, gestures silently fail -- no errors, just no recognition.
import { GestureHandlerRootView } from "react-native-gesture-handler";
export function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<AppContent />
</GestureHandlerRootView>
);
}
Why good: single root wrapper, flex: 1 ensures full-screen coverage
Gotcha (Android modals): React Native Modals on Android create a separate native view hierarchy. Wrap Modal content in its own GestureHandlerRootView -- gestures inside a Modal won't work otherwise.
Gotcha (native navigation): When using a native navigation library (separate screen containers per screen), wrap each registered screen individually rather than a single app-level root.
See examples/core.md for the full setup pattern.
Pattern 2: Pan Gesture with Shared Values
The most common pattern: drag an element by tracking translation deltas.
const offset = useSharedValue(0);
const pan = Gesture.Pan()
.onChange((event) => {
offset.value += event.changeX; // Incremental delta
})
.onFinalize((event) => {
offset.value = withDecay({ velocity: event.velocityX });
});
// Wrap with GestureDetector + Animated.View
<GestureDetector gesture={pan}>
<Animated.View style={animatedStyle} />
</GestureDetector>
Why onChange over onUpdate: onChange provides changeX/changeY (delta since last event) -- add it to an offset. onUpdate provides translationX/translationY (cumulative since gesture start) -- use it as an absolute position. Mixing them causes position drift.
See examples/core.md for complete pan, tap, pinch, and rotation examples.
Pattern 3: Gesture Composition
Compose multiple gestures on the same view with three strategies:
const pan = Gesture.Pan().onChange(/* ... */);
const pinch = Gesture.Pinch().onUpdate(/* ... */);
const rotation = Gesture.Rotation().onUpdate(/* ... */);
// All three active simultaneously (photo viewer)
const composed = Gesture.Simultaneous(pan, pinch, rotation);
// First to activate wins, rest fail (swipe vs long-press)
const racing = Gesture.Race(pan, longPress);
// Priority order: first arg wins ties (double-tap beats single-tap)
const exclusive = Gesture.Exclusive(doubleTap, singleTap);
<GestureDetector gesture={composed}>
<Animated.View />
</GestureDetector>
Key rule: Pass the composed gesture to a single GestureDetector. Do not nest multiple GestureDetector components for gestures that should interact -- use composition instead.
See examples/composition.md for full photo viewer and tap disambiguation patterns.
Pattern 4: Gesture State Machine
Every gesture follows a state machine. Understanding it is critical for debugging gesture conflicts:
UNDETERMINED ──> BEGAN ──> ACTIVE ──> END ──> UNDETERMINED
│ │
├──> FAILED ─────────┘
│ │
└──> (ACTIVE) ──> CANCELLED ──> UNDETERMINED
Lifecycle callbacks map to states:
| Callback | When it fires |
|---|---|
onBegin | UNDETERMINED -> BEGAN (touch detected, not yet recognized) |
onStart | BEGAN -> ACTIVE (gesture recognized, meets criteria) |
onUpdate | While ACTIVE (cumulative: translationX, scale) |
onChange | While ACTIVE (incremental: changeX, changeY) |
onEnd | ACTIVE -> END (finger lifted normally) |
onFinalize | Fires for ANY terminal state (END, FAILED, CANCELLED) |
onEnd vs onFinalize: Use onEnd for success-only cleanup (save position). Use onFinalize for guaranteed cleanup (reset state regardless of outcome). onFinalize receives a second success boolean parameter.
See reference.md for the complete state transition diagram.
Pattern 5: Cross-Component Gesture Relations
When gestures live on different components (parent scroll + child drag), use relation methods:
const childPan = Gesture.Pan();
const parentScroll = Gesture.Native(); // Wraps native ScrollView gesture
// Child drag must fail before parent scroll activates
parentScroll.requireExternalGestureToFail(childPan);
// Or: both active simultaneously
childPan.simultaneousWith(parentScroll);
// Or: child blocks parent while active
childPan.blocksExternalGesture(parentScroll);
Key difference from composition: Gesture.Simultaneous() composes gestures on the same component. .simultaneousWith() relates gestures across different components in the view hierarchy.
See examples/composition.md for cross-component patterns.
Pattern 6: ReanimatedSwipeable for List Rows
Use ReanimatedSwipeable (not the legacy Swipeable) for swipeable list items with smooth 60fps animations.
import ReanimatedSwipeable from "react-native-gesture-handler/ReanimatedSwipeable";
const SWIPE_THRESHOLD = 40;
const OVERSHOOT_FRICTION = 8;
<ReanimatedSwipeable
friction={2}
rightThreshold={SWIPE_THRESHOLD}
overshootFriction={OVERSHOOT_FRICTION}
renderRightActions={renderRightActions}
onSwipeableOpen={handleDelete}
>
<ListItemContent />
</ReanimatedSwipeable>
Why ReanimatedSwipeable over Swipeable: Rewritten with worklets for native-thread animations. The legacy Swipeable animates on JS thread and drops frames during heavy renders.
See examples/swipeable.md for full implementation with action panels and FlatList integration.
Pattern 7: Hover Gesture (Pointer Devices)
Hover gesture detects mouse/stylus/trackpad hovering -- useful for iPad with trackpad, macOS, and web targets. Does not fire on phone touch.
const hover = Gesture.Hover()
.onBegin(() => {
isHovered.value = true;
})
.onEnd(() => {
isHovered.value = false;
});
Platform support: iOS (iPad with trackpad/mouse), macOS, web. Does NOT work on Android touch or iPhone touch. On iOS, the optional hoverEffect prop on GestureDetector provides system-level visual effects (highlight, lift, automatic).
See examples/advanced.md for hover with visual effects.
<decision_framework>
Decision Framework
Which Gesture Type?
What user interaction are you handling?
├─ Drag/move element → Gesture.Pan()
├─ Single tap → Gesture.Tap()
├─ Double tap → Gesture.Tap().numberOfTaps(2)
├─ Long press → Gesture.LongPress()
├─ Pinch to zoom → Gesture.Pinch()
├─ Two-finger rotate → Gesture.Rotation()
├─ Quick directional swipe → Gesture.Fling()
├─ Mouse/trackpad hover → Gesture.Hover()
└─ Wrap a native gesture → Gesture.Native() (for ScrollView, etc.)
Which Composition?
How should multiple gestures interact?
├─ All active at once (pan + pinch + rotate in photo viewer)
│ └─ Gesture.Simultaneous(gesture1, gesture2, ...)
├─ First to activate wins (swipe vs long-press on same view)
│ └─ Gesture.Race(gesture1, gesture2, ...)
├─ Priority order (double-tap must beat single-tap)
│ └─ Gesture.Exclusive(highPriority, lowPriority)
└─ Gestures on DIFFERENT components (child drag vs parent scroll)
├─ Parent waits for child to fail → parent.requireExternalGestureToFail(child)
├─ Both active simultaneously → child.simultaneousWith(parent)
└─ Child blocks parent → child.blocksExternalGesture(parent)
onChange vs onUpdate?
How are you using the gesture position data?
├─ Adding to an offset (shared value += delta)
│ └─ Use onChange (provides changeX, changeY)
├─ Setting absolute position from gesture start
│ └─ Use onUpdate (provides translationX, translationY)
└─ Need both (rare)
└─ Use onChange for offsets + onUpdate for display values
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Missing
GestureHandlerRootViewat app root -- gestures silently fail with no error message - Using legacy
PanGestureHandler/TapGestureHandlercomponents -- deprecated, useGesture.Pan()+GestureDetector - Using
onUpdateto add deltas to shared values --onUpdateprovides cumulative values, not deltas; useonChangefor incremental updates - Nesting multiple
GestureDetectorcomponents for gestures that should compose -- useGesture.Simultaneous()/Race()/Exclusive()instead - Using
React.PanResponder-- replaced entirely by Gesture Handler; PanResponder runs on JS thread and blocks the UI
Medium Priority Issues:
- Not specifying
minDistanceonGesture.Pan()when coexisting with tap gestures -- pan activates immediately at 0px, stealing taps - Missing
onFinalizecleanup --onEndonly fires on success; cancelled/failed gestures skip it - Using
Swipeableinstead ofReanimatedSwipeable-- legacy component runs animations on JS thread - Creating new gesture instances inside render (not in useMemo or outside component) -- causes gesture to reset every render
Gotchas & Edge Cases:
Gesture.Exclusive(doubleTap, singleTap)-- double-tap MUST be the first argument (higher priority) or it will never fire because single-tap activates first- Android modals need their own
GestureHandlerRootView-- gestures in modals fail silently without it onChangecallback is NOT available in the v3 hooks API -- it was removed; useonUpdatewith thechange*properties on the event object instead- Gesture callbacks are automatically workletized when your animation library is installed -- don't manually add
"worklet"directives unless you need them without the animation library Gesture.Native()wraps platform-native gestures (ScrollView, FlatList) -- use it when you need to create relations between custom gestures and native scrollingonFinalizereceives(event, success)-- thesuccessboolean tells you whether the gesture ended normally (END) or was cancelled/failed- Reusing the same gesture instance across multiple
GestureDetectorcomponents causes undefined behavior -- create separate instances - iPad trackpad two-finger gestures require
enableTrackpadTwoFingerGestureon both Pan andReanimatedSwipeable hoverEffectprop on GestureDetector only works on iOS 17.0+ and provides system-level visual effectsGesture.Fling()only fires at the end of the fling, not continuously -- useGesture.Pan()if you need continuous position tracking during a swipe
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST wrap the app root in GestureHandlerRootView -- gestures will silently fail without it)
(You MUST use GestureDetector with the builder API (Gesture.Pan(), etc.) -- NOT the legacy PanGestureHandler components)
(You MUST use onChange for incremental shared value updates and onUpdate for cumulative values -- mixing them causes drift)
(You MUST use Gesture.Simultaneous() for multi-touch interactions (pinch + pan) -- without it, only one gesture activates)
(You MUST NOT nest GestureDetector components using different API styles (hooks vs builder) under the same root -- this causes undefined behavior)
Failure to follow these rules will cause silent gesture failures, animation drift, and broken multi-touch interactions.
</critical_reminders>
Frequently asked questions
What to verify before installation and use
What does the mobile-animation-gesture-handler source document cover?
Quick Guide: Use Gesture Handler's v2 builder API (Gesture.Pan(), Gesture.Tap(), etc.) with GestureDetector for all touch interactions. Wrap your app root in GestureHandlerRootView. Compose gestures with Gesture.Simultaneous(), Gesture.Race(), and Gesture.Exclusive(). Use onChan…
How do I install mobile-animation-gesture-handler?
The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-animation-gesture-handler". Inspect the command and pinned source before running it.
Alternatives
Compare before choosing
event4u-app/agent-config
existing-ui-audit
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.
kensaurus/cursor-kenji
enhance-web-web3d
Add purposeful 3D/WebGL and scroll choreography to an existing site with Three.js/R3F, GSAP, or Motion. Use when "add 3D", "WebGL hero", "React Three Fiber", or "scroll-driven 3D". General UI polish → enhance-web-ui. Motion without 3D → enhance-motion.
UiPath/skills
uipath-coded-apps
UiPath Coded Apps — scaffold, build, run, and deploy Coded Web Apps and Coded Action Apps: React/TypeScript apps that call UiPath Cloud APIs via the `@uipath/uipath-typescript` SDK and ship to Automation Cloud (push/pull to Studio Web, pack, publish, deploy, OAuth-PKCE). Also generates live analytics & governance dashboards from a plain-language request, wired to tenant data via the Insights real-time API, with edit and deploy flows. For RPA→uipath-rpa, Python agents→uipath-agents, Maestro flows
hyperfx-ai/marketing-skills
slack
Slack messaging, file sharing, Block Kit formatting, and channel management. Use when the user wants to send Slack messages, post rich Block Kit layouts, share files, react, or manage channels and members.