The back room · working notes

How this shelf works

A bookshop where the piles are the database. These are the keeper's notes on the mechanism: what the physics is for, how it stays calm, and what three hostile review passes caught.

Front of shop

The brief, as taken at the counter

Build a fictional used and rare bookshop where the inventory is the layout. Book spines are real interactive elements under 2D rigid body physics, stacked in leaning piles. Pull one out and the pile settles. Change the sort and the shelves rebuild themselves. Every spine opens a bookplate with a story, a condition note, and a price. The hard rule underneath it all: the physics must carry information. If you switched the simulation off, the site should stop making sense.

The test we held every pass to: no body without a meaning, no meaning without a body. There is no decorative physics on this page. All thirty simulated rectangles are books you can open, and nothing else is simulated.

The physics is the filing system

Four facts about the inventory are readable straight off the simulation, no labels required:

Which pile a book sits in
is its section, or its era, colour, or size once you re-sort. The grouping you see is the current query.
Where it sits in the pile
is the order of the chosen sort. Oldest at the bottom like sediment. Folios under pocket books. Dark spines under light ones.
How scuffed it looks
is its handling count. Wear is authored per book and grows as you open plates; the scruffiest spines are the shop's real favourites.
How the pile leans
is a warning. Staff Picks is stacked with a deliberate cumulative drift, so the tower reads as precarious before you touch it.

Remove the engine and each of those channels dies at once. That is the whole argument for simulating a bookshop instead of drawing one.

Tuned like furniture, not fireworks

Every body is created heavy on purpose. Books do not bounce, they thud. Cloth grips cloth, folios outweigh paperbacks, and a dragged book is speed capped on release so nobody can throw a first printing across the room.

const body = Bodies.rectangle(0, -2000, book.len, book.thick, {
  friction: 0.85,          /* cloth grips cloth */
  frictionStatic: 1.05,
  frictionAir: 0.018,      /* dusty air, nothing floats */
  restitution: 0.015,      /* books thud, they do not bounce */
  density,                 /* folios are genuinely heavier */
  slop: 0.02,
  chamfer: { radius: 2 },  /* softened corners settle kindly */
  sleepThreshold: book.section === 'staff' ? 55 : 35
});

Gravity runs slightly heavy at 1.12. The lean itself is authored, then verified by the solver: stacking targets carry a seeded sideways jitter, Staff Picks adds 5.2px of drift per book, and then real contact and friction decide whether the tower holds. It always has. So far.

Calm is a feature

A shop should be quiet when nobody is touching it. Bodies sleep individually through Matter's own thresholds, a settle clock force sleeps anything still trembling after 1.2 seconds of near stillness, and once every book sleeps the animation loop is cancelled outright. Not throttled. Cancelled. A settled page costs zero frames until you wake it.

/* force calm: near still for 1.2s means asleep, staff pile included */
if (maxSpeed < 0.09 && anyAwake()) {
  settleClock += dt;
  if (settleClock > 1200) records.forEach(r => Sleeping.set(r.body, true));
}
if (!anyAwake() && !flights.size && !motes.length && !dragState) {
  stopLoop();   /* zero rAF, zero CPU: the shop goes quiet */
  onCalm();
}

Waking is cheap and explicit: a grab, a sort, a resize. Nothing else runs.

The same books, twice

The physics view and the semantic inventory are one structure, not two copies that could drift apart. The shelf is a real list; each simulated book is a real list item; each spine is a real button that opens a real dialog. The transform is presentation, the markup is the truth.

<ul class="inventory"
    aria-label="Every book on the shelves, thirty in stock.">
  <li class="book" style="transform: translate3d(…) rotate(…)">
    <button class="spine" aria-haspopup="dialog"
      aria-label="Wintering at the Signal House. Abel Storrow,
                  1902. Staff Picks. $180. Open the bookplate.">

Three consequences fall out of that choice. Screen readers get the full inventory with section, year, and price on every entry. The keyboard path reaches every bookplate, and after each settle the list items are re-appended in visual order, pile by pile, top to bottom, so tab order walks the shelves the way eyes do. And under prefers-reduced-motion the books render pre-settled with dragging disabled: same shop, composed and browsable, no tumble. Every spine also passes a scripted 4.5:1 contrast audit against its actual background, all thirty of them.

The tumble, choreographed then released

Re-sorting flies each book along a quadratic arc toward a slot above its new pile, bottom books first, collisions off so there is no mid air chaos. The last 42 pixels are not animated at all: the book is handed back to gravity and lands for real, which is where the settle, the thud, and the dust come from.

Body.setStatic(body, true);       /* the keeper's hand takes over */
body.collisionFilter.mask = 0;    /* no collisions in flight */
const pc = { x: (p0.x + p1.x) / 2,
             y: Math.min(p0.y, p1.y) - 130 };   /* the arc */

/* on arrival, 42px above the slot: */
Body.setStatic(body, false);
body.collisionFilter.mask = 0xFFFFFFFF;
Body.setVelocity(body, { x: 0, y: 1.2 });  /* gravity lands it */

Provenance

Everything visual is procedural: spines are layered CSS gradients over inline feTurbulence noise, the wall, floor, bench, and cat are CSS and hand written SVG, the shadows are two canvas layers. No photographs, no generated images, no stock anything. The thirty books, their authors, their condition notes, and their prices were written for this shop and exist nowhere else.

Type: Domine for display and plates, Work Sans for text, with EB Garamond, Oswald, and Domine as the spine pool and Caveat for anything handwritten. Physics: matter.js 0.20.0, MIT, vendored locally. Motion beyond the simulation uses hand picked cubic beziers throughout.

What each pass caught

  1. Pass one

    The stage was two thirds empty wall and the section labels clipped at the fold. Ten spines failed a 4.5:1 contrast audit, gilt on sage worst of all. The piles read as real stacks already, which confirmed the physics; everything else needed furniture. Queued: shorter stage, a bench, thicker books, scripted contrast fixes.

  2. Pass two

    The first bench render failed its own review: two floating rails with wall glare between them. Rebuilt as plank, apron, legs, and floor shadow. Stickers were clipping titles on short spines, so stickered text now centres in the region left of the sticker, and a spine that still cannot fit its title drops the sticker instead. Found a real bug where the drop-in spawn ladder could rest on the containment lid at mobile heights. Upgrade shipped: dust motes on hard landings.

  3. Pass three

    The era and size sorts proved the information argument (sediment and pyramids), reduced motion rendered pre-settled, and the mobile plate composed cleanly. The cat arrived and was promptly half hidden behind Staff Picks in five pile sorts, so the bench grew into a trestle and the cat now sleeps underneath it, visible in every sort, startled by nearby landings. Upgrade shipped: the cat. Rule four finally means something.