From 3019f7ffda7d7c82cfd8b31ea7397b0ab528ec65 Mon Sep 17 00:00:00 2001
From: Solstice <solstice@local>
Date: Tue, 9 Jun 2026 00:52:52 -0700
Subject: feat: ambient sound engine and volume controls

---
 src/components/AmbientControl.tsx | 98 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 src/components/AmbientControl.tsx

(limited to 'src/components/AmbientControl.tsx')

diff --git a/src/components/AmbientControl.tsx b/src/components/AmbientControl.tsx
new file mode 100644
index 0000000..5b5017a
--- /dev/null
+++ b/src/components/AmbientControl.tsx
@@ -0,0 +1,98 @@
+import { ChangeEvent } from 'react';
+import { useAudioStore, type AmbientSound } from '../store/audioStore';
+
+const SOUND_OPTIONS: Array<{ value: AmbientSound; label: string }> = [
+  { value: 'none', label: 'Silent' },
+  { value: 'rain', label: 'Rain' },
+  { value: 'cafe', label: 'Cafe' },
+  { value: 'white_noise', label: 'White Noise' },
+];
+
+export function AmbientControl() {
+  const { available, sound, volume, setSound, setVolume } = useAudioStore();
+
+  const handleSoundChange = async (event: ChangeEvent<HTMLSelectElement>) => {
+    await setSound(event.target.value as AmbientSound);
+  };
+
+  const handleVolumeChange = async (event: ChangeEvent<HTMLInputElement>) => {
+    await setVolume(Number(event.target.value));
+  };
+
+  return (
+    <div
+      style={{
+        display: 'flex',
+        alignItems: 'center',
+        gap: '12px',
+        padding: '8px 10px',
+        border: '1px solid var(--line-2)',
+        borderRadius: 'var(--r-3)',
+        background: 'rgba(17, 21, 28, 0.85)',
+        boxShadow: 'var(--shadow-1)',
+      }}
+    >
+      <div style={{ display: 'flex', flexDirection: 'column', gap: '2px', minWidth: '90px' }}>
+        <span className="eyebrow" style={{ letterSpacing: '0.14em' }}>
+          Ambient
+        </span>
+        <span
+          style={{
+            fontFamily: 'var(--font-sans)',
+            fontSize: '12px',
+            color: available ? 'var(--fg-3)' : 'var(--negative)',
+          }}
+        >
+          {available ? 'Looping background audio' : 'Audio unavailable'}
+        </span>
+      </div>
+
+      <select
+        value={sound}
+        onChange={handleSoundChange}
+        disabled={!available}
+        style={{
+          fontFamily: 'var(--font-sans)',
+          fontSize: '13px',
+          color: available ? 'var(--fg-1)' : 'var(--fg-4)',
+          background: 'var(--ink-3)',
+          border: '1px solid var(--line-2)',
+          borderRadius: 'var(--r-2)',
+          padding: '6px 10px',
+          outline: 'none',
+          minWidth: '132px',
+        }}
+      >
+        {SOUND_OPTIONS.map((option) => (
+          <option key={option.value} value={option.value}>
+            {option.label}
+          </option>
+        ))}
+      </select>
+
+      <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+        <input
+          type="range"
+          min={0}
+          max={1}
+          step={0.05}
+          value={volume}
+          onChange={handleVolumeChange}
+          disabled={!available}
+          style={{ width: '112px', accentColor: 'var(--brass)' }}
+        />
+        <span
+          style={{
+            fontFamily: 'var(--font-mono)',
+            fontSize: '12px',
+            color: available ? 'var(--fg-2)' : 'var(--fg-4)',
+            width: '36px',
+            textAlign: 'right',
+          }}
+        >
+          {Math.round(volume * 100)}%
+        </span>
+      </div>
+    </div>
+  );
+}
-- 
cgit v1.3-2-g0d8e

