Skip to content

Viscosity

The world’s websites just got faster. Having found no project doing something which I expected to be deterministically possible, I created Viscosity, the world’s first automatic, ahead-of-time Array of Structures to Structures of Arrays compiler for any language, starting with JavaScript and TypeScript, with more languages to come.
Tariq Shams
Want to learn how this works deeply, compiler engineering from scratch, and perhaps become a contributor? I wrote a book with you in mind. Read the book

Measured, not promised

Whole JavaScript programs, original vs compiled by Viscosity, on two engines. Longer bars are faster.

2.54× geometric mean on Node (V8)
1.74× geometric mean on Bun (JavaScriptCore)
10.9× faster compiles: Rust CLI vs TS CLI over 40 programs
  • particles ps=soa
    Node 4.37×
    Bun 3.00×
  • heat cells=soa
    Node 4.11×
    Bun 1.02×
  • ledger tx=soa
    Node 3.75×
    Bun 2.88×
  • boids fl=soa
    Node 1.31×
    Bun 1.85×
  • n-body bs=soa
    Node 1.20×
    Bun 0.97×

Speed-up = original time / compiled time of each program’s timed section, best of 9 fresh processes on a shared 4-vCPU VM (2026-10-31); checksums matched on every run. Differences under about 10% are noise. Full tables and method →

Safe by proof

Viscosity only rewrites a collection when no code could notice. Aliasing, escaping elements, unknown callers or non-numeric data mean it leaves your code alone and says why.

It explains itself

viscosity explain lists every collection, the layout chosen, which loops touch which fields, and every reason it refused.

Many languages, one engine

JavaScript, TypeScript and a Python subset lower into one language-neutral IR (VIR), and every language shares the same analyses.

// you write:
const ps = [];
for (let i = 0; i < n; i++) ps.push({ x: i, vx: 1 });
for (const p of ps) p.x += p.vx * dt;
// Viscosity emits (abridged):
const ps = new __Vsc_ps(); // one Float64Array per field
for (let i = 0; i < n; i++) ps.push(i, 1);
for (let p = 0; p < ps.length; p++) ps.x[p] += ps.vx[p] * dt;