klaudio 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/package.json +1 -1
- package/src/cli.js +21 -3
package/README.md
CHANGED
|
@@ -11,9 +11,10 @@ npx klaudio
|
|
|
11
11
|
The interactive installer walks you through:
|
|
12
12
|
|
|
13
13
|
1. **Choose scope** — install globally (`~/.claude`) or per-project (`.claude/`), or launch the **Music Player**
|
|
14
|
-
2. **Pick a source** — use a built-in preset, scan your Steam & Epic Games library
|
|
14
|
+
2. **Pick a source** — use a built-in preset, OS system sounds, scan your Steam & Epic Games library, or provide custom files
|
|
15
15
|
3. **Preview & assign** — listen to sounds and assign them to events (tab to switch between events)
|
|
16
|
-
4. **
|
|
16
|
+
4. **Toggle voice summary** — enable TTS to hear a spoken summary when tasks complete
|
|
17
|
+
5. **Install** — writes Claude Code hooks to your `settings.json`
|
|
17
18
|
|
|
18
19
|
## Sound Sources
|
|
19
20
|
|
|
@@ -21,6 +22,10 @@ The interactive installer walks you through:
|
|
|
21
22
|
|
|
22
23
|
Ready-made sound packs (Retro 8-bit, Minimal Zen, Sci-Fi Terminal, Victory Fanfare) that work out of the box.
|
|
23
24
|
|
|
25
|
+
### System Sounds
|
|
26
|
+
|
|
27
|
+
Use your OS built-in notification sounds (Windows Media, macOS system sounds, Linux sound themes).
|
|
28
|
+
|
|
24
29
|
### Game Sound Scanner
|
|
25
30
|
|
|
26
31
|
Scans your local Steam and Epic Games libraries for audio files:
|
|
@@ -47,15 +52,25 @@ Play longer game tracks (90s–4min) as background music while you code:
|
|
|
47
52
|
|
|
48
53
|
Requires previously extracted game audio (use "Scan local games" first).
|
|
49
54
|
|
|
55
|
+
## Voice Summary (TTS)
|
|
56
|
+
|
|
57
|
+
When enabled, klaudio speaks a short summary of what Claude did after playing the task-complete sound. Uses [Piper](https://github.com/rhasspy/piper) for fast, offline neural text-to-speech (auto-downloaded on first use, ~40MB total).
|
|
58
|
+
|
|
59
|
+
- Toggle with `t` on the scope or confirm screen
|
|
60
|
+
- Reads the first sentence of Claude's last message
|
|
61
|
+
- Uses the `en_GB-alan-medium` voice (British male)
|
|
62
|
+
- Hooks receive data via stdin from Claude Code — no extra setup needed
|
|
63
|
+
|
|
50
64
|
## Features
|
|
51
65
|
|
|
52
66
|
- **Auto-preview** — sounds play automatically as you browse the list (toggle with `p`)
|
|
53
67
|
- **Multi-game selection** — pick sounds from different games, tab between events
|
|
54
68
|
- **Category filtering** — drill into voice, ambient, SFX, etc. when a game has enough variety
|
|
55
69
|
- **Type-to-filter** — start typing to narrow down long lists
|
|
70
|
+
- **Duration filter** — type `<10s`, `>5s`, `<=3s` etc. to filter by audio length
|
|
56
71
|
- **10-second clamp** — long sounds are processed with ffmpeg: silence stripped, fade out baked in
|
|
57
72
|
- **Background scanning** — game list updates live as directories are scanned
|
|
58
|
-
- **
|
|
73
|
+
- **Re-apply current sounds** — re-running the installer shows your current selections with a quick re-apply option
|
|
59
74
|
|
|
60
75
|
## Events
|
|
61
76
|
|
|
@@ -74,7 +89,8 @@ npx klaudio --uninstall
|
|
|
74
89
|
|
|
75
90
|
- Node.js 18+ (Claude Code already requires this)
|
|
76
91
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed
|
|
77
|
-
- For packed audio extraction: internet connection (vgmstream-cli
|
|
92
|
+
- For packed audio extraction: internet connection (vgmstream-cli downloaded automatically)
|
|
93
|
+
- For voice summaries: internet connection on first use (Piper TTS downloaded automatically)
|
|
78
94
|
- For best playback with fade effects: [ffmpeg/ffplay](https://ffmpeg.org/) on PATH (falls back to native players)
|
|
79
95
|
|
|
80
96
|
> **Note:** Currently only tested on Windows. macOS and Linux support is planned but not yet verified.
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -169,8 +169,13 @@ const ScopeScreen = ({ onNext, onMusic, tts, onToggleTts }) => {
|
|
|
169
169
|
};
|
|
170
170
|
|
|
171
171
|
// ── Screen: Preset ──────────────────────────────────────────────
|
|
172
|
-
const PresetScreen = ({ onNext, onBack }) => {
|
|
172
|
+
const PresetScreen = ({ existingSounds, onNext, onReapply, onBack }) => {
|
|
173
|
+
const hasExisting = existingSounds && Object.values(existingSounds).some(Boolean);
|
|
173
174
|
const items = [
|
|
175
|
+
...(hasExisting ? [{
|
|
176
|
+
label: "✓ Re-apply current sounds — update config with current selections",
|
|
177
|
+
value: "_reapply",
|
|
178
|
+
}] : []),
|
|
174
179
|
...Object.entries(PRESETS).map(([id, p]) => ({
|
|
175
180
|
label: `${p.icon} ${p.name} — ${p.description}`,
|
|
176
181
|
value: id,
|
|
@@ -180,18 +185,29 @@ const PresetScreen = ({ onNext, onBack }) => {
|
|
|
180
185
|
{ label: "🕹️ Scan your games library — find sounds from Steam & Epic Games", value: "_scan" },
|
|
181
186
|
{ label: "📁 Custom files — provide your own sound files", value: "_custom" },
|
|
182
187
|
];
|
|
183
|
-
const GAP_AT = Object.keys(PRESETS).length; // separator before non-preset options
|
|
188
|
+
const GAP_AT = (hasExisting ? 1 : 0) + Object.keys(PRESETS).length; // separator before non-preset options
|
|
184
189
|
const [sel, setSel] = useState(0);
|
|
185
190
|
|
|
186
191
|
useInput((input, key) => {
|
|
187
192
|
if (key.escape) onBack();
|
|
188
193
|
else if (input === "k" || key.upArrow) setSel((i) => Math.max(0, i - 1));
|
|
189
194
|
else if (input === "j" || key.downArrow) setSel((i) => Math.min(items.length - 1, i + 1));
|
|
190
|
-
else if (key.return)
|
|
195
|
+
else if (key.return) {
|
|
196
|
+
if (items[sel].value === "_reapply") onReapply();
|
|
197
|
+
else onNext(items[sel].value);
|
|
198
|
+
}
|
|
191
199
|
});
|
|
192
200
|
|
|
193
201
|
return h(Box, { flexDirection: "column" },
|
|
194
202
|
h(Text, { bold: true }, " Choose a sound preset:"),
|
|
203
|
+
hasExisting
|
|
204
|
+
? h(Box, { flexDirection: "column", marginLeft: 4, marginBottom: 1 },
|
|
205
|
+
h(Text, { dimColor: true }, "Current sounds:"),
|
|
206
|
+
...Object.entries(existingSounds).filter(([_, p]) => p).map(([eid, p]) =>
|
|
207
|
+
h(Text, { key: eid, color: "green", dimColor: true }, ` ✓ ${EVENTS[eid].name}: ${basename(p)}`),
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
: null,
|
|
195
211
|
h(Box, { flexDirection: "column", marginLeft: 2 },
|
|
196
212
|
...items.map((item, i) => h(React.Fragment, { key: item.value },
|
|
197
213
|
i === GAP_AT ? h(Text, { dimColor: true }, "\n ...or pick your own") : null,
|
|
@@ -1480,6 +1496,8 @@ const InstallApp = () => {
|
|
|
1480
1496
|
|
|
1481
1497
|
case SCREEN.PRESET:
|
|
1482
1498
|
return h(PresetScreen, {
|
|
1499
|
+
existingSounds: sounds,
|
|
1500
|
+
onReapply: () => setScreen(SCREEN.CONFIRM),
|
|
1483
1501
|
onNext: (id) => {
|
|
1484
1502
|
if (id === "_music") {
|
|
1485
1503
|
setScreen(SCREEN.MUSIC_MODE);
|