Dumpert Design System

The shared visual language behind DumpertTV — an unofficial Dumpert client for Apple TV. Brand, design tokens, components, patterns and platform rules, extracted directly from the SwiftUI source so design and code never drift.

tvOS 18+ Swift 6 SwiftUI · @Observable Liquid Glass CloudKit Dark-only
Foundations

Principles

Five ideas the interface keeps returning to. Every token and component below exists to serve one of them.

Lean back, never wait

It's a 10-foot couch experience. Loading is a threshold, not a wait — the loading screen is gone the instant data is ready. Skeletons mirror real layout so nothing jumps.

The content is the hero

Pure-black canvas, immersive blurred backdrops, chrome that recedes. Thumbnails are face-centered and upgrade themselves to the best frame. Green appears only to mean something.

Focus must be obvious

From across the room you must always know where the Siri Remote is. Focus = scale-up, white border, and a green glow. Ambiguity is a bug.

Native first, brand always

Follow Apple TV conventions and SF Symbols, adopt Liquid Glass where it lands — but the green, the voice and the wordmark are unmistakably Dumpert.

Accessible by construction

VoiceOver labels, Reduce Motion alternatives and Dynamic Type aren't a pass at the end — they live in the component. A card without its accessibility label is unfinished.

Foundations

Brand

The wordmark, the mark, and the voice. The identity is loud, green, and a little irreverent — true to Dumpert.

Logo

dumpert-logo · vector
Do

Keep clear space around the wordmark, render it on black or dark imagery, and preserve the vector so it stays crisp at any TV resolution. The app-icon mark is the green wordmark on a pure-black background.

Don't

Recolor, stretch, add effects, or place the mark on busy light backgrounds. "DumpertTV" is the product name (white "Dumpert", green "TV"); the app is unofficial and never implies endorsement by DPG Media.

Voice & tone

Dutch-first, casual, dry-funny. Labels are short verbs and nouns; nothing corporate. The product's own section names set the register:

ToppersNieuwReetenVrijMiCoClassicsGekekenZoekenInstellingenOpnieuw proberen
Foundations

Color

One brand green doing real work, an almost-black canvas, translucent surfaces, and a tight set of semantic colors. Click any swatch to copy its hex.

Brand

dumpiGreen
Primary accent · AccentColor
#65B32Ecopy
dumpiGreenLight
Highlights, shimmer
#73C740copy
dumpiGreenDark
Backgrounds, subtle accents
#4D8C1Fcopy
logo green
Wordmark / app icon
#66CC22copy

Canvas & surfaces

bg.app
Pure black — the content canvas
#000000copy
bg.elevated
Cards / sheets over black
#191C20copy
surface.glass
Liquid Glass / translucent fill
white 8%copy
surface.control
Inactive chips, toggles, tracks
white 15%copy

Semantic & text

intent.positive
Success, "on", kudos ≥ 100
#65B32Ecopy
intent.error
systemRed · NSFW, destructive, offline
#FF453Acopy
intent.neutral
systemGray · kudos 0–99
#8E8E93copy
text.primary
Titles, focused content
#FFFFFFcopy
text.secondary
Metadata, descriptions
white 60%copy
text.tertiary
Separators, de-emphasis
white 35%copy
Kudos color ramp. A video's score color encodes sentiment without a number: ≥ 100 green   0–99 grey   negative red. The same logic drives the thumbs-up/down glyph.
Foundations

Typography

One typeface: the system font (SF Pro), driven entirely by SwiftUI semantic text styles so it scales with tvOS Dynamic Type. Numbers use monospacedDigit() so counts and timers don't jitter. No custom fonts, ever.

Die ene NSB-collega
.largeTitle · bold
Hero / player titles
Trending Nu
.title2 / .title3 · bold
Section & row headers
Geen video's gevonden
.title3 · semibold
Empty-state titles
Minimale kudos
.headline / .body
Settings rows, primary copy
Toegevoegd aan kijklijst
.callout · medium
Toasts, chips, banners
Verberg video's onder dit aantal
.subheadline / .footnote
Row descriptions
Je mag ook niks meer
.caption · medium
Card titles
1.2k · 30.2k · 0:35
.caption2 · bold · mono
Counts, durations, badges
Why no point sizes here? Styles are referenced by name (.font(.caption)), and tvOS renders them at its own Dynamic Type sizes — larger than iOS for couch viewing. Hard-coding pixels would break that contract. The samples above are scaled for the web only.
Foundations

Spacing

A soft 2-based ramp. Two values carry most of the layout: 50 for the horizontal screen safe-margin and 30 for vertical rhythm and grid gutters.

TokenValuePrimary use
space.66Badge insets, card corner padding
space.8space.128–12Inner stack spacing, card info padding
space.16space.2016–20Chip gaps, row padding
space.3030Grid column gutter, vertical section padding
space.3535Grid row gutter
space.5050Screen horizontal safe-margin (every scroll view)
Foundations

Radius & Shape

Cards and surfaces are gently rounded; anything interactive and pill-shaped is a full Capsule. Tiny radii (2–4) keep glass pills and progress accents crisp.

4 · pills
6 · badges
8 · tiles
12 · cards
24 · sheets
full · capsule

Glass duration pills and NSFW labels use radius 4. Kudos and "Bekeken" badges use radius 6. Video cards and skeletons clip to radius 12. Buttons, chips, toasts, tab bar and banners are all Capsule.

Foundations

Elevation & Focus

There is no ambient drop-shadow language — depth comes from translucency and, above all, from focus. On Apple TV the focused element lifts toward the viewer. Hover a swatch below to see it.

hover to focus
2:14

Focus treatment

Scale
1.08 (cards via .card), pressed 0.96
Border
3 pt solid white (capsule controls)
Glow — card
dumpiGreen @ 30% · radius 15
Glow — control
white @ 25% · radius 14
Thumbnail
brightness +0.05 · saturation 1.15
Animation
spring(0.25–0.35, bounce 0.2)

Translucency tiers

Instead of shadows, overlapping content separates with material:

Liquid Glass (tvOS 26+)ultraThinMaterialblack 75% pillwhite 5–15% fills

Glass effects always ship with a pre-26 fallback — see Platform.

Foundations

Motion

Springy and quick. Focus and selection use a gentle spring; appearance/dismissal use ease-out; the brand has a couple of signature moments. Hover a tile to play it. All tokens live in Animation+Dumpert.swift and are applied as reduceMotion ? nil : .dumpiFocus — so every animation collapses to nothing under Reduce Motion.

motion.focus
spring · 0.25 · bounce .2
motion.card
spring · 0.35
motion.standard
easeOut · 0.3
motion.press
easeOut · 0.12
motion.toast
spring · 0.4 · bounce .2
motion.logo
spring · 1.2 · bounce .3
motion.selection
spring · 0.5
motion.carousel
spring · 0.7 · bounce .15
motion.overlay
easeInOut · 0.5
Signature moments. The launch logo springs in, then beats a realistic two-step lub-dub heartbeat (scale 1.12 → 0.92 → 1.06 → 0.85) and exits with a 50× zoom-burst. The shimmer skeleton sweeps a green gradient on a 1.5s linear loop. Under Reduce Motion both collapse to a calm cross-fade.
Foundations

Iconography

Icons are SF Symbols exclusively — no custom icon set. Filled variants are preferred, and a symbol's .fill form signals its active/on state (e.g. eyeeye.fill). The web stand-ins below approximate the real symbols.

flame.fill
sparkles
square.grid.2x2.fill
eye.fill
magnifyingglass
gearshape.fill
hand.thumbsup.fill
checkmark.circle.fill
wifi.slash
video.slash
timer
photo.fill
Library

Components

Live reproductions of the app's reusable SwiftUI views, each with its anatomy, states and source file. Hover anything interactive to see its focus state.

Tab bar

ContentView.swift

Top-anchored Liquid Glass capsule. Six destinations, each an SF Symbol + label. The focused tab fills with a near-white capsule.

Toppers
Nieuw
Categorieën
Gekeken
Zoeken

Button

FocusableCapsuleButtonStyle.swift

Capsule with an explicit, couch-legible focus state — because .plain gives no focus cue on tvOS.

States

Default
Capsule, no border
Focused
scale 1.08 · 3pt white border · white glow
Pressed
scale 0.96 · easeOut 0.12

Accessibility

Verb-first label. Focus is conveyed visually and via the system focus ring; never rely on color alone.

struct FocusableCapsuleButtonStyle: ButtonStyle {
  // scale + white border + glow keep focus unambiguous
  .scaleEffect(isPressed ? 0.96 : (isFocused ? 1.08 : 1.0))
  .animation(.spring(duration: 0.25, bounce: 0.2), value: isFocused)
}

Filter chip

SearchFilterBar.swift

A Menu that shows every option on open (the active one checked). Active filters fill green and go semibold so refinement is never hidden behind guesswork.

Video card

VideoCardView.swift

The atom of the whole app. A 16:9 face-centered thumbnail (which silently upgrades to a better frame and plays a muted preview after 1.5s of focus), corner badges, a green progress bar, then title + kudos/views/date.

NSFW BEKEKEN 0:35
Die ene NSB-collega — je mag ook niks meer tegenwoordig
1.2k 30.2k ·14 uur geleden
2:48
Politieachtervolging eindigt op de A2
84 5.1k ·2 dagen geleden

Anatomy

Thumbnail
16:9, face-centered, smart-upgraded
Top-left
NSFW (red), mute indicator
Top-right
Bekeken glass badge
Bottom
duration pill · progress bar · year
Info
title (2 lines) · kudos · views · date

States & a11y

Focused → lift, green glow, brighter thumbnail, preview after 1.5s. Watched → title goes secondary. Combined into one VoiceOver element: "NSFW, {title}, Video, 0:35, 1.2k kudos, 38% bekeken".

Kudos & Watched badges

KudosBadgeView · WatchedBadgeView

Kudos pill (radius 6) colors itself by score. "Bekeken" is an uppercase glass badge.

1.2k 84 -19 BEKEKEN

Section title

SectionTitleView.swift

Bold label over a green underline that's exactly one-third of the text width — the system's most recognizable signature (used for every section heading on this page too).

Trending Nu

Toast & Offline banner

ToastView · ContentView

Transient confirmation rises from the bottom on a glass capsule and auto-dismisses after 3s (also posted to VoiceOver). The offline banner is a red glass capsule that floats without reflowing the tab bar.

Toegevoegd aan kijklijst
Geen internetverbinding

Skeleton

SkeletonView.swift

Loading placeholders mirror the exact card layout (16:9 + 2 title lines + meta row) with a green shimmer sweep, so content swaps in without a reflow.

Empty state

EmptyStateView.swift

Pulsing 56pt SF Symbol, a title that says what happened, a description that says what to do, and an optional retry. Covers empty, first-use and error.

Geen video's gevonden
Er zijn nog geen video's in deze categorie. Probeer het later opnieuw.

Settings list

SettingsComponents.swift

A uniform row grammar: leading 28pt icon, title + description, trailing value or control. Toggle icons turn green and swap to their .fill form when on. Destructive rows are red and always confirm.

Content
Minimale kudosVerberg video's onder dit aantal
Alles tonen ›
NSFW-content tonenToon content die als niet-veilig is gemarkeerd
Bekeken verbergenVerberg video's die je al hebt gezien
Beheer
Wis cacheVerwijdert opgeslagen thumbnails en data

Hero banner

ToppersSectionView.swift

The Toppers showcase: a large auto-rotating card with a bottom gradient, large title, subtitle, the standard kudos/views/duration/date meta row, and carousel dots.

Die ene NSB-collega

Je mag ook niks meer
1.2k 30.2k 0:3514 uur geleden
Library

Patterns

How components combine into the flows that define the experience. On a TV, patterns matter more than isolated parts — the platform's expectations are strong.

Loading

Launch shows the animated logo screen (a threshold, not a timer — gone the instant data is ready, with a 0.6s floor). In-content loads use shimmer skeletons that match the final layout. A "skip" hint only appears if a load is genuinely slow (3s+).

Empty & error

One component (EmptyStateView) serves no-content, first-run and error, always with a recovery action. Errors name cause + fix, never "Something went wrong".

Offline

A network monitor surfaces a floating red banner; cached content stays browsable. ETag caching and exponential-backoff retry keep things resilient.

Search

Recent searches, a horizontal filter bar (type · period · kudos · duration), live results, and an empty-result state. Filters use the Menu chip so every option is visible.

Playback

Autoplay + preload-next, playback speed, a resume overlay for partially-watched videos, an Up-Next overlay, a top-comment overlay, and Now Playing on the remote/Control Center.

Settings & sync

Grouped list with toggles, navigation pickers and a tile-size preview. Watch progress, settings, curation and search history sync via CloudKit across Apple TVs.

Standards

Platform — tvOS

This is a focus-driven, lean-back platform: no touch, no hover, no keyboard — a Siri Remote moving focus across a 10-foot screen. The system embraces that rather than porting a phone UI.

Focus engine

Every interactive element must show focus (scale, border, glow). Cards use the system .card button style for parallax + lift; custom controls use FocusableCapsuleButtonStyle. Swipe gestures on the remote skip previous/next.

Liquid Glass + fallbacks

On tvOS 26+ pills/badges/toasts use .glassEffect; every use ships a graceful fallback (ultraThinMaterial or a black-75% pill) so older tvOS still looks right.

if #available(tvOS 26, *) {
  content.glassEffect(in: RoundedRectangle(cornerRadius: 4))
} else {
  content.background(.black.opacity(0.75)).cornerRadius(4)
}

Safe areas & layout

Content honors the 50pt horizontal / 30pt vertical screen margins. Top Shelf integration surfaces fresh content above the app icon. Immersive blurred backdrops sit behind the TabView.

Architecture

SwiftUI + @Observable with Environment injection; an actor-based API client; a single VideoRepository source of truth. 122+ tests guard behavior.

Standards

Accessibility

Not a separate page — a requirement baked into every component. The rules below are guaranteed system-wide.

AreaGuarantee
VoiceOverEvery control has a label; cards combine children into one element with a rich description (type, duration, kudos, watched %). Filters expose active/inactive state.
Reduce MotionHonored via @Environment(\.accessibilityReduceMotion): the logo zoom-burst, heartbeat and card upgrade collapse to calm cross-fades.
Dynamic TypeAll text uses semantic styles, so it scales with the system text-size setting. No fixed font sizes in layout.
AnnouncementsToasts post an AccessibilityNotification.Announcement so confirmations are spoken, not just shown.
Don't rely on colorKudos sentiment pairs color with a thumbs-up/down glyph; focus pairs the green glow with scale + border.
LocalizationDutch + English via String Catalogs, with comments for translators and plural-aware count strings.
Standards

Content & Voice

The words are part of the design. Dutch-first, short, human, never corporate.

Do

Name the cause and the fix.
"Er zijn nog geen video's. Probeer het later opnieuw."
Use verb-first actions: "Opnieuw proberen", "Bekijk video". Keep the section names playful (Toppers, Reeten, VrijMiCo).

Don't

Ship vague failures.
"Er is iets misgegaan."
Avoid jargon, long sentences, or title-case English buttons. Don't imply any affiliation with Dumpert / DPG Media.

SurfaceRuleExample
ButtonsVerb-first, conciseOpnieuw proberen
Empty statesWhat happened + what nextGeen video's gevonden
ErrorsCause · effect · recoveryGeen internetverbinding
ToastsConfirm in ≤ 4 wordsToegevoegd aan kijklijst
DatesRelative, locale-aware14 uur geleden
Standards

Token Output

One concept, three renderings. The product meaning stays identical; each platform expresses it natively. The CSS variables at the top of this file are the web output.

ConceptWeb (CSS)iOS (Swift)Value
color.brand.primary--greenColor.dumpiGreen#65B32E
color.intent.error--redColor.dumpiError#FF453A
surface.glass--glass.glassEffect()white 8% / Liquid Glass
radius.card--r-12cornerRadius: 1212
space.screen--s-50.padding(.horizontal, 50)50
motion.focus--ease-springAnimation.dumpiFocusspring

Source of truth — the actual brand definition

// Dumpert/Extensions/Color+Dumpert.swift
extension Color {
  /// Dumpert brand green (#65B32E)
  static let dumpiGreen      = Color(red: 0.396, green: 0.702, blue: 0.180)
  static let dumpiGreenLight = Color(red: 0.45,  green: 0.78,  blue: 0.25)
  static let dumpiGreenDark  = Color(red: 0.30,  green: 0.55,  blue: 0.12)
}
Standards

Governance

How the system stays coherent as the app grows.

Single source

Tokens live in Swift (Color+Dumpert, Animation+Dumpert, asset catalog). This page is generated from that reality — no parallel definitions to drift.

Reuse over redo

Shared primitives (DurationFormatter, GlassPillModifier, badges) are extracted, not re-implemented. New UI should ask "which pattern applies?" first.

Quality gates

122+ tests, accessibility labels per view, and Reduce-Motion/fallback paths are part of "done" — not follow-ups.

The bar. The system succeeds when contributors stop asking "what should this look like?" and start asking "which pattern applies here?" — and the answer is already on this page.