Phosphor Score
Vertical CRT sheet music — notes slide down a grand staff, bloom and flare at the playhead, then fade with a phosphor afterglow.
A falling score, not a piano roll. A grand staff of beamed runs, chords, slurs and dynamics scrolls down to a playhead: each note brightens as it arrives, blooms and flares as it plays, then fades with a phosphor afterglow. Default theme="auto" follows the site — phosphor green in dark, forest ink in light, both on the page background. glow is 0–100 (default 50) and stays a tight halo on the note. Change Seed to crossfade to a new score. Press d to toggle the theme.
Preview
Slow camera drift around the plane
Installation
pnpm dlx shadcn@latest add @23rd/phosphor-scoreOr install straight from the public GitHub source registry:
pnpm dlx shadcn@latest add radiumcoders/23rd.dev/phosphor-scoreUsage
Give the parent a size. The canvas fills the parent and fades out at its top and bottom edges on its own.
"use client"
import { PhosphorScore } from "@/components/ui/phosphor-score"
export function HeroScore() {
return (
<div className="relative h-svh w-full bg-background">
<PhosphorScore />
</div>
)
}Lock a theme or push the bloom. Omit color to follow light / dark.
<PhosphorScore theme="light" glow={50} />
<PhosphorScore theme="dark" color="#4DFF6A" glow={50} />Change the viewing angle. The plane turns about the playhead in perspective, like CSS rotateX() rotateY() rotateZ(), and fades out as it recedes.
<PhosphorScore rotateX={50} />
<PhosphorScore rotateX={35} rotateY={-20} rotateZ={8} />prefers-reduced-motion: reduce holds a still frame of the score and stops drawing. The animation also pauses while the canvas is off-screen or the tab is hidden.
Props
| Prop | Type | Default |
|---|---|---|
color | string | theme phosphor / forest ink — any CSS color |
glow | number | 50 — 0–100, halo size at the playhead |
speed | number | 1.35 — beats per second |
density | number | 1 — 0.35–1.85, how packed the notation is |
sway | boolean | true — slow camera drift |
seed | number | 23 — a new seed crossfades to a new score |
rotateX | number | 0 — degrees, -70–70, tips the top away |
rotateY | number | 0 — degrees, -70–70, swings the right away |
rotateZ | number | 0 — degrees, spins the plane clockwise |
theme | "light" | "dark" | "auto" | "auto" |
className | string | React only |
class | string | Svelte only |
Omit color and theme="auto" picks phosphor green on dark, forest ink on light. The canvas is transparent in both themes, so it sits on whatever background the parent paints.