app
Adom TTS: Text to Speech
Public Made by Adomby adom
Adom's shared voice service. Reads your AI's answers back to you while you drive, and renders perfectly-timed voiceover tracks for your demo videos, so you never record your own voice.
← Commit history
Set hero image (page.json hero) + grid thumbnail
2 files changed
+16−64
page.json+16−64@@ -5,71 +5,23 @@ "title": "adom-tts — your AI's voice (drive mode + demo voiceover)", "brief": "Adom's shared voice service. Reads your AI's answers back to you while you drive, and renders perfectly-timed voiceover tracks for your demo videos — so you never record your own voice.", "version": "0.2.0",- "tags": [], "license": "MIT",+ "tags": ["tts", "voice", "audio", "demo", "accessibility"],+ "hero": {+ "type": "image",+ "path": "screenshots/hero.png",+ "thumbnail": "screenshots/hero-thumb.png"+ },+ "discovery_pitch": "Hands-free in the car? Say 'read me your last answer, I'm driving' and adom-tts speaks it aloud. Making a demo video? Feed it your script and get a perfectly-timed narration track in the house voice — no recording booth, no retakes. One shared edge-tts service with Adom pronunciation overrides and an instant source-hash cache.",+ "discovery_triggers": ["adom-tts", "text to speech", "tts", "voiceover", "demo narration", "narration", "synthesize speech", "make audio from text", "read it to me", "read me your answer", "read that back", "read me the last prompt", "I'm driving", "hands-free", "drive mode", "narrate the answer", "play this audio"], "sample_prompts": [- {- "label": "Drive mode",- "prompt": "Read me your latest answer, I'm driving"- },- {- "label": "Synthesize and play",- "prompt": "Synthesize a 30-second walkthrough of this design and play it for me"- },- {- "label": "Replay last",- "prompt": "Play the last TTS clip again"- },- {- "label": "Open playground",- "prompt": "Open the TTS Playground webview"- },- {- "label": "Add pronunciation",- "prompt": "Teach the TTS service that aci is pronounced A-C-I"- }+ { "label": "Drive mode", "prompt": "Read me your last answer, I'm driving" },+ { "label": "Demo voiceover", "prompt": "Render this script as a demo voiceover track" },+ { "label": "Synthesize and play", "prompt": "Synthesize a 30-second walkthrough of this design and play it for me" },+ { "label": "Replay last", "prompt": "Play the last TTS clip again" },+ { "label": "Add pronunciation", "prompt": "Teach the TTS service that aci is pronounced A-C-I" } ], "install": {- "binary_name": "adom-tts",- "install_dir": "",- "install_hint": "",- "version_cmd": ""- },- "readme": "# adom-tts\n\nThin Rust CLI + webview playground for [service-tts](/apps/service-tts) — Adom's shared edge-tts wrapper with pronunciation overrides + source-hash cache.\n\n## What's new in 0.1.2 — built-in auto-player\n\nThe CLI now plays its own mp3s. **Stop authoring custom autoplay HTML or `python3 -m http.server` workarounds.**\n\n```bash\n# One shot: synthesize and auto-play. CLI returns immediately (detached).\nadom-tts say \"Read me your latest answer, I'm driving.\" --out /tmp/x.mp3 --play\n\n# Replay the newest history clip.\nadom-tts play last\n\n# Replay any history clip by full id or unique substring of its hash.\nadom-tts play 5f79f0\n```\n\n**How it works.** `play` (and `say --play`) spins up a one-shot tiny_http server bound to a 127.0.0.1 ephemeral port, serving the mp3 + a small autoplay page. The container's `$VSCODE_PROXY_URI` wraps the port into a Cloudflare-routable URL. The chosen surface — Hydrogen webview tab (default) or pup browser window — navigates to that URL. Same plumbing both surfaces, no port mappings, no clip-size limits, no base64 URL bloat.\n\n**Tab/window auto-closes** when the audio's `ended` event fires (or a 5-min cap). Programmatic, not AI-driven — the binary handles cleanup. Override with `ADOM_TTS_KEEP_OPEN=1` if you want the player to linger.\n\n**Surface precedence:** `--surface hydrogen|pup` flag → `$ADOM_TTS_SURFACE` env → `~/.adom/tts/config.toml` (`[play] surface = \"...\"`) → `\"hydrogen\"` default.\n\n**Self-teaching hints.** `say` without `--play` emits stderr hints pointing the AI at the auto-player and warning against the anti-patterns we've seen sessions fall into (custom HTML, port-add, etc.). Silenceable via `ADOM_TTS_NO_HINTS=1`.\n\n## Hands-free trigger phrases\n\nWhen the user says \"I'm driving\", \"read it to me\", \"can't read the screen\", \"in the car\", \"narrate the answer\" — they CANNOT see your text response. Synthesize and `--play`. The skill front-matter lists the full trigger catalog.\n\n## Playground webview (unchanged from 0.1.1)\n\n`adom-tts serve` opens a Hydrogen webview panel. Type what you want to hear, pick a voice, hit Enter. Every clip you generate (or that any other tool drops via `adom-tts say --history` / `adom-tts push`) is saved to `~/.adom/tts/history/` and replayable from the list. Download, copy shareable URLs, delete — all per-clip.\n\n**Pronunciation authoring.** A live view of the global pronunciation table sits next to the compose area. When your input contains a term that already has an override, a hint appears: \"*adom-tsci* will be voiced as `adom t s c i` · global override\". An Add form lets you propose new entries, with a **Preview** button that synthesizes raw + phoneticized forms back-to-back, and a **Propose** button that writes straight into `gallia/skills/tts-pronunciation/pronunciations.json`.\n\n**Everything is AI-drivable.** Every UI action has an HTTP equivalent — `POST /synth`, `GET /history`, `DELETE /history/:id`, `GET /pronunciations`, `POST /pronunciation/propose`, `GET /state`, `GET /console`, `POST /shutdown`.\n\n## Install (Tier B)\n\nPaste-into-Claude:\n\n```bash\ncurl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-tts/adom-tts \\\n -o /tmp/adom-tts && chmod +x /tmp/adom-tts \\\n && sudo install -m 0755 /tmp/adom-tts /usr/local/bin/adom-tts \\\n && adom-tts install \\\n && adom-tts health\n```\n\n`adom-tts install` deploys the SKILL.md + `adom-tts-build` sibling skill + bash completions. Gallia's 30-min refresh hook keeps the installed version in sync with the wiki's `pub_version`.\n\n## CLI\n\n```bash\n# Synthesis + auto-play (the common case)\nadom-tts say \"Hello from adom-tsci\" --out hello.mp3 --play\nadom-tts say \"narration\" --out n.mp3 --voice en-US-AriaNeural --play\n\n# Replay\nadom-tts play last\nadom-tts play /tmp/x.mp3 --wait # block until ended (max 5 min)\nadom-tts play /tmp/x.mp3 --surface pup\n\n# Synthesis only (rare — when you genuinely just need the file)\nadom-tts say \"for later\" --out later.mp3\n\n# Playground\nadom-tts serve [--port 8795]\nadom-tts push path/to/clip.mp3\n\n# Pronunciations\nadom-tts pron list\nadom-tts pron add \"adom-tsci\" \"adom t s c i\" --reason \"letter-by-letter forces 4-letter reading\"\n\n# Introspection\nadom-tts voices | jq '.count'\nadom-tts pronunciations | jq '.count'\nadom-tts health\nadom-tts config # current service URL + bake/env source\nadom-tts config --show # also dump resolved play surface + config path\n```\n\n`$ADOM_TTS_API` overrides the baked-in service URL. Default voice is `en-US-AndrewNeural` — the house voice for every Adom demo.\n\n## Anti-patterns the new auto-player exists to prevent\n\n- ❌ `python3 -m http.server <port>` to serve the mp3. Pup runs on the user's *desktop*; container localhost is unreachable. Hydrogen webviews have the same constraint.\n- ❌ Custom HTML with base64-inlined mp3 + `data:` URL. Past 2 MB this hits Chrome's URL length limit.\n- ❌ `adom-cli carbon containers port-add` for a permanent `*.adom.cloud` subdomain. Total overkill for a one-shot.\n- ✅ Just use `--play`. The binary handles surface, URL, autoplay, and cleanup.\n\n## Who uses this\n\n- `demo-recording` / `voiceover` / `tour` — everyone that renders narration\n- `aci voice` — backend precedence `$ACI_VOICE_API → adom-tts CLI → edge-tts local fallback`\n- Drive-mode users via Claude RC — synthesize + auto-play means hands-free answers\n- Any new tool that needs spoken output should shell out to `adom-tts say` rather than calling edge-tts directly\n\n## Exit codes\n\n| code | meaning |\n|---|---|\n| `0` | ok |\n| `1` | invalid input (empty text, missing `--out`) |\n| `2` | service unreachable — check `adom-tts config` or set `$ADOM_TTS_API` |\n| `4` | service-side error (edge-tts failed, etc.) |\n\nSource (private): [`adom-inc/adom-tts`](https://github.com/adom-inc/adom-tts). Service backend: [service-tts](/apps/service-tts). Pronunciation source of truth: `gallia/skills/tts-pronunciation/pronunciations.json`.\n",- "author": {- "id": "695820315b5f1e4db2fcf602",- "name": "Kyle Bergstedt",- "email": "[email protected]"- },- "visibility": {- "public": true- },- "hero": null,- "discovery_triggers": [- "adom-tts",- "text to speech",- "tts",- "voiceover",- "demo narration",- "narration",- "synthesize speech",- "make audio from text",- "read it to me",- "read me your answer",- "read that back",- "read me the last prompt",- "I'm driving",- "hands-free",- "drive mode",- "narrate the answer",- "play this audio"- ],- "discovery_pitch": "Hands-free in the car? Say 'read me your last answer, I'm driving' and adom-tts speaks it aloud. Making a demo video? Feed it your script and get a perfectly-timed narration track in the house voice — no recording booth, no retakes. One shared edge-tts service with Adom pronunciation overrides and an instant source-hash cache.",- "metadata": {},- "created_at": "2026-05-28T05:29:06.606Z",- "updated_at": "2026-06-16T16:43:21.830Z",- "skills": [],- "author_name": "John Lauer",- "hero_type": "image",- "hero_path": "screenshots/hero.png"-}+ "binary_name": "adom-tts"+ }+}
screenshots/hero-thumb.pngadded⋯ 1 unchanged line ⋯