react-brain
Browse decisions
React & language foundations 3App architecture 11UI 13Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness benchnewsletterarchitecturechangelogmethodologyroadmap

entriesui · verified 2026-10-08 · react + react-native

Animation & gestures

reviewedconfidence: mediumtrack: weakenedthis tier holds 71% on the public scorecard (7/20 graded · 0 overturned) →

related decisions: nav · charts · games · svg · lists

cited by: rn-versions · styling · lists · charts · svg · calendars · polish · native · games · ondevice-ai

re-verified 7× — 2026-10-08 · 2026-09-24 · 2026-09-21 · 2026-09-10 · 2026-09-01 · 2026-08-24 +1 · changelog

recommendation

React Native → Reanimated 4 + Gesture Handler 3 for UI-thread animation and gestures, with Worklets Bundle Mode on; core Animated (native driver) only for trivial cases. Web (React DOM) → Motion (framer-motion's successor). Reanimated 4.7 needs RN 0.86+; older apps take the RN 0.83–0.85 clause.

  • web animation (React DOM) → Motion / framer-motion — Reanimated and Gesture Handler are React Native only
  • React Native app on RN 0.83–0.85 → Reanimated 4.6 (with Worklets 0.12.x; 4.7 peers RN 0.86 - 0.88 and Worklets 0.13.x)
  • custom/GPU drawing or visuals → react-native-skia (new installs: `react-native-skia` 3.x, Graphite, minSdk 26 / iOS 15.1, dev build; existing @shopify apps: `react-native-skia@2` is the same v2 line renamed — hold @shopify ≤2.14 while Victory Native XL or react-native-livechart peer on the old name)
  • designer-made animations → lottie-react-native, else Skia's Skottie player
  • designer animations that need INTERACTIVITY/state machines, or many Rive views sharing files → Rive (new work on the Nitro line @rive-app/react-native, 0.4.x — pin; not the legacy package)
  • image-to-image morph transition → react-native-morph-view (GPU shader; niche)
  • simple declarative fade/slide on React Native → LayoutAnimation, else a Reanimated entering/exiting preset (Moti is dormant — see its row)
  • custom screen / shared-element transitions on React Navigation → react-native-screen-transitions (pin)
  • shared-element transitions on EXPO ROUTER → react-native-screen-choreography (the only pick that supports it; 0.x — pin the exact version, prototype on real screens)
  • hundreds of concurrently-animating views blowing the frame budget → react-native-ease (fully native-driven; young — benchmark it on your screens first)
  • heavy animation perf → react-native-best-practices (owns the perf rules)

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
Reanimated 4UI-thread worklet + CSS-style animations/transitions; New Architecture only. 4.7.0 (2026-09-18, verified vs npm 2026-09-24) peers react-native 0.86 - 0.88 + react-native-worklets 0.13.x and makes the new layout-animations engine the default; 4.6.0 (2026-08-21) peers RN 0.83 - 0.87 + Worklets 0.12.x. See note: REANIMATED 4.711.0M/wk · ships in 12/34
Gesture Handler 3.0native gestures; v3 adds a hook-based API built for the React Compiler + Reanimated 4, and a single unified Touchable button component that replaces (and deprecates) the library's 9 legacy button/touchable exports10.7M/wk · ships in 12/34
react-native-worklets (0.13.x)the worklets runtime under Reanimated 4, its own package. 0.13.0 (2026-09-18, verified vs npm 2026-09-24; peer react-native 0.86 - 0.88) pairs with Reanimated 4.7, 0.12.x with 4.6. Turn Bundle Mode on (stable since 0.10) and measure cold start. See note: WORKLETS BUNDLE MODE, WORKLETS 0.1310.2M/wk · ships in 10/34
react-native-skia (3.x; 2.x line)GPU 2D drawing; plays Lottie via Skottie; pairs with Reanimated. NOW PUBLISHED AS `react-native-skia` by its author: 3.0.0 (2026-10-02) renders with Graphite (Vulkan on Android, minSdk 26; iOS 15.1+; no Expo Go, no tvOS/Android TV/Mac Catalyst), 3.1.0 latest (2026-10-07); the v2 line continues as react-native-skia@2 (2.15.0). @shopify/react-native-skia STOPS at 2.14.0 (2026-10-01) and is not npm-deprecated; 2.13.0 removed legacy-architecture support. Verified vs npm + the fork's README + migration guide. See note: SKIA STEWARDSHIP1.6M/wk · ships in 3/34
lottie-react-nativedesigner Lottie/JSON animations; v7 adds visionOS1.7M/wk · ships in 7/34
Rive — @rive-app/react-native (Nitro) / rive-react-native (legacy)designer-driven INTERACTIVE vector animation (state machines), the Lottie alternative. The Nitro rewrite @rive-app/react-native (0.4.20, 2026-08-19, early line — pin) shares files/view-models as typed HybridObjects: up to 94× multi-view loads + ~4.7× lower memory vs legacy (rewrite authors' own benchmark). Legacy rive-react-native 9.8.5 (2026-07-17). See note: RIVE159k/wk · ships in 1/34
react-native-morph-view (Software Mansion)GPU image-morph transitions (Metal/AGSL shaders, metaball blend); RN 0.76+, iOS 15.1+/Android 13+; niche/new
Animated (core)built-in; RN 0.85 shared backend allows layout-prop animation with the native driver (from 0.85.1)11.0M/wk · ships in 12/34
Moti / LayoutAnimationdeclarative transitions. Moti wraps Reanimated but is DORMANT: npm 0.30.0 (2025-01-29), no repo commits since 2025-03-11 (verified 2026-08-18), and its wildcard Reanimated peer means nothing warns you on Reanimated 4. Keep it if installed and working; start new work on LayoutAnimation or plain Reanimated353k/wk · ships in 2/34
react-native-screen-choreographyshared-element transitions that cover Expo Router (peers expo-router >=56.1.1 OR @react-navigation/native-stack >=6) with typed defineTransition recipes, native forward preparation on iOS + Android, reduced-motion support. 0.6.0 (2026-09-17, verified vs npm + README + release notes); 0.x and moving fast — pin it. See note: SCREEN-CHOREOGRAPHY7k/wk
react-native-screen-transitionscustom screen/shared-element transitions FOR React Navigation (blank-stack navigator, bounds-driven navigation.zoom(), gesture choreography); featured on the official React Navigation blog. v4.0 (2026-08-27, verified vs npm + the migration guide) requires React 19.2 + Reanimated 4 + Worklets 0.8; stay on v3 for React <19.2 / Reanimated 3 / React Navigation 659k/wk
react-native-easeanimations driven entirely by Core Animation/ObjectAnimator — no per-frame JS OR UI-thread worklet work; author-run benchmark shows it holding frame budget at view counts where Reanimated saturates; young, and see the benchmark-bias caveat in reading53k/wk
Motion / framer-motion (WEB)the web (React DOM) animation default — declarative layout/exit/gesture animation; Motion is framer-motion's successor; React Native uses Reanimated instead. See note: MOTION 1328.3M/wk · ships in 4/34

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

Migration lines

version and deprecation lines this decision tracks — for YOUR repo's sequenced plan: the doctor or npx -y @heart-it/react-brain migrate .

@shopify/react-native-skia → react-native-skia (3.x Graphite; or react-native-skia@2 for the same v2 line under the new name) [superseded · effort M]

The author's fork publishes as `react-native-skia`; @shopify/react-native-skia stops at 2.14.0 (not npm-deprecated). Swap the dependency and rewrite every import (deep imports and Jest config too); never install both. Taking 3.x also means Android minSdk 26 (Vulkan), iOS 15.1, a dev build instead of Expo Go, no tvOS/Android TV/Mac Catalyst, and removed Canvas props debug/colorSpace/androidWarmup. HOLD if you use victory-native or react-native-livechart: both still peer on @shopify/react-native-skia.

registry.npmjs.org/react-native-skia · wcandillon.github.io/react-native-skia/docs/getting-sta… · registry.npmjs.org/victory-native/latest

npm weekly downloads (from the corpus's last signals run): react-native-reanimated 11.0M · react-native-gesture-handler 10.7M · react-native-worklets 10.2M · framer-motion 58.5M · motion 28.3M · lottie-react-native 1.7M · @shopify/react-native-skia 1.6M · moti 353k · react-native-screen-transitions 59k · react-native-screen-choreography 7k · react-native-ease 53k · @rive-app/react-native 159k · rive-react-native 80k

Verified notes

The selection axis is which thread pays for every frame. Reanimated 4 runs animation code as worklets on the UI thread, so JS-thread work cannot stutter it, and Gesture Handler 3 recognizes gestures natively and feeds those worklets directly — that pair is the React Native default. Since RN 0.85 (2026-04, verified vs the official RN 0.85 blog) core Animated and Reanimated ride one shared C++ animation backend built with Software Mansion, so the built-in is a native-driven option for trivial cases, not a competing engine. Fully native drivers (react-native-ease) remove per-frame worklet cost when hundreds of views animate at once; Skia is for drawing, not view properties. On the web the same reasoning lands on Motion. Heavy-animation perf routes to react-native-best-practices. REANIMATED 4.7 (2026-09-18 release; peers verified vs registry.npmjs.org 2026-09-24): two changes decide the upgrade. FLOOR: 4.7.0 peers react-native 0.86 - 0.88 and react-native-worklets 0.13.x; 4.6.0 (2026-08-21) peers 0.83 - 0.87 and 0.12.x, so an app on RN 0.83–0.85 stays on 4.6. 4.6 also fires the CSS animation/transition callbacks (onCSSAnimationStart/End/Iteration/Cancel, onCSSTransition*) natively on iOS + Android. DEFAULT FLIP: layout animations now run on the NEW light-tree-based engine. The documented escape is the USE_LEGACY_LAYOUT_ANIMATIONS_PROXY feature flag, but the legacy engine does not support shared element transitions, so that flag and ENABLE_SHARED_ELEMENT_TRANSITIONS cannot both be on → an app doing shared-element work has no rollback; it upgrades onto the new engine or stays below 4.7. WORKLETS BUNDLE MODE (Hermes V1 finding 2026-07-28, verified vs the Software Mansion writeup and reproduced in the Calazans benchmark in reading; RN 0.87 fix verified vs the v0.87.0 tag's package.json; Worklets 0.12 verified vs the worklets-0.12.0 release): Hermes V1 attached ~512KB of debug metadata to EVERY eval'd worklet, and Worklets' Legacy Eval Mode ships animation code to the UI runtime as strings, so memory scaled with unique worklets triggered. Software Mansion measured Expensify's bundle at 1,000+ unique worklets, with 100+ evaluated just to initialize (≥50MB at startup). The Hermes fix was backported to 250829098.0.15, and RN 0.87 (2026-08-11) pins hermes-compiler 250829098.0.16, so the regression is closed from 0.87 up. BELOW 0.87, in preference order: turn on Bundle Mode (exposes the mmap'd bytecode bundle instead of eval'ing strings — measured −~100MB PSS, ~45%, native heap ~142MB→~32MB, frame rate and CPU unchanged), the experimental bytecode option for Legacy Eval Mode, or pin Hermes 250829098.0.15. ON 0.87+ turn Bundle Mode on anyway: Software Mansion recommends it for its own performance gains, and Worklets 0.12 (2026-08-11) brought its script loading to parity with React Native's own loaders — local bundles are mmapped instead of held in an in-memory std::string for the app's lifetime, and Android dev-server bundles stream to a cache file. COUNTER-DATAPOINT (2026-09-10, TWiR #296 — the RN navigation benchmark cited in RB-E-NAV): its author reports Bundle Mode REGRESSING cold start, because it must parse the whole bundle, while measuring Reanimated + Worklets at a ~125 MB RAM premium (a second Hermes runtime, almost all anonymous heap). That is one device and one trivial app against Software Mansion's guidance, so the recommendation stands → measure cold start when you turn Bundle Mode on rather than treating it as free. WORKLETS 0.13 (2026-09-18, verified vs the 0.13.0 changelog; npm latest verified 2026-09-24): the line Reanimated 4.7 pairs with. It adds a standalone networking module (fetch/XHR/Blob/FormData/AbortController) for Bundle Mode runtimes — createWorkletRuntime takes an enableNetworking option defaulting to true, replacing the FETCH_PREVIEW_ENABLED preview flag — a Rust/OXC port of the Babel plugin (react-native-worklets/plugin-oxc/babel) for Bundle Mode, createSynchronizable({ fixedType }) with setDirty, and Swift Package Manager integration on iOS. Earlier lines: 0.11 added experimental Hermes-bytecode worklets + Shareable values across isolated runtimes; 0.12 added WeakRef on worklet runtimes and the Bundle Mode loader parity above. SCREEN-CHOREOGRAPHY (2026-09-21, verified vs npm, the README and the 0.5/0.6 release notes): the Expo Router shared-element pick. Expo Router is a declared peer (>=56.1.1) with its own installation guide and example app; 0.5 added typed `defineTransition` recipes and native forward preparation on BOTH platforms (destination layout-stability checks, batched target measurement) plus Android CI benchmarks; 0.6 added scoped Enter/Exit reveals with reduced-motion support, `presentationProgress`, and duration-based springs. Why it is a PIN and not a default: it was 0.x with 13 published versions at 0.6.0, and 0.4→0.5 renamed most of the public API (SharedElement.Live→SharedElement, makeLiveTransition→makeTransition, StandInContainer→TransitionSurface, and ~6 type renames) with another feature release seven days later. It also drags in a FIVE-LIBRARY native peer stack — Reanimated >=4, Worklets >=0.8, Screens >=4 and react-native-teleport >=1.2 on top of the navigator — and the author states that those lower bounds are "not a full tested compatibility matrix" → prototype it on your real screens, pin the exact version, and rebuild native (pods on iOS) because forward preparation is native. RIVE (2026-07-13, Margelo blog pass; versions verified vs npm 2026-09-24): the RN SDK's Nitro rewrite ships as the scoped @rive-app/react-native (0.4.20, 2026-08-19) while the legacy unscoped rive-react-native is at 9.8.5 (2026-07-17) — a supersession in progress. The migrate rule waits for the new line reaching 1.0 or a formal legacy deprecation; both are wired as tripwires. SKIA STEWARDSHIP (2026-09-21, verified vs Shopify's announcement + npm + the GitHub API): Shopify is migrating its apps off React Native. It SPONSORS react-native-skia through the end of 2026; William Candillon (its author) continues working on it beyond that, will FORK THE REPO in the coming months and publish under a NEW NAME, and the original Shopify repo is archived once that transition completes. Nothing is deprecated: @shopify/react-native-skia latest is 2.13.0 (2026-09-24) — eight days AFTER the announcement — and neither the repo nor the npm package carries an archive/deprecation flag (checked 2026-09-21; npm re-checked 2026-10-01) → keep using it, pin rather than float across the window, and expect to change the dependency name (and this corpus's detect rows) when the fork publishes. 2.13.0 REMOVES legacy-architecture support entirely (New Architecture only from here) — an app still on the old architecture cannot take Skia past 2.12.x, on top of the pending rename. This thread is owned here; RB-E-CHARTS, RB-E-GAMES and RB-E-SVG carry pointers. The same announcement puts FlashList on critical-fixes-only (RB-E-LISTS owns that) and archives Restyle, which this corpus never recommended. THE HANDOVER LANDED (2026-10-08, verified vs npm, the fork's README and migration guide, and the GitHub API, whose Shopify/react-native-skia lookup now answers "Moved Permanently" to wcandillon/react-native-skia): the package is now `react-native-skia` (maintainers wcandillon, kudochien, chrfalch). 3.0.0 (2026-10-02) is "React Native Skia Graphite" — Vulkan instead of OpenGL on Android with minSdk 26, iOS 15.1 minimum, a development build required (no Expo Go), tvOS / Android TV / Mac Catalyst dropped, the Canvas props debug / colorSpace / androidWarmup removed, screenshot tests may differ; the drawing API is unchanged. 3.1.0 (2026-10-07) links Dawn from react-native-webgpu-dawn so Skia and react-native-webgpu share one GPU device. The v2 line stays maintained as `react-native-skia@2` (2.15.0, 2026-10-02). @shopify/react-native-skia stops at 2.14.0 (2026-10-01, which also removed the mutable SkPath API) and carries NO npm deprecation flag, so the tripwire that waited for one would never have fired; its then: was done by hand. Migrating = swap the dependency, rewrite imports (including deep imports and Jest config), never install both names side by side. The catch is downstream: victory-native 42.0.1 peers @shopify/react-native-skia >=2.6.0 <3.0.0 and react-native-livechart 4.26.0 peers @shopify/react-native-skia >=2.6.0, so chart stacks stay on the @shopify name until those libraries repoint (RB-E-CHARTS). SKIA 2.10 MOVED OFF HostObject (2026-07-23, verified vs the release + the published manifest): the release's one feature is "migrate from host objects to native states" (#3964) — Skia's JSI objects now use NativeState rather than HostObject, the direction the Hermes team favors because HostObject routes every property access back through a C++ trampoline. Its published peer range is react-native >= 0.78 and react >= 19.0, with react-native-reanimated >= 4.0.0 and react-native-worklets >= 0.7.0 as OPTIONAL peers → Skia does not force Reanimated on you, but if you pair them the v4 line is the floor. MOTION 13 (web; 2026-08-06, verified vs npm + the motion.dev upgrade guide): one breaking change — it drops @emotion/is-prop-valid as an auto-detected optional dependency, so styled-components/Emotion codebases must inject the prop-validation function via MotionConfig (or invert composition so the styling library controls prop forwarding) or previously-filtered props leak onto the DOM. framer-motion (the legacy package name) moved to 13.0.0 in lockstep; neither package is deprecated. HISTORY: 2026-10-08 REOPENED: the Skia handover landed — npm `react-native-skia` 3.x (Graphite) by its author, v2 continues as react-native-skia@2, @shopify/react-native-skia stops at 2.14.0 (not npm-deprecated); option row, when-clause, detect and migrate rows repointed; the deprecation tripwire retired with its then: done by hand. 2026-10-01 REOPENED: Skia 2.13.0 removes legacy-architecture support entirely — apps on the old architecture are capped at 2.12.x, on top of the pending author-fork rename. 2026-09-24 CORRECTED: legacy rive-react-native is at 9.8.5 (2026-07-17), not 9.8.3 "quiet since 2026-04". 2026-09-21 GAP CLOSED: Expo Router shared-element transitions → react-native-screen-choreography 0.6 (opened 2026-09-10; skipped twice as too-early at 0.4, TWiR #296). 2026-07-17 CORRECTED: react-native-worklets is a 0.x line, not '8.0'. 2026-06-25 GAP CLOSED: web (React DOM) pick Motion added — the [react]-platform entry had recommended for React Native only.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

React Native Gesture Handler's Touchable: The Button We Wish We Had SoonerJakub Piasecki (Software Mansion), 2026-08-20

The maintainer's account of why Gesture Handler had accumulated NINE separate button components (drop-ins for RN's Touchables, then for Pressable, each with different feedback) and why RNGH 3's answer is one configurable Touchable that deprecates the rest. The durable selection fact for anyone on RNGH 3: new pressables go through Touchable, not the legacy exports; the post includes measured press-feedback latency comparisons against RN's Pressable.

CSS vs. JavaScript AnimationsJosh W. Comeau

First-principles explainer on the real distinction (main-thread contention, compositor-friendly properties, WAAPI) rather than the CSS-is-always-faster myth. A durable animation mental model that applies to web and RN reasoning alike.

How react-native-ease runs animations with no JavaScript loopPeter Piekarczyk

Deep dive on driving animations entirely via Core Animation / ObjectAnimator with no per-frame JS, incl. iOS model vs presentation layers and cross-platform spring physics. The mental model for truly native-driven RN animation.

Chasing a Phantom Jump: making Skia + Reanimated smooth on low-end AndroidVishesh Raheja (Margelo)

A low-end-Android profiling deep-dive: smoothness is frame-cadence timing, not curve math; the dominant fix is SurfaceView over TextureView (no per-frame texture upload, ~50-65% less RenderThread CPU), plus stable-reference buffer mutation and quantizing per-frame values. With profiler-triangulation methodology (gfxinfo/Perfetto/Hermes).

The real cost of React Native animations: benchmarking every approachJanic Duplessis (Expo; react-native-ease author)

The only cross-library per-frame benchmark: UI-thread cost of core Animated vs Reanimated (shared values AND the CSS API) vs Ease on real devices — at ~500 animating views only the fully native-driven approach stays under frame budget (Reanimated SVs measured ~36ms/frame). CAVEAT: the author created Ease, the approach that wins — treat the numbers as vendor-run and re-measure on your own screens; the methodology and the per-frame cost model are the durable part.

Which React Native Animation Library Should You Use for Performance?Andrei Calazans

The INDEPENDENT replication the Expo/Ease benchmark above asks for — same three-way question (Animated with useNativeDriver, Reanimated 4.5, Ease 0.7), different author, reproducible harness (AndreiCalazans/react-native-animation-performance), Android release build on New Arch, 90Hz physical device, Maestro-driven, median of 3, 60 boxes animating. It splits the answer BY ANIMATION TYPE instead of picking a winner: for touch/state/loop all three keep JS at the idle floor and Ease drops the fewest frames with Animated close behind; SCRUB is the fork — Animated drives the value via PanResponder→setValue on the JS thread (29% JS CPU, ~26% of JS frames dropped, and useNativeDriver cannot save a value you set from JS each frame) while Reanimated keeps it entirely on the UI thread (2.9% JS CPU). Blunt version: Reanimated when a finger is dragging, Ease or the native driver otherwise. Two caveats the author states himself: 60 independent nodes deliberately punishes per-node cost (Reanimated's useAnimatedStyle mapper), so the UI-thread loop ranking is partly an artifact — at one hero element Reanimated is likely best overall; and the ~50MB memory premium it measured DISAPPEARS with Worklets Bundle Mode on (−~100MB PSS in the follow-up re-run).

A React trick to improve exit animationsMax Barvian

Uses Suspense to freeze exiting content during animations; explains Fragment refs, useInsertionEffect, and Suspense DOM-update behavior. A durable web exit-animation technique grounded in React internals.

Rewriting Rive React Native with Nitro Modules: up to 94× Faster Multi-View LoadsMiklós Fazekas (Margelo)

Why the Rive RN SDK's wins came from MODELING, not micro-optimization: the legacy module flattened files/view-models into a per-view God object, so every view re-parsed state; Nitro HybridObjects make them shared typed objects (parse once, render many) — 94× on a 24-view load, ~4.7× lower memory, ~0.3-0.4µs calls vs ~1.5µs TurboModule / ~21µs legacy bridge (iPhone 13 mini, release; the rewrite authors' own benchmark). A general lesson for native-module design: model objects, not modules.

Sources

Depth (in-domain rules) is owned by the react-native-best-practices skill — this entry is selection breadth.

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About animation & gestures — where the per-frame work runs

Diataxis: Explanation. This page builds understanding of the animation landscape — the reasoning behind the picks. It is not an API guide. Animation performance rules (thresholds, profiling) are owned by react-native-best-practices; GPU drawing by RB-E-GAMES/RB-E-SVG. Read this for the why.

The one question that organises everything: which thread pays, every frame?

An animation is a piece of work that must complete every ~16ms, forever, while the rest of your app keeps running. So the durable selection axis is not API style — it is where that per-frame work executes. There are four tiers, each cheaper than the one before:

  1. JS thread (core Animated with useNativeDriver: false) — every frame crosses into your busiest thread. One GC pause, one heavy render, and the animation stutters.
  2. UI thread via worklets (Reanimated) — JS code compiled to run on the UI thread's own runtime (react-native-worklets, now a standalone package). Immune to JS-thread jank, but the worklet itself still costs UI-thread time per frame.
  3. Fully native drivers (native-driven Animated, react-native-ease) — the animation is handed to Core Animation / ObjectAnimator once and no per-frame JS or worklet runs at all.
  4. GPU canvas (Skia) — for drawing that isn't view-property animation at all.

Everything in the entry falls out of this ladder, including the failure modes.

The default, and why

React Native → Reanimated 4 + Gesture Handler 3 for real UI-thread animation and gestures. Web (React DOM) → Motion (framer-motion's successor).

Reanimated 4 sits at tier 2 and is the ecosystem's center of gravity: CSS-style transitions, shared values, and — since RN 0.85 — a shared C++ animation backend with core Animated, so the built-in and the library ride one engine instead of two competing ones. Gesture Handler 3 completes it: gestures are recognized natively and feed worklets directly, and its v3 hook-based API was rebuilt for the React Compiler era (RB-E-REACT-CORE). On the web the same reasoning lands on Motion: declarative layout/exit/gesture animation over compositor-friendly properties — Reanimated and Gesture Handler are React Native-only.

The landscape, tier by tier

Reanimated 4 / react-native-worklets — the tier-2 workhorse. Worklets are now their own package, which matters beyond animation (VisionCamera frame processors, Expo UI synchronous state — RB-E-NATIVE-UI).

Gesture Handler 3 — native gesture recognition; the input half of the animation story.

Core Animated — fine at tier 3 (native driver) for simple cases; since 0.85.1 it can even drive layout props natively. Its trap is tier 1: useNativeDriver: false silently moves the work to the JS thread (the corpus's source-signal rule flags exactly this).

react-native-ease — the tier-3 specialist: animations driven entirely by Core Animation / ObjectAnimator, zero per-frame JS or worklet work. The author's cross-library benchmark shows it holding frame budget at view counts where worklet approaches saturate — read with the stated caveat that the benchmark's author built the winner; the cost model is the durable part.

react-native-screen-transitions — screen/shared-element choreography for React Navigation (RB-E-NAV); featured on the official React Navigation blog, new — pin.

Skia / Lottie / morph-view — tier 4 and specials: react-native-skia for custom GPU drawing (and Lottie via Skottie), lottie-react-native for designer-made animation files, react-native-morph-view for GPU image-morph transitions (niche).

Moti — declarative sugar over Reanimated; dormant since early 2025. Fine if installed; prefer plain Reanimated or LayoutAnimation for new work.

Facts that change the pick (verified 2026-09-24)

  • Reanimated 4.7 raises the floor. 4.7.0 peers react-native 0.86 – 0.88 and react-native-worklets 0.13.x; an app on RN 0.83–0.85 stays on 4.6 (Worklets 0.12.x). 4.7 also makes the new layout-animations engine the default, and its rollback flag cannot be combined with shared element transitions — shared-element apps have no rollback.
  • Turn on Worklets Bundle Mode. Below RN 0.87 it is the fix for the Hermes V1 per-worklet memory regression (measured −~100MB PSS); on 0.87+ Software Mansion still recommends it. One independent benchmark saw it regress cold start, so measure that when you switch.
  • Skia is changing hands. Shopify is leaving React Native; react-native-skia's author will fork it under a new package name and the Shopify repo will be archived. Nothing is deprecated yet (2.12.0 shipped 2026-09-16) — pin across the transition.
  • Expo Router shared elements go to react-native-screen-choreography (0.x, pin the exact version); React Navigation stacks keep react-native-screen-transitions.
  • Interactive designer animation (state machines) goes to Rive's Nitro line, @rive-app/react-native (0.4.x, pin), not the legacy rive-react-native.

Tradeoffs and failure modes to name out loud

  • useNativeDriver: false — the classic tier-1 trap: JS-thread animation that jitters under load. Native-drive it or move it to Reanimated.
  • Hundreds of concurrently animating views — even tier 2 pays per-frame worklet cost per view; at scale (~hundreds) only tier 3 stays under budget. Benchmark before committing an animation-heavy screen design.
  • Reaching for Skia to animate view properties — GPU canvas is for drawing; transform/ opacity animation belongs in tiers 2–3.
  • Two animation systems fighting — pre-0.85 this was real (Animated vs Reanimated timing); the shared C++ backend resolved it. On ≥0.85 mixing them is no longer an architectural smell.
  • Web habits on native (and vice versa) — Motion doesn't exist on RN; Reanimated doesn't exist on the web. Shared-codebase teams keep animation platform-local (RB-E-CROSSPLATFORM).

How it interacts with the rest of the stack

  • Navigation (RB-E-NAV). Screen transitions are animations with navigation semantics — react-native-screen-transitions builds them on React Navigation rather than forking it.
  • Native (RB-E-NATIVE). Worklets are the same machinery VisionCamera v5 frame processors use; understanding tier 2 here pays off there.
  • Lists (RB-E-LISTS). List re-renders and animations compete for the same frame budget — the "render once" discipline in the STATE/LISTS readings is the other half of smoothness.
  • React core (RB-E-REACT-CORE). Gesture Handler 3's hook API assumes the Compiler era; animation values deliberately live outside React state to avoid re-render coupling.

In one paragraph

Pick animation tooling by which thread pays every frame. React Native's default is Reanimated 4 + Gesture Handler 3 — UI-thread worklets, one shared C++ engine with core Animated since RN 0.85 — with core Animated (native-driven) for trivial cases, ease when hundreds of concurrent animations demand zero per-frame work, Skia for GPU drawing, and react-native-screen-transitions for shared-element navigation choreography. On the web, use Motion. The failure modes are all the same mistake in different clothes: putting per-frame work on a thread that has better things to do.


*See also: RB-E-NAV (screen transitions), RB-E-NATIVE (worklets/JSI machinery), RB-E-GAMES

  • RB-E-SVG (GPU drawing), RB-E-LISTS (the other half of the frame budget). Performance rules and thresholds: the react-native-best-practices skill.*

Related in ui: styling · component-libs · lists · a11y · i18n · charts · editors · svg · maps · calendars · sheets · polish