Void Ember
RipFeed's confirmed visual identity. Near-black purple backgrounds, amber waveforms, gold usernames. Every decision in this document is locked — use it as the single source of truth for all product, marketing, and web surfaces.
All decisions at a glance
| Decision | Choice | Notes |
|---|---|---|
| Theme name | Void Ember | Near-black purple bg, amber waveform accent. Confirmed primary. |
| Background | #0F0E11 / #1A1820 | Base bg / card surface. Two stops only. |
| Waveform color | #D4813A amber | Replaces old #7F77DD in FFmpeg filter. See FFmpeg section. |
| Username / display | #F0C27A gold | Primary identity color — usernames, wordmark, active nav. |
| Primary text | #F5F2FF | Headings, labels, nav items. |
| Clip title / body | #9a94aa ash | Clip titles, body copy, muted readable text. |
| Muted text | #6a6474 dusk | Captions, secondary muted copy. |
| Trending accent | #7F77DD purple | Signal-only — trending badge, left border on trending cards. Used nowhere else. |
| Display font | Space Grotesk 700 | Wordmark, large headings, usernames. ✓ Confirmed. |
| UI font | Space Grotesk 400/500 | Body copy, captions, nav labels, card titles. ✓ Confirmed. |
| Utility font | DM Mono 400/500 | Tags, timestamps, play counts, badges, all numeric/data UI. ✓ Confirmed. |
| App icon (primary) | Inverted — amber bg, dark bars | ✓ Confirmed. Pops on both light and dark home screens. |
| App icon (fallback) | Waveform — dark bg, amber bars | Use where amber bg clashes with wallpaper. |
| Corner radius (cards) | 14px | Clip cards, ad cards, modals. |
| Corner radius (pills) | 20px (full pill) | Tags, trending badge, nav pills. |
| Border weight | 0.5px | All borders. Never 1px. |
| Backup theme | Night Bloom | Void bg + lime green waveform + gold trending. Held in reserve. |
Palette
Ten named values. Every UI element maps to one of these. No off-palette hex values — ever.
Color usage rules
Type system — ✓ confirmed
Two families. Space Grotesk for everything human-readable; DM Mono for everything that is data — timestamps, counts, tags, badges. Never mix within a single semantic element.
Google Fonts import
<!-- Add to index.html or _document.tsx --> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
Icon system — ✓ confirmed
Primary: inverted palette — amber background, dark waveform bars. Pops on both light and dark home screens. Fallback: dark bg with amber bars for contexts where amber clashes.
Primary — Inverted (amber bg) ✓
Fallback — Waveform (dark bg)
Icon SVG — primary (1024×1024 for App Store)
<!-- Primary icon — amber bg, dark bars --> <svg width="1024" height="1024" viewBox="0 0 96 96"> <rect width="96" height="96" rx="22" fill="#D4813A"/> <g fill="#0F0E11"> <rect x="18" y="34" width="6" height="28" rx="3"/> <rect x="28" y="26" width="6" height="44" rx="3"/> <rect x="38" y="38" width="6" height="20" rx="3"/> <rect x="48" y="18" width="6" height="60" rx="3"/> <rect x="58" y="30" width="6" height="36" rx="3"/> <rect x="68" y="38" width="6" height="20" rx="3"/> <rect x="78" y="26" width="6" height="44" rx="3"/> </g> </svg>
Clip card anatomy
Every card follows the same structure. Playing state, trending state, and ad cards are variants — not separate components. Implemented as a FlatList in React Native with ad injection every 8–10 organic cards (free users only).
Card anatomy
Card states
border-left: 2px solid #7F77DD. TRENDING badge in DM Mono, purple bg. Purple is used nowhere else in the feed.usePro() hook returns true → skip ad entirely. No placeholder, no gap.Bottom navigation
7-screen onboarding
Splash auto-advances after ~2 seconds. Sign-in users jump directly to screen 7. Progress bar shown on screens 4–6 only — those are the form steps. Hidden elsewhere so the flow doesn't feel like a checklist.
| Screen | Name | Key details |
|---|---|---|
| 1 | Splash | Animated waveform bars + wordmark + tagline. Auto-advance ~2s. No user action required. |
| 2 | Value prop | "15 seconds. Maximum damage." Large waveform visual. Single CTA: Get started. Existing users: Sign in link. |
| 3 | Sign up | Email + password fields. Google SSO. Apple SSO. "Create account" amber CTA. RipFeed wordmark top-left. |
| 4 | Username | @ handle picker. Amber active border on input field. DM Mono availability check (green ✓ available). Progress bar 50%. Keyboard "next" key in amber. |
| 5 | Notifications | Bell icon + explanation. Native iOS/Android permission sheet. "Allow" in amber. Progress bar 75%. |
| 6 | Content policy | ✓/✕ do/don't list. Satisfies Apple guideline 1.2. "Original recordings only" stated clearly. Terms + Content Policy linked. Progress bar 100%. |
| 7 | Welcome | Primary icon + "You're in." + @handle greeting. Two CTAs: "Browse the feed" (amber primary) + "Record your first clip" (outlined secondary). |
Copy decisions
ripfeed.io/clip/[id]
Minimal Cloudflare Pages site. Reads clip metadata from Supabase public API (anon key, is_public=true only). Streams audio via HTML5 <audio> from R2 CDN. No auth, no additional backend infrastructure required.
Page sections
<audio> pointing at R2 CDN URL.Open Graph tags (server-rendered per clip)
<!-- Powers link previews in iMessage, Twitter, WhatsApp, Slack --> <meta property="og:title" content="@username on RipFeed"/> <meta property="og:description" content="[clip title] [tags]"/> <meta property="og:image" content="https://cdn.ripfeed.io/waveforms/{clipId}.png"/> <meta property="og:audio" content="https://cdn.ripfeed.io/clips/{clipId}.aac"/> <meta property="twitter:card" content="player"/>
The waveform PNG from FFmpeg doubles as the OG image. Same file, zero extra work. Visually distinctive — immediately reads as "audio content" before anyone taps.
FFmpeg waveform command
Waveform color is updated to amber #D4813A from the original purple #7F77DD. One character change in the filter string. The transparent background flag is non-negotiable.
# Void Ember — single pass, two outputs # ⚠️ Waveform color updated: #7F77DD → #D4813A (amber) # Update in: lib/ffmpeg-worker/index.ts ffmpeg -i input \ -c:a aac -b:a 128k -t 15 output.aac \ -filter_complex "aformat=channel_layouts=mono,compand,showwavespic=s=300x64:colors=#D4813A|0x00000000" \ -frames:v 1 waveform.png # Filter chain: # aformat=channel_layouts=mono — collapse stereo to unified waveform shape # compand — dynamic range compression, every clip looks alive # showwavespic=s=300x64 — 300×64px static waveform image # colors=#D4813A|0x00000000 — AMBER bars, TRANSPARENT background (mandatory) # # Night Bloom backup theme: swap #D4813A → #5CDD6E (one-char change)
lib/ffmpeg-worker/index.ts) before first clip upload goes live.0x00000000 is mandatory — the PNG must composite correctly over #1A1820 card and #0F0E11 base backgrounds.-t 15 flag is non-negotiable. Server-side hard cap. Never remove regardless of subscription tier. The 30s Pro path does not exist yet.#D4813A → #5CDD6E in the filter string. One-character change enables the full backup theme waveform color.Night Bloom
Held in reserve. Same Void background as the primary theme — only the waveform color and trending accent change. Candidate for Pro custom themes or a seasonal variant in Phase 3. Do not display both themes simultaneously.
Non-negotiables
These rules protect the identity and the product. Breaking any degrades the system.
0x00000000 in FFmpeg filter is mandatory. Opaque backgrounds mismatch on card surfaces.usePro() before rendering any ad component. If isPro === true, skip entirely — no placeholder.APP_NAME from config throughout.is_public=true clips only. No authenticated routes. No sensitive data on the web player.