diff --git a/.project/designs/app/src/pages/AudioPackDetail.tsx b/.project/designs/app/src/pages/AudioPackDetail.tsx
index 59a07a42..b8e301bd 100644
--- a/.project/designs/app/src/pages/AudioPackDetail.tsx
+++ b/.project/designs/app/src/pages/AudioPackDetail.tsx
@@ -3,7 +3,7 @@ import { useMemo, useState } from "react";
import styled from "styled-components";
import { t } from "../theme";
import { AUDIO_PACK_BY_ID, type AudioPack } from "../data/audioPacks";
-import audioSourcesCsv from "@game-assets/audio/sources.csv?raw";
+import audioSourcesCsv from "@resources/audio/sources.csv?raw";
// ── Glob: staging directory contents (unzipped pack samples) ────────────────
//
@@ -301,7 +301,7 @@ export function AudioPackDetailPage(): React.ReactElement {
{" output_path"}{pack.source_url}#<inner_path>{""}{pack.license}{""}{pack.publisher}{""}edits-note,
then run bash tools/audio-fetch-batch.sh tools/audio-batch-NN.tsv.
The driver downloads the zip, extracts, encodes, and writes to{" "}
- public/games/age-of-dwarves/assets/audio/....
+ public/resources/audio/....
>
) : (
<>
diff --git a/.project/designs/app/src/pages/AudioPacks.tsx b/.project/designs/app/src/pages/AudioPacks.tsx
index 61588ec6..ccd4e294 100644
--- a/.project/designs/app/src/pages/AudioPacks.tsx
+++ b/.project/designs/app/src/pages/AudioPacks.tsx
@@ -2,7 +2,7 @@ import { Link } from "react-router-dom";
import styled from "styled-components";
import { t } from "../theme";
import { AUDIO_PACKS, type AudioPack, type License, type PackStatus } from "../data/audioPacks";
-import audioSourcesCsv from "@game-assets/audio/sources.csv?raw";
+import audioSourcesCsv from "@resources/audio/sources.csv?raw";
// ── Counting "files used" per pack from sources.csv ─────────────────────────
diff --git a/.project/designs/app/src/pages/AudioSystem.tsx b/.project/designs/app/src/pages/AudioSystem.tsx
index 857876c6..7c6d133b 100644
--- a/.project/designs/app/src/pages/AudioSystem.tsx
+++ b/.project/designs/app/src/pages/AudioSystem.tsx
@@ -12,7 +12,7 @@ import { t } from "../theme";
// rather than a parsed module. Keys are absolute glob-resolved paths;
// we normalise them into the manifest's `audio/...` shape below.
const REAL_OGG_URLS = import.meta.glob(
- "@game-assets/audio/**/*.ogg",
+ "@resources/audio/**/*.ogg",
{ eager: true, query: "?url", import: "default" },
) as Record;
diff --git a/.project/designs/app/src/pages/Credits.tsx b/.project/designs/app/src/pages/Credits.tsx
index ff5913b2..e95b52d1 100644
--- a/.project/designs/app/src/pages/Credits.tsx
+++ b/.project/designs/app/src/pages/Credits.tsx
@@ -2,7 +2,7 @@ import { Link } from "react-router-dom";
import styled from "styled-components";
import { t } from "../theme";
import creditsData from "@game-data/credits.json";
-import audioSourcesCsv from "@game-assets/audio/sources.csv?raw";
+import audioSourcesCsv from "@resources/audio/sources.csv?raw";
// ── Types: mirror credits.json + sources.csv ─────────────────────────────────
diff --git a/.project/designs/app/vite.config.ts b/.project/designs/app/vite.config.ts
index a46de62c..3c86e51c 100644
--- a/.project/designs/app/vite.config.ts
+++ b/.project/designs/app/vite.config.ts
@@ -8,6 +8,8 @@ export default defineConfig({
alias: {
"@game-data": path.resolve(__dirname, "../../../public/games/age-of-dwarves/data"),
"@game-assets": path.resolve(__dirname, "../../../public/games/age-of-dwarves/assets"),
+ // Shared cross-theme resources (audio lives here, not under any one game).
+ "@resources": path.resolve(__dirname, "../../../public/resources"),
"@audio-alts": path.resolve(__dirname, "../../../.local/audio-alternatives"),
"@audio-staging": path.resolve(__dirname, "../../../.local/audio-staging"),
},
@@ -26,12 +28,12 @@ export default defineConfig({
},
watch: {
// import.meta.glob bakes its result at module-eval time. When new
- // .ogg files appear under public/games/.../assets/audio after the
- // module first loaded, the glob doesn't see them and the design
- // page misses their play buttons. Telling Vite's watcher to track
- // the assets dir triggers an HMR reload of the AudioSystem module
+ // .ogg files appear under public/resources/audio after the module
+ // first loaded, the glob doesn't see them and the design page
+ // misses their play buttons. Telling Vite's watcher to track the
+ // shared audio dir triggers an HMR reload of the AudioSystem module
// when files are added/removed there, which re-evaluates the glob.
- ignored: ["!**/public/games/age-of-dwarves/assets/audio/**"],
+ ignored: ["!**/public/resources/audio/**"],
},
},
});
diff --git a/public/games/age-of-dwarves/assets/c/victory.ogg b/public/games/age-of-dwarves/assets/c/victory.ogg
deleted file mode 100644
index 85923476..00000000
Binary files a/public/games/age-of-dwarves/assets/c/victory.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/ic/golden_age.ogg b/public/games/age-of-dwarves/assets/ic/golden_age.ogg
deleted file mode 100644
index b1ed8b7c..00000000
Binary files a/public/games/age-of-dwarves/assets/ic/golden_age.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/ic/overworld_kingdoms.ogg b/public/games/age-of-dwarves/assets/ic/overworld_kingdoms.ogg
deleted file mode 100644
index 0501e2bd..00000000
Binary files a/public/games/age-of-dwarves/assets/ic/overworld_kingdoms.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/ic/victory_domination_c.ogg b/public/games/age-of-dwarves/assets/ic/victory_domination_c.ogg
deleted file mode 100644
index 1e63d4e0..00000000
Binary files a/public/games/age-of-dwarves/assets/ic/victory_domination_c.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/io/music/victory_culture_b.ogg b/public/games/age-of-dwarves/assets/io/music/victory_culture_b.ogg
deleted file mode 100644
index 291e7360..00000000
Binary files a/public/games/age-of-dwarves/assets/io/music/victory_culture_b.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/music/overworld_industry.ogg b/public/games/age-of-dwarves/assets/music/overworld_industry.ogg
deleted file mode 100644
index e1c0a375..00000000
Binary files a/public/games/age-of-dwarves/assets/music/overworld_industry.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/music/victory_culture_a.ogg b/public/games/age-of-dwarves/assets/music/victory_culture_a.ogg
deleted file mode 100644
index 5f164dbb..00000000
Binary files a/public/games/age-of-dwarves/assets/music/victory_culture_a.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/music/victory_economic_b.ogg b/public/games/age-of-dwarves/assets/music/victory_economic_b.ogg
deleted file mode 100644
index b087e212..00000000
Binary files a/public/games/age-of-dwarves/assets/music/victory_economic_b.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/o/music/victory_domination_b.ogg b/public/games/age-of-dwarves/assets/o/music/victory_domination_b.ogg
deleted file mode 100644
index a7d75f84..00000000
Binary files a/public/games/age-of-dwarves/assets/o/music/victory_domination_b.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/o/music/victory_science_b.ogg b/public/games/age-of-dwarves/assets/o/music/victory_science_b.ogg
deleted file mode 100644
index aa221c8a..00000000
Binary files a/public/games/age-of-dwarves/assets/o/music/victory_science_b.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/sic/victory_culture_c.ogg b/public/games/age-of-dwarves/assets/sic/victory_culture_c.ogg
deleted file mode 100644
index 593d0d4f..00000000
Binary files a/public/games/age-of-dwarves/assets/sic/victory_culture_c.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/udio/sfx/wonder_built_rival.ogg b/public/games/age-of-dwarves/assets/udio/sfx/wonder_built_rival.ogg
deleted file mode 100644
index b8b70204..00000000
Binary files a/public/games/age-of-dwarves/assets/udio/sfx/wonder_built_rival.ogg and /dev/null differ
diff --git a/public/games/age-of-dwarves/assets/usic/overworld_craft.ogg b/public/games/age-of-dwarves/assets/usic/overworld_craft.ogg
deleted file mode 100644
index f8480e8d..00000000
Binary files a/public/games/age-of-dwarves/assets/usic/overworld_craft.ogg and /dev/null differ
diff --git a/public/resources/audio/LICENSES.md b/public/resources/audio/LICENSES.md
index 572e6add..eec5a103 100644
--- a/public/resources/audio/LICENSES.md
+++ b/public/resources/audio/LICENSES.md
@@ -28,7 +28,6 @@ Each row records one `.ogg` shipped under `public/games/age-of-dwarves/assets/au
| `audio/music/victory_economic_b.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%231%20%5BExploration%5D%20by%20Juhani%20Junkala.zip#Exploration4 - Prairie Nights.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
| `audio/music/victory_science_a.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%231%20%5BExploration%5D%20by%20Juhani%20Junkala.zip#Exploration3 - Tha'el Mines.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
| `audio/music/victory_science_b.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%231%20%5BExploration%5D%20by%20Juhani%20Junkala.zip#Exploration6 - Tropical Island.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
-| `audio/sfx/border_expanded.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/pluck_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
| `audio/sfx/buildings/build_complete_civic.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
| `audio/sfx/buildings/build_complete_def.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/buildings/build_complete_mil.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
@@ -38,14 +37,21 @@ Each row records one `.ogg` shipped under `public/games/age-of-dwarves/assets/au
| `audio/sfx/buildings/generic_complete.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_medium_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/buildings/infrastructure_complete.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMining_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/buildings/research_complete.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_light_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/buildings/wonder_built.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/buildings/wonder_built_own.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/fanfare_0.ogg) | Spring Spring (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
+| `audio/sfx/buildings/wonder_built_rival.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-22/TP=-6+ogg 128kbps (extra-quiet for distant feel) | 2026-04-28 |
+| `audio/sfx/city/city_founded.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/bong_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
| `audio/sfx/city/city_grew.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3/LRA=11+wav→ogg 128kbps | 2026-04-27 |
| `audio/sfx/city/city_starved.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/error_004.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/city_founded.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/bong_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/combat/combat_hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_medium_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/combat/combat_started.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/combat_hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_medium_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/culture_researched.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_003.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/defeat_stinger.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
-| `audio/sfx/era_advanced.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
+| `audio/sfx/combat/unit_defeated.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
+| `audio/sfx/combat/unit_killed.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/combat/unit_victorious.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
+| `audio/sfx/era/defeat_stinger.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
+| `audio/sfx/era/era_advanced.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
+| `audio/sfx/era/golden_age_swell.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
+| `audio/sfx/era/victory_fanfare.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/fauna/apex_attack.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/80-CC0-creature-SFX_0.zip#monster_01.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/fauna/apex_death.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/80-CC0-creature-SFX_0.zip#scream_02.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/fauna/apex_hit.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/80-CC0-creature-SFX_0.zip#hurt_05.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
@@ -69,16 +75,14 @@ Each row records one `.ogg` shipped under `public/games/age-of-dwarves/assets/au
| `audio/sfx/generic/complete.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_medium_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/generic/death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactGeneric_light_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/generic/hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactGeneric_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/golden_age_swell.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/research_start.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/tick_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/tech_researched.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/turn_ended.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/minimize_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/turn_started.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/maximize_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/unit_defeated.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
-| `audio/sfx/unit_killed.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/unit_moved.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/click_004.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/unit_promoted.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_004.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
-| `audio/sfx/unit_victorious.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
+| `audio/sfx/ui/border_expanded.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/pluck_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/culture_researched.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_003.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/research_start.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/tick_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/tech_researched.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/turn_ended.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/minimize_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/turn_started.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/maximize_001.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/unit_moved.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/click_004.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
+| `audio/sfx/ui/unit_promoted.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/confirmation_004.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/civilian/death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_light_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/melee/attack_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_light_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/melee/attack_02.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_light_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
@@ -88,30 +92,26 @@ Each row records one `.ogg` shipped under `public/games/age-of-dwarves/assets/au
| `audio/sfx/units/melee/hit_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_heavy_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/melee/hit_02.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/melee/hit_03.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactMetal_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/units/melee_spawn.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/melee/spawn.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/units/ranged/death_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_light_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/ranged/fire_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactGeneric_light_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/ranged/fire_02.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactGeneric_light_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/ranged/hit_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlank_medium_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/ranged/hit_02.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlank_medium_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/units/ranged_spawn.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/ranged/spawn.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_003.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/units/siege/bombard_01.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/units/siege/bombard_02.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_heavy_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/units/siege_death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_medium_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/units/siege_hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlank_medium_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/units/support_attack.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/pluck_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-29 |
-| `audio/sfx/units/support_death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactSoft_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/units/support_hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactSoft_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/victory_fanfare.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
+| `audio/sfx/units/siege/death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlate_medium_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/siege/hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactPlank_medium_004.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/support/attack.ogg` | CC0-1.0 | [link](https://github.com/Calinou/kenney-interface-sounds/blob/master/addons/kenney_interface_sounds/pluck_002.wav) | Kenney (Calinou repackage) | loudnorm I=-16/TP=-3+wav→ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/support/death.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactSoft_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
+| `audio/sfx/units/support/hit.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactSoft_heavy_001.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/weather/blizzard.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_loops.zip#weird_01.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/weather/drought.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_loops.zip#weird_03.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/weather/heat_wave.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_loops.zip#weird_02.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
| `audio/sfx/weather/hurricane.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_loops.zip#ambient_02.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
| `audio/sfx/weather/storm.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_100_v2.zip#sfx100v2_thunder_01.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
| `audio/sfx/weather/tornado.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/sfx_loops.zip#ambient_03.ogg) | rubberduck (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-27 |
-| `audio/sfx/wonder_built.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactWood_heavy_000.ogg) | Kenney (Impact Sounds) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-29 |
-| `audio/sfx/wonder_built_own.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/fanfare_0.ogg) | Spring Spring (OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps | 2026-04-28 |
-| `audio/sfx/wonder_built_rival.ogg` | CC0-1.0 | [link](https://kenney.nl/media/pages/assets/impact-sounds/8aa7b545c9-1677589768/kenney_impact-sounds.zip#Audio/impactBell_heavy_002.ogg) | Kenney (Impact Sounds) | loudnorm I=-22/TP=-6+ogg 128kbps (extra-quiet for distant feel) | 2026-04-28 |
| `c/victory.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%235%20%5BAction%5D%20by%20Juhani%20Junkala.zip#Action3 - Preparing For Battle.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
| `ic/golden_age.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%235%20%5BAction%5D%20by%20Juhani%20Junkala.zip#Action2 - Army Approaching.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
| `ic/overworld_kingdoms.ogg` | CC0-1.0 | [link](https://opengameart.org/sites/default/files/JRPG%20Music%20Pack%20%232%20%5BTowns%5D%20by%20Juhani%20Junkala.zip#Town4 - Bazaar.ogg) | Juhani Junkala (SubspaceAudio | OpenGameArt) | loudnorm I=-16/TP=-3+ogg 128kbps |
diff --git a/src/game/engine/scenes/menus/credits.gd b/src/game/engine/scenes/menus/credits.gd
index 9eed7080..27c7e756 100644
--- a/src/game/engine/scenes/menus/credits.gd
+++ b/src/game/engine/scenes/menus/credits.gd
@@ -4,7 +4,7 @@ extends Control
## headings, each with (name — role) rows.
const CREDITS_PATH: String = "res://public/games/age-of-dwarves/data/credits.json"
-const AUDIO_SOURCES_CSV: String = "res://public/games/age-of-dwarves/assets/audio/sources.csv"
+const AUDIO_SOURCES_CSV: String = "res://public/resources/audio/sources.csv"
@onready var _title_label: Label = %TitleLabel
@onready var _content_vbox: VBoxContainer = %ContentVBox
diff --git a/src/game/engine/src/autoloads/audio_manager.gd b/src/game/engine/src/autoloads/audio_manager.gd
index 28464402..6d88b930 100644
--- a/src/game/engine/src/autoloads/audio_manager.gd
+++ b/src/game/engine/src/autoloads/audio_manager.gd
@@ -252,13 +252,14 @@ func _crossfade_to(next_player: AudioStreamPlayer, target_db: float) -> void:
func _load_stream(relative_path: String) -> AudioStream:
+ # Audio assets live in the shared cross-theme pool at
+ # `public/resources/audio/...`, not under the theme's own assets dir.
+ # Manifest paths look like `audio/sfx/ui/turn_started.ogg`.
if relative_path.is_empty():
return null
if _stream_cache.has(relative_path):
return _stream_cache[relative_path]
- var abs_path: String = ThemeAssets.resolve(relative_path)
- if abs_path.is_empty():
- return null
+ var abs_path: String = "res://public/resources/" + relative_path
if not ResourceLoader.exists(abs_path):
_stream_cache[relative_path] = null
return null
diff --git a/tools/audio-fetch-batch.sh b/tools/audio-fetch-batch.sh
index 07dd5a2c..e0df2eea 100755
--- a/tools/audio-fetch-batch.sh
+++ b/tools/audio-fetch-batch.sh
@@ -18,8 +18,8 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
-THEME="age-of-dwarves"
-ASSETS_ROOT="$REPO_ROOT/public/games/$THEME/assets"
+# Audio assets live in the shared cross-theme pool, not under any one theme.
+ASSETS_ROOT="$REPO_ROOT/public/resources"
SOURCES_CSV="$ASSETS_ROOT/audio/sources.csv"
STAGING="$REPO_ROOT/.local/audio-staging"
TODAY="$(date -u +%Y-%m-%d)"
diff --git a/tools/audio-licenses-render.py b/tools/audio-licenses-render.py
index db3ccca6..be8524aa 100755
--- a/tools/audio-licenses-render.py
+++ b/tools/audio-licenses-render.py
@@ -168,7 +168,8 @@ def load_rows(csv_path: Path) -> list[dict]:
def validate_rows(rows: list[dict], theme: str) -> list[str]:
errors: list[str] = []
- asset_root = REPO / "public" / "games" / theme / "assets"
+ # Audio is shared — lives at public/resources/audio/, not under any theme.
+ asset_root = REPO / "public" / "resources"
seen_paths: set[str] = set()
required = {"output_path", "source_url", "license", "attribution",
"edits", "added"}
@@ -217,7 +218,10 @@ def main() -> int:
)
args = parser.parse_args()
- asset_dir = REPO / "public" / "games" / args.theme / "assets" / "audio"
+ # Audio assets are shared cross-theme; LICENSES.md and sources.csv live
+ # at public/resources/audio/. The `--theme` flag is retained only for
+ # the human-readable header in the rendered file.
+ asset_dir = REPO / "public" / "resources" / "audio"
sources_csv = asset_dir / "sources.csv"
licenses_md = asset_dir / "LICENSES.md"
diff --git a/tools/audio-validate.py b/tools/audio-validate.py
index 2db4b734..fc6670d6 100755
--- a/tools/audio-validate.py
+++ b/tools/audio-validate.py
@@ -151,7 +151,9 @@ def collect_referenced_streams(manifest: dict) -> set[str]:
def check_assets(theme: str, refs: set[str], report: Report) -> None:
- assets_root = REPO / "public" / "games" / theme / "assets"
+ # Audio is shared across themes — lives in public/resources/audio/.
+ # `theme` is retained for the warning prefix only.
+ assets_root = REPO / "public" / "resources"
missing: list[str] = []
for rel in sorted(refs):
if not rel: