1. readsOpen Library's ratings for a shelf
  2. becomesreview consensus → mass — the Evidence math, retargeted
  3. writes--w--cat
  4. you seewell-attested books carry weight; each subject tints its spine

No canvas is drawn here — the field is invisible; these variables are its only output. Without it you would build: star-sort plus genre filters.

field-ui · invisible fields · catalog

Consensus on the shelf.

A bookshelf is usually a ranking in disguise: sort by rating count, slap a score badge on each cover, and the top row wins. These 28 books are a real Open Library science-fiction shelf run as a field instead. Each book is a body, and its rating count goes through the same formula the Evidence example runs over citationstrust = log(ratings + 1) / log(maxRatings + 1) — so log-normalized rating counts become gravitational mass.

The consensus shows in the spine, not a score badge: heavier-rated books carry more type weight, more ink, and a stronger left anchor. The field is invisible — no particle swarm, no overlay. Hover or focus a book and every shelf-mate sharing a subject lights up, with the strongest shared subject floating beside it. Re-weight by anticipation or longevity and watch the shelf re-settle. Toggle the field off and it collapses to a plain grid.

Field
Weight by
Color by
Data snapshot · 2026-06-10

size = ratings — the evidence trust math, retargeted at the shelf · color = first subject — the shelf each book sits on

How it's built

Every book is ordinary semantic HTML — an <article> with a handful of data attributes. field-ui reads them, runs a spatial field over the grid, and the trust score is written once as --w; CSS turns it into type heft, ink, and the spine. No canvas. No particle swarm. Shelf-mate affinity is class toggles, not SVG. Two live channels ride on top: the page's hidden engine writes --d (local particle density) to every data-hot card each frame, and the scoped recipe's attention lane writes an eased --field-attention — CSS turns both into a felt glow and lift, and both go quiet when the field is off. In the browser the counts refresh from the same Open Library search once per visit, on purpose — shelf counts drift slowly (a few ratings a day, not a ticker), so polling would be theater. Fresh counts run back through the active weighting and the shelf re-settles.

1 — mark each book as a field body

HTML
<article
  id="bk-OL893415W"
  data-body="attract"
  data-strength="1.87"
  data-feedback
  data-hot
  data-subjects="science fiction|time travel"
  style="--w: 0.92; --cat: #4da3ff;"
>
  <!-- title · author -->
  <!-- the ratings line declares itself a
       measurement of this card -->
  <span data-field-visual-for="#bk-OL893415W"
        data-field-visual-role="measurement">
    ★ 4.02 · 9,440 ratings
  </span>
</article>
  • data-body="attract" — registers as a field participant
  • data-strength — gravitational mass (0 → faint, 2 → heavy anchor)
  • data-subjects — the shelf-mate affinity edges
  • data-feedback — opt in to --field-* writebacks
  • data-hot — opts into the live density gather: hover and --d climbs toward 1
  • data-field-visual-for — names the ratings line a measurement of its card

2 — the evidence formula, retargeted

TypeScript
// IDENTICAL to /evidence — only the
// signal changed: citations → ratings.
// the shape is core's weight primitive:
import { logNormalize } from "@fundamental-engine/core";
trust = logNormalize(ratings, maxRatings)
      // = log(ratings + 1) / log(maxRatings + 1)

// the other lenses re-run the same shape:
// anticipation → wantToRead counts
// longevity    → edition counts
// then a FLIP re-sort settles the shelf

One log-normalized count becomes mass, exactly as on the Evidence page. Swapping which count feeds the formula is the whole difference between the three weightings.

3 — CSS reads the field's output

CSS
.cat-title a {
  font-variation-settings:
    'wght' calc(380 + var(--w) * 360);
}
.cat-card {
  /* --d: the engine's live local density,
     written every frame; gathers toward 1
     when a data-hot card is hovered/focused.
     --field-attention: the scoped recipe's
     eased attention lane. */
  --live: var(--d, 0);
  box-shadow: 0 0 calc(var(--live) * 16px) -6px
    color-mix(in srgb, var(--cat)
      calc(var(--live) * 55%), transparent);
  opacity: calc(0.58 + var(--w) * 0.42);
}
/* the floating affinity chip charges with
   the hovered card's --live (mirrored by
   the runtime while the hover holds) */
.cat-chip {
  border-color: color-mix(in srgb,
    var(--accent)
    calc(45% + var(--live, 0) * 45%),
    var(--line));
}

Type heft, ink, and the spine all read from one normalized trust score — the field drives the measurement; CSS drives the presentation. The glow and the chip's charge read --d and --field-attention — live writes, zeroed when the field is off.