← back to Rose City Rooftop Solstice

README.md

94 lines

# Rose City Rooftop Solstice

A self-contained, animated urban-fantasy gallery piece. At sunset, interconnected
city rooftops become a communal dance garden above a glowing city — the whole
thing rendered live on a single HTML canvas with no external assets, no build
step, and no network calls.

Open `index.html` in any modern browser. That's the entire program.

## What's in the scene

**Four choreography zones**
- A **turning circle** of figures orbiting an abstract rose-shaped light sculpture.
- **Bridge couples** crossing narrow rooftop bridges in mirrored steps.
- **Freestyle dancers** near the water towers, tracing curved motion trails.
- A quiet **procession** climbing the fire escapes into the celebration.

**Animal companions**
- Bears sway with grounded weight, cats leap between ledges, pigeons rise in
  coordinated spirals, dogs weave among the dancers, and moths gather at the lanterns.

**Depth & atmosphere**
- Parallax skyline layers, drifting clouds, swaying laundry lines, reflective
  windows with a moving specular sweep, a luminous city-glow band, and light that
  shifts from gold to indigo.

**Three scenes**, each with its own palette and movement complexity:
`Arrival` (warm, calm) → `Long Light` (luminous, fuller) → `Midnight Bloom`
(deep indigo, moon, lanterns, the rose in full bloom). They drift automatically,
or you can pin one.

## Controls

- **Cameras** — Skyline, Rooftop, Bird's-eye (with a plan-view tilt).
- **Visual tempo** and **crowd density** sliders.
- **Isolate group** — focus a single choreography zone; the others fade to ghosts.
- Toggles for **animal & zone names**, **motion trails**, and **route diagrams**.
- **Pause**, **Restart**, and a true **Reduced motion** still composition.

Keyboard: `Space` pause · `1 2 3` cameras · `R` restart · `N` names ·
`T` trails · `D` diagrams · `M` reduced motion · `C` hide panel.

## Music — live and audio-reactive (from the archive)

The control dock has a **Music · from the archive** section that streams live
**Grateful Dead** recordings from the [Internet Archive](https://archive.org)'s
`GratefulDead` collection — a public, keyless API. The band was famously
taping-friendly, and these recordings are shared with their blessing; each
now-playing show links back to its archive.org item for credit.

**When music plays, the whole scene reacts to it — live.** Each track is fetched
and decoded, then played through a Web Audio graph
(`BufferSource → Analyser → Gain`). Every frame the analyser is read for
**bass / mid / treble / overall level** plus a **beat onset**, and those features
drive *everything*:

- the master clock speeds up with musical energy (the whole gathering moves faster when it's loud),
- **dancers** grow their moves with loudness and **lift on every beat**,
- the **rose sculpture** pulses and blooms with the bass and beat,
- **lanterns** and the **city glow** breathe with the music,
- **bears** sway harder on bass, **cats** leap higher, **pigeons** get extra lift on beats, **moths** flutter with the treble.

Controls: **Play/Pause**, **Shuffle show** (queries the archive live for a random
popular show), **⏮ / ⏭** track stepping, and a volume slider (independent of the
analysis, so quiet music still drives the visuals).

Why buffer-and-decode rather than a plain `<audio>` element? Reading a stream's
spectrum through Web Audio needs the decoded samples in the graph; the
buffer-source path guarantees that reactivity works on every browser (it's the
same synthesis path as an oscillator), which a `MediaElementSource` does not.
Tradeoff: each track is fetched in full first (the light 64 kbps derivative,
~2–3 MB, ~2 s), and the next track is prefetched while the current one plays.

This music is the **only** part of the piece that touches the network, and it's
**audio only** — it starts on a click (respecting autoplay rules) and reports
plainly if you're offline. With the music **off**, the visuals are fully
self-contained and run on their authored rhythm.

## An honest note

The piece keeps its own time. Its rhythm, swells and blooms are **authored** — a
composed visual tempo — and are **not** reactive to any audio or microphone.
Turning on *Reduced motion* yields a calm, composed still (and the OS
`prefers-reduced-motion` setting is honored on load).

## Craft notes

- Pure Canvas 2D, ~1.2k lines of vanilla JS in one file. Deterministic PRNG so the
  composition is repeatable; `Restart` reseeds it.
- Responsive + DPR-aware, keyboard-accessible native controls with strong focus
  states, refined serif/sans type.
- All imagery is original — the gathering evokes the generous, improvisational
  spirit of Grateful Dead rooftop culture without reproducing any of it.