Skip to content

About

Generative radio for your mental state. No playlists, no accounts, no ads

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

63 Commits

Folders and files

Repository files navigation

Addiction.fm — generative radio

Generative radio. One button — sound built for your mental state.

Open the radio version 2.4 268 breaks zero dependencies Deploy site

English · Русский

No playlists. No accounts. No ads. Pick a state — get a unique sound that never repeats.

Contents

📸 How it looks

Three states on one phone screen — the accent colour, the ambient glow and the sliders all follow whichever state you pick:

DRIVE, FOCUS and CALM on a phone

Light theme, the settings menu, and the About dialog:

Light theme, settings and About

Wide layout — the player becomes a single sticky row:

Addiction.fm on desktop


🔥 What's new in 2.4

CALM is violet now, and it breathes. The preset moved off green (#46A171 → #7A5AC8), and the whole layer — drone, pad, rain, brown noise and the bells — sits on one bus whose gain is rocked by a 0.0917 Hz oscillator: a 10.9 s cycle, about five breaths a minute. The master lowpass dropped from 600–5400 Hz to 420–2420 Hz, the bells moved an octave down into E3–D4 with a 0.55 s attack and a 6 s tail, and the random fifth and octave above were replaced by a single quiet unison an octave below. Measured across three tracks: the envelope energy in the slow 0.02–0.3 Hz band went from 12–17% to 53–58%, sharp rises per 91 s fell by 1.6–1.8×, and everything above 2 kHz dropped from –18 dB to –37 dB. The preset is 3.5 dB quieter overall — that is the intent, not a bug.

The interface now takes its colour from the state. One data-m attribute on <html> repaints the ambient background, the propeller, both sliders, the active chips and the text selection. Typed custom properties (@property) let those colours interpolate, so switching DRIVE → FOCUS → CALM cross-fades over half a second instead of snapping; browsers without support just change instantly.

Sliders finally look filled. The track is painted up to the thumb — --p from JS for WebKit, ::-moz-range-progress for Firefox. The gradient is clipped to padding-box, which kills the coloured crescent that used to peek past the rounded end of the track.

Touch behaviour got cleaned up. The grey Android tap-highlight is gone, controls no longer select their text on long-press, and touch-action: manipulation removes the double-tap delay — while the press feedback stays. The propeller lost its badge ring, and the logo shrinks slightly below 420 px so the tagline holds one line at 390 px. On mobile the timer chips are pills again rather than vertical capsules.

The audio graph no longer grows forever. Every one-shot — kick, hat, snare, sub, pluck, piano and each pad chord — now disconnects its chain once the tail has rung out. DRIVE used to pile up 350 dead filters in three minutes of playing.

Fixes

  • The pink-noise loop clicked once every 2 seconds: the filter state at the seam didn't match itself. It now gets a crossfaded pre-roll, the same treatment brown noise already had.
  • When the phone froze the context (screen off, audio focus lost), CALM's setTimeout chain kept running while ctx.currentTime stood still, so up to 40 bells were queued to the same instant and fired together on resume as a clipped burst. A ring is now skipped unless the context clock is actually moving.
  • The propeller animation loop sleeps when the velocity reaches zero instead of being woken 60 times a second — 391 ms of machine time per 30 s of idle, measured.
  • The sleep-timer end bell was retuned (0.12 s attack, 800 Hz cutoff) so it reads as a soft cue rather than an alarm.
🕰 Older releases — 2.3 and 2.1 in detail

2.3

The player bar stopped moving. The break name now sits in a fixed-width plate that covers ~90% of the bank, with the full name in a tooltip. The 🎲 button keeps its slot reserved while the dice is switched on, so changing presets no longer nudges the sliders by a pixel, and long labels truncate instead of colliding. The whole row still holds together down to 633 px.

Background playback got tougher. The scheduler no longer trusts document.hidden — it measures how late its own ticks actually arrive and grows the lookahead to match real throttling. Coming back from a hard freeze ducks the master for half a second instead of firing every queued note at once, and an AudioContext state-change handler re-primes the grid when iOS wakes the context without telling anyone.

The propeller has three speeds now. DRIVE, FOCUS and CALM spin at their own rate and ease between them instead of snapping to a stop.

The README grew up. One bilingual page with a hero, badges and a table of contents; the 2.1 notes folded away, and the "run it locally" section dropped now that the radio lives at sewerdev.github.io/Addiction.fm.

Publishing is automated. Pushing to main runs .github/workflows/deploy-site.yml, which builds the Pages artifact and deploys it — no more manual branch pushes to gh-pages.

Fixes

  • The ⏺ rec button no longer sticks on "⏹ stop" after a recording finishes — a local variable was shadowing the translation function, so the label-revert timer never got armed.
  • The last used preset survives a reload; the page used to always come back to FOCUS.
  • Decoded breaks release their base64 source: about a third of the bank's memory is no longer held for nothing.
  • Dead code removed, and the player is now drawn by a single render pass instead of four functions writing the same nodes.

2.1

Addiction.fm is now hosted!

  • Background: added deep "ocean floor" hum (brown noise, –6 dB/oct), seamless loop, 480 Hz filter.
  • Reliability: scheduler looks 1.6 s ahead — tab switching won't break the audio stream.
  • Interface: system language (ru/en/es) on first launch, long track names truncated with tooltip, dark theme with no white flash.
  • Fixes: audio filter leak patched, held keys no longer duplicate commands, bank counter now shows the real number (268 breaks).

The biggest update since launch: the mobile interface was rebuilt from scratch, the drum bank grew five and a half times, and you can now run the radio without ever opening the tab.

System-wide media controls

The radio is no longer trapped inside a browser tab. It shows up wherever a normal music player does, with its own artwork:

  • Android — a card in the notification shade and on the lock screen: play/pause, track skipping, and a dedicated "another break" button.
  • Windows — the Chrome and Edge media panel (the one behind the address-bar icon, which also feeds the system media controls), plus hardware media keys on keyboards and headsets.
  • iOS/macOS — lock screen and Control Center.
  • With a sleep timer armed, the system card draws a real countdown, so you can see what's left without unlocking the phone.

This turned out to be the fiddliest part of the release: the operating system has no idea Web Audio exists, so the card is carried by a separate inaudible <audio> element. Chrome and Edge only promote tracks longer than 5 seconds into the system controls, and a track of pure zeroes gets written off as "no audio at all" — so the carrier runs for 30 seconds and holds a square wave one least-significant bit tall: quieter than the noise floor of any signal chain, yet unmistakably real audio to the OS.

268 real breaks instead of 49

The drum bank went from 49 to 268 live loops — real breaks, not synthesis. The large packs live in separate files and are only fetched once DRIVE is playing, so the page still opens instantly.

Every visit sounds new

Track #1 used to sound the same forever. Now the bank is reshuffled on every visit: the same track number today and tomorrow lands on completely different drums. Within a single session the numbering stays deterministic, so going back to ‹‹ #N ›› still returns the same track.

Redesigned mobile player

The phone player was rebuilt: a sticky panel at the bottom edge, a CSS-grid layout instead of wrapping rows, thumb-sized tap targets, and dedicated breakpoints for narrow screens. Sliders, timer, and track controls no longer fall apart at 360 pixels wide.

Small things you can see and hear

  • mp3 codec delay compensation — decoders leave up to 25 ms of silence at the head of a file, which made the slicing land just barely late. The real start of the loop is now detected from the signal, so hits sit exactly on the grid.
  • The break name heads the player in DRIVE and sits on the second line of the system card.
  • Custom icon — the app artwork doubles as the tab favicon, the home-screen icon, and the system player cover.
  • Bank counter in the About dialog shows how many breaks are loaded.
  • FOCUS was rewritten around pure synthesis — the genres.js file from 1.1 is gone.

💡 Why this exists

Most music services require you to choose. Choosing is a distraction. Addiction.fm removes the choice entirely: one button, one state, one stream of sound. Runs in the browser, no install required, no login needed.


🎚 States

State Genre For
🔴 DRIVE Amen-break · Jungle · ~180 BPM Energy, task focus, movement
🔵 FOCUS Deep ambient Sub-bass, dark pads, rare synth plucks — no drums
🟣 CALM Breathing drone + rain Relaxation, sleep, recovery

🔊 How it works

Sound is generated in real time via the Web Audio API — this is not streaming, not a playlist. Every press creates a unique combination:

  • DRIVE — a break from a 268-loop bank sliced into 16th notes with DJ jumps, stutters and rolls, soft piano on top
  • FOCUS — sub-bass synthesized in the chosen key, dark pads whose lowpass is swept by a 0.06 Hz LFO
  • CALM — drone from detuned oscillators, filtered noise, low bells, the whole bed rocked by a 0.09 Hz breathing LFO

⚡ Shortcuts

Key Action
Space pause
1 2 3 state
V / B previous / next track
X another break — in DRIVE, with the 🎲 switch on

📦 Files

File What's inside Required
index.html the whole app: engine, interface, artwork yes
breaks.js base bank, 49 breaks yes
breaks2.js main pack, 219 breaks optional, but far more fun
breaks3.js pack top-up optional
screens/ README screenshots only — the site doesn't load them no

Without breaks2.js and breaks3.js the radio runs on the base bank; without breaks.js it falls back to synthesized drums. You can delete them for fun, but the songs won't sound very good.


💪 Why Addiction.fm

  • Runs everywhere — Chrome, Firefox, Safari, Android, iOS, Windows. Open and play.
  • Controlled from the OS — Android shade, Windows media controls, lock screen, media keys
  • Works offline — download the files and run locally from any folder
  • No accounts — no tracking, no ads, no recommendation algorithms
  • Always different — the generative engine creates a new version on every press
  • 268 breaks — the bank is reshuffled on every visit
  • Deterministic tracks — the ‹‹ #N ›› counter locks a specific track by seed number within a session
  • WAV recording — the ⏺️ rec button captures the track in real time and downloads it as .wav
  • Propeller — spins at the tempo of the current state, coasts down on pause

🧰 Tech stack

Layer What does the work
Web Audio API synthesis, slicing, mixing, real-time recording
Media Session API system media controls, artwork, sleep-timer countdown
ScriptProcessorNode PCM capture for WAV export
Pure HTML/JS zero dependencies, zero frameworks, single file

👤 Author

Made by Sewerbox / sewerdev · Telegram: @VestronVulture

Addiction.fm is not a playlist. It's a state of mind.


🔥 Русский

Генеративное радио. Одна кнопка — и звук создаётся под твоё состояние.

Слушать онлайн версия 2.4 268 брейков ноль зависимостей Деплой сайта

English · Русский

Никаких плейлистов, аккаунтов и рекламы. Выбери состояние — получи уникальный звук, который никогда не повторится.

Содержание

📸 Как это выглядит

Три состояния на одном экране телефона — акцент, фоновая подсветка и ползунки перекрашиваются под выбранный пресет:

РАЗГОН, ФОКУС и ПОКОЙ на телефоне

Светлая тема, меню настроек и окно «о приложении»:

Светлая тема, настройки и «о приложении»

Широкая вёрстка — плеер собирается в одну липкую строку:

Addiction.fm на десктопе


🔥 Что нового в 2.4

ПОКОЙ стал фиолетовым и научился дышать. Пресет ушёл с зелёного (#46A171 → #7A5AC8), и весь слой — дрон, пэд, дождь, коричневый шум и сами колокольчики — сидит теперь на одной шине, которую осциллятор 0.0917 Гц качает по громкости: цикл 10.9 с, примерно пять «дыханий» в минуту. Мастер-фильтр опустился с 600–5400 Гц до 420–2420, колокольчики уехали на октаву вниз в E3–D4 с атакой 0.55 с и хвостом 6 с, а случайные квинта и октава сверху заменены одним тихим унисоном на октаву ниже. Замер по трём трекам: доля спектра огибающей в медленной полосе 0.02–0.3 Гц выросла с 12–17% до 53–58%, резких подъёмов на 91 с стало меньше в 1.6–1.8 раза, всё выше 2 кГц упало с –18 дБ до –37 дБ. Пресет стал тише на 3.5 дБ — это замысел, а не потеря.

Интерфейс берёт цвет от состояния. Один атрибут data-m на <html> перекрашивает фоновую подсветку, пропеллер, оба ползунка, активные чипы и выделение текста. Типизированные custom properties (@property) позволяют этим цветам интерполироваться, поэтому переключение РАЗГОН → ФОКУС → ПОКОЙ перетекает за полсекунды, а не щёлкает; браузеры без поддержки просто сменят цвет мгновенно.

Ползунки наконец выглядят заполненными. Дорожка закрашена до бегунка — --p из JS для WebKit и ::-moz-range-progress для Firefox. Градиент обрезан по padding-box, что убрало цветной серп, который выглядывал за скругление правого края дорожки.

Тач-поведение вычищено. Убрана серая подсветка тапа Android, контролы больше не выделяют текст при долгом нажатии, а touch-action: manipulation снимает задержку двойного тапа — отклик на нажатие при этом остаётся. Пропеллер лишился кольца-бейджа, а логотип чуть ужимается ниже 420 px, чтобы подпись держалась в одну строку на 390 px. На мобильном чипы таймера снова таблетки, а не вертикальные капсулы.

Аудиограф больше не растёт до бесконечности. Каждый one-shot — кик, хэт, снейр, суб, плак, пианино и каждое созвучие пэда — снимает свою цепочку с шины, когда отзвучал хвост. В РАЗГОНЕ за три минуты игры накапливалось 350 мёртвых фильтров.

Исправления

  • Петля розового шума щёлкала раз в 2 секунды: состояние фильтра на стыке не совпадало само с собой. Теперь у неё есть кроссфейд-прогон — тот же приём, что уже применялся к коричневому шуму.
  • Когда телефон ставил контекст на паузу (экран, потеря аудиофокуса), цепочка setTimeout у ПОКОЯ продолжала идти, а ctx.currentTime стоял на месте: до 40 звонков набирались в один момент и после разморозки стартовали разом с клиппингом. Теперь звонок не планируется, пока часы контекста реально не идут.
  • Цикл анимации пропеллера засыпает при нулевой скорости вместо 60 пробуждений в секунду — 391 мс машинного времени на 30 с простоя, измерено.
  • Колокольчик окончания таймера перенастроен (атака 0.12 с, срез 800 Гц) — теперь это мягкий сигнал, а не будильник.
🕰 Прошлые версии — 2.3 и 2.1 подробно

2.3

Плеер перестал ездить. Имя брейка живёт в плашке фиксированной ширины — она закрывает ~90% банка, полное имя лежит в подсказке. Когда кубик включён, его слот остаётся занятым, поэтому смена пресета больше не сдвигает ползунки на пиксель, а длинные подписи обрезаются, а не наезжают друг на друга. Ряд целиком держится вплоть до 633 px.

Фон стал жёстче. Планировщик больше не верит флагу document.hidden — он меряет, насколько реально опаздывают его тики, и растягивает упреждение под фактический троттлинг. Возврат из жёсткой заморозки на полсекунды приглушает мастер вместо того, чтобы выстрелить всеми запланированными нотами разом, а AudioContext сам перепланировывает сетку, когда iOS разбудит контекст и никому об этом не скажет.

У пропеллера три скорости. РАЗГОН, ФОКУС и ПОКОЙ крутятся каждая в своём темпе и плавно перетекают друг в друга, а не обрываются щелчком.

Ридми повзрослел. Одна двуязычная страница с шапкой, бейджами и оглавлением; заметки про 2.1 свёрнуты, а раздел «как запустить локально» удалён — радио живёт на sewerdev.github.io/Addiction.fm.

Публикация автоматизирована. Пуш в main запускает .github/workflows/deploy-site.yml, который собирает артефакт Pages и выкладывает его — руками ветку больше трогать не нужно.

Исправления

  • Кнопка ⏺ rec больше не залипает на «⏹ стоп» после записи — локальная переменная затеняла функцию перевода, из-за чего таймер возврата надписи просто не ставился.
  • Последний выбранный пресет переживает перезагрузку; раньше страница всегда возвращалась на ФОКУС.
  • Расшифрованный брейк освобождает свою base64-строку: примерно треть банка больше не висит в памяти впустую.
  • Мёртвый код убран, а плеер теперь рисуется одним проходом, а не четырьмя функциями, пишущими в одни и те же узлы.

2.1

Addiction.fm теперь на хосте!

  • Фон: добавлен глубокий гул «дна океана» (коричневый шум, –6 дБ/окт), бесшовная петля, фильтр 480 Гц.
  • Надёжность: планировщик смотрит на 1,6 с вперёд — переключение вкладок не рвёт звук.
  • Интерфейс: язык системы (ru/en/es) при первом запуске, длинные имена треков сокращаются с подсказкой, тёмная тема без белой вспышки.
  • Исправления: утечка аудиофильтров, зажатые клавиши не дублируют команды, счётчик банка показывает реальное число (268 брейков).

Самое крупное обновление с момента запуска: переписан мобильный интерфейс, банк ударных вырос в пять с половиной раз, а управлять радио теперь можно, не открывая вкладку.

Системный пункт управления

Радио больше не заперто во вкладке браузера. Оно появляется там же, где обычный музыкальный плеер, со своей обложкой:

  • Android — карточка в шторке уведомлений и на экране блокировки: play/pause, переключение треков, отдельная кнопка «другой брейк».
  • Windows — панель мультимедиа Chrome и Edge (та, что открывается по иконке в адресной строке и попадает в системный пункт управления), плюс аппаратные медиаклавиши на клавиатуре и наушниках.
  • iOS/macOS — экран блокировки и Пункт управления.
  • Если заведён таймер сна, в системной карточке рисуется реальный обратный отсчёт — видно, сколько осталось, не разблокируя телефон.

Технически это оказалось самой муторной частью: Web Audio для операционной системы не существует, поэтому карточку «несёт» отдельный неслышимый элемент <audio>. Chrome и Edge берут в системные контролы только дорожку длиннее 5 секунд, а на дорожке из чистых нулей система решает, что звука нет вообще — поэтому носитель длится 30 секунд и содержит меандр амплитудой в один младший бит: тише, чем шум любого тракта, но для системы это настоящий звук.

268 настоящих брейков вместо 49

Банк ударных вырос с 49 до 268 живых петель — реальные брейки, а не синтез. Большие паки лежат отдельными файлами и подтягиваются только когда включён РАЗГОН, так что страница по-прежнему открывается мгновенно.

Каждый заход — новый звук

Раньше трек #1 всегда звучал одинаково. Теперь порядок банка перетасовывается заново при каждом заходе на сайт: тот же номер трека сегодня и завтра — совершенно разные ударные. Внутри одного сеанса номера остаются детерминированными, так что вернуться на ‹‹ #N ›› и услышать то же самое по-прежнему можно.

Редизайн мобильного плеера

Плеер на телефоне собран заново: липкая панель у нижней кромки экрана, раскладка на CSS-сетке вместо переносов, крупные зоны нажатия под большой палец, отдельные брейкпойнты для узких экранов. Ползунки, таймер и переключение треков больше не разъезжаются на 360 пикселях ширины.

Мелочи, которые слышно и видно

  • Компенсация задержки mp3-кодека — декодер оставляет в начале файла до 25 мс тишины, из-за чего нарезка едва заметно запаздывала. Теперь реальное начало петли ищется по сигналу, и доли попадают ровно в сетку.
  • Имя брейка — заголовок плеера в РАЗГОНЕ и вторая строка системной карточки.
  • Своя иконка — обложка приложения работает как фавикон вкладки, иконка на домашнем экране и обложка в системном плеере.
  • Счётчик банка в окне «О приложении» показывает, сколько брейков подгружено.
  • ФОКУС переписан на чистый синтез — файл genres.js из версии 1.1 больше не нужен.

💡 Зачем это существует

Большинство музыкальных сервисов требуют выбора. Выбор — это отвлечение. Addiction.fm убирает выбор полностью: одна кнопка, одно состояние, один поток звука. Работает в браузере, не требует установки, не просит логин.


🎚 Состояния

Состояние Жанр Для чего
🔴 РАЗГОН Amen-break · Jungle · ~180 BPM Энергия, фокус на задаче, движение
🔵 ФОКУС Глубокий эмбиент Суббасс, тёмные пэды, редкие щипки — никаких ударных
🟣 ПОКОЙ Дышащий дрон + дождь Расслабление, сон, восстановление

🔊 Как это работает

Звук генерируется в реальном времени через Web Audio API — это не стриминг и не плейлист. Каждое нажатие создаёт уникальную комбинацию:

  • РАЗГОН — брейк из банка на 268 петель нарезается по 16-м долям с DJ-прыжками, статтерами и роллами, мягкое пианино поверх
  • ФОКУС — суббасс синтезируется в заданной тональности, тёмные пэды со свипом lowpass от LFO на 0.06 Гц
  • ПОКОЙ — дрон из расстроенных осцилляторов, фильтрованный шум, низкие колокольчики; вся подкладка качается дыхательным LFO на 0.09 Гц

⚡ Горячие клавиши

Клавиша Действие
Space пауза
1 2 3 состояние
V / B трек назад / вперёд
X другой брейк — в РАЗГОНЕ, при включённом кубике 🎲

📦 Файлы

Файл Что внутри Обязателен
index.html приложение целиком: движок, интерфейс, обложка да
breaks.js базовый банк, 49 брейков да
breaks2.js основной пак, 219 брейков нет, но с ним интереснее
breaks3.js добор пака нет
screens/ только картинки для README — сайт их не грузит нет

Без breaks2.js и breaks3.js радио работает на базовом банке, без breaks.js — на синтезированных ударных. Вы можете по приколу их удалить, но звучать песни будут не очень.


💪 Преимущества

  • Работает везде — Chrome, Firefox, Safari, Android, iOS, Windows. Открыть и играть.
  • Управление из системы — шторка Android, пункт управления Windows, экран блокировки, медиаклавиши
  • Без интернета — скачай файлы и запусти локально из любой папки
  • Нет аккаунтов — нет трекинга, нет рекламы, нет алгоритмов рекомендаций
  • Каждый раз разный — генеративный движок создаёт новую версию при каждом нажатии
  • 268 брейков — банк перетасовывается при каждом заходе
  • Детерминированные треки — счётчик ‹‹ #N ›› фиксирует конкретный трек по seed-номеру внутри сеанса
  • Запись в WAV — кнопка ⏺️ rec захватывает трек в реальном времени и скачивает как .wav
  • Пропеллер — крутится в темпе текущего состояния, плавно тормозит на паузе

🧰 Технологии

Слой Что делает работу
Web Audio API синтез, нарезка, микширование, запись в реальном времени
Media Session API системный пункт управления, обложка, обратный отсчёт таймера
ScriptProcessorNode захват PCM для экспорта в WAV
Чистый HTML/JS ноль зависимостей, ноль фреймворков, один файл

👤 Автор

Сделано Sewerbox / sewerdev · Telegram: @VestronVulture

Addiction.fm — это не плейлист. Это состояние.

About

Generative radio for your mental state. No playlists, no accounts, no ads

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages