wnur website
overview
new website for wnur 89.3 fm, northwestern's student-run radio station. it's live at wnur.org, go hit listen. the old site didn't really match what wnur is, but this one does: station branding, a listen bar that follows you around, live on-air info, and an ascii visualizer that reacts to the broadcast in real time. bass hits move the field, mids warp it, treble adds detail.
it has also grown past a listen page. djs log sets from their own accounts, listeners can browse and search playlists, and wavelength editors publish from the same site. built with others from the 2026-2027 exec board. i led website development and design, and i am wavelength lead.
features
- ascii hero that reads the live stream: open the site, press play, watch the canvas move with whatever's on air
- global listen bar with play/pause and now-playing context on every page
- radio and schedule pages with today's lineup and the current show highlighted
- dj playlist logging during a set, with optional spotify playlist import
- public recent playlists archive and playlist search
- wavelength publishing: editors write and update articles in-site, readers get the public magazine
- sticky header cat logo that animates when you're listening
- about, contact, news, wavelength, and sports section layouts
playlists and dj tools
approved djs sign in at /dj, wait for station admin approval if they're new, then log tracks at /dj/log while they're on air. they can also pull tracks in from a spotify playlist. listeners don't need an account: they get the archive and search. password resets go through supabase so the email opens the live site, not localhost.
wavelength
wavelength is wnur's publication. editors use a gated workspace at /dj/wavelength to draft and update articles; published pieces live at /wavelength. same login system as the dj tools, different permission gate.
technical details
- next.js 16 app router, react 19, typescript, tailwind css v4
/api/stream: same-origin proxy for the live rcs revma stream so the browser can run web audio analysis without cors issuesAudioReactiveCanvas: canvas flow-field visualizer driven by analyser metrics from the stream (production react/typescript version; separate from the vanilla demo on this portfolio site)/api/on-air: schedule data from a google sheet csv export, parsed in chicago time; revalidates every 60 seconds- supabase for dj accounts, approvals, playlist logging, and wavelength articles
- spotify oauth for importing a playlist into the logger
/api/contact: contact form email through resend with validation and a honeypot field- sticky header with animated cat logo states for idle vs. playing
- page transitions and reduced-motion fallbacks sitewide
schedule workflow
djs maintain a shared google sheet (day | start | show | dj). the site reads a public csv export url from env, derives now playing and up next, and polls the on-air api from the client. no separate cms or database for the schedule.
related work
the ascii visualizer has its own write-up here: ascii audio interpreter.