← Powrót do strony głównej

Case study

Budowa streambeats.live

Skoncentrowany odtwarzacz muzyki i widget OBS dla streamerów — zaprojektowany i zbudowany iteracyjnie w maju 2026.

Czas
Maj 2026 · ~4 tygodnie
Rola
Design + frontend
Stack
Next.js 16 · React 19 · Tailwind v4

Problem

Spotify nielegalne. Istniejące widgety generyczne.

Streamerzy nie mogą puszczać Spotify na Twitchu ani YouTubie — ToS zabrania publicznego odtwarzania, a fala DMCA strike'ów z 2020–2024 ostatecznie to wyrżnęła. Fallback to StreamElements / StreamLabs — dają generyczny widget i tyle. Dodaj do tego ręczne wpisywanie artysty + tytułu dla każdego MP3 i workflow streamera robi się jednym wielkim tarciem.

Discovery

Czego streamerzy faktycznie chcą.

Porozmawiałem z kilkoma streamerami: chcą wrzucać własne MP3 (legalnie posiadane), widzieć automatycznie wczytane okładki i tytuły, i streamować widget na OBS bez 30 minut grzebania w CSS. Platforma powinna znikać w tle — nie być kolejnym zadaniem produkcyjnym.

Design system

Żółty bloom, frosted glass, anty-generyczne reguły.

Token-driven przez Tokens Studio (Figma) — 11-stopniowe skale Primary / Secondary / Neutral, plus tokeny glow + glass + radius + shadow które istnieją bo Figma ich wymagała. Typografia Satoshi (display) + Roboto (body). Hardcoded anty-generyczne reguły w Visual Identity Commitments: zero shadcn defaults, zero płaskich fillów, zero sticky-bar navów, zero zamienników Google Fonts. Każdy primitive (BloomBackground, GlassCard, PillNav) zbudowany ręcznie przed jakimkolwiek feature kodem.

Decyzje techniczne

Cztery problemy warte pokazania pracy.

Notch saga to prawdziwy bałagan środka. Refactor persistent audio to punkt zwrotny architektury. Pipeline metadanych i model two-player oprawiają produkt.

Dwóch playerów, nie jeden

Powierzchnia /app/player w przeglądarce to panel DJ-a. Route /w/[widgetId] to wizual renderowany w OBS Browser Source. Dzielą stan przez BroadcastChannel (NowPlayingSnapshot), ale to różne produkty z różnymi budżetami designu — jeden zoptymalizowany pod kontrolę, drugi pod czytelność z drugiego końca pokoju streamera.

Notch w hero — trzy nieudane podejścia

Pierwsza próba: CSS clip-path: path() z @supports gate dla corner-shape: notch. Chrome renderował panel jako niewidoczny bo eksperymentalna property była rozpoznana ale niezaimplementowana. Druga: SVG mask z mask-composite — kruchy między buildami Chromium. Trzecia: element SVG z `clipPath` aplikowanym na `image` — referencja clipPath URL nie była honorowana po hydration. Finalna: czysty CSS clip-path: path() na divie z background-image. Prawdziwy boolean cutout, smooth Q-curve inner corners, działa w każdej przeglądarce. Lekcja: bleeding-edge CSS czuje się jak postęp aż przestaje.

Pipeline metadanych — ID3, Last.fm, iTunes, fallbacki

Test corpus to 16 MP3 z yt-dlp, zero ID3 tagów. Filename był jedynym sygnałem — ale mój pierwszy parser brał prefix 'NN - ' jako artystę i zwracał artist='14' dla jednego pliku. Fix: zawsze strip 'NN - ', potem split na ' - ', potem strip YouTube noise typu '(Official Video)'. Last.fm daje indie korekty; iTunes fallback łapie mainstream releases z ostrymi okładkami 600×600.

Persistent audio przez nawigacje

Pierwotnie element `audio` żył w /app/player — nawigacja go unmounta i zatrzymywała muzykę. Refactor: wyniesienie do /app/layout jako komponent `AudioEngine`. Muzyka teraz przeżywa każdą zmianę route. Spotify-style MiniPlayer pojawia się na każdej stronie /app poza pełnym playerem. Bonus: widget OBS dostaje czystszy BroadcastChannel state bo jest jeden emitter.

Wyniki

Shipped prawdziwą rzecz, nie deck Figmy.

Działający end-to-end pipeline: drop MP3 → auto-metadane → DJ surface → widget OBS renderujący się na streamie. View Transitions API do nawigacji. Real Web Audio AnalyserNode napędzający szablon Equalizer. Custom HSL color picker generujący całą skalę 50–950 z jednego odcienia. Dwujęzyczne PL/EN. Anty-generyczna identyfikacja wizualna — specyficznie streambeats, nie wymienna z żadną inną stroną shadcn.

Co dalej

v0.2 — konta, widget builder, cloud sync.

Canvas /app/widget-builder (już zaprojektowany w Figmie) staje się prawdziwym builderem: drag-drop elementy, własny CSS, save & share. Konta + Supabase dla cloud-syncowanych configów widgetów i cross-device sync player ↔ widget. Integracja StreamBeats / Pretzel API dla gotowych DMCA-safe bibliotek.

Tech stack

Zbudowane z

Next.js 16 App Router · React 19 · Tailwind v4 · Zustand · Dexie (IndexedDB) · Framer Motion · next-intl · music-metadata · Last.fm + iTunes APIs · BroadcastChannel + Web Audio API