Motivated by my own need for an appropriate working soundscape, I created this web application that plays natural soundscapes with minimal user interaction. The core principle was to make the app act as an „acoustic window" rather than a traditional media player.
Using the current sunrise and sunset times, the app determines the currently appropriate time setting, night, dawn, and day, and selects a soundscape from a curated list each time it is launched. The app has a minimalist interface with only one interaction: muting and unmuting the soundscape - in line with the "window" metaphor mentioned above. When an audio stream ends, the app picks a new one automatically. To get a different soundscape, the user reloads the page.
For more background information, please view this post on my personal web page.
The app is currently hosted on Vercel and available online for you to try out.
First, install the dependencies and run the development server:
npm install
npm run devOpen http://localhost:3000 with your browser to see the running page.
To verify the project before opening a pull request, run:
npm run buildapp/page.tsxrenders the main page shell and source/contact links.components/MinimalPlayer.tsxowns playback state, loading state, and soundscape rotation.components/YouTubeAudioPlayer.tsxwraps Video.js and the YouTube source plugin.lib/soundscapes.tsreads and filterspublic/soundscapes.csv.lib/daytimes.tsdetermines night, dawn, or day from geolocated sunrise/sunset data.
The app estimates the listener's location through IP-based geolocation in order to calculate local sunrise and sunset times. If geolocation fails, it falls back to London coordinates.
Browser behavior for media playback in background tabs can vary by browser, platform, power state, and embedded player implementation. App-level JavaScript should not assume that timers, media key events, source changes, or playback state callbacks will be delivered consistently while a tab is hidden. Prefer keeping time-limited behavior tied to the existing media player, and treat background playback handling as best-effort rather than fully deterministic.
When browser behavior differs between foreground and background playback, prefer predictable foreground behavior and a safe fallback in the background over complex background synchronization. Avoid adding separate notification audio for playback-window events; use the existing media player state instead.
Relevant references: MDN Page Visibility API, Chrome Page Lifecycle API, and MDN Media Session API.
You can add new soundscapes by appending YouTube links and the appropriate category to the public/soundscapes.csv file. The category is encoded as an integer, where 1 is night, 2 is dawn, and 3 is day.
Each row in public/soundscapes.csv contains:
youtube_url,categoryCategories:
1: night2: dawn3: day
If you want to batch categorize YouTube videos, you may find the YouTube Video Categorizer repository helpful.
Feel free to create pull requests for new soundscapes (or other changes and features).