Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 74 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Sim-specific context for AI assistants. General SceneryStack guidance: [OpenPhys

## Project

Reusable single-screen SceneryStack template. When forking, search-and-replace `sim-template` / `SimTemplate` / `Sim Template` / `SimModel` / `SimScreen` throughout.
Reusable single-screen SceneryStack template. Run `npm run rename` to fork it to a new sim name automatically. For multi-screen sims, see `doc/multi-screen.md`.

## Key files

Expand All @@ -18,7 +18,44 @@ Reusable single-screen SceneryStack template. When forking, search-and-replace `
| `src/sim-screen/view/SimScreenView.ts` | Visual nodes, layout, `screenSummaryContent` + `pdomOrder` |
| `src/sim-screen/view/SimScreenSummaryContent.ts` | Accessible screen summary (reference a11y pattern) |
| `src/sim-screen/view/SimKeyboardHelpContent.ts` | Keyboard-help dialog content |
| `src/common/SimPanel.ts` | Pre-themed `Panel` wrapper (uses `SimColors` automatically) |
| `src/common/TimeModel.ts` | Composable play/pause + elapsed-time model for animated sims |
| `scripts/generate-icons.ts` | PNG icons from `public/icons/icon.svg` |
| `scripts/rename-sim.ts` | Automated fork/rename across all files and folders |

## Common components

### SimPanel

Every control panel and info box in the sim should use `SimPanel` so that
default/projector color switching is automatic:

```typescript
import { SimPanel } from "../../common/SimPanel.js";
const panel = new SimPanel(content); // uses SimColors defaults
const panel = new SimPanel(content, { xMargin: 20 }); // override any PanelOption
```

### TimeModel

For simulations with animation, compose `TimeModel` into your screen model:

```typescript
import { TimeModel } from "../../common/TimeModel.js";

export class FrictionModel implements TModel {
public readonly timer = new TimeModel(); // starts paused; pass true to auto-play

public step(dt: number): void {
this.timer.step(dt);
// use this.timer.timeProperty.value for physics
}
public reset(): void { this.timer.reset(); /* … */ }
}
```

Wire the view to `TimeControlNode` from `scenerystack/scenery-phet` binding on
`model.timer.isPlayingProperty`.

## Accessibility

Expand All @@ -31,11 +68,46 @@ every interactive node. Full convention and checklist: [../ACCESSIBILITY.md](../

## Customizing a new sim from this template

1. **Rename** — replace template identifiers in `init.ts`, `brand.ts`, `package.json`, and screen folders
### Automated rename (recommended)

```sh
npm run rename -- --id friction --name "Friction"
# or for multi-word names:
npm run rename -- --id wave-interference --name "Wave Interference"
```

This replaces all template identifiers in file contents and renames files/folders. Run `npm run check` afterwards to verify TypeScript is clean.

### Manual checklist (if not using the rename script)

1. **Rename** — replace `sim-template` / `Sim Template` / `Sim` prefix in `init.ts`, `brand.ts`, `package.json`, class names, and screen folders
2. **Locale** — add `strings_XX.json`, register in `StringManager`, add locale to `init.ts` `availableLocales`
3. **Icon** — edit `public/icons/icon.svg`, run `npm run icons`; match theme color in `index.html` / `vite.config.ts`
4. **Colors** — edit `SimColors.ts` (`default` + `projector` profiles per property)

## Multi-screen sims

Full guide: **`doc/multi-screen.md`**

Summary:
- Create a new screen folder mirroring `src/sim-screen/` for each screen
- Add screen-name keys to all locale JSON files
- Expose new `StringProperty` getters in `StringManager.getScreenNames()`
- For shared state, create a root model passed to each per-screen model
- Register all screens in the `screens` array in `main.ts`

## Using this template beyond a direct copy

| Approach | When to use |
|---|---|
| **GitHub template** ("Use this template" button) | Starting a single new sim |
| `npm run rename` after cloning | Same, automated |
| **npm workspace / monorepo** | Managing a suite of sims with shared tooling |
| **`npm create` scaffolder** | Org-wide standardized sim bootstrapping |
| **git subtree** for pulling updates | Keeping forks in sync with template improvements |

See `doc/multi-screen.md` → "Using this template beyond a direct copy" for details on each approach.

## PWA

After `npm run build`, the sim is installable offline via Workbox (`dist/manifest.webmanifest`).
106 changes: 84 additions & 22 deletions doc/implementation-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,113 @@

## Architecture Overview

TemplateSingleSim is a minimal starter scaffold for forking new single-screen SceneryStack simulations. It demonstrates the Model-View pattern, color profiles, localization, and reset behavior without domain-specific physics.
TemplateSingleSim is a minimal starter scaffold for forking new single-screen SceneryStack simulations. It demonstrates the Model-View pattern, color profiles, localization, reset behavior, and reusable common components without domain-specific physics.

### High-Level Architecture

The simulation follows a modular architecture:
```
main.ts
└─ SimScreen (Screen<SimModel, SimScreenView>)
├─ SimModel state + logic (src/sim-screen/model/)
└─ SimScreenView visuals (src/sim-screen/view/)
├─ SimScreenSummaryContent (PDOM overview)
└─ SimKeyboardHelpContent (keyboard help dialog)

- **Model Layer (`src/sim-screen/model/`)**: Stub model with TODO hooks for `step()` and `reset()`
- **View Layer (`src/sim-screen/view/`)**: Placeholder background, label, and Reset All button
- **Bootstrap**: `brand.js` must load first in `main.ts`; `init.ts` configures locales and splash
src/common/
├─ SimPanel.ts pre-themed panel (all screens share SimColors)
└─ TimeModel.ts composable play/pause + elapsed time

Data flows from Model → View through AXON-ready property patterns documented in `SimModel.ts`.
src/preferences/
├─ SimPreferencesModel sim-specific pref state
├─ SimPreferencesNode pref UI shown in Preferences → Simulation
└─ simQueryParameters query-parameter declarations
```

Data flows Model → View through AXON `Property` objects. The view observes
properties via `.link()` or `.lazyLink()` and updates reactively.

## Model Components

### Core Model Design
### SimModel

An empty coordinator with documented hooks for `step(dt)` and `reset()`.
Add physics state as `BooleanProperty`, `NumberProperty`, etc. from
`scenerystack/axon`.

### TimeModel (common)

`SimModel` is an empty coordinator with commented examples for observable properties and simulation stepping.
`src/common/TimeModel.ts` is a reusable play/pause + elapsed-time model for
animated sims. Compose it into your screen model rather than subclassing:

When forking this template:
```typescript
export class YourModel implements TModel {
public readonly timer = new TimeModel();

1. Rename `SimModel`, `SimScreen`, and `SimScreenView` to match the new sim name
2. Replace `SimColors.ts` and `SimNamespace.ts` with sim-specific files
3. Add physics logic in `step()` and state restoration in `reset()`
public step(dt: number): void {
this.timer.step(dt);
// physics driven by this.timer.timeProperty.value
}
public reset(): void { this.timer.reset(); }
}
```

## View Components

### SimScreenView as Coordinator

The screen view demonstrates layout using `layoutBounds`, background fill from `SimColors.ts`, and a `ResetAllButton` wired to `model.reset()`.
The screen view demonstrates layout using `layoutBounds`, background fill from
`SimColors.ts`, and a `ResetAllButton` wired to `model.reset()`. Add
specialized sub-nodes under `src/sim-screen/view/`.

When extending the view:
### SimPanel (common)

- Add specialized nodes under `src/sim-screen/view/`
- Keep colors in `SimColors.ts` and strings in `src/i18n/strings_*.json`
- Run `scripts/generate-icons.ts` after updating branding assets
`src/common/SimPanel.ts` wraps SceneryStack's `Panel` with the sim's color
scheme baked in. All control panels should use `SimPanel` so projector-mode
switching is automatic:

```typescript
const panel = new SimPanel(content); // defaults
const panel = new SimPanel(content, { xMargin: 20 }); // any PanelOption override
```

### Color Scheme

`SimColors.ts` defines `ProfileColorProperty` instances for default and projector profiles. This is the pattern all forked sims should follow.
`SimColors.ts` defines `ProfileColorProperty` instances for "default" (dark)
and "projector" (light) profiles. SceneryStack switches profiles automatically
when the user toggles Projector Mode in Preferences.

## Forking this template

### Automated rename

### Fork Checklist
```sh
npm run rename -- --id friction --name "Friction"
npm run check
```

- Update package name, sim title, and locale files (en, es, fr)
- Regenerate PWA icons and splash assets
`scripts/rename-sim.ts` replaces all template identifiers in file content and
renames files and folders in one pass.

### Manual fork checklist

- Update `package.json` name, `init.ts` name/version, `brand.ts`
- Replace placeholder view content with play area and control panels
- Replace `SimColors.ts` colors with sim-specific palette
- Update locale JSON files: title, screen names, a11y strings
- Regenerate PWA icons (`npm run icons`) after editing `public/icons/icon.svg`
- Add `doc/implementation-notes.md` describing the new sim's architecture

Note that no dispose functions have been used, which should be addressed once listeners are added.
## Multi-screen simulations

See `doc/multi-screen.md` for a complete guide covering:
- Independent vs. shared-model architectures
- File structure for each screen
- StringManager and locale changes
- Home-screen icon requirements
- Per-screen accessibility strings

## Known gaps / TODOs

- No dispose() calls yet — add them once Properties gain external listeners.
- `SimModel.step()` and `reset()` bodies are stubs — fill in with real physics.
- `SimScreenView` pdomOrder TODO comment — add interactive nodes as they are created.
Loading
Loading