A starter kit for building a personalized keyboard-smash desktop app for toddlers.
Press keys, get big visuals and overlapping sounds.
Try the browser demo: OttoSmash Live Demo
Notes:
- audio starts after your first key press/tap (browser autoplay policy)
- this demo serves the starter assets and base behavior from this repo
If you have never used Terminal or installed Node before, read this first:
src/Electron + TypeScript app sourcesounds/full starter sound setpics/empty folder (add your own images)scripts/render_emojis.swift+scripts/emoji_config.json(optional emoji generator)scripts/split_utterances.mjs(split long recordings into individual utterance clips)PLAN.mdstep-by-step build plan for one-shot AI-assisted development
- Clone this repo.
- Open it in Codex or Claude Code.
- Ask for a one-shot build/customization using the prompt in
PLAN.md.
If you are new to coding assistants, follow this exactly:
- Get this folder onto your computer.
- Open this folder (
ottosmash_starter_kit) in your AI coding tool. - Install dependencies first:
npm install- Paste one clear request, such as:
Read PLAN.md and build this app in one pass. Keep all existing scripts. Assume dependencies are installed. Then run typecheck and build, and tell me what command to run next.
- Let the assistant edit files and run commands.
- When it finishes, run:
npm run devUse plain language. Example prompts:
Make this version themed for trucks and dinosaurs.Use only sounds that start with family_ in sounds/.Add a settings panel with sliders for fade speed and polyphony.Set family pictures to appear twice as often as emoji pictures.
- Codex: open this folder as the workspace, then ask it to execute the plan in
PLAN.md. - Claude Code: open this folder in the Claude coding environment and give the same prompt.
- OpenCode: open this folder as the project root and use the same prompt; the workflow is the same.
You do not need to understand every file first. Start with one clear request, run the app, then iterate with small follow-up requests.
For the best toddler experience, use:
- familiar voices (parents, siblings, grandparents) for sounds
- photos of familiar people, pets, and favorite objects in
pics/
- Node.js
22.12+(LTS recommended) - npm
10+(normally bundled with Node 22+) ffmpegandffprobeon PATH (for audio conversion/splitting)
npm install
npm run devnpm run build- bundle app todist/npm run build:web- build static browser demo tosite/(for GitHub Pages)npm run dev- build + launch appnpm run start- launch app from existingdist/npm run typecheck- run TypeScript checksnpm run render:emojis- generate emoji PNGs intopics/npm run split:utterances -- --input <file>- split a long recording into many.wavclipsnpm run normalize:audio -- --dry-run- preview WAV normalization + AIFF conversion jobsnpm run dist- unsigned ARM64 macOS DMG inrelease/npm run dist:universal- unsigned universal macOS DMG inrelease/npm run dist:win- Windows NSIS installer buildnpm run dist:linux- Linux AppImage build
Pushes to main trigger .github/workflows/pages.yml, which:
- runs
npm ci - runs
npm run build:web - deploys
site/to GitHub Pages
- Add
.wavfiles tosounds/ - Add
.png/.jpg/.jpeg/.webp/.giffiles topics/
The app also auto-loads from these optional folders if they exist:
~/Music/ottosmashfor extra sounds (.wav)~/Pictures/ottosmashfor extra images
On macOS, if assets in these folders do not appear, grant Files and Folders permission for the app in System Settings -> Privacy & Security.
If you record a long session with multiple utterances separated by silence, split it automatically:
npm run split:utterances -- --input ./raw/family_session.wav --prefix family --out ./soundsUseful tuning options:
--noise -35silence threshold in dB (higher magnitude like-45is more sensitive)--gap 0.35minimum silent gap to split utterances--min-clip 0.18minimum output clip duration--pad 0.03small padding added around each segment--dry-runpreview segments without writing files
Outputs are normalized to mono 44.1kHz 16-bit WAV.
If you have mixed audio formats, this helper script can:
- re-encode existing
sounds/*.wavto mono 44.1kHz 16-bit WAV - convert
aifs/*.aiforaifs/*.aifftosounds/ottosmash_*.wav - write a manifest CSV and backup overwritten files
Preview first:
npm run normalize:audio -- --dry-runRun conversion:
npm run normalize:audioUseful options:
--source-aifs <dir>custom AIFF source directory--sounds-dir <dir>custom output sounds directory--overwriteoverwrite existing AIFF-converted targets
The app supports two image categories:
- emoji pics: filenames starting with
emoji_,emoji-, orpic-emoji - family pics: filenames starting with
familyorpic-family
Anything non-emoji in ~/Pictures/ottosmash is treated as a family pic by default.
fforce family pictureeforce emoji picturesforce shapelforce letter- press
Escape5 times to quit
scripts/render_emojis.swiftis macOS-specific (uses AppKit).- On Windows/Linux, use a platform-appropriate workflow (for example, emoji source assets, Twemoji-based rendering, or a Python/Pillow pipeline) and place resulting images in
pics/. - This repo intentionally does not include generated Apple emoji artwork.
OttoSmash is inspired by the original BabySmash (1990s shareware) by Justin Cohen. This project references that original lineage, not newer apps that use the same name.