Commit: a0c8550
Parent: e9c5ce1

Add project README and expand CLAUDE.md with vision and code style

Mårten Åsberg committed on 2026-05-23 at 17:12
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CLAUDE.md +25 -18
diff --git a/CLAUDE.md b/CLAUDE.md
index ed8e922..23f2967 100644
@@ -2,6 +2,10 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this project is
BirdGO is an offline-first SPA that works like PokémonGO but for real birds. The user taps to listen; BirdNET (via TensorFlow.js) classifies bird sounds locally in the browser; identified species go into a local collection. No audio or data is sent to any server. Online accounts and leaderboards are a planned future feature.
## Commands
All tasks run via Deno. Use `deno task` instead of `npm run`.
@@ -13,40 +17,43 @@ deno task preview # preview production build
deno task check # svelte-kit sync + svelte-check (type checking)
deno task lint # ESLint
deno task test # run all Playwright e2e tests
deno fmt # format (spaces, double quotes, includes Svelte components)
```
Run a single e2e test file:
```bash
DENO_DIR=/home/developer/.cache/deno deno run -A npm:playwright test src/routes/path/to/page.svelte.e2e.ts
deno run -A npm:playwright test src/routes/path/to/page.svelte.e2e.ts
```
Format source files (Svelte component formatting requires the `fmt-component` unstable flag, already set in `deno.json`):
```bash
deno fmt
```
## Code style
- **TypeScript everywhere, full types.** No `any`, no type assertions unless truly unavoidable.
- **Nested CSS inside `<style>` blocks.** Use element and hierarchy selectors (`nav a`, `section > h2`) over classes wherever the HTML structure makes the selector unambiguous. Classes only when hierarchy isn't enough.
- **Semantic HTML.** Use `<main>`, `<nav>`, `<section>`, `<article>`, `<button>`, `<dialog>`, etc. correctly.
- **No premature component extraction.** Keep markup inline until a piece is genuinely reused in two or more places. A component for one caller is noise.
- **Simplest possible implementation.** No abstractions for hypothetical futures. Three similar lines beat a premature helper.
- **Svelte 5 runes only.** `$state()`, `$derived()`, `$effect()`, `$props()`. The Options API is disabled globally in `svelte.config.js`.
## Architecture
This is a **SvelteKit** app using **Svelte 5** with **Deno** as the runtime and package manager.
This is a **SvelteKit** SPA using **Svelte 5** with **Deno** as the runtime and package manager. SvelteKit is used for its component model, routing, and build tooling — not for SSR. All data lives in the browser (IndexedDB).
### Key conventions
### Key layers
- **Svelte 5 runes mode is enforced globally** via `svelte.config.js`. All components must use the runes API (`$props()`, `$state()`, `$derived()`, `$effect()`, etc.). The `runes: true` compiler option is applied to every file outside `node_modules`.
- **`$lib`** maps to `src/lib/`. Put shared components, utilities, and assets there.
- **File-based routing** under `src/routes/`. Each route segment is a directory; `+page.svelte` is the page, `+layout.svelte` wraps child routes.
- **E2e tests are collocated with routes** using the `.e2e.{ts,js}` extension (e.g., `src/routes/demo/playwright/page.svelte.e2e.ts`). Playwright's `testMatch` is set to this pattern.
- **`src/routes/`** — file-based routing. `+page.svelte` is the page, `+layout.svelte` wraps child routes.
- **`src/lib/`** — shared code only. Accessed via the `$lib` alias. Subdivide as needed: `$lib/audio/`, `$lib/db/`, `$lib/model/`.
- **Audio pipeline** — Web Audio API → BirdNET (TensorFlow.js TFJS model) → species result. Runs entirely client-side.
- **Persistence** — IndexedDB for the bird collection and user state. No backend.
- **Offline** — PWA / service worker (not yet implemented).
### Config files
- `deno.json` — Deno tasks, formatter config (`fmt-component` unstable flag for Svelte files), and the `DENO_DIR` cache.
- `deno.json` — Deno tasks and formatter config (`fmt-component` unstable flag enables Svelte formatting).
- `package.json` — npm-compatible dependency declarations consumed by Deno's npm compatibility layer.
- `svelte.config.js` — SvelteKit adapter (`adapter-auto`) and runes enforcement.
- `playwright.config.ts` — e2e tests run against a **production build** (not dev server) on port 4173.
- `tsconfig.json` — extends the generated `.svelte-kit/tsconfig.json`; strict mode enabled.
- `playwright.config.ts` — e2e tests run against a **production build** (port 4173), not the dev server. Test files use the `.e2e.{ts,js}` extension, collocated with their routes.
- `tsconfig.json` — extends `.svelte-kit/tsconfig.json`; strict mode enabled.
### Environment
The Deno npm cache is not at the default location. When running `deno` commands directly (not via `deno task`), set:
```bash
DENO_DIR=/home/developer/.cache/deno
```
`DENO_DIR` is set to `/home/developer/.cache/deno` in `.claude/settings.json` (the default `/deno-dir/` is not writable). This is applied automatically — no manual export needed.
README.md +28 -30
diff --git a/README.md b/README.md
index f3a6f53..3195609 100644
@@ -1,42 +1,40 @@
# sv
# BirdGO
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
> Catch (the sounds of) them all!
## Creating a project
BirdGO is an offline-first Progressive Web App that turns your surroundings into a bird-watching game. Hold up your phone, let it listen, and discover what birds are singing nearby — all without sending audio to any server.
If you're seeing this, you've probably already done this step. Congrats!
## How it works
```sh
# create a new project
npx sv create my-app
```
To recreate this project with the same configuration:
```sh
# recreate this project
deno run npm:sv@0.15.3 create --template minimal --types ts --add eslint playwright --no-download-check --install deno /home/developer/BirdGO
```
- **Listen** — tap to start listening; [BirdNET](https://github.com/birdnet-team/birdnet) runs entirely in your browser via TensorFlow.js
- **Identify** — the model analyzes short audio clips and returns the most likely species
- **Collect** — every new species you hear is added to your local field journal
- **Explore** — browse your collection, see stats, and hunt for species you haven't found yet
## Developing
No account needed. No audio ever leaves your device.
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```sh
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Tech stack
## Building
- [SvelteKit](https://kit.svelte.dev) — SPA framework (Svelte 5, runes mode)
- [BirdNET](https://github.com/birdnet-team/birdnet) + [TensorFlow.js](https://www.tensorflow.org/js) — on-device bird sound classification
- Browser APIs: Web Audio, IndexedDB, Geolocation
- [Deno](https://deno.com) — runtime and package manager
To create a production version of your app:
## Development
```sh
npm run build
```bash
deno task dev # start dev server at localhost:5173
deno task build # production build
deno task check # type-check
deno task lint # lint
deno task test # e2e tests (Playwright)
deno fmt # format
```
You can preview the production build with `npm run preview`.
## Roadmap
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
- [ ] Bird listening and identification (BirdNET + TensorFlow.js)
- [ ] Local collection / field journal (IndexedDB)
- [ ] Offline support (PWA / service worker)
- [ ] Online accounts and leaderboards
- [ ] Region-based species lists and seasonal challenges