Skip to content

Benchmarks

Every performance number on this site comes from a reproducible benchmark you can run on your own hardware.

Measured on Apple M2, 24 GB RAM, macOS. Your numbers will vary by hardware. Run bun run bench:full to measure on your own machine.

ScenarioText Measure (P50)Canvas Draw (P50)PNG Encode (P50)Full Pipeline (P50)Full Pipeline (P95)
Baseline (og, 1 line, Outfit)114µs50µs21.39ms21.57ms22.79ms
Long text (og, overflow, Outfit)390µs78µs24.34ms24.83ms26.41ms
Story format (1080x1920, Outfit)426µs98µs59.37ms59.96ms65.02ms
CJK (og, Noto Sans JP)126µs79µs24.12ms24.34ms26.92ms

PNG encoding dominates render time. The actual text layout and compositing — the part that replaces Puppeteer’s browser engine — takes under 0.5ms for all scenarios.

ScenarioWarm P50Warm P95Cold P50Cold P95
Baseline (og, 1 line, Outfit)128.75ms165.98ms657.55ms837.24ms
Long text (og, overflow, Outfit)132.14ms153.42ms634.03ms788.19ms

Warm = browser reused between renders (best case for Puppeteer, typical for long-running servers). Cold = fresh browser launch per render (realistic for serverless / Lambda / edge functions).

ScenarioOG Engine (P50)Puppeteer Warm (P50)Speedup
Baseline21.57ms128.75ms6x
Long text24.83ms132.14ms5x

Against cold-start Puppeteer (serverless deployments), the speedup is 30x.

PhaseWhat it doesTypical time
Text measurementWord-wrap computation for title + description~0.1ms
Canvas drawGradient, grid, glow, text, decorations composited onto Canvas~0.05ms
PNG encodeCanvas buffer encoded to PNG binary~21ms
Full pipelineAll three (= API response time)~22ms

The speed advantage over Puppeteer comes from architecture, not just raw encoding speed:

  • No browser launch — zero cold start overhead
  • No DOM/CSS — text layout computed mathematically, not via Blink
  • No Xvfb — no headless display server required
  • 10MB vs 200-500MB — per-render memory footprint
  • 500+ concurrent renders — single Node.js process vs 5-10 Chrome instances
  • OG Engine: 1000 iterations per scenario, 50 warmup discarded
  • Puppeteer warm: 50 iterations, browser reused, 5 warmup
  • Puppeteer cold: 10 iterations, fresh browser per render
  • All times measured with performance.now()
  • P50 (median) used for all headline numbers
  • Machine info captured in every report
Terminal window
git clone https://github.com/phmatray/og-engine
cd og-engine
bun install
bun run fonts:download
bun run bench:full

Results are saved to benchmarks/results/. The markdown report is human-readable; the JSON contains every individual timing for your own analysis.

The benchmark code is in the benchmarks/ directory.