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.
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.
| Prop | Type | Default | Description |
|---|---|---|---|
| districts | SkylineBrushDistrict[] | 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 | 36 | The tallest a tower can rise, in floors, 8 to 60. A change replays the preview stroke. |
| falloff | number | 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 | 0.6 | The share of windows lit, 0 (dark glass) to 1 (every window). |
| value / defaultValue | string | null | null | The pinned district's id, or null; a pinned district stays raised. Controlled or uncontrolled. |
| onValueChange | (id: string | null) => void | — | Fires from the tap or key that pinned or cleared a district. |
| radius | number | 48 | The brush's reach on screen, px. |
| hold | number | 1100 | ms a brushed tower stands before it starts to sink. |
| sinkDuration | number | 2600 | ms a tower takes to sink back to its footprint. |
| shadow | number | 1.2 | How long the low sun's shadows run, 0 (none) to 2. |
| intro | boolean | true | On first view, one stroke raises a band across the plan and lets it sink. |
| groundColor | string | 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 | 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 | a warm pigment from the warn token | Lit windows, any CSS colour. |
| seed | number | 1 | Seeds the plan: streets, plots, parks, the river and every window. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| label | string | "City plan" | The plan's accessible name. |
| disabled | boolean | false | No brushing, taps or keys. |
| className | string | — | Sizes the plan; it fills its parent by default. |