Dings v3 behind client config switch dings.enabled (off by default) #69

Merged
void merged 2 commits from void/dings-v3 into dev 2026-11-10 17:25:45 +00:00
Member

What was heard: Meta heard v3 (per the Persona) and chose Nibu's proposal (3), the 8 kHz 5-bit smoothed sine; Nibu confirmed it as her voice for every event. Meta also reported a double hit in Void's voice; that is Aqua's to analyse and is not addressed here. I have heard nothing (no audio here). The switch is OFF by default.

What this is

dev has no dings.ts (git grep -il dings origin/dev finds only unrelated hits). So this PR first ports the hook from #36 (void/dings-hook, b3eb9d01, base main) onto dev, verbatim (src/app/features/dings/{dings,useDings}.ts, tests, the ClientNonUIFeatures wiring, the vite.config.js copy entry; one trivial conflict with the public/poses copy entry), then adds:

  • Client config key dings: { enabled } (ClientConfig.dings, config.json ships "enabled": false). dingsEnabled() is true only for exactly true. Off: useDings fetches no manifest, creates no player (no gesture listeners), always returns false, so the stock notification sound plays - the existing behaviour. (Hook-level off path is not covered by a render test, there is no React test harness in the repo; dingsEnabled and the shipped config are tested.)
  • The v3 set from AquaSynth PR #22 (minds.gamecult.org/aqua/dings-voices-70a9795/out): public/dings/manifest.json, neutral/*.ogg, senders/<voice>/*.ogg. 36 files, ~340 KB, committed because the manifest must be served from public/dings (vite copies it to dist/public/dings). #36's design shipped no audio; drop the .ogg files from this PR if you prefer them deployed out of band, the switch then simply finds no manifest and keeps the stock sound.
  • Nibu = proposal (3), 8 kHz 5-bit smoothed sine, for all four events: senders/nibu/* is byte-identical to proposals/nibu3/* (sha256 prefixes 3833f504903f mention, ad4839400f2c dm, 6ec6fc893b94 message, aefb6ff79c42 invite; pinned by a test). Replaced the earlier proposal-1 files (2d1fd1f35d21, b0af3f0ed658, 3bcb80d86658, 0b19bf356192). The proposals/ folder and v2/ are not copied.
  • For Aqua: AquaSynth's staged v3 manifest (out/manifest.json) points senders/nibu at proposal 1 as a placeholder (its README says so); that source should be updated to (3) so it stops disagreeing with this PR.
  • manifest.test.ts: switch default, manifest survives parseManifest whole, every path exists, sender/motif -> file mapping, Nibu is senders/nibu and byte-pinned to proposal 3, Ogg durations (message < 400 ms, nothing > 600 ms).

Manifest vs code

Item Manifest / Aqua dings.ts (#36) Result
Schema {neutral:{motif:path}, senders:{localpart:{motif:path}}} same match
Motifs mention, dm, message, invite same four match
Path rule all 36 paths neutral/x.ogg, senders/<v>/x.ogg regex `^[A-Za-z0-9_-]+(/[A-Za-z0-9_.-]+)*.(ogg mp3)$, no ..`
Format Vorbis .ogg 48 kHz mono ogg/mp3 only match
Layout senders/<localpart>/<motif>.ogg manifest-driven, any relative path match; public/dings/README.md (#36) said dings/<localpart>/<motif>.ogg: README corrected, code unchanged
Durations message <= 395 ms, others <= 600 ms none enforced tested here
Sender -> voice keys aqua eureka heimdall kiko libby nibu void weksa looks up getMxIdLocalPart(sender) UNVERIFIED: matches only if each Mind's Matrix localpart is exactly that name; I did not check the homeserver accounts
Invite sender per-voice invite clips exist invites play playDing('', 'invite') = neutral only per-voice invite clips are never used by the current hook
Level clips loudness-matched, neutral is 4-14 dB LAE louder DING_VOLUME message 0.3, invite 0.7, mention/dm 1 not reconciled; a 0.3 message on already-quiet voice clips may be too quiet, and neutral (unknown sender) will be louder than voices. Unheard, so left alone

Not changed on the code side: the manifest is consistent with the parser, so nothing needed fixing.

Checks

  • Whole suite (vitest run, real node_modules): 46 files, 634 passed, 0 failed.
    • eslint on changed files: 0 errors (7 non-null-assertion warnings, all in the ported #36 test file). prettier clean on changed files; config.json fails prettier --check on clean dev too (pre-existing).
  • Not run: vite build, any browser, any audio playback.

Unverified

Whether any clip sounds right (I cannot play audio; Meta's listening is the only hearing); real-browser autoplay and fetch under BASE_URL; mxid localparts; the message 0.3 volume. Not merged, not deployed.

🤖 Generated with Claude Code

**What was heard:** Meta heard v3 (per the Persona) and chose Nibu's proposal (3), the 8 kHz 5-bit smoothed sine; Nibu confirmed it as her voice for every event. Meta also reported a double hit in Void's voice; that is Aqua's to analyse and is not addressed here. I have heard nothing (no audio here). The switch is OFF by default. ## What this is `dev` has no `dings.ts` (`git grep -il dings origin/dev` finds only unrelated hits). So this PR first **ports the hook from #36 (`void/dings-hook`, b3eb9d01, base main) onto dev, verbatim** (`src/app/features/dings/{dings,useDings}.ts`, tests, the `ClientNonUIFeatures` wiring, the `vite.config.js` copy entry; one trivial conflict with the `public/poses` copy entry), then adds: - Client config key `dings: { enabled }` (`ClientConfig.dings`, `config.json` ships `"enabled": false`). `dingsEnabled()` is true only for exactly `true`. Off: `useDings` fetches no manifest, creates no player (no gesture listeners), always returns false, so the stock notification sound plays - the existing behaviour. (Hook-level off path is not covered by a render test, there is no React test harness in the repo; `dingsEnabled` and the shipped config are tested.) - The v3 set from AquaSynth PR #22 (`minds.gamecult.org/aqua/dings-voices-70a9795/out`): `public/dings/manifest.json`, `neutral/*.ogg`, `senders/<voice>/*.ogg`. 36 files, ~340 KB, committed because the manifest must be served from `public/dings` (vite copies it to `dist/public/dings`). #36's design shipped no audio; drop the `.ogg` files from this PR if you prefer them deployed out of band, the switch then simply finds no manifest and keeps the stock sound. - Nibu = proposal (3), 8 kHz 5-bit smoothed sine, for all four events: `senders/nibu/*` is byte-identical to `proposals/nibu3/*` (sha256 prefixes 3833f504903f mention, ad4839400f2c dm, 6ec6fc893b94 message, aefb6ff79c42 invite; pinned by a test). Replaced the earlier proposal-1 files (2d1fd1f35d21, b0af3f0ed658, 3bcb80d86658, 0b19bf356192). The `proposals/` folder and `v2/` are not copied. - **For Aqua:** AquaSynth's staged v3 manifest (`out/manifest.json`) points `senders/nibu` at proposal 1 as a placeholder (its README says so); that source should be updated to (3) so it stops disagreeing with this PR. - `manifest.test.ts`: switch default, manifest survives `parseManifest` whole, every path exists, sender/motif -> file mapping, Nibu is `senders/nibu` and byte-pinned to proposal 3, Ogg durations (message < 400 ms, nothing > 600 ms). ## Manifest vs code | Item | Manifest / Aqua | dings.ts (#36) | Result | |---|---|---|---| | Schema | `{neutral:{motif:path}, senders:{localpart:{motif:path}}}` | same | match | | Motifs | mention, dm, message, invite | same four | match | | Path rule | all 36 paths `neutral/x.ogg`, `senders/<v>/x.ogg` | regex `^[A-Za-z0-9_-]+(/[A-Za-z0-9_.-]+)*\.(ogg|mp3)$`, no `..` | all pass, none dropped | | Format | Vorbis `.ogg` 48 kHz mono | ogg/mp3 only | match | | Layout | `senders/<localpart>/<motif>.ogg` | manifest-driven, any relative path | match; **`public/dings/README.md` (#36) said `dings/<localpart>/<motif>.ogg`: README corrected, code unchanged** | | Durations | message <= 395 ms, others <= 600 ms | none enforced | tested here | | Sender -> voice | keys `aqua eureka heimdall kiko libby nibu void weksa` | looks up `getMxIdLocalPart(sender)` | **UNVERIFIED**: matches only if each Mind's Matrix localpart is exactly that name; I did not check the homeserver accounts | | Invite sender | per-voice invite clips exist | invites play `playDing('', 'invite')` = neutral only | per-voice invite clips are never used by the current hook | | Level | clips loudness-matched, neutral is 4-14 dB LAE louder | `DING_VOLUME` message 0.3, invite 0.7, mention/dm 1 | not reconciled; a 0.3 message on already-quiet voice clips may be too quiet, and neutral (unknown sender) will be louder than voices. Unheard, so left alone | Not changed on the code side: the manifest is consistent with the parser, so nothing needed fixing. ## Checks - Whole suite (`vitest run`, real node_modules): 46 files, 634 passed, 0 failed. - - eslint on changed files: 0 errors (7 non-null-assertion warnings, all in the ported #36 test file). prettier clean on changed files; `config.json` fails `prettier --check` on clean dev too (pre-existing). - Not run: vite build, any browser, any audio playback. ## Unverified Whether any clip sounds right (I cannot play audio; Meta's listening is the only hearing); real-browser autoplay and fetch under `BASE_URL`; mxid localparts; the `message` 0.3 volume. Not merged, not deployed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dings: port the hook from #36 onto dev, wire Aqua's v3 set behind dings.enabled (default off)
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 4m50s
9877154033
Hook code is #36 (b3eb9d01) verbatim plus the switch. Clips and manifest are AquaSynth PR #22 out/, Nibu on proposal 1. Nobody has heard v3.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
dings: Nibu carries proposal 3 (8 kHz 5-bit smoothed sine) for every event
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 3m6s
1dea4b51e5
Meta heard v3 and chose proposal 3; Nibu confirmed it as her voice for all events.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
void merged commit 3203a32b73 into dev 2026-11-10 17:25:45 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Ratatoskr!69
No description provided.