# Scroll stories

`SKILL.md` points here: how the full-stack band builds a figure as the reader scrolls, and the svh and dvh law. Moved from `SKILL.md` on 2026-10-10, unchanged.

## The model

The full-stack band is the model for a story that builds a figure as the reader scrolls (`sections/fullstack/FullStack.tsx` and `fullstack.css` in gt-cloud; `src/app/d/_v0/sections/` in Prototemplate; DESIGN.md sections 13 and 14).

- The story keys on two lines with separate jobs. The read line at 55 percent of the viewport is structural: a beat locks in when the center of its copy block crosses it, and the tower's build clock, the capstone scrub and the sticky figure's seat all key on it. The highlight line at 80 percent belongs to the spotlight alone: a beat's copy lights as its center rises through it, while the arriving layer is still building. In code, `READ_LINE = 0.55` and `HIGHLIGHT_LINE = 0.8`.
- Anchors are measured on the copy itself and from flow geometry. The beat window's top runs about half a viewport ahead of its copy, and anchoring on it made every layer arrive early (Kevin: "each layer arrives too early"). The finale is sticky, so its flow top is the previous beat's bottom; its own rect would read the stuck pose on a refresh mid-dwell. Re-anchor on every ScrollTrigger refresh.
- One scrubbed dial spans the read. A piecewise map from measured lock-ins to story time holds the clock while a row is being read and spends each gap as hold, build, lock, so a layer stands locked before its copy reaches the read line.
- The figure is CSS sticky. JavaScript never positions it ("the diagram keeps moving down as i scroll past agents, which is wrong"). The agents beat gets a dwell runway before the native sticky release carries the figure out with the band.
- At 1020px and below (with at least 500px of height) the band becomes a stage: a CSS-sticky grid that fills the viewport, with the figure in the top 55 percent and one beat's copy in the bottom 45 percent (`grid-template-rows: minmax(0, 11fr) minmax(0, 9fr)`). The tower's width budget `--v0sm-tw` uses the same 0.55 factor, so the split and the factor change together; short windows (500 to 639px tall) rebalance both to 0.5. One ScrollTrigger over the `.v0sm-runway` spacer after the grid is the story clock. The stage's bullets stay 15px / 1.5 because the longest beat must fit the text zone.
- The svh and dvh law sets every stage height. Reach is dvh: whatever must touch the true screen bottom (the stage's rails, the text zone) sizes from `100dvh`. Layout is svh: any height that takes part in layout uses `100svh`, because a dvh layout height grows the document on every browser chrome toggle and the scroll jitters. The difference is the token `--v0sm-bar-gap` (`--v0sm-stage-h` minus `--v0sm-stage-h-stable`, 0 while the URL bar shows), and only overhangs spend it. Anything sized from the stage derives from the stable var.
- Every loop is created paused and plays only while its band is on screen. Under `prefers-reduced-motion` the setup is skipped and the markup pose is the still: the full stack with the first beat lit and the mark's shimmer parked.
- Scrolling is native. `shared/SmoothScroll.tsx` is a pass-through kept as a mount point; no Lenis or Locomotive, no `scroll-smooth`, no `behavior: 'smooth'`, and in-page links jump. Prototemplate exempts only `/present`, the presenter.
