層 · A LAYOUT ENGINE FOR TYPESCRIPT
Every box,
neatly in its place.
Flexbox, CSS Grid, and block layout in plain TypeScript. Style data goes in, pixel positions come out — no WASM to load, no async init, no node lifecycles to manage. Verified against Chrome.
grid · display: 'grid', gridTemplateColumns: [fr(1.4), fr(1), fr(1), fr(0.8)]
11 nodes, laid out by the engine in 4.01 ms — the boxes only transition between its computed positions.
Three modes, one tree
A grid inside a flex row inside a block page is the normal case, not a special one. Each preview below is computed by the engine on the server, as this page renders.
Flexbox
Grow, shrink, wrap, alignment with the safe variants, auto margins — the full algorithm, not the easy subset.
CSS Grid
Tracks, spans, repeat(), auto-fill, dense packing — the grid Yoga releases still don’t ship.
Block
Normal flow with CSS 2.2 margin collapsing — the mode document generators actually spend their time in.
The whole setup, ten lines
Nodes are ordinary JavaScript objects with ordinary lifetimes — an unreferenced subtree is just garbage collected. No engine instance to register with, no free() to remember, and it runs the same in Node, a browser, a worker, or an edge runtime.
- Styles are data — flat camelCase properties, the same spelling as element.style.
- Content-driven sizing — leaf nodes take a measure callback for text and images.
- Browser-faithful rounding — pixels snap cumulatively, so adjacent boxes never gap or overlap.
import { LayoutNode, computeLayout } from 'bento-layout';
const left = LayoutNode.make({ flexGrow: 1 });
const right = LayoutNode.make({ flexGrow: 1 });
const root = LayoutNode.make({ width: 400, height: 300 }, [left, right]);
computeLayout(root, { width: 'max-content', height: 'max-content' });
left.layout.size; // { width: 200, height: 300 }
right.layout.location; // { x: 200, y: 0 }5,304
conformance fixtures, asserted at 0.1px against headless Chrome
0
runtime dependencies, WASM binaries, and async loaders
3
layout modes — flexbox, grid, block — composing in one tree
4
variants per fixture: both box-sizing modes × LTR and RTL
Chrome is the oracle
Correctness is defined as agreement with a pinned Chrome. An in-repo pipeline extracts geometry from the real browser into replayable fixtures, and a differential fuzzer generates random trees, compares the engine against Chrome, and shrinks every disagreement to a minimal reproduction. When this engine says a box is at x: 137, that is where Chrome puts it too.
The job of a layout engine is to be correct and invisible — a small, boring dependency that installs with the ceremony of lodash.

Ready when you are.
One import, zero dependencies, layout on the next line.
いただきます·itadakimasu