Spotify
A dark-first music platform where a single vivid green carries every action. Circular's rounded geometry, near-black surfaces layered like a venue at night, and bold condensed display type give the interface a stage-light energy — album art supplies the color, the chrome stays out of the way. Cards sit on subtly elevated surfaces, never casting shadows; hierarchy comes from brightness steps and type weight alone.
tokens(front matter)
version: alpha
name: Spotify-design-analysis
description: A dark-first music platform where a single vivid green carries every action. Circular's rounded geometry, near-black surfaces layered like a venue at night, and bold condensed display type give the interface a stage-light energy — album art supplies the color, the chrome stays out of the way. Cards sit on subtly elevated surfaces, never casting shadows; hierarchy comes from brightness steps and type weight alone.
colors:
primary: "#1db954"
primary-bright: "#1ed760"
on-primary: "#000000"
canvas: "#000000"
surface-elevated: "#121212"
surface-card: "#181818"
surface-hover: "#282828"
text: "#ffffff"
text-muted: "#b3b3b3"
text-subdued: "#6a6a6a"
hairline: "#2a2a2a"
banner-warm: "#e8115b"
banner-cool: "#1e3264"
banner-purple: "#503750"
banner-orange: "#e13300"
banner-cream: "#e9e3d4"
banner-sky: "#8d67ab"
banner-sunset: "#af2896"
typography:
hero-display:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 64px
fontWeight: 900
lineHeight: 1.15
letterSpacing: -0.04em
display-lg:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 48px
fontWeight: 900
lineHeight: 1.2
letterSpacing: -0.03em
display-md:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 32px
fontWeight: 700
lineHeight: 1.3
letterSpacing: -0.02em
title:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 24px
fontWeight: 700
lineHeight: 1.4
letterSpacing: -0.01em
card-title:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 16px
fontWeight: 700
lineHeight: 1.5
letterSpacing: 0
body:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 16px
fontWeight: 400
lineHeight: 1.5
letterSpacing: 0
body-bold:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 16px
fontWeight: 700
lineHeight: 1.5
letterSpacing: 0
caption:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 14px
fontWeight: 400
lineHeight: 1.45
letterSpacing: 0
button:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 14px
fontWeight: 700
lineHeight: 1
letterSpacing: 0.02em
nav-link:
fontFamily: "Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif"
fontSize: 16px
fontWeight: 700
lineHeight: 1
letterSpacing: 0
rounded:
xs: 2px
sm: 4px
md: 8px
lg: 16px
pill: 500px
spacing:
xxs: 4px
xs: 8px
sm: 16px
md: 24px
lg: 32px
xl: 48px
xxl: 64px
section: 96px
components:
button-primary:
backgroundColor: "{colors.primary}"
textColor: "{colors.on-primary}"
typography: "{typography.button}"
rounded: "{rounded.pill}"
padding: 14px 32px
button-primary-hover:
backgroundColor: "{colors.primary-bright}"
textColor: "{colors.on-primary}"
rounded: "{rounded.pill}"
button-secondary-pill:
backgroundColor: transparent
textColor: "{colors.text}"
typography: "{typography.button}"
rounded: "{rounded.pill}"
borderWidth: 1px
borderColor: "{colors.text-muted}"
padding: 14px 32px
top-nav:
backgroundColor: "{colors.canvas}"
textColor: "{colors.text}"
typography: "{typography.nav-link}"
height: 80px
hero-section:
backgroundColor: "{colors.canvas}"
textColor: "{colors.text}"
typography: "{typography.hero-display}"
padding: "{spacing.section} 24px"
feature-band:
textColor: "#000000"
typography: "{typography.display-lg}"
padding: "{spacing.section} 24px"
album-card:
backgroundColor: "{colors.surface-card}"
textColor: "{colors.text}"
typography: "{typography.card-title}"
rounded: "{rounded.md}"
padding: 16px
album-card-hover:
backgroundColor: "{colors.surface-hover}"
rounded: "{rounded.md}"
playlist-row:
backgroundColor: transparent
textColor: "{colors.text-muted}"
typography: "{typography.body}"
rounded: "{rounded.sm}"
padding: 8px 16px
playlist-row-active:
backgroundColor: "{colors.surface-hover}"
textColor: "{colors.text}"
rounded: "{rounded.sm}"
nav-item:
backgroundColor: transparent
textColor: "{colors.text-muted}"
typography: "{typography.nav-link}"
rounded: "{rounded.pill}"
padding: 12px 24px
nav-item-active:
backgroundColor: "{colors.surface-card}"
textColor: "{colors.text}"
rounded: "{rounded.pill}"
footer:
backgroundColor: "{colors.canvas}"
textColor: "{colors.text-muted}"
typography: "{typography.caption}"
padding: "{spacing.xxl} 24px"Overview
Spotify's web presence runs on a single idea: the app is a venue, and the music is the show. Surfaces are near-black — pure {colors.canvas} for the shell, {colors.surface-elevated} for raised regions, {colors.surface-card} for cards — so that the only saturated color on screen is either Spotify Green or the artwork itself. Marketing pages lean into this contrast hard: enormous 900-weight Circular headlines in white on black, one green pill button per screen section, and photography that bleeds edge to edge.
The signature is boldness without noise. Headlines go up to 64px at weight 900 with tight negative tracking; body copy stays quiet at 16px/400 in {colors.text-muted}. Accent colors outside green are absent from the product chrome — the warm pinks, deep blues, and sunset purples live only in editorial playlist banners ({colors.banner-*}), where they backdrop large display type. Interaction feedback is brightness, not shadow: cards step from #181818 to {colors.surface-hover} on hover, buttons brighten from {colors.primary} to {colors.primary-bright}.
Key Characteristics:
- Dark-first surfaces with brightness-step hierarchy; zero drop-shadows anywhere in the system.
- Exactly one interactive accent:
{colors.primary}(Spotify Green #1db954). Hover state brightens to{colors.primary-bright}— never a second hue. - Circular typeface at extreme weight range (400 → 900); display sizes carry
-0.02 → -0.04emtracking for the "stadium poster" cadence. - Pill-shaped CTAs (
{rounded.pill}) with black text on green — inverted contrast from most brand systems. - Album-art grids do the visual heavy lifting; chrome recedes to grayscale.
- Editorial banner colors (
{colors.banner-warm},{colors.banner-cool}, etc.) form a curated pool reserved for playlist/feature banners — never for interactive elements. - Rounded card geometry (
{rounded.md}8px) everywhere content sits in a container; pills reserved for actions.
Colors
Source pages analyzed: marketing homepage, logged-out landing, web player shell, playlist page, footer. The palette is identical across surfaces; only banner-color usage differs.
Brand & Accent
- Spotify Green (
{colors.primary}— #1db954): The single interactive color. Every primary CTA, every active-state indicator, the logo mark. Black text on green ({colors.on-primary}) keeps the pill readable and unmistakably non-link-like. - Bright Green (
{colors.primary-bright}— #1ed760): The hover/energy variant. Primary buttons shift to this on hover; marketing moments that need more voltage use it directly. Never used for static body content. - Green never appears as a text color on dark surfaces — it is reserved for fills and indicators. Text links use white with underline instead.
Surface Ladder
- Canvas Black (
{colors.canvas}— #000000): The page background and top nav. The venue floor. - Elevated (
{colors.surface-elevated}— #121212): The web player's main panel and footer bands — one brightness step above canvas to suggest a raised platform without a shadow. - Card (
{colors.surface-card}— #181818): Album cards, nav pills (active), and contained content. The default "thing" surface. - Hover (
{colors.surface-hover}— #282828): Both the hover step for cards and the active state for list rows. A single token doing double duty keeps the two patterns visually rhyming. - Hairline (
{colors.hairline}— #2a2a2a): 1px separators in lists and the footer.
Text
- White (
{colors.text}— #ffffff): Headlines, card titles, and active nav. Pure white on near-black gives the type its stage-light crispness. - Muted (
{colors.text-muted}— #b3b3b3): Body copy, captions, inactive nav. The workhorse secondary. - Subdued (
{colors.text-subdued}— #6a6a6a): Timestamps, counters, and fine print. The quietest readable gray on black.
Editorial Banner Pool
The {colors.banner-*} family (warm pink #e8115b, deep blue #1e3264, dusk purple #503750, vermilion #e13300, cream #e9e3d4, violet #8d67ab, magenta #af2896) is a curated pool assigned per-editorial-section, never per-component. A banner gets one flat color and black or white text at display scale. These are the only non-green hues in the entire system — and they are permanently quarantined from interactive elements.
No gradients. Depth comes from brightness steps and artwork, never from CSS transitions between colors.
Typography
Font Family
- Everything:
Circular, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif— one family for display, body, and UI. The system has no serif, no mono, no secondary face.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
{typography.hero-display} |
64px | 900 | 1.15 | -0.04em | Marketing hero headline |
{typography.display-lg} |
48px | 900 | 1.2 | -0.03em | Feature band headlines, banner type |
{typography.display-md} |
32px | 700 | 1.3 | -0.02em | Section headers |
{typography.title} |
24px | 700 | 1.4 | -0.01em | Card shelf titles ("Made for you") |
{typography.card-title} |
16px | 700 | 1.5 | 0 | Album/playlist card names |
{typography.body} |
16px | 400 | 1.5 | 0 | Paragraph copy, descriptions |
{typography.body-bold} |
16px | 700 | 1.5 | 0 | Inline emphasis, prices |
{typography.caption} |
14px | 400 | 1.45 | 0 | Card metadata, footer links |
{typography.button} |
14px | 700 | 1 | 0.02em | All button labels (always caps-agnostic, always bold) |
{typography.nav-link} |
16px | 700 | 1 | 0 | Top nav and footer headings |
Principles
- Weight 900 is the display voice. Marketing headlines live at the top of the ladder; the tight tracking (-0.03 → -0.04em) keeps the extreme weight from spilling.
- Letter-spacing flips sign by size. Display tightens (-0.04em), buttons loosen slightly (+0.02em) so 14px bold reads cleanly at small sizes.
- Body never drops below 14px. Captions are the floor; there is no fine-print tier.
- Muted color does hierarchy work weight would otherwise do. A card title is white/700; its metadata is muted/400 — same size, different color.
- No italic anywhere. Emphasis is weight or color, never slant.
Note on Font Substitutes
Circular is Spotify's proprietary face. When building off-system:
- The stack falls back to
-apple-system/BlinkMacSystemFontfirst — on Apple platforms this resolves to a geometric-enough system face. - Figtree or Poppins (Google Fonts, weight 400–900) are the closest open equivalents to Circular's rounded terminals and tall x-height; Poppins at 700/900 with tracking tightened by
-0.01emreads nearly identical. - Arial is the terminal fallback and is acceptable — Circular's geometry is close enough that the substitution doesn't break the layout rhythm.
Layout
Spacing System
- Base unit: 8px. Tokens:
{spacing.xxs}4px ·{spacing.xs}8px ·{spacing.sm}16px ·{spacing.md}24px ·{spacing.lg}32px ·{spacing.xl}48px ·{spacing.xxl}64px ·{spacing.section}96px. - Section vertical padding:
{spacing.section}(96px) on marketing sections — generous by SaaS standards, giving hero type room to dominate. - Card internal padding: 16px. Shelf gaps:
{spacing.sm}(16px) between cards. - Grid gutters: 24px at desktop, 16px below 768px.
Grid & Container
- Max content width: 1440px on marketing pages; the web player is fluid full-width with a fixed 240px sidebar.
- Card shelves:
auto-fillgrids with a ~180px floor — typically 4–6 album cards per row on desktop, 2 on mobile. - Hero: left-aligned single column at desktop (headline → subcopy → pill CTA), center-stacked on mobile.
- Feature bands: full-bleed single color, content constrained to 960px.
Whitespace Philosophy
Sections breathe at 96px so each feels like its own "song." Inside cards, the 16px padding keeps the artwork dominant. The nav is the densest zone (80px tall, links at 24px gaps); everything else errs toward air. Nothing on the page sits closer than 16px to anything else.
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| Flat | No shadow, no border | Everything — cards, nav, buttons, banners |
| Brightness step | Background shift #121212 → #181818 → #282828 |
Elevation and hover |
| Hairline | 1px {colors.hairline} |
Footer separators, list dividers |
Shadow philosophy. There are no shadows. Not on cards, not on dropdowns, not on modals. The system's depth vocabulary is entirely brightness-based — a platform dark enough that shadows would be nearly invisible anyway, so hierarchy is carried by surface steps and the artwork itself. Interactive elements signal with green fill, not elevation.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
{rounded.xs} |
2px | Checkboxes, tiny indicators |
{rounded.sm} |
4px | Playlist rows, list items |
{rounded.md} |
8px | Album cards, containers, inputs |
{rounded.lg} |
16px | Large editorial tiles |
{rounded.pill} |
500px | Every button, nav pills, tags |
Artwork Geometry
- Album/playlist covers: perfect squares (1:1), never rounded themselves — the rounding lives on the card container so artwork runs to the card's rounded corners.
- Editorial banners: full-bleed rectangles, no radius.
- Avatars: circles (via
{rounded.pill}on square images). - Photography in marketing heroes is full-bleed and edge-to-edge; no framed or floating imagery.
Components
Top Navigation
top-nav — Black bar, 80px tall. Left: green logo mark + wordmark. Center: nav links in {typography.nav-link} (16px/700), muted until active. Right: "Log in" as a {component.button-secondary-pill} and "Sign up" as a {component.button-primary}. Links highlight white on hover — never green.
Buttons
button-primary — The signature action. Background {colors.primary}, text {colors.on-primary} (black on green — the inversion is the brand), {typography.button} (14px/700/+0.02em), rounded {rounded.pill} (full pill), padding 14px × 32px. Hover brightens to {component.button-primary-hover} ({colors.primary-bright}).
button-secondary-pill — Ghost pill. Transparent background, 1px {colors.text-muted} border, white text, same padding and radius as primary. Used alongside a primary when two actions are offered ("Log in" next to "Sign up").
Buttons are the only pill-shaped elements that are not also navigation. A pill that navigates is a nav-item; a pill that acts is a button.
Cards & Containers
album-card — The content workhorse. Background {colors.surface-card}, rounded {rounded.md} (8px), padding 16px. Contents: 1:1 artwork, then card title in {typography.card-title} (white/700/16px), then metadata line in {typography.caption} (muted/14px). Hover steps the whole card to {component.album-card-hover} ({colors.surface-hover}) — background change only, no transform, no shadow.
playlist-row — Compact list row for tables and track lists. Transparent by default with muted text; the active track flips to {component.playlist-row-active} (hover surface + white text). Rounded {rounded.sm} (4px).
hero-section — Marketing hero. Canvas black, {typography.hero-display} headline in white, one {typography.body} subcopy line in muted, and a single {component.button-primary}. Optional full-bleed artwork behind at reduced opacity.
feature-band — Full-bleed editorial section. One flat {colors.banner-*} background, {typography.display-lg} headline in black or white per the banner's luminance, optional 1:1 artwork cluster. The only place non-green color appears at scale.
footer — Black on black — {colors.canvas} background with {colors.surface-elevated} top hairline, link columns in {typography.caption} muted, social icons in a row. Padding {spacing.xxl} (64px) vertical.
Inputs
Search and form inputs use {rounded.md} (8px) — not pill, distinguishing them from actions — with {colors.surface-card} background and white text.
Do's and Don'ts
Do
- Use
{colors.primary}for every primary action and its hover variant{colors.primary-bright}— nothing else in the system may be green. - Set marketing headlines in
{typography.hero-display}or{typography.display-lg}with the specified negative tracking — the tight 900-weight look is the brand's voice. - Put black text on green buttons (
{colors.on-primary}); the inversion is deliberate and non-negotiable. - Build hover states as background brightness steps (
{colors.surface-card}→{colors.surface-hover}) — never as transforms or shadows. - Round containers at
{rounded.md}and reserve{rounded.pill}for actions and nav. - Let album artwork carry the color; keep chrome grayscale so covers pop.
- Assign banner colors from the curated
{colors.banner-*}pool at the section level — one color per band.
Don't
- Don't use green as a text color, and don't use white or black buttons for primary actions — the green pill is the one true CTA.
- Don't add drop-shadows to anything — depth is brightness, full stop.
- Don't introduce a second accent hue outside the banner pool; even banners get exactly one color each.
- Don't set letter-spacing positive at display sizes, or negative at button sizes — the sign flips by scale.
- Don't round album artwork independently of its card; the container's
{rounded.md}clips the square cover. - Don't use italic, serif, or a secondary typeface — one family, weights 400/700/900.
- Don't put muted text on elevated surfaces below 14px —
{colors.text-subdued}is the floor for readable contrast.
Responsive Behavior
Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile | ≤ 480px | Hero drops to 40px/900; single-column card grid; nav collapses to logo + hamburger |
| Large phone | 481–768px | 2-column card grid; nav links hide into drawer; buttons full-width |
| Tablet | 769–1024px | 3-column card grid; secondary nav returns |
| Desktop | 1025–1440px | Full 4–6 column grid; nav complete; hero at 64px |
| Wide desktop | ≥ 1441px | Content locks at 1440px centered |
Collapsing Strategy
- Top nav: full link row on desktop → logo + hamburger + primary CTA below 768px.
- Card grids:
auto-fillat a 180px floor handles the ladder naturally — no per-breakpoint column overrides needed. - Hero: left-aligned at desktop → center-stacked below 768px, headline stepping 64px → 48px → 40px.
- Buttons: pill padding holds; only grid context changes. No button ever becomes full-width on desktop.
Image Behavior
- Album covers stay 1:1 at every size; the grid absorbs width changes.
- Marketing hero photography switches art direction at mobile (center-crop on the subject).
- Lazy-loading below the first viewport; the hero loads eagerly.
Iteration Guide
- Focus on ONE component at a time. Reference its YAML key directly (
{component.album-card},{{component.feature-band}}). - Variants (
-hover,-active) live as separate entries incomponents:. - Use
{token.refs}everywhere — never inline hex. - Never document hover on buttons — Default and Hover are the two documented states for cards; buttons document Default and their hover variant.
- Headlines are 900 or 700, body is 400 — no intermediate weights.
- When in doubt about emphasis: raise the type weight or step the surface brightness before adding any new color.
Known Gaps
- Form validation and error states were not surfaced in the analyzed pages; only the neutral search input is documented.
- The web player's right-hand "Now Playing" panel and its queue drawer were not analyzed in depth — documented structure covers the shell and shelves.
- Equalizer/progress-bar micro-interactions (the animated bars on playing tracks) are a platform widget, not a documented token.
- Podcast pages introduce occasional full-color artwork backgrounds not covered by the banner pool; treat them as artwork, not chrome.
- The exact brand-lockup clear-space rules live in Spotify's separate brand-asset guidelines, not the product design system.