summaryrefslogtreecommitdiff
path: root/internal/generator/templates
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-16 09:35:31 +0300
committerPaul Buetow <paul@buetow.org>2026-05-16 09:35:31 +0300
commit1b24076788868f50812468b1bf4bb0ae86214e8c (patch)
tree389fd715b5c27e0fe036f6c123b8d09e3872da1c /internal/generator/templates
parentfbac3d13a575a410c2ee3f49418bf4b462544b4f (diff)
Add theme background musicv0.16.0
Diffstat (limited to 'internal/generator/templates')
-rw-r--r--internal/generator/templates/embed.go3
-rw-r--r--internal/generator/templates/shared/nav.tmpl61
-rw-r--r--internal/generator/templates/shared/shared.css53
-rw-r--r--internal/generator/templates/shared/shared.js224
-rw-r--r--internal/generator/templates/themes/aurora/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/aurora/ambient.oggbin0 -> 1396111 bytes
-rw-r--r--internal/generator/templates/themes/aurora/sounds.json8
-rw-r--r--internal/generator/templates/themes/aurora/theme.css2
-rw-r--r--internal/generator/templates/themes/biomech/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/biomech/ambient.oggbin0 -> 1317802 bytes
-rw-r--r--internal/generator/templates/themes/biomech/sounds.json8
-rw-r--r--internal/generator/templates/themes/biomech/theme.css2
-rw-r--r--internal/generator/templates/themes/brutalist/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/brutalist/ambient.oggbin0 -> 1428440 bytes
-rw-r--r--internal/generator/templates/themes/brutalist/sounds.json8
-rw-r--r--internal/generator/templates/themes/brutalist/theme.css2
-rw-r--r--internal/generator/templates/themes/cathedral/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/cathedral/ambient.oggbin0 -> 1048852 bytes
-rw-r--r--internal/generator/templates/themes/cathedral/sounds.json8
-rw-r--r--internal/generator/templates/themes/cathedral/theme.css2
-rw-r--r--internal/generator/templates/themes/cosmos/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/cosmos/ambient.oggbin0 -> 2706024 bytes
-rw-r--r--internal/generator/templates/themes/cosmos/sounds.json8
-rw-r--r--internal/generator/templates/themes/cosmos/theme.css2
-rw-r--r--internal/generator/templates/themes/dos/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/dos/ambient.oggbin0 -> 1039452 bytes
-rw-r--r--internal/generator/templates/themes/dos/sounds.json8
-rw-r--r--internal/generator/templates/themes/dos/theme.css2
-rw-r--r--internal/generator/templates/themes/matrix/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/matrix/ambient.oggbin0 -> 276371 bytes
-rw-r--r--internal/generator/templates/themes/matrix/sounds.json8
-rw-r--r--internal/generator/templates/themes/matrix/theme.css2
-rw-r--r--internal/generator/templates/themes/neon/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/neon/ambient.oggbin0 -> 3565740 bytes
-rw-r--r--internal/generator/templates/themes/neon/sounds.json8
-rw-r--r--internal/generator/templates/themes/noir/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/noir/ambient.oggbin0 -> 2440360 bytes
-rw-r--r--internal/generator/templates/themes/noir/sounds.json8
-rw-r--r--internal/generator/templates/themes/noir/theme.css2
-rw-r--r--internal/generator/templates/themes/nukem/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/nukem/ambient.oggbin0 -> 691008 bytes
-rw-r--r--internal/generator/templates/themes/nukem/sounds.json8
-rw-r--r--internal/generator/templates/themes/nukem/theme.css2
-rw-r--r--internal/generator/templates/themes/ocean/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/ocean/ambient.oggbin0 -> 2313143 bytes
-rw-r--r--internal/generator/templates/themes/ocean/sounds.json8
-rw-r--r--internal/generator/templates/themes/ocean/theme.css2
-rw-r--r--internal/generator/templates/themes/plasma/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/plasma/ambient.oggbin0 -> 1949772 bytes
-rw-r--r--internal/generator/templates/themes/plasma/sounds.json8
-rw-r--r--internal/generator/templates/themes/plasma/theme.css2
-rw-r--r--internal/generator/templates/themes/retro/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/retro/ambient.oggbin0 -> 1937080 bytes
-rw-r--r--internal/generator/templates/themes/retro/sounds.json8
-rw-r--r--internal/generator/templates/themes/retro/theme.css2
-rw-r--r--internal/generator/templates/themes/retrofuture/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/retrofuture/ambient.oggbin0 -> 500879 bytes
-rw-r--r--internal/generator/templates/themes/retrofuture/sounds.json8
-rw-r--r--internal/generator/templates/themes/retrofuture/theme.css2
-rw-r--r--internal/generator/templates/themes/spaceage/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/spaceage/ambient.oggbin0 -> 477361 bytes
-rw-r--r--internal/generator/templates/themes/spaceage/sounds.json8
-rw-r--r--internal/generator/templates/themes/spaceage/theme.css2
-rw-r--r--internal/generator/templates/themes/surveillance/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/surveillance/ambient.oggbin0 -> 148158 bytes
-rw-r--r--internal/generator/templates/themes/surveillance/sounds.json8
-rw-r--r--internal/generator/templates/themes/surveillance/theme.css2
-rw-r--r--internal/generator/templates/themes/synthwave/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/synthwave/ambient.oggbin0 -> 655778 bytes
-rw-r--r--internal/generator/templates/themes/synthwave/sounds.json8
-rw-r--r--internal/generator/templates/themes/synthwave/theme.css2
-rw-r--r--internal/generator/templates/themes/terminal/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/terminal/ambient.oggbin0 -> 888400 bytes
-rw-r--r--internal/generator/templates/themes/terminal/sounds.json8
-rw-r--r--internal/generator/templates/themes/terminal/theme.css2
-rw-r--r--internal/generator/templates/themes/tropicale/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/tropicale/ambient.oggbin0 -> 363392 bytes
-rw-r--r--internal/generator/templates/themes/tropicale/sounds.json8
-rw-r--r--internal/generator/templates/themes/tropicale/theme.css2
-rw-r--r--internal/generator/templates/themes/volcano/MUSIC_LICENSE.txt7
-rw-r--r--internal/generator/templates/themes/volcano/ambient.oggbin0 -> 977074 bytes
-rw-r--r--internal/generator/templates/themes/volcano/sounds.json8
-rw-r--r--internal/generator/templates/themes/volcano/theme.css2
83 files changed, 598 insertions, 81 deletions
diff --git a/internal/generator/templates/embed.go b/internal/generator/templates/embed.go
index 56fc673..191f4ad 100644
--- a/internal/generator/templates/embed.go
+++ b/internal/generator/templates/embed.go
@@ -20,6 +20,7 @@ import (
// theme.js — required, always present
// meta.json — required, always present
// sounds.json — required, always present
+// ambient.ogg — optional, background music loop
// <Family-Weight>.woff2 — optional, one or more self-hosted web fonts
// <Family-Weight>.woff — optional, fallback / non-woff2 web fonts
// FONT_LICENSE.txt — required iff any font file is present;
@@ -34,7 +35,7 @@ import (
// match at least one file. When you introduce a new font extension
// that no other theme uses yet, append the matching glob here.
//
-//go:embed shell.tmpl shared/*.tmpl shared/shared.css shared/shared.js themes/*/theme.css themes/*/theme.js themes/*/meta.json themes/*/sounds.json themes/*/*.woff themes/*/*.woff2 themes/*/FONT_LICENSE.txt
+//go:embed shell.tmpl shared/*.tmpl shared/shared.css shared/shared.js themes/*/theme.css themes/*/theme.js themes/*/meta.json themes/*/sounds.json themes/*/*.ogg themes/*/*.woff themes/*/*.woff2 themes/*/FONT_LICENSE.txt themes/*/MUSIC_LICENSE.txt
var FS embed.FS
// themeStandardFiles lists the per-theme files that have dedicated
diff --git a/internal/generator/templates/shared/nav.tmpl b/internal/generator/templates/shared/nav.tmpl
index b04b160..9759761 100644
--- a/internal/generator/templates/shared/nav.tmpl
+++ b/internal/generator/templates/shared/nav.tmpl
@@ -44,38 +44,65 @@
{{end}}
{{define "navhints"}}
-<div class="nav-hints" role="region" aria-label="Keyboard shortcuts">
+<div class="nav-hints" role="region" aria-label="Controls and shortcuts">
<div class="nav-hints-row nav-hints-nav">
<span class="nav-hints-label">nav</span>
- <span><kbd>j</kbd><kbd>k</kbd><kbd>↑</kbd><kbd>↓</kbd> post</span>
- <span><kbd>h</kbd><kbd>l</kbd><kbd>←</kbd><kbd>→</kbd> page</span>
- <span><kbd>PgUp</kbd><kbd>PgDn</kbd> scroll</span>
- <span><kbd>Enter</kbd> open</span>
- <span><kbd>Esc</kbd> close</span>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="prev-post" aria-label="Previous post">
+ <i class="fas fa-arrow-up" aria-hidden="true"></i><kbd>j</kbd><kbd>↑</kbd><span class="sno-btn-text">post</span>
+ </button>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="next-post" aria-label="Next post">
+ <i class="fas fa-arrow-down" aria-hidden="true"></i><kbd>k</kbd><kbd>↓</kbd><span class="sno-btn-text">post</span>
+ </button>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="prev-page" aria-label="Previous page">
+ <i class="fas fa-arrow-left" aria-hidden="true"></i><kbd>h</kbd><kbd>←</kbd><span class="sno-btn-text">page</span>
+ </button>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="next-page" aria-label="Next page">
+ <i class="fas fa-arrow-right" aria-hidden="true"></i><kbd>l</kbd><kbd>→</kbd><span class="sno-btn-text">page</span>
+ </button>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="open" aria-label="Open selected post">
+ <i class="fas fa-expand" aria-hidden="true"></i><kbd>Enter</kbd><span class="sno-btn-text">open</span>
+ </button>
+ <button type="button" class="nav-fx-button sno-nav-btn" data-sno-nav="close" aria-label="Close modal">
+ <i class="fas fa-compress" aria-hidden="true"></i><kbd>Esc</kbd><span class="sno-btn-text">close</span>
+ </button>
</div>
<div class="nav-hints-row nav-hints-fx">
<span class="nav-hints-label">fx</span>
- <button type="button" class="nav-fx-button" data-sno-fx="wild" aria-pressed="false" aria-label="Toggle wild mode"><kbd>w</kbd> wild</button>
- <button type="button" class="nav-fx-button" data-sno-fx="crt" aria-pressed="false" aria-label="Toggle CRT effect"><kbd>c</kbd> crt</button>
- <button type="button" class="nav-fx-button" data-sno-fx="ghost" aria-pressed="false" aria-label="Toggle ghost mode"><kbd>g</kbd> ghost</button>
- <button type="button" class="nav-fx-button" data-sno-fx="blank" aria-pressed="false" aria-label="Toggle blank mode"><kbd>b</kbd> blank</button>
- <button type="button" class="nav-fx-button" data-sno-fx="ambient" aria-pressed="false" aria-label="Start or pause ambient music"><kbd>p</kbd> music</button>
- <button type="button" class="nav-fx-button" data-sno-fx="flash" aria-label="Trigger flash effect"><kbd>f</kbd> flash</button>
- <button type="button" class="nav-fx-button" data-sno-fx="scatter" aria-label="Trigger scatter effect"><kbd>x</kbd> scatter</button>
- <span class="nav-hints-spacer"><kbd>t</kbd> theme</span>
+ <button type="button" class="nav-fx-button" data-sno-fx="wild" aria-pressed="false" aria-label="Toggle wild mode">
+ <i class="fas fa-bolt" aria-hidden="true"></i><kbd>w</kbd><span class="sno-btn-text">wild</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="crt" aria-pressed="false" aria-label="Toggle CRT effect">
+ <i class="fas fa-tv" aria-hidden="true"></i><kbd>c</kbd><span class="sno-btn-text">crt</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="ghost" aria-pressed="false" aria-label="Toggle ghost mode">
+ <i class="fas fa-ghost" aria-hidden="true"></i><kbd>g</kbd><span class="sno-btn-text">ghost</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="blank" aria-pressed="false" aria-label="Toggle blank mode">
+ <i class="fas fa-eye-slash" aria-hidden="true"></i><kbd>b</kbd><span class="sno-btn-text">blank</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="ambient" aria-pressed="false" aria-label="Start or pause ambient music">
+ <i class="fas fa-music" aria-hidden="true"></i><kbd>p</kbd><span class="sno-btn-text">music</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="flash" aria-label="Trigger flash effect">
+ <i class="fas fa-camera" aria-hidden="true"></i><kbd>f</kbd><span class="sno-btn-text">flash</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="scatter" aria-label="Trigger scatter effect">
+ <i class="fas fa-wind" aria-hidden="true"></i><kbd>x</kbd><span class="sno-btn-text">scatter</span>
+ </button>
+ <button type="button" class="nav-fx-button" data-sno-fx="theme" aria-label="Random theme">
+ <i class="fas fa-palette" aria-hidden="true"></i><kbd>t</kbd><span class="sno-btn-text">theme</span>
+ </button>
<select id="sno-theme-select" class="nav-fx-button" aria-label="Theme"></select>
</div>
</div>
{{end}}
-
{{define "navmodal"}}
<div class="post-modal" id="post-modal" role="dialog" aria-modal="true" aria-label="Expanded post">
<div class="modal-inner">
- <button class="modal-close" onclick="closeModal()">[ ESC ] CLOSE</button>
+ <button class="modal-close" onclick="closeModal()" aria-label="Close post"><i class="fas fa-times" aria-hidden="true"></i> CLOSE</button>
<div id="modal-content"></div>
<div class="sno-scroll-end" id="sno-scroll-end" aria-hidden="true"></div>
</div>
</div>
{{end}}
-
diff --git a/internal/generator/templates/shared/shared.css b/internal/generator/templates/shared/shared.css
index 5fab9ac..35f4aef 100644
--- a/internal/generator/templates/shared/shared.css
+++ b/internal/generator/templates/shared/shared.css
@@ -21,10 +21,12 @@
gap:clamp(16px,4vw,48px); }
/* Flex column layout: let #post-content shrink so overflow-y scrolls; footer stays visible */
#post-content.content { min-height:0; }
-.page-nav-footer { flex-shrink:0; width:100%; box-sizing:border-box; }
+ .page-nav-footer { flex-shrink:0; width:100%; box-sizing:border-box; }
.page-nav-footer .page-nav { margin:0; }
/* ~Half-height footer bar vs default .page-nav padding */
.page-nav-footer .page-nav a { padding-top:4px; padding-bottom:4px; }
+/* Reorganized nav-hints shared layout */
+.nav-hints { display:flex; flex-direction:column; gap:0; padding:0 !important; }
/* Shared nav FX keyframes — themes apply these classes for brief effects */
/* Modal open: post zooms/flies into the modal overlay */
@keyframes sno-modal-zoom { 0%{transform:scale(0.82) translateY(18px);opacity:0} 60%{transform:scale(1.02) translateY(-3px);opacity:1} 100%{transform:scale(1) translateY(0);opacity:1} }
@@ -947,9 +949,56 @@ body[data-sno-theme="matrix"] .post-text img,
body[data-sno-theme="terminal"] .post-text img,
body[data-sno-theme="dos"] .post-text img { animation:sno-matrix-decode 0.8s ease-out both; }
-/* Mobile touch-target and padding overrides */
+/* Mobile touch-target and layout overrides */
@media(max-width:640px) {
+ .nav-hints { padding:4px 14px !important; gap:0; position:sticky; top:0; z-index:25; }
+ /* Remove navigation row on mobile */
+ .nav-hints-nav { display:none !important; }
+ /* FX row: single horizontal line of icon-only tiles */
+ .nav-hints-fx { display:flex !important; flex-direction:row !important;
+ flex-wrap:nowrap; padding:0; gap:4px; overflow-x:auto;
+ -webkit-overflow-scrolling:touch; scrollbar-width:none; }
+ .nav-hints-fx::-webkit-scrollbar { display:none; }
+ .nav-hints-label, .nav-hints-spacer,
+ .nav-hints-row kbd, .sno-btn-text { display:none !important; }
+ .nav-fx-button {
+ flex:1 1 auto; min-height:44px; min-width:36px; max-width:none;
+ justify-content:center; align-items:center; gap:0; padding:0;
+ font-size:0; width:auto;
+ }
+ .nav-fx-button i, .nav-fx-button i.fas { font-size:1rem; display:inline-block; }
+ /* Suppress the theme select dropdown in the bar */
+ .nav-hints-fx #sno-theme-select { display:none !important; }
.modal-inner { padding:20px 14px !important; }
.transmit-btn { padding-top:11px !important; padding-bottom:11px !important; min-height:44px !important; }
.page-nav a { padding-top:10px !important; padding-bottom:10px !important; min-height:44px !important; }
+ /* Floating action button for quick one-handed control */
+ #sno-fab {
+ position:fixed; right:14px; bottom:14px; z-index:5001;
+ width:56px; height:56px; border-radius:50%;
+ border:0; background:rgba(0,0,0,0.75); color:#fff;
+ font-size:1.2rem; cursor:pointer; display:flex; align-items:center; justify-content:center;
+ box-shadow:0 4px 16px rgba(0,0,0,0.48); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
+ transition:transform 0.18s ease, box-shadow 0.18s ease;
+ -webkit-tap-highlight-color:transparent;
+ }
+ #sno-fab:focus-visible { outline:2px solid #fff; outline-offset:3px; }
+ #sno-fab:active { transform:scale(0.94); }
+ #sno-fab .sno-fab-menu {
+ position:absolute; bottom:64px; right:0;
+ display:flex; flex-direction:column; gap:10px;
+ opacity:0; pointer-events:none; transform:translateY(6px);
+ transition:opacity 0.2s ease, transform 0.2s ease;
+ }
+ #sno-fab.open .sno-fab-menu { opacity:1; pointer-events:auto; transform:translateY(0); }
+ #sno-fab .sno-fab-menu button {
+ width:48px; height:48px; border-radius:50%;
+ border:0; background:rgba(0,0,0,0.72); color:#fff;
+ font-size:1.05rem; display:flex; align-items:center; justify-content:center;
+ box-shadow:0 2px 10px rgba(0,0,0,0.35); backdrop-filter:blur(4px);
+ -webkit-tap-highlight-color:transparent;
+ }
+ #sno-fab .sno-fab-menu button:active { transform:scale(0.92); }
+ /* Swipe hint for first-time mobile visitors */
+ #sno-swipe-hint { display:flex; }
}
diff --git a/internal/generator/templates/shared/shared.js b/internal/generator/templates/shared/shared.js
index 09de580..1e29831 100644
--- a/internal/generator/templates/shared/shared.js
+++ b/internal/generator/templates/shared/shared.js
@@ -471,6 +471,9 @@
var melodyIndex = 0;
var drumTimer = null;
var drumIndex = 0;
+ var ambientAudio = null;
+ var ambientAudioSrc = '';
+ var ambientAudioFadeTimer = null;
function wildifyPreset(base) {
if (!base) return base;
@@ -493,9 +496,108 @@
var ambient = SNONUX_SOUNDS.ambient;
if (!ambient) return null;
var base = isWild ? (ambient.wild || ambient.normal) : ambient.normal;
+ if (base && !base.file && ambient.normal && ambient.normal.file) {
+ var inherited = {};
+ for (var k in base) inherited[k] = base[k];
+ inherited.file = ambient.normal.file;
+ if (inherited.volume == null && ambient.normal.volume != null) inherited.volume = ambient.normal.volume;
+ base = inherited;
+ }
return isWild ? wildifyPreset(base) : base;
}
+ function resolveAmbientFile(file) {
+ if (!file) return '';
+ if (/^(https?:)?\/\//.test(file) || file.charAt(0) === '/') return file;
+ if (file.indexOf('themes/') === 0) return file;
+ return 'themes/' + snonuxDetectThemeName() + '/' + file;
+ }
+
+ function ambientFileVolume(preset) {
+ var v = preset && preset.volume != null ? preset.volume : 0.46;
+ if (isWild) v = Math.min(v * 1.08, 0.8);
+ return Math.max(0, Math.min(v, 0.8));
+ }
+
+ function clearAmbientAudioFade() {
+ if (ambientAudioFadeTimer) {
+ clearInterval(ambientAudioFadeTimer);
+ ambientAudioFadeTimer = null;
+ }
+ }
+
+ function fadeAmbientAudioTo(target, duration, done) {
+ if (!ambientAudio) {
+ if (done) done();
+ return;
+ }
+ clearAmbientAudioFade();
+ var start = ambientAudio.volume || 0;
+ var dur = Math.max(duration || 0.35, 0.01);
+ var started = Date.now();
+ ambientAudioFadeTimer = setInterval(function() {
+ if (!ambientAudio) {
+ clearAmbientAudioFade();
+ if (done) done();
+ return;
+ }
+ var t = Math.min((Date.now() - started) / (dur * 1000), 1);
+ ambientAudio.volume = start + (target - start) * t;
+ if (t >= 1) {
+ clearAmbientAudioFade();
+ if (done) done();
+ }
+ }, 30);
+ }
+
+ function stopFileAudio(resetPosition) {
+ clearAmbientAudioFade();
+ if (!ambientAudio) return;
+ try {
+ ambientAudio.pause();
+ ambientAudio.volume = 0;
+ if (resetPosition) ambientAudio.currentTime = 0;
+ } catch (_) {}
+ }
+
+ function startFileAudio(preset) {
+ var src = resolveAmbientFile(preset.file);
+ if (!src) return;
+ currentPreset = preset;
+
+ if (!ambientAudio || ambientAudioSrc !== src) {
+ if (ambientAudio) {
+ try { ambientAudio.pause(); } catch (_) {}
+ }
+ ambientAudio = new Audio(src);
+ ambientAudio.loop = true;
+ ambientAudio.preload = 'auto';
+ ambientAudio.volume = 0.22;
+ ambientAudioSrc = src;
+ }
+
+ isPlaying = true;
+ var target = ambientFileVolume(preset);
+ if (ambientAudio.volume < 0.18) ambientAudio.volume = Math.min(target, 0.22);
+ var playResult;
+ try {
+ playResult = ambientAudio.play();
+ } catch (_) {
+ isPlaying = false;
+ return;
+ }
+ if (playResult && playResult.then) {
+ playResult.then(function() {
+ if (!isPlaying) return;
+ fadeAmbientAudioTo(target, 0.16);
+ }).catch(function() {
+ isPlaying = false;
+ });
+ } else {
+ fadeAmbientAudioTo(target, 0.16);
+ }
+ }
+
function ensureCtx() {
if (!ctx) {
ctx = new (window.AudioContext || window.webkitAudioContext)();
@@ -732,6 +834,7 @@
stopDrums();
stopDrones();
stopNoise();
+ stopFileAudio(true);
}
// ── drum synthesizer ──────────────────────────────────────────────
@@ -849,6 +952,10 @@
var preset = getPreset();
if (!preset) return;
currentPreset = preset;
+ if (preset.file) {
+ startFileAudio(preset);
+ return;
+ }
ensureCtx();
// Begin scheduling only once the AudioContext is running.
@@ -887,7 +994,12 @@
function pauseEngine() {
isPlaying = false;
- var fadeOut = currentPreset && currentPreset.release != null ? currentPreset.release : 0.5;
+ var fadeOut = ambientAudio ? 0.5 : (currentPreset && currentPreset.release != null ? currentPreset.release : 0.5);
+ if (ambientAudio) {
+ fadeAmbientAudioTo(0, fadeOut, function() {
+ if (!isPlaying) stopFileAudi