KQ-1619 · YEAR/RINGS
Year Rings
An archive as a cross-section of a tree: items are grouped by year into concentric rings, the oldest at the core, over timber drawn from a seed whose rays, check and growth lines scale with grain. Every ring turns at its own slow pace, the pictures riding it upright; hovering or focusing a ring brakes it to a stop by constant friction while its band brightens and its year reads above the slice. A click brings a picture forward from its own rectangle on the glide spring to a framed view over the centre while the rings pause, and Escape, the close button or the scrim send it back with focus returned. Pictures share one roving tab stop: Left and Right move along a ring, Up and Down between years, Home the core and End the bark, Enter brings forward.
Fieldline Studio
Six years of field notes
Pictures are grouped by year, the oldest at the core. Left and right move along a ring, up and down between years; Enter brings a picture forward and Escape sends it back.
48 pictures · 2020 to 2025 · oldest at the core
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/year-rings
Props
- items
- { src?: string; alt: string; caption?: string; year: number }[]
- default 48 drawn pictures, 2020 to 2025
- The archive, any order: grouped into one ring per year, the oldest at the core.
- value / defaultValue
- number | null
- default null
- The picture brought forward, by index into items, controlled or initial.
- onValueChange
- (index: number | null) => void
- default —
- Fires from the press or key that brought a picture forward or sent it back.
- ringGap
- number
- default 1.4
- Space between rings, in picture widths (1.1 to 2).
- speed
- number
- default 1
- How fast the rings turn, 0 (still) to 2.
- grain
- number
- default 0.7
- How much of the timber is drawn, 0 (a clean diagram) to 1 (rays, a check and every growth line).
- alternate
- boolean
- default true
- Neighbouring rings turn opposite ways.
- brake
- boolean
- default true
- Hovering or focusing a ring stops it.
- wood
- "oak" | "cedar" | "ash" | "walnut"
- default "oak"
- The timber.
- captions
- boolean
- default true
- Show the year label above the slice.
- paused
- boolean
- default false
- Hold every ring still.
- label
- string
- default "Archive by year"
- The archive's accessible name.
- disabled
- boolean
- default false
- No hovering, pressing or keys.
- className
- string
- default —
- Sizes the archive; it fills a 544px-tall box by default.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { src?: string; alt: string; caption?: string; year: number }[] | 48 drawn pictures, 2020 to 2025 | The archive, any order: grouped into one ring per year, the oldest at the core. |
| value / defaultValue | number | null | null | The picture brought forward, by index into items, controlled or initial. |
| onValueChange | (index: number | null) => void | — | Fires from the press or key that brought a picture forward or sent it back. |
| ringGap | number | 1.4 | Space between rings, in picture widths (1.1 to 2). |
| speed | number | 1 | How fast the rings turn, 0 (still) to 2. |
| grain | number | 0.7 | How much of the timber is drawn, 0 (a clean diagram) to 1 (rays, a check and every growth line). |
| alternate | boolean | true | Neighbouring rings turn opposite ways. |
| brake | boolean | true | Hovering or focusing a ring stops it. |
| wood | "oak" | "cedar" | "ash" | "walnut" | "oak" | The timber. |
| captions | boolean | true | Show the year label above the slice. |
| paused | boolean | false | Hold every ring still. |
| label | string | "Archive by year" | The archive's accessible name. |
| disabled | boolean | false | No hovering, pressing or keys. |
| className | string | — | Sizes the archive; it fills a 544px-tall box by default. |