Architecture

The full pipeline — react-reconciler building SootSimNode trees, Yoga flexbox, CanvasKit/Skia rendering, scroll physics, the responder touch system, the Animated API, how your app bundle loads, and the test bridge.

Rendering pipeline

React Components ↓ Custom Reconciler (react-reconciler) ↓ SootSimNode Tree ↓ Yoga Layout (flexbox computation) ↓ CanvasKit Renderer (Skia GPU rendering) ↓ <canvas> element

Key components

Reconciler (engine/reconciler.ts)

SootSim uses react-reconciler to build a custom React renderer. Instead of creating DOM elements or native views, it creates SootSimNode instances.

The reconciler handles:

  • creating/updating/removing nodes
  • managing the node tree hierarchy
  • scheduling commits (batched updates)

Node tree (engine/node.ts)

SootSimNode is the core data structure. Each node has:

  • type — component type (View, Text, Image, etc.)
  • props — React props
  • style — resolved styles
  • layout — computed layout from Yoga
  • children — child nodes

Layout engine (engine/yoga-layout.ts)

Uses Yoga (the same layout engine as React Native) to compute flexbox layouts. Every node gets a Yoga node, styles are applied, and layout is computed in a single pass.

Canvas renderer (engine/canvaskit-renderer.ts)

Renders the node tree to a <canvas> element using CanvasKit (Skia compiled to WebAssembly). Handles:

  • background colors, borders, border radius
  • text rendering with proper fonts
  • image loading and display
  • shadows and opacity
  • scroll clipping
  • scroll fade gradients

Scroll physics (engine/scroll.ts)

Implements iOS scroll behavior:

  • momentum scrolling with deceleration
  • rubber band effect at bounds
  • snap-to-page
  • scroll indicators

Touch system (engine/touch/)

Implements the React Native responder system:

  • hit testing through the node tree
  • responder negotiation (onStartShouldSetResponder, etc.)
  • touch event propagation

Animation (engine/animated.ts)

Implements the Animated API:

  • Animated.Value with listeners
  • Animated.timing(), Animated.spring(), Animated.sequence()
  • useNativeDriver support (renders animations in the canvas frame loop)
  • interpolation and color interpolation

Loading your app

SootSim works like React Native: you point it at a JS bundle URL and it runs that bundle. The bundle is produced by your own bundler — Metro, Expo, or One — the same way you would build for a device. SootSim has no opinion about how you bundle.

http://localhost:5173/?bundle=http://localhost:8082/index.bundle?platform=ios

The React Native runtime your app imports (View, Text, ScrollView, the Animated API, and native-module behavior) is provided by SootSim’s engine, so a standard React Native bundle runs unchanged.

Testing infrastructure

Test bridge (src/test-bridge.ts)

Exposes window.__sootsimTest with methods to query the node tree from Playwright tests. All test drivers (Detox, Maestro, raw Playwright) use this bridge.

Detox driver (test/detox-driver/)

Drop-in replacement for the detox package. Remaps Detox’s element/matcher/expect API to SootSim’s test bridge.

Maestro driver (test/maestro-driver/)

Runs Maestro-compatible YAML flows by:

  1. parsing YAML into step objects
  2. executing each step against the SootSim test bridge
  3. coordinating with Playwright for screenshots and video

Ready to build?

Run your React Native app in the browser. No simulators, no native toolchain, no waiting.

npm i -g sootsim