# Backdrops: living backgrounds for OxygenHub Status: the engine and the dashboard's Your sky are built (oxygenhub#157, 2026-10-13); the other scenes are proposed (oxygenhub#156). ## 1. What a backdrop is A backdrop is a quiet, moving picture behind a page's content: a field of small marks that drift slowly and respond a little to the cursor. It gives the hub a sense of motion and depth without asking for attention. Three rules shape everything else: 1. **True, not invented.** The footer says "nothing here is inferred: what a page says, the object store says". A backdrop keeps that promise. Every mark stands for something real the viewer may see: one of their repositories, a change, a push, a runner. Nothing is made-up decoration that only looks like data, such as fake chunks or fake peers. 2. **Behind, never in the way.** Content is opaque cards on top. A backdrop shows only in the margins and the gaps between cards. It never takes a click, never moves the layout, and is never needed to read or use the page. 3. **Cheap and polite.** It costs well under a millisecond a frame. It stops when the tab is hidden, and it is still for people who ask for reduced motion. Anyone can turn it off. ## 2. Which pages | Page | Scene | Shows | |---|---|---| | Dashboard | **Your sky** (§5) | Your repositories as clusters; their activity in the last 30 days as the marks around them | | Signed-out home, Explore | **The hub's sky** | The same scene from public repositories only | | Sign in, register, device sign-in | **The mark** | The Oxygen mark's two rings with marks orbiting them; brand only, no data | | A repository's Diffusion tab | **Ripples** | The upstream and its consumers as the Diffusion mark draws them: a pulse goes out on a bump, green or red as its run ends | | Admin › Runners › Images | **The swarm** | Runners as nodes; chunks moving between them while an image is fetched, from the swarm tracker's live state | | Not found, server error | **Adrift** | One mark drifting away from the rest | **Never:** code, file, blame, diff, conflict and proposal pages, the editor, issues and proposals while being written, settings and admin tables. Those pages are for reading closely, and motion behind them costs attention. Repository overviews have none for the same reason; their README is the picture. Each scene is its own issue, done one at a time, the dashboard first. ## 3. Colours A backdrop takes its colours from the page's own tokens, so it is right in both looks (GitHub, the default, and classic) and in both themes (light, the default, and dark), and it follows a theme switch at once. Three new tokens join each look's light and dark sets: | Token | Use | GitHub light | GitHub dark | Classic (dark) | |---|---|---|---|---| | `--bd-mark` | a resting mark | `--mute` at 16% | `--mute` at 14% | `--acc` at 12% | | `--bd-lit` | a mark near the cursor | `--acc` (#0969da) at 70% | brand cyan #00F0FF at 75% | #00F0FF at 85% | | `--bd-link` | a line between lit marks | `--acc` at 22% | #00F0FF at 28% | #00F0FF at 35% | Two more colour rules: - **The brand gradient (#00F0FF → #0072FF)** is kept for moments: a new push arriving, the mark scene. A whole field in it would shout. - **Status colours are used only where the data has a status:** the Diffusion pill's green, amber and red, and a run's outcome. They never appear as decoration. In light mode a backdrop must be barely there: if you notice it before the content, it is too strong. The contrast test (`tests/contrast.rs`) gains a check that `--bd-mark` stays under 1.3:1 against `--bg`. ## 4. Motion and the cursor - **Drift.** Marks move slowly, at most 12 px a second, along gentle streams around their cluster. Two streams can cross: their marks pass each other without touching, and the change in order means nothing. That is how Oxygen's changes behave, which is where this comes from. - **The cursor lights, it does not pull.** Marks within about 140 px of the cursor light up in `--bd-lit`, ramping in over 150 ms and fading out over 600 ms. Nothing is attracted or pushed, so the cursor never rearranges the picture. - **Lines mean something.** Among the lit marks, a faint line joins two marks only when they belong together in the data: events of the same repository that happened one after another and sit within 70 px of each other, so a busy repository reads as a constellation, not a scribble. Lines fade as the cursor moves on or rests for 2 s. - **Labels, sparingly.** When the cursor rests near a cluster, its name fades in just above the cluster's outer ring in `--mute`, small. This is the only text a backdrop draws, and it is never a link; the dashboard's own list is the link. - **Parallax.** Three depth layers shift by at most 6 px, 3 px and 1 px against the cursor's offset from the page's centre. That gives a little depth with no feeling of motion sickness. - **Arrivals.** When the page learns of new activity, its mark appears with one soft ring in the brand gradient that widens and fades over 1.2 s. This is the one moment a backdrop may draw the eye, and only briefly. ## 5. The dashboard: Your sky **Data.** The dashboard handler already loads your repositories and the activity feed from the database. The backdrop needs a little more of the same: - the repositories in Your repositories, by name; - up to 1,500 events from the last 30 days across them (pushes, proposal and issue events, releases, Flow runs), each with its repository, kind and time, and for a push the number of changes it brought. A push draws one dot for each change, up to 40, and the sky draws up to 3,000 marks. The handler embeds these as JSON in the page (`