| Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Task: 7b
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Add Oxanium-Regular.woff2 and Oxanium-Bold.woff2 (latin + latin-ext
subset, ~22 KB total) by Tyler Finck, fetched 2026-05-01 from
https://gwfh.mranftl.com/fonts/oxanium (mirrors Google Fonts);
released under SIL OFL 1.1.
- biomech/theme.css: add @font-face blocks pointing at the local
files. The CSS already declared 'Oxanium' as the body font but
the family was never loaded, so it silently fell back to system
sans-serif. Now the geometric techy face actually renders.
- biomech/FONT_LICENSE.txt: full attribution + OFL link + source
URL + fetch date so future maintainers can re-fetch deterministically.
- templates/embed.go: append themes/*/*.woff2 to the //go:embed glob
(deferred from task ra because go:embed requires every pattern to
match at least one file, which biomech now satisfies).
- README.md: append biomech entry to the bundled-fonts bullet list.
Self-hosted, no third-party CDN requests at page load; verified via
grep -RnE 'googleapis|gstatic|@import url\(http' against both source
and generated dist.
Amp-Thread-ID: https://ampcode.com/threads/T-019de000-c062-73c5-9afc-c9af422473cf
Co-authored-by: Amp <amp@ampcode.com>
|
|
(task ra)
- dos theme: bundle 'WebPlus IBM VGA 8x16' (.woff) by VileR from
the Ultimate Oldschool PC Font Pack v2.2 (CC BY-SA 4.0); replace
the never-loaded VT323 reference with @font-face + a self-hosted
bitmap face matching the BBS/DOS aesthetic.
- templates/embed.go: add ThemeExtraFiles + extend the //go:embed
glob with themes/*/*.woff and themes/*/FONT_LICENSE.txt so any
theme can ship its own font assets without further code changes;
add a NOTE comment block documenting the per-theme directory
convention and the //go:embed pattern-matching constraint.
- generator/writeThemeAsset: copy any extra files (fonts, license
notices) verbatim from the embedded FS into dist/themes/<name>/.
- README.md: rewrite the 'Third-party assets' section into a bullet
list with self-hosting policy, attribution for the bundled dos
font, and a step-by-step recipe for adding new bundled fonts.
- dos/FONT_LICENSE.txt: full attribution + CC BY-SA 4.0 notice.
Self-hosted, no third-party CDN requests at page load.
Amp-Thread-ID: https://ampcode.com/threads/T-019de000-c062-73c5-9afc-c9af422473cf
Co-authored-by: Amp <amp@ampcode.com>
|
|
- loadAllPosts: pre-allocate posts slice with capacity len(entries) since
each directory entry may become a post.
- paginate: pre-allocate pages slice with capacity (len(posts)+pageSize-1)/pageSize.
The concat function no longer exists in the codebase (removed when theme
sound data was moved to embedded JSON files in commit 06dd860).
|
|
|
|
- Generate sounds.json for each theme inside templates/themes/<name>/
- Load sound data at runtime from embedded FS via templates.ThemeSounds()
- Replace ~1100 lines of hardcoded builder functions and presets with a
145-line loader (soundCache, initSoundCache, loadThemeSounds)
- Update embed.go to include themes/*/sounds.json in the embedded FS
- Update tests to use loadThemeSounds() instead of themeSoundPresets
- Eliminates duplication between themeSoundPresets and JSON output
Improves cohesion and DRY by keeping theme assets (CSS, JS, meta, sounds)
in a single location per theme directory.
|
|
|
|
atom.Generate, syncOutput)
- generator.Run(ctx, cfg) – ctx passed through to atom.Generate
- processor.Run(ctx, cfg) – signature updated for cancellation propagation
- atom.Generate(ctx, posts, cfg) – accepts ctx for future cancellation
- syncOutput(ctx, cfg) – rsync subprocesses now use exec.CommandContext
- Updated all call sites in tests, cmd/snonux/main.go, and integration tests
- All call sites pass context.Background() / context.TODO()
All tests pass: go test ./...
|
|
|
|
Fixes data loss risk in writePage:
- Write to a temp file instead of the target path.
- Explicitly close the temp file and check the error (was ignored).
- Rename to the final path only after successful close.
- Remove the temp file on any error so truncated output is never left on disk.
Added TestWritePage (happy path + template error) and
TestWritePage_tempFileCleanedOnError to verify no corruption of existing file.
|
|
- New blank mode hides all UI except the WebGL canvas; toggled via
the ‘blank’ nav button or the b key.
- Theme switching is now in-place (no page reload), avoiding the
Web Audio context reset that used to kill ambient music.
- Nukem ambient/riff rebuilt around the classic Grabbag riff (E5
E5 G5 A5 …).
|
|
- New theme directory: templates/themes/nukem/ (meta.json, theme.css, theme.js)
- Red/gold/black color palette with monospace typography
- WebGL: rising sparks, falling debris, rubble blocks, explosion glow
- Sound preset: 140 BPM E-minor power riffs with fanfare stabs (wild: 180 BPM thrash)
- All nav/open/close/scroll/wild/page effects implemented
Amp-Thread-ID: https://ampcode.com/threads/T-019dcd42-8558-748b-8c28-3f848400026d
Co-authored-by: Amp <amp@ampcode.com>
|
|
Complete rewrite of all 19 theme ambient presets to eliminate the
slow waltz/lo-fi feel. Every preset now targets a driving rock/
industrial/hardstyle vibe with:
- **Much faster BPM**: normal 120–180, wild 180–260 (was 60–70 / 120–140)
- **Power chords** replace major/minor triads — aggressive distortion-ready
- **Straight eighth-note drive** replaces swung waltz melodies — punchy,
rhythmic, no floaty legato
- **More active drum patterns**: double-kick, snare backbeats,
sixteenth-note hats, clap stabs on the 16th
- **Shorter attack / release** on normal (0.3→0.02, 0.5→0.15) so everything
hits harder
- **Higher filter cutoffs** for a brighter, more aggressive timbre
- **Three drone voices** (was 4) with lower fundamental octave, fewer
frequencies, more focused. Sub-bass added via buildRockSong octave divider.
- **buildRockSong** replaces buildSong: adds sub-bass (/2 voice) and bass
hits per measure, making each bar feel like a down-beat impact
- **buildDriveMelody** replaces buildSwingMelody: straight eighth notes, no swing
- **buildStabMelody** for wild mode: short 16th-note bursts with gaps
Also bumped test BPM cap from 250→400 to accommodate the new range.
|
|
Audit found universal mobile issues in every theme + shared CSS:
- body/overlay height:100vh had no 100dvh dynamic-viewport fallback on any theme
- @media(max-width:640px) was too minimal; 3 themes had no .content/.modal-inner reduction
- .modal-close buttons had zero padding → tap target well below 44×44px
- .transmit-btn and .page-nav a vertical height too small on most themes
Fixes applied:
Go/CSS common (shared.css):
- Add .modal-close padding + min 44×44px touch target
- Add overflow:hidden to #sno-wild-banner to prevent wild-mode banner overflow
- Add mobile @media override block with !important for .modal-inner padding,
.transmit-btn, and .page-nav a min-height to guarantee 44px touch targets
All 19 themes:
- Add height:100dvh fallback after height:100vh on body and .overlay
- Expand @media(max-width:640px) with missing .content/.modal-inner padding,
.transmit-btn min-height, and .modal-close touch-target padding where absent
Specific themes:
- DOS: enlarge .transmit-btn base padding from 4px to 8px
- Spaceage: bump .post-text from 0.86rem (~13.8px) to 0.9rem (~14.4px)
- Brutalist / Retrofuture / Synthwave: these previously had no .content or
.modal-inner reduction in their media queries; now filled in
|
|
Rewrite all 19 theme ambient presets with chord progressions, bass drones,
overlapping chord pads (dur > step on melodyNote), and swing melodies.
Add per-theme 16-step drum patterns (kick, snare, hat, clap) synthesized
in the Web Audio engine.
Go (theme_sounds.go):
- Add Step field to melodyNote for sequencer timing independent of duration
- Add Drums []string field to ambientPreset for 16-step patterns
- Add buildMeasure, buildSong, buildSwingMelody, and pat helpers
- Rewrite every sounds*() func with I–IV–V–I progressions, bass, and melody
JS (shared.js):
- Fix startEngine() to await ctx.resume() before scheduling
- Make masterGain a binary gate (fade to 1.0 in ~50 ms), not preset.gain
- Fix startDrones() to scale by preset.gain instead of 1.0/numDrones
- Add twin-oscillator detuned timbre in playMelodyNote()
- Add synthesized drum engine: playDrum(), scheduleDrums(), stopDrums()
- Keep splash sounds bypassing masterGain so they never get gated out
|
|
Rewrite all 19 theme melodies into proper ~10-16 second looping songs
with bass drones, chord pads, and scalar melody lines using the new
'step' field for polyphonic overlap on a monophonic step sequencer.
Fix four bugs that caused total silence:
1. masterGain was faded to preset.gain while each note was ALSO scaled
by preset.gain*0.6, squaring volume to ~-68 dB.
2. fadeMasterTo ramped the gate for 0.5-1.5s, swallowing first notes.
3. startDrones set per-osc gain to 1.0/numDrones, clipping and burying
the melody.
4. AudioContext resume was not awaited; notes fired into a suspended
context and were lost.
Shared.js:
- startEngine() waits for ctx.resume() before scheduling anything.
- masterGain acts as a binary gate (fades to 1.0 over 50ms).
- playMelodyNote uses twin detuned oscillators for richer timbre.
- startDrones scales by preset.gain so drones match melody level.
Theme_sounds.go:
- Add 'step' field to melodyNote struct.
- Add chord-building helpers (major/minor triads).
- Add buildSong() / buildMeasure() for structured 4-bar loops.
- All 19 themes: audible bass (130-220Hz), chord pads (260-520Hz),
melodies (330-1046Hz), real chord progressions, proper BPM.
|
|
Each theme now has a distinctive looping melodic phrase (normal + wild variants)
played by the Web Audio ambient engine. This replaces the generic random-pulse
behavior that made all themes sound the same.
Go changes:
- Add melodyNote struct with freq/dur/gain fields to ambientPreset
- Add n() helper for concise melody construction
- Rewrite all 19 theme presets with unique melodic phrases:
neon=glassy arpeggio, terminal=sparse CRT beeps, synthwave=warm minor,
plasma=tritone shimmer, brutalist=concrete rumble, volcano=phrygian,
aurora=high shimmer, matrix=digital ostinato, ocean=wave flow,
dos=8-bit arpeggio, retro=VHS warmth, cosmos=vast fifths,
retrofuture=lounge minor-7, spaceage=pure ascending, tropicale=pentatonic,
noir=smoky minor-7, cathedral=organ thirds, surveillance=fourth alert,
biomech=diminished unease
JS changes:
- Add melodyTimer/melodyIndex state to ambient engine
- Add playMelodyNote() with per-note gain and filter support
- Add scheduleMelodyNote() with phrase-rest gaps
- schedulePulse() now routes to melody player when melody is present
- Add sawtooth support to snonuxWaveType()
- Reset melody index on startEngine() and stopAll()
Test changes:
- TestThemeSoundPresetsAmbientPopulated now accepts melody as valid content
- TestThemeSoundPresetsAmbientValuesBounded validates melody note freq/dur
|
|
The splash overlay played its chime on pointerdown (click) but not when
dismissing via Enter or Space. Expose playSplashChime on window so the
global keydown handler can trigger the same sound before dismissal.
Escape continues to dismiss silently.
|
|
- generator_test.go:
- TestThemeSoundPresetsAmbientPopulated: every theme has Ambient.Normal and
Ambient.Wild with at least one drone or pulse frequency.
- TestThemeSoundPresetsAmbientValuesBounded: gains/durations/intervals are
positive and below conservative max values.
- TestThemeSoundsJSON_neonAmbientRoundTrip: themeSoundsJSON unmarshals and
contains ambient.normal and ambient.wild.
- integration_test.go:
- TestKeyboardNavJS: verify p=ambient, f=flash hotkeys and nav hints.
- TestIndexHTMLBakesSounds: verify index.html bakes window.SNONUX_SOUNDS.
- TestThemeSelection: dynamically test all registered themes and assert
generated sounds.json includes ambient data for each.
|
|
Replace generic ambient() helper calls with detailed ambientPreset literals
for every registered theme. Normal presets are now subtle (gain 0.02-0.03),
loopable, and low-fatigue. Wild presets are recognizably the same theme but
faster, denser, and more dramatic (gain 0.05-0.065).
Theme-specific changes:
- neon: glass drone with filter sweep; wild adds brighter arps
- terminal: CRT hum + sparse ticks; wild becomes rapid process storm
- synthwave: warm minor pad; wild doubles pulse with octave jumps
- plasma: tritone shimmer; wild adds aggressive sweep and noise
- brutalist: concrete rumble; wild adds blunt sub impacts with rhythm
- volcano: magma drone; wild adds tremor pulses and heat noise
- aurora: airy fifths; wild adds solar-storm detune shimmer
- matrix: digital rain ostinato; wild speeds code-rain pulses
- ocean: tidal swell + surf noise; wild adds storm surge
- dos: PC speaker hum; wild becomes IRQ panic at 200 BPM
- retro: amber chip tones; wild adds tape-eat jitter and noise
- cosmos: wide fifth/octave drone; wild adds supernova pulse
- retrofuture: atomic lounge pad; wild adds Geiger-like rhythm
- spaceage: theremin sines; wild adds re-entry alarm pings
- tropicale: dusk pentatonic surf; wild adds category-5 percussion
- noir: smoky minor drone; wild adds siren-like intervals
- cathedral: organ stacked sines; wild adds bell/requiem intensity
- surveillance: monitor hum/scanner; wild adds alert cascade
- biomech: organic asymmetric drone; wild adds nervous wet pulses
All generator tests pass.
|
|
- When wild mode turns on, automatically start ambient playback using the
theme's wild ambient variant, even if normal ambience was off.
- Track wild-forced ambient starts via _snonuxAmbientWildForced so that
deactivation can fade to silence when the user never opted in, or
crossfade back to normal when they did.
- Do not persist forced-wild playback as a normal ambient preference;
only user toggles (p key / ambient button) are saved.
- Enhance wild ambient playback: denser pulses (1.5x bpm), increased noise
texture, slightly raised gain (capped at 0.15), and deeper lowpass filter
sweeps on pulses.
- Re-sync FX button states after ambient start/stop so the ambient button
accurately reflects the current state.
|
|
- Change ambient playback hotkey from 'm' to 'p'
- Move flash effect hotkey from 'p' to 'f'
- Update nav button labels: '<kbd>p</kbd> music' and '<kbd>f</kbd> flash'
- Update splash hint to advertise 'p' music alongside 'w' wild
- Add 'p' and 'f' hotkey support in splash and modal states
- Persist ambient enabled/disabled state in localStorage (snonuxAmbientEnabled)
- Default off; restore preference on page load without overwriting via wild mode
- Improve accessibility with explicit aria-labels and aria-pressed state sync
|
|
Adds a reusable ambient controller in shared.js with:
- One shared AudioContext + master gain node for all ambient sound
- Long-running drone oscillators from SNONUX_SOUNDS.ambient droneFreqs
- Scheduled short pulse oscillators with BPM-derived interval jitter
- Looped buffer-source noise when noiseGain is present (no AudioWorklet)
- Fade in/out (~0.3-0.8s) using preset attack/release on start/pause/switch
- snonuxAmbientStart/Pause/Toggle/SetWild/SyncPreset/IsPlaying window APIs
Integrates with existing UI:
- Ambient toggle button (<kbd>m</kbd> ambient) in nav-fx-buttons
- m hotkey toggles ambient in both splash and main keyboard handlers
- w key starts wild ambient and crossfades preset when switching wild state
- Theme sounds.json fetch completion triggers snonuxAmbientSyncPreset()
- One-shot UI sounds (splash/nav/open/close/bounce) remain unchanged and
route through their own AudioContexts, never through the ambient master.
|
|
Extend themeSounds with Ambient field containing Normal and Wild
variants. Each ambientPreset carries numeric/string fields for
generative background audio: bpm, pulseInterval, gain, wave,
droneFreqs, pulseFreqs, cutoffMin/cutoffMax, noiseGain, attack,
release, detuneCents, and rhythm.
Populate all 19 existing themes with normal and wild ambient presets
using a concise ambient() helper. Existing splash/nav/open/close/bounce
fields remain unchanged for backwards compatibility.
Add TestThemeSoundsJSON_ambientSchema to verify every theme emits
valid JSON containing both ambient variants alongside the legacy
sound fields.
|
|
|
|
|
|
post afterimage
Amp-Thread-ID: https://ampcode.com/threads/T-019db698-f351-7161-a397-1cce1fdab440
Co-authored-by: Amp <amp@ampcode.com>
|
|
first-visit burst
Amp-Thread-ID: https://ampcode.com/threads/T-019db698-f351-7161-a397-1cce1fdab440
Co-authored-by: Amp <amp@ampcode.com>
|
|
Amp-Thread-ID: https://ampcode.com/threads/T-019db698-f351-7161-a397-1cce1fdab440
Co-authored-by: Amp <amp@ampcode.com>
|
|
|
|
|