Architecture

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

Module resolution

SootSim’s Vite plugin handles:

  1. redirecting react-native to SootSim’s RN shim
  2. resolving .ios.ts > .native.ts > .ts (metro-style)
  3. stubbing native packages with compat stubs
  4. transforming CJS require() to ESM imports
  5. handling JSX in .js files from node_modules

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