Wiki › Implementation › Dev Guide
How to run, build, and navigate the codebase.
npm install
npm run dev # http://localhost:5678 (opens browser)The dev script includes --host, so the server is also accessible on your local network — useful for testing on a real mobile device: http://<your-machine-ip>:5678.
Other scripts:
| Command | Purpose |
|---|---|
npm run build |
Production build |
npm run preview |
Preview production build |
npm run check |
TypeScript + Svelte type checking |
npm run test |
Pure-logic unit tests (see below) |
npm run docs:links |
Check wiki relative links + heading anchors |
npm run lint |
Prettier + ESLint |
npm run format |
Auto-format with Prettier |
flowchart TB
root[CosmicWorkOut/]
root --> docs[docs/ — project wiki]
root --> src[src/]
root --> static[static/]
root --> pkg[package.json]
root --> vite[vite.config.ts]
docs --> wiki[README.md — start here]
src --> routes[routes/ — pages]
src --> lib[lib/ — components, stores, db]
src --> appcss[app.css — design tokens]
classDef root fill:#3b3f8c,stroke:#23264f,color:#ffffff;
classDef folder fill:#1f6f6f,stroke:#0f3a3a,color:#ffffff;
classDef leaf fill:#465569,stroke:#28313e,color:#ffffff;
class root root;
class docs,src,static folder;
class pkg,vite,wiki,routes,lib,appcss leaf;
| File | Why it matters |
|---|---|
src/routes/+layout.svelte |
App boot, global overlays |
src/lib/db/database.ts |
IndexedDB open, read, write |
src/lib/db/seed.ts |
Built-in exercises and programs |
src/lib/db/types.ts |
All data interfaces |
src/lib/stores/*.svelte.ts |
Application state |
src/app.css |
Design tokens and global styles |
src/lib/itemLibrary.ts |
Per-Discipline LibrarySheet config |
src/lib/db/backupPayload.ts |
Backup envelope, validation, restore preflight |
npm test runs Node's built-in test runner over *.test.ts files with type
stripping — no framework, no browser, no new dependencies. Covered today:
goal-plan generation, baseline aggregation and duration parsing, Overview card
ordering, the backup/restore payload path, chart axis math (charts.test.ts),
Insights aggregation and heat shading (insights.test.ts), and habit color
defaults (habitColors.test.ts).
The npm test globs cover src/lib/*.test.ts plus a few named folders, so new
test files for other folders live at src/lib/ (e.g. src/lib/charts.test.ts
tests src/lib/charts/scale.ts) rather than changing the script.
Tests therefore reach pure modules only. A file is testable when it imports
nothing at runtime beyond other pure modules — import type from $lib/... is
fine (type stripping erases it), but a runtime $lib import or a .svelte.ts
store is not resolvable and will fail.
When logic worth testing sits behind IndexedDB or the DOM, split the decision out into a pure module and leave the plumbing behind. That is why
backupPayload.tsexists apart frombackup.ts: restore is the one failure the user cannot recover from, so the checks that run beforeclearWorkoutData()are tested even though the transactions around them are not.
Add a new test directory to the test script's globs in package.json.
Three layers, in order of preference:
- Design tokens (
:rootinapp.css) — colours, spacing, radii, easing. Never hard-code a value a token already covers. - Primitive components (
lib/components/) —Button,Chip,FieldLabel,DialogTitle,SheetBody,SheetHeader. A recurring visual pattern becomes a component that owns its own scoped CSS. See Components. - Scoped component CSS — everything genuinely local to one component.
app.css is global-only: tokens, reset, .sr-only, focus ring, app shell, .page,
keyframes. Per Decision 4,
shared UI patterns are wrapper components, not global utility classes — a global
.btn/.chip layer was tried and reverted in September 2026.
Two consequences worth knowing:
A parent cannot restyle a child component's markup. Scoped selectors carry a
.svelte-*hash, and an element rendered by a child component does not carry the parent's hash. So a primitive needs a real prop for anything a caller must vary — never aclasspass-through, which silently does nothing.
Tag selectors stop at the component boundary too.
.field > label { … }will not reach a<label>rendered byFieldLabel. Style the primitive from the inside.
- Add entry to
builtInExercisesinseed.ts - Exercises upsert on boot — no migration needed
- Add to a workout in
makeWorkoutA/B/C()if it should appear in the default program
How code gets written in this repo — for any contributor, human or AI.
- Clean, modern code. Svelte 5 runes, current idioms; match the style of the surrounding file.
- No new dependencies. Solve it with what's already in
package.jsonunless there's a compelling, discussed reason to add a package. - Small, focused components. Prefer composition over large multi-purpose components — see Components.
- Implement, then review. For a multi-step task, work through the whole thing and present it for review at the end rather than stopping for sign-off between steps. Surface a question mid-stream only when a decision is genuinely blocking and ambiguous.
- Docs are the project's memory. When a decision is locked or behavior changes, update the relevant doc in
docs/so it reflects reality — see Documenting decisions. Deferred ideas go on the roadmap.
Open browser DevTools → Application → IndexedDB → cosmic-workout. LocalStorage keys are prefixed cwout:.
To reset workout data in-app: Settings → Data → Clear workout data. To reset preferences only: Settings → Data → Reset preferences.
For a full manual reset via DevTools: delete the IndexedDB database and clear localStorage, then reload.
- App Structure — Routes and boot flow
- Tech Stack — Framework choices
- Implementation Status — What's built