diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-10 09:22:06 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-10 09:22:06 +0300 |
| commit | f3155cbc866a1b261a0aafe61683da1e3c25b1ef (patch) | |
| tree | dedad4708adf0b377dd06c11c1bc957bc1bfe302 /internal/generator/shared.go | |
| parent | 3e61d09873065f5342efc414ee3ea0d5fdc4c767 (diff) | |
add WebGL scenes to all themes, sounds, image sizing, new themes
- All 11 themes now have unique Three.js WebGL backgrounds:
aurora: flowing sine-wave ribbon meshes with additive blending
brutalist: harsh rotating white/red wireframe boxes
glass: drifting crystal icosahedron shards, semi-transparent
matrix: digital rain particle columns with per-vertex colour fade
ocean: animated vertex-displaced wave surface with orbiting light
retro: amber demo-scene cube with orbiting octahedrons
synthwave: sunset sphere with scan-line rings and perspective grid
terminal: green icosahedron wireframe with orbiting torus particles
neon: existing Three.js orb and rings (unchanged)
plasma (replaces minimal): drifting additive-blend colour blobs
volcano (replaces paper): rising ember particles with lifecycle
- shared.go: distinct sounds for j/k nav (220Hz beep), Enter (ascending
triangle chime), and Esc (descending sine sweep)
- shared.go: images are now thumbnails (max-height:220px) in list view
and expand to full width inside the modal (CSS override in navmodal)
- main.go: --list-themes flag prints all theme names and exits;
--theme random picks a random theme at all generation time
- themes.go: updated registry with plasma/volcano replacing minimal/paper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/generator/shared.go')
| -rw-r--r-- | internal/generator/shared.go | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/internal/generator/shared.go b/internal/generator/shared.go index eed4de3..12a91f4 100644 --- a/internal/generator/shared.go +++ b/internal/generator/shared.go @@ -3,13 +3,12 @@ package generator // navDefs is appended to every theme template when parsing. // It defines three named sub-templates shared across all themes: // - "navhints" — keyboard shortcut hint bar HTML -// - "navmodal" — full-screen expanded-post modal HTML -// - "navscript" — keyboard navigation JavaScript +// - "navmodal" — full-screen expanded-post modal HTML + image-sizing CSS +// - "navscript" — keyboard navigation JavaScript with distinct sounds per action // // Each theme calls {{template "navhints" .}}, {{template "navmodal" .}}, and // {{template "navscript" .}} at the appropriate points in its HTML. -// All CSS for these elements (colours, borders, backdrop) lives in each theme -// so themes remain self-contained and independently styled. +// All theme-specific CSS lives in each theme file so themes stay self-contained. const navDefs = ` {{define "navhints"}} <div class="nav-hints" aria-label="keyboard shortcuts"> @@ -21,6 +20,12 @@ const navDefs = ` {{end}} {{define "navmodal"}} +<style> +/* Thumbnail sizing in list view; modal overrides to full width so images + appear larger when a post is expanded with Enter. */ +.post-image { max-height:220px; max-width:100%; object-fit:cover; cursor:pointer; } +#post-modal .post-image { max-height:none; width:100%; max-width:100%; object-fit:contain; cursor:default; } +</style> <div class="post-modal" id="post-modal"> <div class="modal-inner"> <button class="modal-close" onclick="closeModal()">[ ESC ] CLOSE</button> @@ -51,8 +56,7 @@ const navDefs = ` playNavSound(); } - // playNavSound generates a short beep via the Web Audio API. - // A fresh AudioContext per call avoids state issues across navigations. + // playNavSound: short low beep for post selection (j/k navigation). function playNavSound() { try { const ctx = new (window.AudioContext || window.webkitAudioContext)(); @@ -60,21 +64,55 @@ const navDefs = ` const gain = ctx.createGain(); osc.connect(gain); gain.connect(ctx.destination); osc.frequency.value = 220; osc.type = 'sine'; - gain.gain.setValueAtTime(0.15, ctx.currentTime); + gain.gain.setValueAtTime(0.12, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.08); osc.start(ctx.currentTime); osc.stop(ctx.currentTime + 0.08); } catch (_) {} } + // playOpenSound: bright ascending chime when modal opens (Enter key). + function playOpenSound() { + try { + const ctx = new (window.AudioContext || window.webkitAudioContext)(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); gain.connect(ctx.destination); + osc.type = 'triangle'; + osc.frequency.setValueAtTime(440, ctx.currentTime); + osc.frequency.exponentialRampToValueAtTime(880, ctx.currentTime + 0.14); + gain.gain.setValueAtTime(0.10, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.20); + osc.start(ctx.currentTime); osc.stop(ctx.currentTime + 0.20); + } catch (_) {} + } + + // playCloseSound: descending sweep when modal closes (Esc key). + function playCloseSound() { + try { + const ctx = new (window.AudioContext || window.webkitAudioContext)(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); gain.connect(ctx.destination); + osc.type = 'sine'; + osc.frequency.setValueAtTime(440, ctx.currentTime); + osc.frequency.exponentialRampToValueAtTime(110, ctx.currentTime + 0.15); + gain.gain.setValueAtTime(0.10, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.18); + osc.start(ctx.currentTime); osc.stop(ctx.currentTime + 0.18); + } catch (_) {} + } + function openModal() { if (currentIndex < 0) return; document.getElementById('modal-content').innerHTML = posts[currentIndex].querySelector('.post-text').innerHTML; document.getElementById('post-modal').classList.add('active'); + playOpenSound(); } function closeModal() { document.getElementById('post-modal').classList.remove('active'); + playCloseSound(); } document.addEventListener('keydown', function(e) { |
