This file provides guidance to AI agents when working with code in this repository.
KeyParty is a key-smashing game for kids, built on zero-native: a Zig native shell (window + kiosk keyboard lockdown) hosting a Next.js web UI (all the visuals, sounds, and menu). The same web UI runs on macOS, Windows, and in the browser. See DEVELOPMENT.md for the full architecture.
# Native app (from repo root — needs node_modules/.bin on PATH, so prefix with npx)
npm install # installs zero-native + its CLI, and Changesets
npx zig build run # build and run the app
npx zig build dev # dev mode (hot-reloads the frontend)
npx zig build package # produce a distributable build
zig build test # run Zig tests
# Frontend (from frontend/)
npm run dev # next dev
npm run build # next build
npm run start # next start
# Release tooling (from repo root)
npm run changeset # add a changeset
npm run version # apply versions + sync app.zon (scripts/sync-version.mjs)zig build dev / run / package auto-install the frontend deps
(npm install --prefix frontend). The build reads zero-native from
node_modules/zero-native; override with -Dzero-native-path=….
src/— Zig native shell.main.zig(entry / window / kiosk lockdown),runner.zig.native/— patched native hosts shipped with this repo:appkit_host.m(macOS),webview2_host.cpp(Windows).frontend/— Next.js web UI (React 19, TypeScript).app/page.tsxis the game,app/layout.tsx,app/globals.css,app/analytics.ts.assets/— icons and demo images.scripts/—embed-assets.mjs,make-dmg.sh,sync-version.mjs.build.zig/build.zig.zon/app.zon— Zig build + app metadata.
- Native: Zig (formatted by
zig fmt— 4-space indent). Native hosts are ObjC (.m) / C++ (.cpp). - Frontend: TypeScript (strict), React 19, Next.js. 2-space indent, single
quotes, LF (see
.editorconfig). Package manager is npm. - Releases: managed by Changesets.
npm run versionalso runsscripts/sync-version.mjsto keepapp.zonin sync.
- Prefer colocation.
- Use TypeScript with strict typing. Avoid
anyunless absolutely necessary. - Avoid verbose code comments; write self-explanatory code. Comments are acceptable for:
- Explaining complex logic, workarounds, or decisions
- Documenting public APIs (functions, classes, modules)
- TODO/FIXME notes
- When the user specifically asks for comments
- Prefer concise, clear code:
- Prefer early returns to reduce nesting.
- Prefer single-line
ifstatements for simple conditions.
- If a file gets too long (e.g. >600 lines), refactor into smaller modules.
- Check for existing utilities/hooks/components before creating new ones. Avoid duplication.
- Remove dead and commented-out code; don't preserve old APIs unless asked.
- When moving code, don't leave a re-export behind for backwards compatibility. Update every importer and delete the old definition — single source of truth.
- Variables and regular functions shouldn't be prefixed with
use. Theuseprefix is reserved for React hooks. - Don't use
forwardRef. React 19 passes refs to function components directly. - Avoid
useEffectunless absolutely necessary; prefer custom hooks.- If you use
useEffect, first read https://react.dev/learn/you-might-not-need-an-effect and reevaluate. Always add a comment explaining what the effect does.
- If you use
When changing user-facing behavior or APIs, update all relevant docs in the same change: README.md, DEVELOPMENT.md, CONTRIBUTING.md, AGENTS.md. Documentation must not go stale.