[ Documentation ]
How we measure conformance

How we measure conformance

A simulator is only useful if what you see in it is what your users will see. Peach does not judge that by eye. Each claim of native fidelity is a test case that runs twice, once as a native build on Apple’s or Google’s own frameworks and once in Peach, and the two results are compared.

Paired cases, library by library

A conformance case is a small React Native screen that exercises one capability: a ScrollView inset, a Reanimated spring, a Screens push, an SVG path, a keyboard avoiding view. Cases are grouped by library, starting with React Native itself and then each native library apps depend on.

Each case runs on both targets:

  • +
    Native. The case app is built natively and driven with Detox on iOS 27 (an iPhone 16 profile) or on a Pixel 8 running Android 17 (API 37).
  • +
    Peach. The same JavaScript runs in Peach on the matching device profile.

The case drives both to the same checkpoints, such as after a tap, mid animation, or after a scroll settles, and records what each produced. Visual checkpoints are captured in both light and dark appearance on the same device and runtime.

Visual and semantic proof

A screenshot can show that a button looks right. It cannot show that the tap reached the right handler. So every checkpoint declares which kind of evidence it is:

  • +
    Visual. Peach and native pixels are compared over the checkpoint’s declared output region. Each region has a difference budget of at most 1% of its pixels (1% unless the case sets a tighter one). Graphics compare with a one-pixel anti-aliasing tolerance; text compares with none, so a glyph sitting one pixel off counts.
  • +
    Semantic. Structured observations from both targets are compared: callback counts, lifecycle order, scroll offsets, focus, and measured geometry. Routing and events are proven this way, because pixels do not prove routing.
  • +
    Hybrid. Both a semantic comparison and a pixel verdict, and both must pass.

Motion is captured too. For an animation, Peach parks its clocks and steps frame by frame at 60 fps, and the native recording is anchored to the frame where motion actually starts, so the two are compared at the same moment of the same animation.

A checkpoint with no declared evidence kind counts for nothing. A result measured against older source is shown with the commit it was measured at, never as a current pass. Published difference budgets can only tighten: the comparison rules reject an attempt to loosen a budget or turn off anti-aliasing counting.

When a case does not pass at its final bar yet, it may declare a staged bar above 1% with a written reason. Its results say that it passed at a staged bar, so a near miss never reads as a pass.

What a score means

A compatibility score answers one question: will this work in my app? Two different measures go into answering it, and Peach keeps them apart.

Implementation

The percent shown for a package is its implementation percent: how much of the package’s app-facing API surface Peach implements.

  • +
    Each package is broken into features, and each feature is rated 1 to 3 for how much real apps use it and 1 to 3 for how important it is. The product of the two sets the feature’s weight among its siblings, so a widely used API counts for more than a rarely used one. Splitting a feature into finer parts never increases its share of its parent.
  • +
    Every declared feature stays in the denominator. A deduction names a behavior that is missing or differs from native, and takes the share of the feature that behavior is worth in real usage.
  • +
    Only app-facing capability counts. Private bridge plumbing, unstable_ exports, development tooling and transitive internals are excluded, each with a recorded reason. Nothing is excluded for being rare, hard to test, or currently failing.
  • +
    Some native facilities cannot happen in a browser, such as over-the-air update delivery or launching a development client. For those, full marks means your app imports them cleanly, gets a sane unavailable or no-op result, and never throws.
  • +
    Numbers are rounded once, where they are printed. A partial implementation never displays as 100%; only a complete one does.

Proof

Proof measures how much of that implementation is demonstrated by paired cases. For each API, every declared scenario must pass on both targets before the API counts as passing. Missing, stale, or incomplete evidence is unassessed, never failing and never passing, and a native or harness failure does not count against Peach.

The measured result is passing API usage divided by assessed API usage, shown with the share of usage that was assessed and the platform (iOS by default). Usage here comes from how often each API is referenced in pinned real-world app source; a strict view gives every API one vote instead. Either way it describes coverage of the declared scenarios, not exhaustive parity and not the probability that an entire app works.

Proof case counts are shown next to scores, never as scores. How many cases exist says how much has been demonstrated, not how much works.

Rollups

rollupwhat it covershow it combines
React Nativethe core react-native packageits implementation percent
Essentials14 native libraries almost every app installs: Safe Area Context, Screens, Reanimated, Worklets, AsyncStorage, Gesture Handler, SVG, NetInfo, Sentry, WebView, Get Random Values, Masked View, DateTimePicker, Keyboard Controllerthe libraries’ implementation percents, averaged equally and weighted by weekly downloads
Top 100, 500, 1kthe most-installed npm packages that ship native code, excluding packages that only matter at build time and pure JavaScript packagesthe same, counting popular packages more heavily by weekly downloads

Pure JavaScript packages need no native support; they run from your bundle on Peach’s React Native implementation, so they are not scored separately.

Light packages never count as supported

Some packages are admitted at a light level so that an app which imports them loads. Their native side is an inert no-op generated from the package’s own published source. Light packages are disclosed as exactly that, “loads, native side inert, not validated against the real native build”, wherever a package’s status appears, including peach doctor and the scan on /conformance. They never enter a score’s denominator, and they are never presented as measured, estimated, proven or supported. A light package joins the scored set only once it earns a real implementation figure or paired evidence.

Where to see the results

  • +
    /conformance on peachsim.com shows the React Native, Essentials and ecosystem rollups and a cell for every scanned library. Each library has its own page with the native capture, the Peach capture, and the pixel diff for every visual checkpoint. Drop a package.json or lockfile on it to score your own dependency set.
  • +
    Core coverage gives the React Native and Essentials scores, React Native’s API surface by area, and each of the 14 Essentials libraries with what works and what does not yet.
  • +
    Every library lists every scanned library by category, linking each to its proof page.

The coverage pages are generated from the same data /conformance uses, so their scores match it. To see how your own project scores, run peach doctor (see Compatibility). For how Peach renders and animates in the first place, see How Peach works.