Last active
April 15, 2026 17:34
-
-
Save ericchansen/51326eddfd8e123769cf7eccca993f64 to your computer and use it in GitHub Desktop.
One-command setup: Warcraft Peon sounds for Windows Terminal (Stable, Preview, Canary) with volume control
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Replace the Windows Terminal bell with Warcraft Peon sounds. | |
| .DESCRIPTION | |
| Downloads Peon WAV files and configures Windows Terminal's native bellSound | |
| setting to randomly play one on each bell event. That's it - no hooks, | |
| no runtimes, no extra dependencies. Just WAVs + a settings.json change. | |
| Supports all Windows Terminal variants: Stable, Preview, and Canary. | |
| Sounds are volume-reduced by default (13%) so they're a subtle nudge, | |
| not a jump-scare. Adjust with -Volume or $env:PEON_BELL_VOLUME. | |
| .PARAMETER Volume | |
| Bell volume as a percentage of original (1-100). Default: 13. | |
| For the irm | iex one-liner, set $env:PEON_BELL_VOLUME instead. | |
| .EXAMPLE | |
| irm https://gist.githubusercontent.com/ericchansen/51326eddfd8e123769cf7eccca993f64/raw/setup-peon-copilot.ps1 | iex | |
| .EXAMPLE | |
| $env:PEON_BELL_VOLUME = 25; irm https://gist.githubusercontent.com/ericchansen/51326eddfd8e123769cf7eccca993f64/raw/setup-peon-copilot.ps1 | iex | |
| .EXAMPLE | |
| .\setup-peon-copilot.ps1 -Volume 30 | |
| #> | |
| param( | |
| [ValidateRange(1,100)] | |
| [int]$Volume = 0 | |
| ) | |
| $ErrorActionPreference = "Stop" | |
| # ── Resolve volume: param > env var > marker file > default ────────────── | |
| $SoundsDir = Join-Path $env:USERPROFILE ".terminal-sounds\peon" | |
| $BellDir = Join-Path $env:USERPROFILE ".terminal-sounds\peon-bell" | |
| $MarkerFile = Join-Path $env:USERPROFILE ".terminal-sounds\.bell-volume" | |
| if ($Volume -eq 0) { | |
| if ($env:PEON_BELL_VOLUME) { | |
| $Volume = [int]$env:PEON_BELL_VOLUME | |
| } elseif (Test-Path $MarkerFile) { | |
| $Volume = [int](Get-Content $MarkerFile -Raw).Trim() | |
| } else { | |
| $Volume = 13 | |
| } | |
| } | |
| $Volume = [Math]::Clamp($Volume, 1, 100) | |
| $Factor = $Volume / 100.0 | |
| Write-Host "" | |
| Write-Host "=== Peon Bell for Windows Terminal ===" -ForegroundColor Yellow | |
| Write-Host " Volume: $Volume%" -ForegroundColor DarkYellow | |
| Write-Host "" | |
| # ── Paths ──────────────────────────────────────────────────────────────── | |
| $PackBase = "https://raw.githubusercontent.com/PeonPing/og-packs/v1.0.0/peon" | |
| # All known Windows Terminal settings.json locations | |
| $WtCandidates = @( | |
| @{ Name = "Stable"; Path = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json" } | |
| @{ Name = "Preview"; Path = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\LocalState\settings.json" } | |
| @{ Name = "Canary"; Path = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminalCanary_8wekyb3d8bbwe\LocalState\settings.json" } | |
| @{ Name = "Unpackaged"; Path = Join-Path $env:LOCALAPPDATA "Microsoft\Windows Terminal\settings.json" } | |
| ) | |
| # ── Step 1: Download Peon WAV files ────────────────────────────────────── | |
| Write-Host "[1/3] Downloading Peon sounds..." -ForegroundColor Cyan | |
| New-Item -ItemType Directory -Path $SoundsDir -Force | Out-Null | |
| # Fetch the manifest to get the file list | |
| $manifest = (Invoke-WebRequest "$PackBase/openpeon.json" -UseBasicParsing).Content | ConvertFrom-Json | |
| # Collect unique sound files from all categories | |
| $soundFiles = @{} | |
| foreach ($cat in $manifest.categories.PSObject.Properties) { | |
| foreach ($sound in $cat.Value.sounds) { | |
| $file = $sound.file -replace '^sounds/', '' | |
| if (-not $soundFiles.ContainsKey($file)) { | |
| $soundFiles[$file] = $sound.label | |
| } | |
| } | |
| } | |
| $downloaded = 0 | |
| $skipped = 0 | |
| foreach ($file in $soundFiles.Keys | Sort-Object) { | |
| $outPath = Join-Path $SoundsDir $file | |
| if (Test-Path $outPath) { | |
| $skipped++ | |
| } else { | |
| Invoke-WebRequest "$PackBase/sounds/$file" -OutFile $outPath -UseBasicParsing | |
| $downloaded++ | |
| } | |
| } | |
| Write-Host " $($soundFiles.Count) sounds ($downloaded downloaded, $skipped cached)" -ForegroundColor Green | |
| # ── Step 2: Create volume-reduced copies ───────────────────────────────── | |
| Write-Host "[2/3] Adjusting volume to $Volume%..." -ForegroundColor Cyan | |
| New-Item -ItemType Directory -Path $BellDir -Force | Out-Null | |
| # Curate: exclude angry/death/warcry (those sound like errors, not "done") | |
| $sourceFiles = Get-ChildItem $SoundsDir -Filter "*.wav" | Where-Object { | |
| $_.Name -notmatch "(Angry|Death|Warcry)" | |
| } | |
| if ($sourceFiles.Count -eq 0) { | |
| $sourceFiles = Get-ChildItem $SoundsDir -Filter "*.wav" | |
| } | |
| $useFfmpeg = $null -ne (Get-Command ffmpeg -ErrorAction SilentlyContinue) | |
| if ($Volume -eq 100) { | |
| # No reduction needed - just copy | |
| foreach ($src in $sourceFiles) { | |
| Copy-Item $src.FullName (Join-Path $BellDir $src.Name) -Force | |
| } | |
| $method = "copy (100%)" | |
| } elseif ($useFfmpeg) { | |
| foreach ($src in $sourceFiles) { | |
| $dst = Join-Path $BellDir $src.Name | |
| ffmpeg -y -loglevel error -i $src.FullName -filter:a "volume=$Factor" $dst 2>&1 | Out-Null | |
| } | |
| $method = "ffmpeg" | |
| } else { | |
| # Pure PowerShell: scale 16-bit PCM samples directly | |
| foreach ($src in $sourceFiles) { | |
| $dst = Join-Path $BellDir $src.Name | |
| $bytes = [System.IO.File]::ReadAllBytes($src.FullName) | |
| # Find the "data" chunk - scan for ASCII "data" after the fmt chunk | |
| $dataOffset = -1 | |
| for ($i = 12; $i -lt ($bytes.Length - 8); $i++) { | |
| if ($bytes[$i] -eq 0x64 -and $bytes[$i+1] -eq 0x61 -and | |
| $bytes[$i+2] -eq 0x74 -and $bytes[$i+3] -eq 0x61) { | |
| $dataOffset = $i + 8 # skip "data" + 4-byte size | |
| break | |
| } | |
| } | |
| if ($dataOffset -lt 0) { | |
| # Can't parse - copy as-is | |
| Copy-Item $src.FullName $dst -Force | |
| continue | |
| } | |
| # Scale each 16-bit sample | |
| for ($i = $dataOffset; $i -lt ($bytes.Length - 1); $i += 2) { | |
| $sample = [BitConverter]::ToInt16($bytes, $i) | |
| $scaled = [Math]::Round($sample * $Factor) | |
| $scaled = [Math]::Clamp($scaled, -32768, 32767) | |
| $le = [BitConverter]::GetBytes([Int16]$scaled) | |
| $bytes[$i] = $le[0] | |
| $bytes[$i+1] = $le[1] | |
| } | |
| [System.IO.File]::WriteAllBytes($dst, $bytes) | |
| } | |
| $method = "PowerShell PCM" | |
| } | |
| # Save volume marker for future re-runs | |
| New-Item -ItemType Directory -Path (Split-Path $MarkerFile) -Force | Out-Null | |
| Set-Content $MarkerFile "$Volume" -NoNewline | |
| $bellSounds = Get-ChildItem $BellDir -Filter "*.wav" | ForEach-Object { $_.FullName } | |
| Write-Host " $($bellSounds.Count) bell sounds at $Volume% via $method" -ForegroundColor Green | |
| # ── Step 3: Configure Windows Terminal bellSound ───────────────────────── | |
| Write-Host "[3/3] Configuring Windows Terminal..." -ForegroundColor Cyan | |
| # Find all installed WT variants | |
| $wtFound = $WtCandidates | Where-Object { Test-Path $_.Path } | |
| if ($wtFound.Count -eq 0) { | |
| Write-Host " No Windows Terminal settings.json found - skipping" -ForegroundColor Yellow | |
| Write-Host " Checked:" -ForegroundColor DarkGray | |
| foreach ($c in $WtCandidates) { Write-Host " $($c.Name): $($c.Path)" -ForegroundColor DarkGray } | |
| Write-Host "" | |
| Write-Host "You can manually add this to your terminal's profiles.defaults:" -ForegroundColor Yellow | |
| Write-Host ' "bellStyle": "audible",' -ForegroundColor White | |
| Write-Host ' "bellSound": [<paths to WAV files>]' -ForegroundColor White | |
| exit 0 | |
| } | |
| # Apply bellSound to every installed WT variant | |
| foreach ($wt in $wtFound) { | |
| $wtRaw = Get-Content $wt.Path -Raw | |
| $wtClean = $wtRaw -replace '(?m)^\s*//.*$', '' -replace ',(\s*[}\]])', '$1' | |
| $wtObj = $wtClean | ConvertFrom-Json | |
| # Ensure profiles.defaults exists | |
| if (-not $wtObj.profiles) { | |
| $wtObj | Add-Member -NotePropertyName "profiles" -NotePropertyValue ([PSCustomObject]@{ | |
| defaults = [PSCustomObject]@{} | |
| list = @() | |
| }) | |
| } | |
| if (-not $wtObj.profiles.defaults) { | |
| $wtObj.profiles | Add-Member -NotePropertyName "defaults" -NotePropertyValue ([PSCustomObject]@{}) | |
| } | |
| $defaults = $wtObj.profiles.defaults | |
| if ($defaults.PSObject.Properties["bellStyle"]) { $defaults.bellStyle = "audible" } | |
| else { $defaults | Add-Member -NotePropertyName "bellStyle" -NotePropertyValue "audible" } | |
| if ($defaults.PSObject.Properties["bellSound"]) { $defaults.bellSound = @($bellSounds) } | |
| else { $defaults | Add-Member -NotePropertyName "bellSound" -NotePropertyValue @($bellSounds) } | |
| $wtObj | ConvertTo-Json -Depth 20 | Set-Content $wt.Path -Encoding utf8NoBOM | |
| Write-Host " $($wt.Name): bellSound set ($($bellSounds.Count) sounds)" -ForegroundColor Green | |
| } | |
| Write-Host "" | |
| Write-Host "Done! Your Peon is ready at $Volume% volume." -ForegroundColor Green | |
| Write-Host "" | |
| Write-Host "How it works:" -ForegroundColor DarkCyan | |
| Write-Host " Windows Terminal plays a random Peon WAV every time the bell fires." -ForegroundColor DarkCyan | |
| Write-Host " Any app that sends a bell character (`a) will trigger a random sound." -ForegroundColor DarkCyan | |
| Write-Host " No hooks, no runtimes, no extra dependencies - just a settings.json change." -ForegroundColor DarkCyan | |
| Write-Host "" | |
| Write-Host "Adjust volume:" -ForegroundColor DarkCyan | |
| Write-Host " Re-run with: `$env:PEON_BELL_VOLUME = 25; irm <url> | iex" -ForegroundColor DarkCyan | |
| Write-Host " Or directly: .\setup-peon-copilot.ps1 -Volume 25" -ForegroundColor DarkCyan | |
| Write-Host "" | |
| Write-Host "Sounds: $SoundsDir (originals)" -ForegroundColor DarkGray | |
| Write-Host "Bell: $BellDir ($Volume%)" -ForegroundColor DarkGray | |
| Write-Host "" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I don't even think you have to restart Windows Terminal. Just works.