Kinetica

Game of Life, four ways

One 72 × 48 finite Conway universe, implemented with four rendering stacks. Every version uses the same dark visual system, B3/S23 rules, preset data, speed controls, accessibility labels, cell-editing behavior, and browser verification contract. Only the state/rendering layer changes.

Play the implementations

  • Kinetica — Kotlin/JS with Kinetica's retained DOM renderer.
  • React — React 19 with memoized cell components.
  • Compose HTML — Kotlin/JS with JetBrains Compose HTML.
  • Vanilla — direct browser DOM updates as the baseline.

Open the full benchmark report for per-operation slowdown factors, bundle sizes, methodology, and links back to every live app. Raw samples and environment metadata are published alongside it.

Performance snapshot

Median milliseconds from the 2026-07-16 run on an Apple M4 Max with Chromium 149.0.7827.55, 5 measured samples after 1 warmup. Interaction traces request reduced motion so the shared 160 ms cell-birth animation cannot hide renderer work. Lower is better.

OperationKineticaReactCompose HTMLVanilla
Cold startup + 3,456-cell mount66.9056.00107.4035.60
Load Pulsar preset21.4221.8734.6227.18
Advance Pulsar24.2328.4331.8524.82
Randomize 24% of the board140.39155.99140.28118.71
Advance randomized board121.97149.87128.78116.83
Toggle one cell14.5018.9313.7513.41
Clear Pulsar21.0020.1533.2820.25
Production bundle, gzip98.3 KB62.3 KB177.3 KB4.1 KB

The numbers are machine-specific, so the committed JSON retains every sample instead of presenting the medians as universal rankings. Sparse operations sit close together; randomized evolution makes the cost of recomputing and updating a large fraction of the board more visible. The seeded generator advances between samples but yields the exact same cells in all four apps.

Shared behavior, reproducible measurement

Kinetica and Compose HTML import one tested Kotlin model. React and Vanilla import one JavaScript model that runs the same stability, oscillator, spaceship, boundary, preset, and editing parity tests. A Playwright gate then drives the same selectors through all four production bundles and checks the rendered 3,456-cell board, preset populations, stepping, editing, speed, run, and pause.

The benchmark uses Kinetica's existing Chrome-trace parser: duration begins at the trusted click EventDispatch and ends at the last Paint or Commit. Reproduce it from the repository root:

node bench/game-of-life/run.mjs --warmup=1 --samples=5