animation-patterns
<!-- Loaded by react-native-engineer when task involves animations, Reanimated, shared values, gestures, press states, interpolation -->
$ npx -y skills add notque/vexjoy-agent --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
<!-- Loaded by react-native-engineer when task involves animations, Reanimated, shared values, gestures, press states, interpolation -->
Agent definition
animation-patterns.mdAnimation Patterns Reference
<!-- Loaded by react-native-engineer when task involves animations, Reanimated, shared values, gestures, press states, interpolation -->
Animate Transform and Opacity for 60fps
**Impact:** HIGH — GPU-accelerated, no layout recalculation
Transform and opacity run on the GPU. Animating `width`, `height`, `top`, `left`, `margin`, or `padding` recalculates layout every frame.
**Instead of:**
const animatedStyle = useAnimatedStyle(() => ({
height: withTiming(expanded ? 200 : 0),
}))**Use:**
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scaleY: withTiming(expanded ? 1 : 0) }],
opacity: withTiming(expanded ? 1 : 0),
}))
return (
<Animated.View style={[{ height: 200, transformOrigin: 'top' }, animatedStyle]}>
{children}
</Animated.View>
)For slides: `transform: [{ translateY: withTiming(visible ? 0 : 100) }]`
GPU-accelerated: `transform` (translate, scale, rotate), `opacity`. Everything else triggers layout.
---
Store State in Shared Values, Derive Visual Output
**Impact:** HIGH — single source of truth, easy to extend
Shared values represent real state (`pressed`, `progress`, `isOpen`), not visual outputs (`scale`, `opacity`). Derive visuals using `interpolate`.
**Instead of:**
const scale = useSharedValue(1)
const tap = Gesture.Tap()
.onBegin(() => scale.set(withTiming(0.95)))
.onFinalize(() => scale.set(withTiming(1)))
**Use:**
import { interpolate } from 'react-native-reanimated'
const pressed = useSharedValue(0)
const tap = Gesture.Tap()
.onBegin(() => pressed.set(withTiming(1)))
.onFinalize(() => pressed.set(withTiming(0)))
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: interpolate(pressed.get(), [0, 1], [1, 0.95]) }],
opacity: interpolate(pressed.get(), [0, 1], [1, 0.7]),
}))---
Use useDerivedValue Over useAnimatedReaction for Derivations
**Impact:** MEDIUM — declarative with automatic dependency tracking
`useDerivedValue` computes new shared values declaratively. `useAnimatedReaction` is for side effects (haptics, `runOnJS`), not producing values.
**Instead of:**
useAnimatedReaction(
() => progress.value,
(current) => { opacity.value = 1 - current }
)**Use:**
const opacity = useDerivedValue(() => 1 - progress.get())
---
Use GestureDetector for Animated Press States
**Impact:** MEDIUM — UI thread animations without JS thread round-trip
`GestureDetector` with `Gesture.Tap()` runs callbacks as worklets on UI thread. Pressable's `onPressIn`/`onPressOut` go through JS thread, adding latency.
**Instead of:**
<Pressable
onPressIn={() => scale.set(withTiming(0.95))}
onPressOut={() => scale.set(withTiming(1))}
onPress={onPress}
>**Use:**
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
import { runOnJS } from 'react-native-reanimated'
const pressed = useSharedValue(0)
const tap = Gesture.Tap()
.onBegin(() => pressed.set(withTiming(1)))
.onFinalize(() => pressed.set(withTiming(0)))
.onEnd(() => runOnJS(onPress)())
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: interpolate(pressed.get(), [0, 1], [1, 0.95]) }],
}))
return (
<GestureDetector gesture={tap}>
<Animated.View style={animatedStyle}>
<Text>Press me</Text>
</Animated.View>
</GestureDetector>
)---
Use .get() and .set() with React Compiler
**Impact:** LOW — required for React Compiler compatibility
With React Compiler, use `.get()` and `.set()` instead of `.value`. The compiler cannot track `.value` access.
**Instead of:**
count.value = count.value + 1
**Use:**
count.set(count.get() + 1)
Inside worklets (`useAnimatedStyle`, `useAnimatedReaction`), `.value` still works — the compiler does not process worklets.
Read more
Animation Patterns Reference
<!-- Loaded by react-native-engineer when task involves animations, Reanimated, shared values, gestures, press states, interpolation -->
Animate Transform and Opacity for 60fps
**Impact:** HIGH — GPU-accelerated, no layout recalculation
Transform and opacity run on the GPU. Animating `width`, `height`, `top`, `left`, `margin`, or `padding` recalculates layout every frame.
**Instead of:**
const animatedStyle = useAnimatedStyle(() => ({
height: withTiming(expanded ? 200 : 0),
}))**Use:**
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scaleY: withTiming(expanded ? 1 : 0) }],
opacity: withTiming(expanded ? 1 : 0),
}))
return (
<Animated.View style={[{ height: 200, transformOrigin: 'top' }, animatedStyle]}>
{children}
</Animated.View>
)For slides: `transform: [{ translateY: withTiming(visible ? 0 : 100) }]`
GPU-accelerated: `transform` (translate, scale, rotate), `opacity`. Everything else triggers layout.
---
Store State in Shared Values, Derive Visual Output
**Impact:** HIGH — single source of truth, easy to extend
Shared values represent real state (`pressed`, `progress`, `isOpen`), not visual outputs (`scale`, `opacity`). Derive visuals using `interpolate`.
**Instead of:**
const scale = useSharedValue(1) const tap = Gesture.Tap() .onBegin(() => scale.set(withTiming(0.95))) .onFinalize(() => scale.set(withTiming(1)))
**Use:**
import { interpolate } from 'react-native-reanimated'
const pressed = useSharedValue(0)
const tap = Gesture.Tap()
.onBegin(() => pressed.set(withTiming(1)))
.onFinalize(() => pressed.set(withTiming(0)))
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: interpolate(pressed.get(), [0, 1], [1, 0.95]) }],
opacity: interpolate(pressed.get(), [0, 1], [1, 0.7]),
}))---
Use useDerivedValue Over useAnimatedReaction for Derivations
**Impact:** MEDIUM — declarative with automatic dependency tracking
`useDerivedValue` computes new shared values declaratively. `useAnimatedReaction` is for side effects (haptics, `runOnJS`), not producing values.
**Instead of:**
useAnimatedReaction(
() => progress.value,
(current) => { opacity.value = 1 - current }
)**Use:**
const opacity = useDerivedValue(() => 1 - progress.get())
---
Use GestureDetector for Animated Press States
**Impact:** MEDIUM — UI thread animations without JS thread round-trip
`GestureDetector` with `Gesture.Tap()` runs callbacks as worklets on UI thread. Pressable's `onPressIn`/`onPressOut` go through JS thread, adding latency.
**Instead of:**
<Pressable
onPressIn={() => scale.set(withTiming(0.95))}
onPressOut={() => scale.set(withTiming(1))}
onPress={onPress}
>**Use:**
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
import { runOnJS } from 'react-native-reanimated'
const pressed = useSharedValue(0)
const tap = Gesture.Tap()
.onBegin(() => pressed.set(withTiming(1)))
.onFinalize(() => pressed.set(withTiming(0)))
.onEnd(() => runOnJS(onPress)())
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: interpolate(pressed.get(), [0, 1], [1, 0.95]) }],
}))
return (
<GestureDetector gesture={tap}>
<Animated.View style={animatedStyle}>
<Text>Press me</Text>
</Animated.View>
</GestureDetector>
)---
Use .get() and .set() with React Compiler
**Impact:** LOW — required for React Compiler compatibility
With React Compiler, use `.get()` and `.set()` instead of `.value`. The compiler cannot track `.value` access.
**Instead of:**
count.value = count.value + 1
**Use:**
count.set(count.get() + 1)
Inside worklets (`useAnimatedStyle`, `useAnimatedReaction`), `.value` still works — the compiler does not process worklets.
Essays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.
Repo: notque/vexjoy-agent
Other agents on vexjoy-agent.
- ansible-automation-engineer
Ansible automation: playbooks, roles, collections, Molecule testing, Vault security.
Open agent - modules
**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes **Version range**: ansible-core 2.14+ / Ansible Collections (community.general 7.0+) **Generated**: 2026-04-04 — verify against current Ansible
Open agent - testing
**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**: Molecule 6.0+ / ansible-lint 6.0+ / ansible-core 2.14+ **Generated**: 2026-04-04 — verify against current Molecule and ansible-lint documentation
Open agent - base-instructions
Universal operational rules injected by /do at agent dispatch. Domain-specific rules live in each agent's .md file.
Open agent - communication-patterns
**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what to detect and how to fix each. **Version range**: all versions **Generated**: 2026-05-11
Open agent - combat-effects-upgrade
Zero-dependency combat visual upgrades: CSS particle replacement, Framer Motion combat juice, CSS 3D card transforms.
Open agent

