Skip to content

redesign: vintage hi-fi turntable with wood + brushed metal#2

Open
w3nerick wants to merge 3 commits into
feat/retro-vinyl-playerfrom
feat/wood-hifi-redesign
Open

redesign: vintage hi-fi turntable with wood + brushed metal#2
w3nerick wants to merge 3 commits into
feat/retro-vinyl-playerfrom
feat/wood-hifi-redesign

Conversation

@w3nerick

Copy link
Copy Markdown
Owner

UI

  • Walnut wood plinth & amp case with grain texture (CSS gradients)
  • Brushed aluminum face plate with engraved brand
  • Cream paper label on vinyl (Playfair Display typography)
  • Analog VU meters (canvas) with tick arc, green/red zones, needle physics
  • Amber LED display: track number, marquee title, scrubbable bar
  • Mechanical transport buttons with travel + amber/red LED indicators
  • Knurled volume knob (vertical drag, wheel, keyboard)
  • 33/45 RPM speed selector, cue lever, decorative pitch fader
  • Power LED, strobe ring, slipmat under the vinyl

Optimizations

  • Single requestAnimationFrame loop drives both VU meters
  • ResizeObserver + DPR-aware canvas resizing (no per-frame realloc)
  • Pointer Events for sliders & knob (mouse + touch + pen unified)
  • Event delegation on the playlist
  • Lazy AudioContext (created on first play)
  • Pause animation when tab is hidden
  • Cached DOM lookups, reusable buffers in rAF

UI additions
- Tabbed control deck: LIBRARY / RADIO / EQ
- 3 wood themes (walnut, rosewood, oak) with engraved swatch picker
- Radio panel: amber FM dial, station marks, signal LED bargraph,
  stereo indicator, station list (SomaFM)
- EQ panel: 3 vertical sliders with brushed metal handles,
  recessed channel, 0 dB tick, 6 presets (Flat/Rock/Jazz/Pop/Classic/Bass+)
- Cover art slot on the vinyl label (rotates with the disc)

Audio
- BiquadFilter chain: lowshelf 120Hz / peaking 1kHz / highshelf 5kHz
- Audio graph: source -> low -> mid -> high -> analyser -> destination
- Static SFX (white noise) generated via AudioBufferSourceNode while tuning

ID3v2 metadata
- Self-contained parser (no dependencies) for TIT2 / TPE1 / TALB / APIC
- Handles ISO-8859-1, UTF-16 BOM/BE, UTF-8 text encodings
- Cover art extracted as blob URL and used as vinyl label background

Persistence
- IndexedDB stores MP3 blobs (survives reload, cover re-derived on load)
- localStorage stores settings: volume, theme, shuffle, repeat,
  speed RPM, current track, last station, EQ gains

Misc
- Mode switching preserves library position when entering radio
- Theme transitions animate the room background gradient
- Single rAF still drives VU meters + radio signal LEDs
@vercel

vercel Bot commented May 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
reproductor-mp3 Ready Ready Preview, Comment May 20, 2026 6:25pm

Privacy
- Removed Google Fonts loader (no requests to fonts.googleapis.com or
  fonts.gstatic.com, which would expose visitor IPs to Google)
- Self-hosted Inter (variable, latin), Playfair Display 700 latin
  and VT323 latin as woff2 in assets/fonts/ (~89 KB total)
- Added meta name='referrer' content='no-referrer' (no referrer
  header is sent on outbound requests)
- Added meta name='robots' content='noindex' (opt-out of indexing)
- Added subtle privacy notice in the footer

Security (defense in depth)
- Added Content-Security-Policy meta tag:
  * default-src 'self'
  * script-src 'self' (no inline scripts, no eval, no CDNs)
  * style-src 'self' (no inline styles, no remote stylesheets)
  * font-src 'self'
  * media-src 'self' blob: https://ice1.somafm.com (only SomaFM allowed)
  * connect-src 'self', object-src 'none', frame-ancestors 'none'
- Refactored renderStations() to use DOM API instead of innerHTML with
  inline style=, so we can drop 'unsafe-inline' from style-src
- 50 MB max per uploaded file to prevent IndexedDB quota abuse
- beforeunload cleanup: revokes blob URLs and closes AudioContext

Verified
- SomaFM endpoints all return Access-Control-Allow-Origin: *,
  so VU meters react correctly with the radio analyser
- No third-party scripts, trackers, analytics, or cookies
- All user audio data stays in the browser (IndexedDB + localStorage)
Adds turntable-realistic SFX generated entirely with Web Audio API
(no external samples, fully CSP-compliant).

Sound effects
- Mechanical button clicks: hi-pitched bandpass burst for transport
  (PLAY / PREV / NEXT), low-pitched for toggles (SHUF / RPT / RPM)
- Soft tap for theme swatches, EQ presets, and tab switches
- Stylus drop: 90 to 40 Hz sub thump + scratchy noise burst, fired
  ~280 ms after the tonearm servo whoosh (matches the visual landing)
- Tonearm servo: filtered sawtooth sweep; rises on play, falls on pause
- Vinyl crackle loop: pink-noise approximation via 3-pole Voss-McCartney
  + sparse pops, band-limited 600-7000 Hz, fades in/out gracefully
- Power-on hum: 120 Hz + 240 Hz sine pulse on the very first play of
  the session (mains hum harmonics)

Implementation
- All SFX route through a dedicated master gain node (-6 dB), so they
  never overshadow the music
- Generated lazily on first user gesture (same AudioContext as the EQ)
- Crackle loop is a single 4-second buffer set to loop, not allocated
  per frame; cancels and stops cleanly when paused

UI
- New SFX toggle button next to RPT in the transport row, with the
  same red LED treatment; default is ON
- Preference persisted in localStorage (sfxEnabled)
- Disabling SFX intentionally makes no sound (would be ironic)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants