1. readsword frequency + your own reviews
  2. becomesthe forgetting curve → decaying mass; review re-binds
  3. writes--w
  4. you seeunreviewed words fade in real time; a review springs the word back

No canvas is drawn here — the field is invisible; these variables are its only output. Without it you would build: a spaced-repetition scheduler and its timers.

field-ui · invisible fields · memory

Knowledge decays. Anchors hold.

Every fact you learn starts fading the moment you look away — but how fast depends on how deeply it's anchored. These 96 words carry real frequencies from the Google Web Trillion Word Corpus, and frequency is the anchor here: a word the world uses fifty million times is held by everything around it; a rarer one slips first.

Drag days since review and the whole grid decays along an Ebbinghaus-shaped curve — each card's retention is its anchor strength times an exponential whose half-life grows with that strength, so the strongest words visibly hold longest. Click a card to review it: it springs back to full at the current day and re-decays as you push the slider further. The field is invisible — retention shows only in type weight, ink, and anchor.

Field
7d reviews persist on this device

size = retention — what's still held at the current day · anchor = corpus frequency — common words decay slower

How it's built

Every card is a <button> carrying its anchor strength as a data attribute. The slider drives one Ebbinghaus-shaped formula across all 96 cards; each result is written to --w and data-strength, and CSS turns it into type heft and ink. Reviews are a per-card timestamp — nothing more. Alongside the curve sit two live channels the engine writes back every frame — --d (local density, gathered by data-hot on hover) and --field-attention (the recipe's eased attention) — which touch only ink; retention stays pure data math.

1 — mark each word as a field body

HTML
<!-- each word is a body. data-feedback: the engine writes
     --d (live local density) back every frame. data-hot:
     hover/focus a card and the field gathers toward it. -->
<button
  data-body="attract"
  data-strength="1.62"
  data-feedback
  data-hot
  data-anchor="0.91"
  style="--w: 0.76; --cat: #4da3ff;"
>
  republic
</button>
  • data-body="attract" — registers as a field participant
  • data-anchor — normalized corpus frequency (the anchor)
  • data-strength — mass, recomputed from retention
  • data-feedback — opt in to --field-* writebacks (--d)
  • data-hot — hover/focus gathers the field toward this card

2 — the forgetting curve, and where reviews live

// the world-time kernel — Ebbinghaus
// retention with a stability term:
//   w = a·exp(−since/τ(a)), τ = 4 + a·56 days
import { retention, DAY_MS } from "@fundamental-engine/core";

// a = zipf, normalized 0.15..1
//     (real Trillion Word Corpus counts)
w = retention(a, days_eff * DAY_MS);
// deep anchors decay slower — τ grows with a

// review: per-card timestamp
days_eff = max(0, slider − reviewedAt)

// slider input → every card's --w
// and data-strength update live

// the scoped field runs invisible (renderless)
// and asks for the attention metric lane —
// the pipeline writes --field-attention per
// card (eased 0..1):
field = applyRecipe(grid, base, {
  bodies: cards,
  annotateBodies: false,
  renderless: true,
  extraMetrics: ["attention"],
});

The shape is Ebbinghaus's: exponential decay with a stability term. The frequencies are real; the curve's constants are tuned for legibility, not fitted to recall data. Reviews and the slider's day persist in this device's localStorage — close the tab, come back, and the field remembers what you reviewed.

3 — CSS reads the retention + the live channels

CSS
.mx-card {
  /* --w = retention (pure data math — the curve)
     --d = live engine density, data-hot gathers it
     --field-attention = the recipe's eased attention */
  --live: var(--d, 0);
  opacity: calc(0.58 + var(--w) * 0.42);
  box-shadow: 0 0 calc(var(--live) * 16px) -6px
    color-mix(in srgb,
      var(--cat) calc(var(--live) * 55%), transparent);
}
.mx-word {
  font-variation-settings:
    'wght' calc(380 + var(--w) * 360);
}
/* a reviewed card's ring breathes with the density */
.mx-card[data-reviewed] {
  outline: 2px solid color-mix(in srgb,
    var(--cat) calc(55% + var(--live) * 35%),
    transparent);
}

One variable in, the whole presentation out — and with prefers-reduced-motion set, the cards skip transitions entirely.