I needed a 2D game engine for an action game I'm building in React Native. I went looking for one. There is no React Native game engine in 2026.
There are four partial options - each serious in its own domain, each missing something fundamental for the others. I spent two weeks mapping exactly where each one breaks. By the end of the second week, I'd started writing the missing layer myself. This post is the map I built before that decision.
The four options I evaluated: react-native-game-engine (RNGE), Phaser 4 inside a WebView, the graphics primitives expo-gl and react-native-wgpu, and @shopify/react-native-skia paired with Reanimated 4. None of these is a React Native game engine in the sense of "install it, add a game loop, render sprites, play audio, manage scenes." Each one is something else - a renderer, a context, a web engine in a sandbox, a dormant project - and each one fails at a specific cliff. Here is where each cliff sits and what it means.
Option 1 - react-native-game-engine (dormant, JS-only)
RNGE was where I started. It is the only library that has ever called itself a React Native game engine, and the API is real - an entity-component update + render loop, the pattern any 2D engine starts from. I cloned it, ran the examples, and the architecture sketch convinced me for about an hour.
Then I read the publish history. The last version is 1.2.0, published in June 2020 - nearly six years ago. Around 2,235 downloads per week, sustained by projects that cannot migrate, not by anyone actively choosing it. The issue tracker has been silent for years.
The deeper problem was architectural, not bibliographic. RNGE renders each game entity by mounting a React Native View. There is no GPU path, no sprite atlas, no draw-call batching. On a mid-range Android, roughly 50 active entities is where frames start to drop. For a turn-based puzzle game with a handful of pieces, RNGE still works - that regime is real and the library still serves it. For anything action-shaped - bullets, particles, animated enemies - the ceiling appears before the game is interesting to play.
This is a reference implementation with a community, not a maintained engine. I closed the tab.
Option 2 - Phaser 4 in a WebView
Phaser is one of the great open-source projects of the decade. Phaser 4 shipped GA in April 2026 with around 40,000 GitHub stars and roughly 166,000 npm downloads per week - those are real numbers from a real engine, on the web. If you are building a 2D game for browsers, this is what you reach for.
Inside a React Native app, the integration is exactly one shape: you mount Phaser inside a <WebView>. That is the entire bridge. There is no shared state with your RN navigation, no shared Reanimated layer, no direct access to native APIs. You are running two runtimes - the host RN app and an embedded Chromium-class browser - and they do not share anything that matters at the engine level. The WebView pays its own startup cost, fights the host app's GC, and sits behind a JS-to-JS bridge for any cross-boundary state.
The performance reality on Android is hard. Phaser 4 itself is fast - the April "Caladan" release describes it as a "completely rewritten WebGL based renderer." But Phaser 4 running inside an Android WebView runs roughly 5-10× slower than the same Phaser scene running in a desktop browser, because the WebView's GPU driver paths and GC behavior are not Chrome's. iOS Safari's JIT narrows the gap. The architectural reality does not change: this is the web's engine running in a sandbox inside your app.
If you already have a Phaser game and want to embed it inside an RN shell as a playable surface, the WebView route works and ships today. Several games on the App Store and Play Store do exactly this. But the project I was running was "render 2D game content using React Native's own rendering pipeline so it shares state with the rest of my app." Phaser-in-WebView is not that project. It is RN-as-a-launcher.
Option 3 - expo-gl and react-native-wgpu (primitives, not engines)
By the third checkpoint I had a hypothesis: maybe the answer is to build straight on the GPU primitives. There are two healthy primitive-layer libraries in the RN ecosystem in 2026. expo-gl exposes a WebGL 2.0 context; its latest version, 55.0.13, was published in May 2026 - actively maintained, broad device support, in Expo Go. react-native-wgpu exposes WebGPU on RN 0.81+ with the New Architecture, backed by Google's Dawn runtime. WebGPU on mobile React Native is real and shipping.
Neither of these is an engine. They are graphics contexts.
What they do not ship: a sprite batcher, a scene system, an asset pipeline, audio sync, an input abstraction, an ECS. Every one of those layers is on you. Building a 2D game on top of expo-gl or react-native-wgpu is the same as building a 2D game on top of WebGL or WebGPU in any other host - perfectly legitimate, but the engine work is the project, not a starting point.
TypeGPU and react-three-fiber's React Native template demonstrate the ecosystem is alive. They also confirm the engine layer above the primitives is empty. The infrastructure is there. Nobody has assembled it. That is not a criticism of the primitive libraries - they are doing exactly what they should - it is a statement about where the gap sits in the stack.
Option 4 - Skia + Reanimated
@shopify/react-native-skia is where the evaluation actually changes shape. It is the only credible native GPU path inside React Native today, downloaded around 750,000 times per week. Paired with Reanimated 4 - the worklet layer that makes per-frame UI-thread computation viable - Skia is the closest thing the RN ecosystem has to an engine-grade renderer.
A regime caveat first, because it is load-bearing. Reanimated 4 is New Architecture only (Fabric, no Paper). The 4.0/4.1 line requires RN 0.78+; the current 4.3.x line (4.3.1 published 2026-05-07) requires RN 0.81+. Apps still on the legacy Paper renderer must stay on Reanimated 3.x, and Reanimated 3's worklet model is not the same animal as 4's. The Skia + Reanimated 4 architecture described here only exists if your app is on the New Architecture.
The primitive that makes this viable is Skia's <Atlas> API combined with Reanimated's useRSXformBuffer. You define a sprite atlas, write a worklet that fills a typed buffer of RSX transforms - one per sprite - and Skia issues a single GPU draw call regardless of sprite count. The transforms are computed on the UI thread, not the JS thread. That is the architecture that makes fast 2D viable on React Native, full stop.
// @shopify/react-native-skia - Atlas + useRSXformBuffer
// docs: https://shopify.github.io/react-native-skia/docs/shapes/atlas/
import { Atlas, useRSXformBuffer } from '@shopify/react-native-skia';
// One RSXform per sprite: [scos, ssin, tx, ty]
// Computed on the UI thread inside a worklet - no JS bridge per frame.
const transforms = useRSXformBuffer(spriteCount, (val, i) => {
'worklet';
const entity = entities[i];
val.set(
entity.cos * entity.scale,
entity.sin * entity.scale,
entity.x,
entity.y,
);
});
// Single GPU draw call regardless of spriteCount.
return <Atlas image={atlas} sprites={rects} transforms={transforms} />;I ran the architecture across realistic game loads on my benchmark device - a Samsung Galaxy A54 5G, release build, Android. Light load (10 enemies + 50 bullets) held at 120 fps. Medium (30 enemies + 150 bullets) held at 117 fps. Heavy (50 enemies + 300 bullets) dropped to 48 fps. The cliff is real, but it sits where I'd want it to sit: at the edge of action-game intensity, not in the middle.
Then I checked the cheap-Android floor and the entire calculus changed. On an OPPO A16 - the kind of budget device that represents a meaningful slice of the Indian and Eastern European markets I want this game to reach - the <Atlas> API tops out at roughly 300 sprites before frames drop. That number comes from Skia GitHub issue #2521 - community-reported, not a controlled benchmark on my desk. The same issue reports an iPhone 12 mini holds up to around 15,000 sprites before slight drops appear. The spread is roughly 50×. If your game or animated UI needs 400 simultaneous sprites and your floor device is budget Android, the headline number is not the design number. The cheap-Android number is.
That insight applies far beyond games. The Atlas + worklet path is exactly what powers animated dashboards, gesture-rich onboarding flows, and custom-rendered card UIs in non-game RN apps. The device floor applies there too. If you are shipping a high-touch animated UI to global Android, the Skia + Reanimated path is real and it is constrained by the same math.
But - and this is where the journey ended for me - Skia is only the renderer. It does not ship sprite sheets, tilemaps, a scene stack, game-shaped audio, input gesture layers, or an ECS. You get a high-performance 2D canvas with good batching semantics on the New Architecture, and everything above that layer - the game engine - is yours to build. That is exactly what I started doing two weeks into this evaluation.
What this means if you want a React Native game engine today
After four checkpoints the map writes itself. The four options sit on a two-by-two grid, on two axes: whether they give you native GPU access (rows) and whether they ship a full engine layer - game loop, scenes, assets, audio, input - above the renderer (columns).
| No engine layer (renderer/context only) | Full engine layer (loop, scenes, assets, audio, input) | |
|---|---|---|
| Native GPU | Skia + Reanimated 4 (renderer only); expo-gl / react-native-wgpu (context only) |
empty: the gap, does not exist in RN |
| No native GPU | react-native-game-engine (RN Views, dormant) |
Phaser 4 in WebView (full engine, separate runtime) |
The top-right cell - native GPU rendering plus a full engine layer - is empty. That thing does not exist in React Native. That is the gap. That is what I started building.
If you are mapping your own project against the grid, here is how I would pick from where I sit today:
RNGE if you have a handful-of-entities puzzle game, a prototype, or a project that needs to ship today and cannot take on a renderer migration. Accept the ceiling; it is real and it will not move.
Phaser-in-WebView if you already have a finished Phaser game and need to embed it in an RN shell. This is a launcher, not an integration. The experience is bounded by WebView performance on your floor device.
expo-gl / react-native-wgpu if you are building the engine on purpose. You want full control of the GPU stack, you understand the scope, and you have time. The primitives are excellent; the work above them is yours.
Skia + Reanimated if your device floor sits above the OPPO A16 class, you accept building scenes, audio, input, and ECS yourself, and you want native GPU batching without leaving React Native. Do the device-floor math against your target market before you commit.
None of these is "React Native game engine" off the shelf. That thing does not exist yet. I am now writing the layer that would close that quadrant. Whether anyone else needs it is the question I am answering by building it.
Limits
Four limits apply to everything above.
Single benchmark device. Every frame number in this post - 120 fps, 117 fps, 48 fps - comes from a Samsung Galaxy A54 5G running a release build, Android only. iOS is not tested in this post's benchmarks. An iPad Pro M-series will laugh at every cliff named here. A 2020 budget Android will fall below the OPPO A16 floor before the numbers even apply.
Crowdsourced device-floor numbers. The ~300 sprites on OPPO A16 and ~15,000 on iPhone 12 mini come from Skia GitHub issue #2521 - community reports, not a controlled benchmark I ran. Treat them as the device-floor lesson, not the device-floor table. I link the issue rather than presenting the numbers as measured data.
This is a comparison, not a recommendation. I do not say "use Skia + Reanimated" here. I say: if your device floor, sprite budget, and willingness to build the engine layer above the renderer all align, that is the only credible native GPU path in RN today. The fit analysis is yours to do.
Phaser-in-WebView is a real path for some games. Content-heavy web ports with a finished Phaser game upstream and minimal RN integration ship today and work. The post's argument is about integration shape - "RN as a launcher" - not about whether the path is wrong. Do not confuse the framing with a dismissal.
No comparison against Unity or Godot is attempted here. Native-first engines deploy via a separate runtime and a different store binary. They are outside the scope of "React Native rendering options."
Close
The gap is real and it is shaped. Zero React Native game engines exist off the shelf in 2026. Four partial options exist, each viable inside its own regime, none viable across all of them. I confirmed that, then started writing the layer that would close the gap.
Next Monday's post is the first chapter of the engine I started writing: the architecture decisions I made before any code, why a strict layering with downward-only dependencies is the load-bearing piece, and how it survives an AI-directed build at all. Subscribe to the RSS feed if you want it in your reader when it lands.