KQ-1876 · SKYLINE/BRUSH

Skyline Brush

A seeded city plan seen from above at an angle — a street grid of blocks cut into plots, parks, a river across one corner and district names lying on the ground in the plan's own perspective. Brushing the pointer across it raises every block it passes into a tower that springs up on the springs.snap constants with one crisp overshoot, its floors appearing lit from the bottom up, and casts a long shadow across the streets from a low sun; after a moment the towers sink back to their footprints on a soft ease, so a stroke leaves a ridge that subsides like a wake. The districts are a listbox: keyboard focus raises the active district and traces it on the ground, arrows move between districts, Enter pins one so it stays raised and Escape clears it.

KQ-1876 · SKYLINE/BRUSH
Waylight Quarter, 22 blocks
Basin Docks, 21 blocks
Fernworks Yards, 22 blocks
Coldbrook Hill, 18 blocks
Gauge Market, 19 blocks

Arrow keys raise one district at a time. Enter pins the district so it stays raised; Escape clears it.

Waylight · 2040 massing study

brush the plan · towers up to 36 floors · 5 districts

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/skyline-brush

Props

districts
SkylineBrushDistrict[]
default defaultSkylineBrushDistricts
The districts the plan is divided into, 2 to 8; each { id, name, height? }, height 0–1 setting how tall it builds.
maxHeight
number
default 36
The tallest a tower can rise, in floors, 8 to 60. A change replays the preview stroke.
falloff
number
default 0.45
How far the brush's raise reaches, 0 (a fine pen: only the blocks under it) to 1 (a broad swell).
lights
number
default 0.6
The share of windows lit, 0 (dark glass) to 1 (every window).
value / defaultValue
string | null
default null
The pinned district's id, or null; a pinned district stays raised. Controlled or uncontrolled.
onValueChange
(id: string | null) => void
default —
Fires from the tap or key that pinned or cleared a district.
radius
number
default 48
The brush's reach on screen, px.
hold
number
default 1100
ms a brushed tower stands before it starts to sink.
sinkDuration
number
default 2600
ms a tower takes to sink back to its footprint.
shadow
number
default 1.2
How long the low sun's shadows run, 0 (none) to 2.
intro
boolean
default true
On first view, one stroke raises a band across the plan and lets it sink.
groundColor
string
default a paper (light) or night (dark) tint of the accent token
The ground, any CSS colour; streets and blocks are shaded from it.
buildingColor
string
default a pale (light) or slate (dark) tint of the accent token
The towers' facades, any CSS colour; the shaded face, roofs and dark windows follow from it.
windowColor
string
default a warm pigment from the warn token
Lit windows, any CSS colour.
seed
number
default 1
Seeds the plan: streets, plots, parks, the river and every window.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
label
string
default "City plan"
The plan's accessible name.
disabled
boolean
default false
No brushing, taps or keys.
className
string
default —
Sizes the plan; it fills its parent by default.