Reanimated Skia Performance

andreev-danila/skills/skills/reanimated-skia-performance

作者 andreev-danila48e4b01e982848af078bdf1bc56ae2815edc6a1b无许可证24 个星标收录于 2026年10月9日更新于 2026年10月9日仓库2个月前更新

Write and review high-performance React Native animations and 2D graphics using react-native-reanimated (v4+) and @shopify/react-native-skia (Canvas scenes, runtime effects/shaders). Use for: gesture-driven interactions, spring/timing transitions, layout/mount animations, Reanimated CSS transitions/animations, Skia drawings, animated shader uniforms, path/vector interpolation, dev-mode tuning panels (sliders), and diagnosing animation jank (JS thread stalls, excessive re-renders, per-frame allocations).

AI 生成的概览

指导编写和审查基于 Reanimated v4 的高性能 React Native 动画与 Skia 二维图形。

功能
提供使用 react-native-reanimated v4 构建手势驱动、弹簧、时间、布局和 CSS 动画的约定、工作流程和代码模式,并涵盖 Skia Canvas 场景与带动画 uniform 的运行时效果着色器。还涉及开发模式下滑块调参面板,以及诊断动画卡顿,如 JS 线程阻塞、过度重渲染和逐帧内存分配。四个参考文件提供更深入的 Reanimated、Skia、开发调参和性能检查清单内容。
适用场景
适用于实现或审查 React Native 动画与二维图形代码时,包括手势交互、过渡、挂载/布局动画、Skia 绘图和动画着色器 uniform。也用于性能检查和调试卡顿动画。
运行要求
需要使用 react-native-reanimated v4+ 和 @shopify/react-native-skia 的 React Native 项目,手势模式还需 react-native-gesture-handler。不附带脚本;该技能由说明和四个参考文档组成。

Reanimated + Skia Performance

Defaults

  • Keep animation state on the UI thread: useSharedValue, useDerivedValue, worklets.
  • Prefer Reanimated v4 declarative APIs; avoid legacy Animated.
  • Prefer shared.get() / shared.set() over shared.value in app code (React Compiler friendly).
  • Minimize JS↔UI crossings: avoid scheduleOnRN/runOnJS except for unavoidable side effects.
  • For Skia, avoid per-frame React renders: pass SharedValues directly to Skia props/uniforms.

Workflow

  1. Define the effect: what animates, duration/curve, interrupt rules, and gesture input.
  2. Choose the renderer:
    • Use Reanimated styles for transforms/opacity/layout.
    • Use Skia for custom drawing, particles, gradients, runtime effects/shaders.
  3. Choose the primitive:
    • Use Reanimated CSS transitions/animations for simple declarative style changes.
    • Use withTiming for tweens, withSpring for physics, withDecay for momentum.
    • Use Layout Animations for mount/unmount or layout changes.
  4. Implement a single data flow on the UI thread (no setState per frame).
  5. Do a perf pass (see references/perf-checklist.md).

Patterns

Shared values (React Compiler safe)

  • Read: progress.get()
  • Write: progress.set(withTiming(1))
ts
import { useEffect } from 'react';import { useSharedValue, withTiming } from 'react-native-reanimated';
const progress = useSharedValue(0);
useEffect(() => {  progress.set(withTiming(1, { duration: 400 }));}, [progress]);

Reanimated v4 CSS transitions

Use for state-driven style changes where you do not need bespoke worklets.

tsx
import Animated from 'react-native-reanimated';
<Animated.View  style={{    width: expanded ? 240 : 160,    opacity: enabled ? 1 : 0.6,    transitionProperty: ['width', 'opacity'],    transitionDuration: 220,    transitionTimingFunction: 'ease-in-out',  }}/>

Reanimated v4 CSS animations (keyframes)

Use for keyframe-like sequences (pulses, wiggles, repeated loops) without writing custom worklets.

Supported settings:

  • animationName (keyframes object)
  • animationDuration
  • animationDelay
  • animationTimingFunction
  • animationDirection
  • animationIterationCount
  • animationFillMode
  • animationPlayState
tsx
import Animated from 'react-native-reanimated';
const pulse = {  from: { transform: [{ scale: 1 }], opacity: 0.9 },  '50%': { transform: [{ scale: 1.06 }], opacity: 1 },  to: { transform: [{ scale: 1 }], opacity: 0.9 },};
<Animated.View  style={{    animationName: pulse,    animationDuration: '900ms',    animationDelay: '80ms',    animationTimingFunction: 'ease-in-out',    animationDirection: 'alternate',    animationIterationCount: 'infinite',    animationFillMode: 'both',    animationPlayState: paused ? 'paused' : 'running',  }}/>

Dev-mode tuning panel (sliders)

Use sliders to tune animation configs or shader uniforms in __DEV__.

  • Keep the tuning UI in a separate component to avoid re-rendering the animated scene.
  • Write slider values into SharedValues via .set().
  • For shader tuning: feed SharedValues into uniforms via useDerivedValue.
  • For animation config tuning: store config params in SharedValues and read them when starting/restarting the animation.

See: references/dev-tuning.md.

Gesture-driven animation (Gesture Builder API)

Update shared values in onUpdate and drive visuals via animated styles.

tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
const x = useSharedValue(0);const gesture = Gesture.Pan()  .onUpdate((e) => {    x.set(e.translationX);  })  .onEnd(() => {    x.set(withSpring(0));  });
const style = useAnimatedStyle(() => ({ transform: [{ translateX: x.get() }] }));
<GestureDetector gesture={gesture}>  <Animated.View style={style} /></GestureDetector>;

Skia shader with animated uniforms

  • Compile the runtime effect once (useMemo).
  • Pass uniforms as a SharedValue<Uniforms> (Skia detects animated props by { value: T }).
  • Do not access .value in your app code; pass the SharedValue object.
tsx
import { useMemo } from 'react';import { Skia, Canvas, Fill, Paint, Shader, type Uniforms } from '@shopify/react-native-skia';import { useDerivedValue } from 'react-native-reanimated';import { useClock } from '@shopify/react-native-skia';
const sksl = `uniform float2 u_resolution;uniform float u_time;
half4 main(float2 xy) {  float2 uv = xy / u_resolution;  float v = 0.5 + 0.5 * sin(u_time * 0.002 + uv.x * 8.0);  return half4(v, v * 0.6, 1.0 - v, 1.0);}`;
const effect = useMemo(() => Skia.RuntimeEffect.Make(sksl), []);if (!effect) return null;
const clock = useClock(); // ms since first frameconst uniforms = useDerivedValue<Uniforms>(() => ({  u_resolution: Skia.Point(width, height),  u_time: clock.get(),}));
<Canvas style={{ width, height }}>  <Fill>    <Paint>      <Shader source={effect} uniforms={uniforms} />    </Paint>  </Fill></Canvas>;

Common pitfalls

  • Do not read shared values in React render; read them in worklets (useAnimatedStyle, useDerivedValue).
  • Do not call runOnJS/scheduleOnRN in onUpdate unless you must.
  • Do not allocate big arrays/paths/images per frame; memoize Skia objects and update via animated props.
  • For runtime effects, always provide every uniform declared in the shader; missing uniforms throw.

References

  • Reanimated v4 patterns and repo conventions: references/reanimated-v4.md
  • Skia Canvas + runtime effects/shaders patterns: references/skia-shaders.md
  • Dev-mode tuning panels (sliders): references/dev-tuning.md
  • Performance checklist + debugging: references/perf-checklist.md

来源与署名

来源:andreev-danila/skills位于skills/reanimated-skia-performance提交48e4b01

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架