Run wall
StableA month of agent runs as a wall of squares, with a sweeping day highlight you can pause.
One row per agent and one square per day for 30 days: an outline for no runs, three fills for few, some and many. The SAMPLE data is hard-coded in home/RunWall.tsx, from a seeded random generator so the server and the browser draw the same squares; the only prop is className. While motion is allowed a highlight sweeps across the days, and the Pause animation button stops it.
Updated View source
Thirty days, twelve agents
import { RunWall } from '@rchursin/home/RunWall'
/** * Twelve agents over thirty days, on sample data. The highlight that sweeps across the days * can be paused, and never moves when reduced motion is on. */export default function RunWallThirtyDays() { return <RunWall className="w-full" />}Usage
import { RunWall } from '@rchursin/home/RunWall'<RunWall className="mt-14" />API
Run wall props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | – | Extra classes on the <figure>. |
Accessibility
Keyboard
| Key | What it does |
|---|---|
| Tab | Moves to Pause animation (when motion is allowed), then to the wall’s scroll region. |
| EnterSpace | Pauses or plays the sweeping highlight. |
| Left arrowRight arrow | Scroll the wall sideways while its region has focus. |
- The sweep loops for as long as the page is open, so a Pause control is required (WCAG 2.2.2). The button sets data-paused on the figure, which pauses the sweep in CSS.
- With reduced motion the sweep and its highlight are not drawn at all, and the button is hidden because there is nothing to pause.
- The button’s label says what a press will do, switching between “Pause animation” and “Play animation”. It has no aria-pressed, so a screen reader hears just “Play animation, button” and never a state that contradicts the words.
- The wall is a <figure>; its caption says what a square means and how many agents ran at all. The squares are aria-hidden, as a picture of those numbers.
- The scroll wrapper is a focusable region named “Agent activity grid (scrolls sideways on small screens)”, so keyboard users can scroll it. The region and the button show focus as a 2 pixel outline in the text colour.
- No runs is an outline; few, some and many are fills at 35, 65 and 100 percent strength. The day count at the end of each row shows each total as text.
Guidelines
Do
- Keep the Pause animation button wherever the sweep runs.
- Keep the Sample data tag while the runs are made up.
Don’t
- Don’t add more levels of fill; three plus empty is about all people can tell apart.
- Don’t autoplay other motion next to it; one moving thing per view.
In use
Related
- Dashboard mockA still picture of the product: four headline numbers, a bar list of skill runs and a ledger with verdicts, on sample data.
- Animated accentsShiny and gradient text, a beam round a border, a shine border, ripples, lines that type in and a scanning column.
- Sample badgeA small “Sample data” marker for anything that shows invented records or numbers.
- Control RoomA home page where the product is the hero: a live dashboard shot, a bento of features, a run wall and an FAQ.
Source
The component’s own files, exactly as they run on this site.
/** * "12 agents. 3 do the work." — one square per agent per day (SAMPLE data). * Filled squares = runs that day (darker = more). Empty squares = no runs. * A highlight sweeps across the days; visitors can pause it, and it never moves * for people who ask for reduced motion. */import { useState } from "react"import { cx } from "../components/cx"import { SampleTag } from "./ui"
const DAYS = 30
/** Small deterministic random generator so server and browser render the same squares */function mulberry32(seed: number) { return () => { seed |= 0 seed = (seed + 0x6d2b79f5) | 0 let t = Math.imul(seed ^ (seed >>> 15), 1 | seed) t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t return ((t ^ (t >>> 14)) >>> 0) / 4294967296