KQ-511 · SPY/INDEX
Spy Index
A table of contents that watches the page. An IntersectionObserver keyed to the reading line marks the section in view, and the marker travels between entries on glide through a shared layoutId while the active entry steps 4px out of the column and the rail beside the list fills with reading progress. Entries are plain links, so Tab reaches them and Enter follows them; clicking scrolls the container smoothly and hands focus to the target.
Scope
Waylight ships a single rail assembly per crate. This note covers the March batch and the two carriers it went out with.
Anything outside the March batch keeps the previous tolerances.
Tolerances
Rail straightness holds to 0.4mm over a metre. Anything past that is re-cut rather than shimmed.
The end caps are checked wet, not dry, because the seal swells.
Bench setup
Two benches, one operator each, both fed from the same spool. Readings are taken after the spool has run for ten minutes.
Results
412 of 416 rails passed on the first reading. The four that did not were all from the tail of the spool.
No carrier damage was recorded on either route.
Sign-off
Signed off for the March batch only. The April spool is measured again from scratch.
Reading Scope
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/spy-index
Props
- sections
- { id: string; label: string }[]
- default —
- The entries, in document order; ids must match headings inside the container.
- container
- React.RefObject<HTMLElement | null>
- default —
- The scrolling element; defaults to the window.
- offset
- number
- default 24
- Pixels from the top of the container that count as in view.
- label
- string
- default "On this page"
- Accessible name for the nav, shown above the list.
- onActiveChange
- (id: string) => void
- default —
- Fires when the section in view changes.
| Prop | Type | Default | Description |
|---|---|---|---|
| sections | { id: string; label: string }[] | — | The entries, in document order; ids must match headings inside the container. |
| container | React.RefObject<HTMLElement | null> | — | The scrolling element; defaults to the window. |
| offset | number | 24 | Pixels from the top of the container that count as in view. |
| label | string | "On this page" | Accessible name for the nav, shown above the list. |
| onActiveChange | (id: string) => void | — | Fires when the section in view changes. |