STYLE.md ·
How Needle works. Every rule, written down.
Music streaming, as a website. It has three pieces:
- The deck. A player bar that sticks to the bottom of the window, so the music follows you down the page. It has previous, play and next, a seek bar and a queue.
- A tracklist. Press any row to play from there. Explicit songs are marked E, a "Clean versions only" switch skips them, and the row that's playing bounces.
- Synced lyrics. The line being sung lights up in volt; click a line to jump there.
The type is Bricolage Grotesque, Figtree and Spline Sans Mono, on a lilac white with ink and one violet. Volt lime is only for what's playing now. The deck is always ink.
Loud · fair · easy
Best for
- Music streaming services and music sites. It's written to the subscription rules (see "Streaming: what we build in").
- Anyone whose site should play music while people browse:
- community radio (Static FM: the live show, just played, the schedule)
- record labels (Kin Records: an EP with lyrics, the roster, how the money's split)
- artists, venues and festivals with line-ups, podcasts, audiobook publishers
- Audiences: listeners who want to press play and keep browsing, parents who want clean versions, and artists who want to know what they're paid.
Less suited to: film and TV catalogues (a screen-streaming style), video creators (Cue), or a band site that only links out to other platforms.
Personality and voice
Loud and friendly, and straight about money.
- Headlines: "Turn it up." · "Where your money goes." · "Plans, in plain words."
- Buttons: "Start listening" · "Play the album" · "Try Solo free"
- Microcopy:
- "Explicit songs are marked E. With clean versions on, they're skipped."
- "First month free, then $12.99 a month. We'll email you 3 days before the trial ends."
- "Cancel online in two steps."
- Words to avoid: "free" for a trial that needs a card without saying so, "unlimited" with fine print, and "cancel anytime" if cancelling needs a phone call.
Colour
| Token | Daylight (light) | After dark (dark) | Role |
|---|---|---|---|
--paper |
#f7f6fb |
#0d0b12 |
Page |
--card |
#ffffff |
#17151d |
Tracklists, lyrics, plans |
--well |
#ece9f5 |
#121017 |
Alternate sections |
--line |
#dedae8 |
#2a2733 |
Hairlines between rows |
--ink / --ink-2 |
#121018 / #37343f |
#f1eff6 / #d1cdd9 |
Text |
--muted |
#5c5966 |
#a39fae |
Artists, times, plays, lyric lines still to come |
--amp |
#5f25c9 |
#c4a8ff |
The one accent: buttons, links, the lit words, the bouncing bars |
--volt |
#c6f432 |
#a8d82a |
What's playing now, the lyric line being sung (with ink) |
--deck |
#121018 |
#07060a |
The player bar and now-playing cards, in both modes |
Measured contrast (WCAG).
- Daylight:
- ink on paper 17.6:1
- muted on paper 6.4:1
- amp on paper 7.5:1 (6.8:1 on well, 6.5:1 on its soft fill), white on amp 8.1:1
- ink on volt 14.7:1
- After dark:
- ink 17.2:1
- muted 7.6:1 (7.0:1 on card)
- amp 9.7:1, text on amp 8.9:1, amp on its soft fill 8.2:1
- ink on volt 11.3:1
- Example dials: signal orange (Static FM), sea green (Kin Records) and indigo (Fieldtone) all meet AA as text and behind button text.
Typography
- Display: Bricolage Grotesque, 500–800. Headlines, song and album titles, lyrics, prices.
- Body: Figtree, 400–700. Reading, artists, buttons.
- Mono: Spline Sans Mono, 500–600. Times, play counts, labels.
| Token | Size | Use |
|---|---|---|
--fs-h1 |
clamp(42px, 5.8vw, 88px) | Page headline |
--fs-h2 |
clamp(30px, 3.6vw, 52px) | Section headline |
--fs-h3 |
21px | Card titles |
--fs-lead |
clamp(17.5px, 1.35vw, 20.5px) | Intro paragraphs |
--fs-body |
16.5px | Body |
| Lyrics | clamp(19px, 2vw, 26px) | Synced lyric lines |
The signature move: the lit words turn violet italic, with three volt bars bouncing after them like a level meter.
Layout
- Frame: a 1200px wrap with a
max(20px, 4vw)gutter. An ink top line with a volt pill; a sticky header with the record mark; the deck fixed to the bottom, with room left for it. - Hero: copy on the left; a now-playing card (a record spinning in its cover) on the right.
- Then: the album head, then the tracklist beside synced lyrics; new releases; how artists are paid; plans with the renewal terms; and an ink closing card with a record spinning in the corner.
Shape
- Rounded:
--r-s10px,--r-m14px,--r-l22px; buttons are pills. - Covers: drawn: a colour field in each release's hue with a record in the middle and the title. Never borrow real album art.
- The mark: a record with a volt label and a violet tonearm.
Motion language
- Deck: the play button changes to pause; the cover's record spins while playing; the queue slides up.
- Tracklist: the playing row's number becomes three bouncing bars.
- Lyrics: each line lights up in volt as it's sung; lines already sung stay darker.
- Elsewhere: the headline's level meter bounces, covers lift on hover, records spin, sections reveal with a 14px rise over 650ms, and the phone menu drops in.
- Motion switch in the footer (
[data-motion-toggle],html.calm, remembered assite-motion, with the default fromprefers-reduced-motion). Calm stops the bars, spinning and lifts; playback and lyrics still work. - After dark switch (
[data-theme-toggle]), remembered assite-theme;theme-colorfollows.
Imagery and illustration
Real cover art belongs to the artist and label: use it only with their licence. The template draws covers so nothing is borrowed. Photos of artists should be ones they've approved.
Signature components
- Tracklist:
.tracklist[data-tracklist]#id, containing:.tl-headwithbutton[data-play-list="#id"]and.switch[data-clean].tl-rows > .tr, each withdata-id,data-title,data-artist,data-dur,data-hue,data-wordanddata-explicit- inside each row:
button.no,.t > b + small(with.explicit),.playsand.dur
- Deck:
.deck[data-deck][data-start="#list"][data-queue-label], containing:.deck-nowwith.cover,bandsmall.deck-midwith.prev,button.dpp,.nextand.deck-bar([data-deck-time],input.deck-seek,[data-deck-dur]).deck-sidewithbutton[data-queue-toggle][aria-controls="queue"].queue#queueas a sibling
- Lyrics:
.lyrics[data-lyrics][data-track="id"] > button[data-t], with.credit. - Supporting pieces:
.cover[data-word](.lg,.spin),.nowcard,.releases > a.rel,.album-head,.plans > .plan(.pick)with.renew,.gigs,.card,.facts,.notice,.side-box,.grid-2.lyr,.close-card(--close-em).
Multi-page kit
- Phone menu:
.menu-btn[aria-controls]opens.site-menu. Escape, an outside click or choosing a link closes it, and Tab stays inside while it's open. - Current page:
aria-current="page", shown as an amp-soft pill. - Inner pages:
.page-head(with grooves on the right),.crumbs, a.tagand a smaller.h1. - Fields:
.field,.fields,.field-wide,fieldset.field-set,.check,.form-card,[aria-invalid="true"];form[data-template]. - Tiles, segmented control, gate, slider, switch, tables:
.choices,.seg,[data-gate],input.range,.switch[role=switch],.table. - Events:
track(id, title, artist),deck(playing),tick(t, id). - Helpers:
Needle.refresh(root),Needle.play(id).
Streaming: what we build in
We checked these for Australian subscription services in October 2026:
- Clear subscription terms, and cancelling as easy as joining. The federal government's 2026 reforms target subscription traps: businesses must disclose key terms before sign-up, notify customers at key points, and offer a clear, straightforward way to cancel. Draft laws were released in February 2026; reports say the rules start on 1 July 2027, so check the final law. The template states the price including GST, what renews and when, a reminder 3 days before a trial ends, 30 days' notice of price changes, and online cancelling in two steps.
- Prices including all mandatory fees. The headline price is the price, with GST.
- Explicit content marked, with a clean-versions switch that also skips explicit songs in the queue.
- Fair-pay transparency (Fieldtone): the published average per play shown as a range, our share, and how listener-centred payments work.
These notes are design guidance, not legal advice.
Do and don't
- Do keep the deck on screen, and leave room for it at the bottom of the page.
- Do mark explicit songs, and respect the clean switch in the queue.
- Do say what renews, when, and for how much, next to every price.
- Don't use volt for anything but what's playing now.
- Don't autoplay.
- Don't use real cover art or lyrics without a licence.
Accessibility
- AA contrast throughout (measured above), including lyric lines still to come; a skip link; a 3px focus ring (white on the deck).
- Tracklist: each row's play button says the song, artist and "explicit"; the clean switch is a real switch, remembered.
- Deck: labelled previous, play/pause and next; the seek bar says the time and total; the queue is a region that opens with
aria-expanded, closes with Escape and returns focus. - Lyrics: every line is a button; the current line is
aria-current. - Testing: responsive to 360px (the deck stacks on phones), and tested with motion on and off, in Daylight and After dark.
How to make it yours
| Dial | Range |
|---|---|
| Accent | Violet (default), signal orange (Static FM), sea green (Kin Records), indigo (Fieldtone). Set --amp, --amp-2, --amp-soft, --focus (plus --on-amp at night) and --close-em. |
| Deck | Your audio player behind the same controls (HTML audio, HLS for live radio, or your platform's SDK). |
| Lists | Albums, playlists, shows or episodes. |
| Plans | Yours, always with the renewal terms beside the price. |
| Not negotiable | The deck that follows you, explicit songs marked with the clean switch, the renewal terms beside every price, volt only for what's playing, and the Motion switch. |



