Skip to content

Commit 1ad93e1

Browse files
committed
Publish music generator post + expand IDEAS.md
Blog: - Publish "How I accidentally built a procedural music generator" as first post of 2026 - Expand "What's next" section with concrete directions - Fix hotdog theme footnote (click to swap, not random) - Add GASP pun to pixel fonts TIL Music generator IDEAS.md: - Add Generation Modes: scene presets, emotion targeting, loop exports, stingers, emotional arcs, parameter locking, extended duration, drift mode - Add Session Workflow: favorites, another take, quick export - Add CLI/API section: programmatic API, HTTP endpoint, game editor plugins, WASM - Add Beyond Music: SFX generation, adaptive music sets, visual sync - Update priority tiers for actual use cases
1 parent d00be3a commit 1ad93e1

3 files changed

Lines changed: 255 additions & 14 deletions

File tree

posts/how-insane-can-i-make-this/index.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
title: "How I accidentally built a procedural music generator"
3-
date: 2025-12-31
3+
date: 2026-01-01
44
tags: [dev, web, building-in-public]
55
slug: how-insane-can-i-make-this
66
description: "I asked 'how insane can I make this?' at midnight. Three sleepless nights later: nine genres, twenty radio stations, and Dumpster Diving Certification ads."
7-
draft: true
7+
draft: false
88
---
99

1010
```
@@ -23,7 +23,7 @@ This is the story of feature creep at 3am.
2323

2424
## December 3rd, midnight
2525

26-
I was tired. I should have gone to sleep. Instead, I started "messing with adding some themes" to this blog.
26+
I was tired. I should have gone to sleep. Instead, I started messing with adding some themes to this blog.
2727

2828
First came the silly ones. A hotdog stand theme with two modes: ketchup (red background, yellow text) and mustard (yellow background, red text). A terminal theme. A few others.[^themes]
2929

@@ -127,11 +127,19 @@ But where's the fun in that?
127127

128128
## What's next
129129

130-
I might use this for game sounds in [some small games I'm making](/posts/making-small-games/). The procedural approach means I don't need to compose anything - just define parameters and let it generate.
130+
This thing is becoming a playground. Some directions I'm excited about:
131131

132-
More genres are planned. The IDEAS.md file has rock/metal, drum & bass, trip-hop, eurodance, industrial, gabber, acid. No timeline. It'll happen when I feel like it.
132+
**More ways to generate:** Right now it reacts to page content or plays radio stations. I want modes for generating specific things - "give me 30 seconds of tense ambient" or "loop-ready chiptune for a game scene." Shareable song seeds so you can save and recall your favorites. Stem exports for mixing.
133133

134-
The whole thing is [open source](https://github.com/AviDuda/nocturnal-scribbles) (MIT license). The code is a beautiful mess, like all good Geocities tributes.
134+
**More genres:** Rock/metal, drum & bass, trip-hop, eurodance, industrial, gabber, acid. The [IDEAS.md](https://github.com/AviDuda/nocturnal-scribbles/blob/main/src/geocities/music/IDEAS.md) has the full list.
135+
136+
**More radio chaos:** Dial-up modem handshake sounds between songs. ICQ "uh oh" notifications. Weather reports for the information superhighway. Time-locked stations that only broadcast at certain hours. Winamp skins for the player.
137+
138+
**Game audio:** I'm [making small games](/posts/making-small-games/) and the procedural approach means I don't need to compose anything - just define parameters and generate. Background music, menu themes, sound effects.
139+
140+
**More silly things:** Easter eggs. A cursor theremin. Typing percussion. Whatever sounds fun at 3 AM.
141+
142+
No timeline. It'll happen when it happens. The whole thing is [open source](https://github.com/AviDuda/nocturnal-scribbles) (MIT license). The code is a beautiful mess, like all good Geocities tributes.
135143

136144
---
137145

@@ -166,7 +174,7 @@ Welcome to the information superhighway.
166174
~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
167175
```
168176

169-
[^themes]: You can try them all in the footer. The hotdog theme is a Windows 3.11 reference - it picks ketchup or mustard randomly on each load.
177+
[^themes]: You can try them all in the footer. The hotdog theme is a Windows 3.11 reference - click it to swap between ketchup and mustard.
170178
[^marquee]: The `<marquee>` element still works in browsers. I'm not saying you should use it. I'm saying I did.
171179
[^nemo]: The winner of Eurovision 2024. Non-binary Swiss artist. Incredible live.
172180
[^beer]: "It can't fuck me up even more when I didn't sleep" - past me, accurately predicting the immediate crash that followed

posts/til-pixel-fonts-blurry/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ArialPixel is designed on a 16×16 pixel grid (em=1024, 64-unit grid). It's outl
1717

1818
When the font size doesn't match the design grid (multiples of 16px), the pixel grid doesn't align with display pixels. Modern browsers apply antialiasing to smooth the edges. Result: blur.
1919

20-
I dug into the font with FontForge.[^fontforge] The GASP table had empty hinting flags - no gridfitting instructions telling renderers how to snap to pixels.
20+
I dug into the font with FontForge.[^fontforge] The GASP table had empty hinting flags - no gridfitting instructions telling renderers how to snap to pixels. (I did gasp when I saw it. Sorry.)
2121

2222
Here's a sandbox comparing everything I tried:
2323

src/geocities/music/IDEAS.md

Lines changed: 239 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,139 @@ Physical dial UI to tune between stations. Static between frequencies. Signal cl
2222

2323
---
2424

25+
## Generation Modes
26+
27+
Beyond tape mode (page-reactive) and radio mode (station-based), additional modes for specific use cases.
28+
29+
### Scene Presets
30+
31+
Pre-configured generation for common contexts:
32+
33+
| Scene | Energy | Brightness | Character |
34+
|-------|--------|------------|-----------|
35+
| Menu | -0.3 | +0.2 | Inviting, loopable, not distracting |
36+
| Gameplay | +0.3 | 0 | Engaging but sustainable for long sessions |
37+
| Tension | +0.4 | -0.6 | Building unease, sparse, unsettling |
38+
| Victory | +0.6 | +0.7 | Triumphant, bright, celebratory |
39+
| Defeat | -0.5 | -0.5 | Somber, deflated, reflective |
40+
| Ambient Background | -0.7 | -0.1 | Atmospheric, unobtrusive, endless |
41+
42+
### Emotion Targeting
43+
44+
Direct mood selection bypassing page analysis:
45+
46+
| Emotion | Energy | Brightness | Notes |
47+
|---------|--------|------------|-------|
48+
| Anxious | +0.2 | -0.4 | Restless, unstable rhythms, minor keys |
49+
| Nostalgic | -0.4 | +0.1 | Warm but melancholic, vintage processing |
50+
| Melancholic | -0.5 | -0.3 | Slow, sparse, minor, lots of reverb |
51+
| Manic | +0.8 | +0.3 | Fast, chaotic, genre-hopping |
52+
| Peaceful | -0.6 | +0.3 | Gentle, major keys, soft timbres |
53+
| Dread | -0.2 | -0.8 | Slow builds, dissonance, dark |
54+
| Lonely | -0.4 | -0.2 | Sparse, single voices, space |
55+
| Hopeful | +0.1 | +0.5 | Building energy, major progressions |
56+
57+
### Loop-Ready Exports
58+
59+
Generate tracks designed for seamless looping:
60+
61+
- **Bar counts:** 4, 8, 16, 32 bars (user selectable)
62+
- **Duration targets:** 15s, 30s, 1min, 2min
63+
- **Loop point markers:** Metadata for DAW import
64+
- **Intro/outro options:** With or without, for flexibility
65+
- **Seamless mode:** End matches beginning for perfect loops
66+
67+
### Transition Stingers
68+
69+
Short musical hits for scene changes:
70+
71+
- **Victory sting:** 2-4 second triumphant hit
72+
- **Defeat sting:** 2-4 second somber hit
73+
- **Discovery sting:** Curious, rising
74+
- **Alert sting:** Attention-grabbing
75+
- **Transition whoosh:** Swoosh between scenes
76+
- **UI confirm/cancel:** Short feedback sounds
77+
78+
### Emotional Arcs
79+
80+
Music that evolves over a defined duration:
81+
82+
- **Build:** Starts sparse, adds layers, crescendos
83+
- **Decay:** Starts full, strips away, fades
84+
- **Wave:** Builds and releases in cycles
85+
- **Shift:** Gradual mood transformation (e.g., hopeful → dread)
86+
- **Arc duration:** User-defined (30s to 5min)
87+
88+
### Parameter Locking
89+
90+
Control what stays constant vs. what varies:
91+
92+
- **Lock tempo:** Keep BPM, change everything else
93+
- **Lock genre:** Stay in genre, vary song
94+
- **Lock mood:** Keep energy/brightness, vary genre
95+
- **Lock key:** Same musical key, different songs
96+
- **Lock structure:** Same form, different content
97+
98+
### Extended Duration Tracks
99+
100+
Currently tracks are 1-3 minutes. Options for longer generation:
101+
102+
- **Duration targets:** 5 min, 10 min, 15 min, 30 min
103+
- **Section variety:** More section types, less repetition over time
104+
- **Development:** Themes introduced early, developed/transformed later
105+
- **Dynamic arrangement:** Instruments enter/exit more gradually
106+
- **Key changes:** Modulation to related keys for freshness
107+
108+
Needs work on structure generation to stay interesting over longer durations.
109+
110+
### Endless / Drift Mode
111+
112+
Continuous generation without song boundaries. Music slowly morphs over time:
113+
114+
- **No endings:** Stream runs indefinitely until stopped
115+
- **Parameter drift:** Tempo, key, energy slowly shift over minutes/hours
116+
- **Genre blending:** Gradually transitions between genres (lofi → ambient → vaporwave)
117+
- **Seamless evolution:** No abrupt changes, everything crossfades organically
118+
- **Drift speed control:** How fast parameters change (glacial → noticeable)
119+
120+
Different from automix (discrete songs with crossfades). This is one continuous piece that becomes something else over time. Like generative ambient for long sessions.
121+
122+
Could have presets:
123+
- **Study drift:** Stays in chill zone, very slow changes
124+
- **Journey drift:** Explores full mood space over hours
125+
- **Night drift:** Follows time of day (energetic evening → ambient late night → gentle morning)
126+
127+
---
128+
129+
## Session Workflow
130+
131+
Features for working with generated music (session-only, no persistence across visits).
132+
133+
### Favorites
134+
135+
- **Star current track:** Save to session favorites list
136+
- **Favorites panel:** Review starred tracks
137+
- **Re-generate from favorite:** Recreate using saved seed
138+
- **Export all favorites:** Batch download
139+
140+
### Another Take
141+
142+
- **Regenerate similar:** New song, same parameters
143+
- **Variation slider:** How different should the new take be (0% = nearly identical, 100% = just the locked params)
144+
- **A/B comparison:** Toggle between current and previous
145+
146+
### Quick Export
147+
148+
WAV and MIDI export already exist. See [Export Improvements](#export-improvements) for format ideas.
149+
150+
Workflow improvements:
151+
152+
- **One-click export:** Download what's playing without opening menus
153+
- **Export from favorites:** Batch download all starred tracks
154+
- **Auto-filename:** Use generated track name as filename
155+
156+
---
157+
25158
## New Genres
26159

27160
Genres that fit the 90s web aesthetic and are achievable with oscillator synthesis:
@@ -433,6 +566,98 @@ Option 1 is cleanest - adds drums/bass/melody/pad/arp/fx gain nodes, mute contro
433566
- **Loop Export** - Just the main loop, perfect for tiling
434567
- **Ringtone Length** - 30-second export option
435568

569+
### CLI / API Design
570+
571+
For using the generator outside the browser (batch generation, game asset pipelines, scripting):
572+
573+
**Architecture goal:** Keep generation logic cleanly separated from browser-specific code (Web Audio API, DOM). Core generation should be pure functions that output note/timing data, with rendering as a separate layer.
574+
575+
**Potential CLI:**
576+
```bash
577+
npx nocturnal-music generate --emotion dread --duration 30 --loop --out track.wav
578+
npx nocturnal-music batch --preset tense-ambient --count 10 --out ./assets/
579+
npx nocturnal-music list-presets
580+
```
581+
582+
**Programmatic API:**
583+
```typescript
584+
import { generate, render } from 'nocturnal-music';
585+
586+
const song = generate({
587+
emotion: 'dread',
588+
duration: 30,
589+
loop: true,
590+
});
591+
592+
await render(song, { format: 'wav', output: 'track.wav' });
593+
```
594+
595+
**Why this matters:** Games using non-JS tech (Godot, Unity, Love2D) can't embed the generator at runtime. But a CLI/API lets you generate assets during development and drop the files into any project.
596+
597+
**HTTP endpoint:**
598+
```
599+
GET /generate?emotion=dread&duration=30&loop=true&format=wav
600+
→ Returns audio file
601+
```
602+
603+
Could run as a local dev server or hosted service. Useful for non-JS projects that want on-demand generation during development.
604+
605+
**Game editor plugins:**
606+
607+
Integrate directly into game engines as editor extensions:
608+
- **Godot plugin** - Generate and import audio from editor panel
609+
- **Unity package** - Custom window for music generation
610+
- **Love2D helper** - Lua script that calls local endpoint
611+
612+
Side benefit: Learning each editor's plugin system while building something useful.
613+
614+
**WASM build:**
615+
616+
Compile generator to WebAssembly for embedding in non-JS environments:
617+
- Rust, Go, C++, etc. can load WASM modules
618+
- Runtime generation in Godot, Unity, Love2D becomes possible
619+
- Same generation logic, different host language
620+
621+
**Not a priority** - web tool with good export workflow covers most use cases. But keeping the code modular makes this possible later.
622+
623+
---
624+
625+
## Beyond Music
626+
627+
### Sound Effects Generation
628+
629+
Procedural SFX using similar synthesis approach:
630+
631+
- **UI sounds:** Clicks, hovers, confirms, cancels, errors
632+
- **Footsteps:** Variations on surface types (wood, stone, grass)
633+
- **Impacts:** Hits, explosions, thuds with energy scaling
634+
- **Ambient loops:** Wind, rain, room tone, forest
635+
- **Pickups/collectibles:** Satisfying chimes and swooshes
636+
637+
Royalty-free, infinite variations, no licensing headaches.
638+
639+
### Adaptive Music Sets
640+
641+
Generate variations of the same theme for dynamic game audio:
642+
643+
- **Calm / Medium / Intense** versions of one piece
644+
- Same key, tempo, core motifs - different energy and density
645+
- Compatible layers that can crossfade based on gameplay
646+
- Export as stems for in-game mixing
647+
648+
Example: Generate a "dungeon theme" → get exploration layer, combat layer, boss layer that all work together.
649+
650+
### Visual Sync / Generative Visuals
651+
652+
Music generation already produces structured data (beats, sections, energy curves). Export this for visual sync:
653+
654+
- **Beat markers** - Drive particle bursts, screen shake, flash
655+
- **Section changes** - Trigger color palette shifts, transitions
656+
- **Energy curves** - Control intensity of visual effects over time
657+
- **Frequency data** - Already have analyser, could export for offline use
658+
659+
Could pair with procedural visual generators. Another "learn a thing" angle (shaders, visual programming).
660+
436661
---
437662

438663
## Wild Ideas
@@ -498,23 +723,31 @@ No user tracking required - all based on time, input, or page content.
498723
## Priority Tiers
499724

500725
### Do Next (High Impact)
501-
- Song seed for sharing
726+
- Song seed for sharing/recreating tracks
727+
- Favorites system (star tracks, review, regenerate from seed)
728+
- Scene/emotion preset selector (menu, tension, peaceful, dread, etc.)
729+
- Loop-ready export options (bar count, seamless mode)
502730

503731
### Do Eventually (Medium Impact)
732+
- Extended duration tracks (5-30 min with more section variety)
733+
- Endless/drift mode (continuous morphing stream)
734+
- Stem export (separate drums/bass/melody files)
735+
- Parameter locking UI (beyond just genre lock)
736+
- Transition stingers (short hits for scene changes)
737+
738+
### Do Maybe (Fun but Effort)
504739
- More visualizer modes
505740
- Station special effects (PIRATE RADIO glitches, THE VOID processing)
506741
- Time-locked stations
507742
- Texture/atmosphere layer
508-
509-
### Do Maybe (Fun but Effort)
510743
- Skin system
511744
- Weather/traffic reports
512-
- Click-to-trigger sounds
513-
- Album art generation
514-
- Easter eggs (Konami code, time-based triggers)
515745
- Tune-in dial UI
516746

517747
### Do If Bored (Wild)
748+
- Click-to-trigger sounds
749+
- Album art generation
750+
- Easter eggs (Konami code, time-based triggers)
518751
- Multiplayer shared radio
519752
- LLM-generated lyrics
520753
- Physical CD burn animation

0 commit comments

Comments
 (0)