| Age | Commit message (Collapse) | Author |
|
Injects an explicit "With music" / "Without music" choice into the splash
overlay at runtime (uniformly across all themes) instead of only letting
visitors discover the 'p' ambient shortcut after they're already inside.
Clicking a button saves the preference, starts/pauses the ambient engine,
and dismisses the splash. Re-injected after the two spots that replace
#splash-overlay's innerHTML wholesale (theme switch / theme-meta swap) so
the buttons survive. Also fixes a keyboard-focus bug this introduced: the
splash's document-level Enter/Space handler was swallowing native button
activation for a Tab-focused choice button.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Removed the mobile-only display:none gate so the share button is visible
on all viewports. On desktop, navigator.share is typically unavailable,
so the existing JS handler falls through to clipboard.writeText() and
shows the 'Link copied' toast. The mobile @media rule still bumps the
touch target to 40x40.
Amp-Thread-ID: https://ampcode.com/threads/T-019e8f2a-b58e-72b3-b572-28d1fb1d9a1d
Co-authored-by: Amp <amp@ampcode.com>
|
|
Each post now exposes a share button in its header that surfaces only on
mobile. Clicking it invokes navigator.share() with a permalink of the
form "<page>#post-<ID>", which the existing deep-link handler in
shared.js already opens directly in the modal.
When navigator.share is unavailable the link is copied to the clipboard
and a brief toast confirms the action; very old browsers fall back to
window.prompt.
Amp-Thread-ID: https://ampcode.com/threads/T-019e8f2a-b58e-72b3-b572-28d1fb1d9a1d
Co-authored-by: Amp <amp@ampcode.com>
|
|
|
|
|
|
- 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 …).
|
|
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.
|
|
- 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.
|
|
|
|
|
|
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>
|
|
|
|
|
|
Non-selected posts now sit at 0.55 opacity so the animated background
bleeds through clearly. Hovering a non-active post raises it to 0.85,
and the active/highlighted post is always fully opaque (1.0).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- PgUp/PgDn now calls snonuxScrollEffect(dir) in all 14 themes
- Each theme gets a unique directional colour strip (theme-matched gradient)
sliding across the screen in the scroll direction; thicker when wild
- Wild mode activation fires dramatic multi-flash lightning overlay plus a
persistent storm overlay that flickers intermittently while active
- Wild mode deactivation shows a brief dark veil then removes the storm
- Fixed WILD MODE badge: animation now only runs under .sno-wild-on so the
badge stays fully hidden (opacity:0, no pulsing) when wild is off
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Each of the 14 themes now has three interactive effect hooks:
- Navigation (j/k): brief thematic flash/shake/glitch per theme
- Page change (h/l): zoom/warp/tunnel transition per theme
- Wild mode (w key): toggles background animation into overdrive
Wild-mode effects per theme:
- neon: rings spin 14x, particles vortex
- matrix: rain falls 10x faster
- volcano: embers/smoke 8x/5x, lava glows brighter
- brutalist: boxes 15x + random jitter
- aurora/ocean/plasma/cosmos/dos/synthwave/terminal/retro/spaceage/retrofuture:
time-offset approach accelerates all sine-based animations 8-11x
Shared infrastructure added to nav.tmpl:
- sno-shake/sno-zoom-fwd/sno-glitch CSS keyframes
- #sno-wild-badge pulsing red overlay badge
- selectPost() calls snonuxNavEffect()
- h/l navigation calls snonuxPageEffect()
- w key calls snonuxWildToggle()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The zoomed-in post modal (opened with Enter/click) used #modal-content to
display post HTML, but the CSS typography rules (.post-text p/ul/ol/li margin
and padding) only targeted the .post-text class used in the list view. This
caused visually different formatting — missing paragraph spacing and unindented
lists — in the expanded modal compared to the feed.
Fix: extend all .post-text typography selectors in nav.tmpl to also cover
#modal-content, so both views apply identical spacing rules.
Also adds a missing spaceage theme sound preset to satisfy the
TestThemeSoundPresetsMatchRegistry test that was already failing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
(task s4)
Move the 12 theme HTML templates out of theme_*.go (~185KB of raw-string
literals) and the shared navDefs/faviconHeadHTML fragments out of
shared.go/favicon.go into separate .tmpl files under
internal/generator/templates/{themes,shared}/. A new templates subpackage
owns a //go:embed FS and exposes Theme(), Shared() and ThemeNames()
helpers so the binary still ships fully self-contained.
The hand-maintained themeRegistry map is replaced by on-startup
enumeration of the embedded FS; getTheme/ListThemes now derive theme
names from the template files themselves, and navDefs/faviconHeadHTML
are loaded once at package init. Rendered output is byte-equivalent — all
unit tests and integration tests pass, go vet is clean.
Made-with: Cursor
|