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
144 changes: 76 additions & 68 deletions doc/implementation-notes.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,73 @@
# Implementation Notes - Solar System Models

## Architecture Overview
## Architecture overview

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
Two independent screens, each a standard `Screen<Model, ScreenView>` pairing (see
[.github/CLAUDE.md](https://github.com/OpenPhysics/.github/blob/main/CLAUDE.md) for the general
SceneryStack Model/View pattern this follows). The screens share no model state — each owns its own
`Model` — but share layout/color/i18n infrastructure at the `src/` root and in `src/common/`.

```
main.ts
└─ SolarSystemModelsScreen (Screen<SolarSystemModelsModel, SolarSystemModelsScreenView>)
├─ SolarSystemModelsModel state + logic (src/solar-system-models-screen/model/)
└─ SolarSystemModelsScreenView visuals (src/solar-system-models-screen/view/)
├─ SolarSystemModelsScreenSummaryContent (PDOM overview)
└─ SolarSystemModelsKeyboardHelpContent (keyboard help dialog)
├─ PtolemaicScreen (Screen<PtolemaicModel, PtolemaicScreenView>)
│ ├─ PtolemaicModel deferent/epicycle/equant geometry, presets, memory store/recall
│ └─ PtolemaicScreenView orbit diagram, "view from Earth" zodiac strip, path trail
└─ ConfigurationsScreen (Screen<ConfigurationsModel, ConfigurationsScreenView>)
├─ ConfigurationsModel Kepler orbits, elongation, synodic event schedule, timeline
└─ ConfigurationsScreenView orbit diagram, elongation indicator, zodiac strip, timeline

src/common/
├─ SimPanel.ts pre-themed panel (all screens share SolarSystemModelsColors)
└─ TimeModel.ts composable play/pause + elapsed time
├─ TimeModel.ts composable play/pause + elapsed-time model; both screen models compose one
├─ CelestialBodyNode.ts Circle auto-positioned from a model Vector2 Property + a reactive
│ ModelViewTransform2 Property; used for Earth/Sun/planet markers
├─ SolarSystemModelsPanel.ts pre-themed Panel wrapper (all screens share SolarSystemModelsColors)
├─ ZodiacConstellationNode.ts and ZodiacConstellationsData.ts — the shared starfield background
└─ ZodiacStripBackground.ts shared "band of sky" backdrop used by both screens' zodiac strips

src/preferences/
├─ SolarSystemModelsPreferencesModel sim-specific pref state
├─ SolarSystemModelsPreferencesNode pref UI shown in Preferences → Simulation
└─ solarSystemModelsQueryParameters query-parameter declarations
```

Data flows Model → View through AXON `Property` objects. The view observes
properties via `.link()` or `.lazyLink()` and updates reactively.
Data flows Model → View through AXON `Property` objects; views observe via `.link()`, `.lazyLink()`, or
`Multilink.multilink()` and update reactively. Neither model imports from its own `view/`.

## Model components

### PtolemaicModel

Owns the deferent/epicycle/equant geometry (see [model.md](./model.md) for the math) as a chain of
`DerivedProperty`s keyed on the adjustable parameters (`epicycleSizeProperty`, `eccentricityProperty`,
`apogeeAngleProperty`, `motionRateProperty`, `planetTypeProperty`) plus the two time-driven angles
(`sunAngleProperty`, `anomalyProperty`), which `step(dt)` advances (wrapped to `[0, 2π)` so they don't
lose precision over a long play session). `applyPreset`/`storeMemory`/`recallMemory` implement the
preset combo box and the memory-recall buttons from the original Flash sim.

## Model Components
### ConfigurationsModel

### SolarSystemModelsModel
Owns the two Kepler orbits (`semimajorAxis{1,2}Property`, `period{1,2}Property`,
`epochAngle{1,2}Property`) and the derived synodic/event schedule
(`synodicPeriodProperty`, `cycleOffsetProperty`, `eventTimesListProperty`, `eventNamesProperty`,
`currentCycleNumberProperty`). The schedule is **entirely derived** — a single internal `DerivedProperty`
recomputes it from the orbital parameters, and the five public Properties above are `TReadOnlyProperty`
views onto that computation, so nothing outside the model can put the schedule out of sync with the
orbits that produced it.

An empty coordinator with documented hooks for `step(dt)` and `reset()`.
Add physics state as `BooleanProperty`, `NumberProperty`, etc. from
`scenerystack/axon`.
Time-driven animation (`step(dt)`) has three mutually exclusive modes, tracked by a private
`"idle" | "slewing" | "countingDown"` union rather than ad-hoc boolean/sentinel fields:

- **idle** — normal playback; `eventActionProperty` (`RUN`/`PAUSE`/`LOCK`) decides what happens when the
clock crosses the next scheduled event.
- **slewing** — an eased animation (`slewToEvent`) that jumps the clock to a specific event, used when
the user clicks an event on the timeline.
- **countingDown** — used by the `PAUSE` event action: play stops at an event for `pauseTimeProperty`
seconds (tracked by `countdownRemainingProperty`) before automatically resuming.

### TimeModel (common)

`src/common/TimeModel.ts` is a reusable play/pause + elapsed-time model for
animated sims. Compose it into your screen model rather than subclassing:
`src/common/TimeModel.ts` is a reusable play/pause + elapsed-time model for animated sims. Compose it
into a screen model rather than subclassing:

```typescript
export class YourModel implements TModel {
Expand All @@ -52,63 +81,42 @@ export class YourModel implements TModel {
}
```

## View Components

### SolarSystemModelsScreenView as Coordinator

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

### SimPanel (common)

`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
Both `PtolemaicModel` and `ConfigurationsModel` compose a `TimeModel` for `isPlayingProperty` and
`animationRateProperty`, but drive their own `ptolemaicTimeProperty`/`timeProperty` from `step(dt)`
directly (in days and years respectively) rather than using `TimeModel`'s own `timeProperty`.

`SolarSystemModelsColors.ts` defines `ProfileColorProperty` instances for "default" (dark)
and "projector" (light) profiles. SceneryStack switches profiles automatically
when the user toggles Projector Mode in Preferences.
## View components

## Forking this template
### Reactive `ModelViewTransform2`

### Automated rename
`ConfigurationsScreenView`'s orbit diagram rescales whenever either semimajor axis changes (so both
orbits stay fit to the diagram). Its `ModelViewTransform2` is exposed as a `TReadOnlyProperty` (a
`DerivedProperty` of the two axis Properties) rather than a plain mutable object — `CelestialBodyNode`
and `ConfigurationsElongationIndicator` each combine that Property with their model-position Property
via `Multilink.multilink`, so they redraw themselves consistently no matter which dependency changed.
`PtolemaicScreenView`'s transform never changes (that screen has no adjustable orbit radius), so it
wraps its static transform in a constant `Property` to satisfy the same interface.

```sh
npm run rename -- --id friction --name "Friction"
npm run check
```
### SolarSystemModelsPanel (common)

`scripts/rename-sim.ts` replaces all template identifiers in file content and
renames files and folders in one pass.
`src/common/SolarSystemModelsPanel.ts` wraps SceneryStack's `Panel` with the sim's color scheme baked
in. Both screens' control/display panels use it so projector-mode switching is automatic.

### Manual fork checklist
### Color scheme

- Update `package.json` name, `init.ts` name/version, `brand.ts`
- Replace placeholder view content with play area and control panels
- Replace `SolarSystemModelsColors.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
`SolarSystemModelsColors.ts` defines `ProfileColorProperty` instances for "default" (dark) and
"projector" (light) profiles; SceneryStack switches profiles automatically when the user toggles
Projector Mode in Preferences.

## 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
See [doc/multi-screen.md](./multi-screen.md) for the general guide this sim's two-screen structure
follows (independent vs. shared-model architectures, per-screen accessibility strings, home-screen icon
requirements). This sim uses the **independent-state** pattern — the two screens share no model — since
the Ptolemaic and Configurations labs are conceptually separate simulators in the original NAAP suite.

## Known gaps / TODOs
## Decompiling the Flash sources

- No dispose() calls yet — add them once Properties gain external listeners.
- `SolarSystemModelsModel.step()` and `reset()` bodies are stubs — fill in with real physics.
- `SolarSystemModelsScreenView` pdomOrder TODO comment — add interactive nodes as they are created.
See the root [CLAUDE.md](../CLAUDE.md) for `npm run decompile`, which extracts the original Flash
simulators' ActionScript into `NAAP/decompiled/` (git-ignored) as a read-only reference for diffing the
port's math against the originals.
109 changes: 94 additions & 15 deletions doc/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,115 @@

This document describes the model (the underlying physics, math, and behavior) for the simulation, in
terms appropriate for an educator. It is the companion to
[implementation-notes.md](./implementation-notes.md), which targets developers. Replace the placeholder
content below with a description of your own sim's model when you fork this template.
[implementation-notes.md](./implementation-notes.md), which targets developers.

## Overview

*One or two paragraphs describing what the simulation models and the key ideas a student should take
away. Write for a teacher, not a programmer — avoid code and class names.*
This sim ports the NAAP *Solar System Models* lab and has two screens that look at the same historical
question — "why do planets sometimes appear to move backward against the stars?" — from two different
models.

The template ships with no domain-specific physics; it is a minimal Model-View scaffold. A real sim
replaces this section with its actual conceptual model.
- **Ptolemaic System** reconstructs the Earth-centered (geocentric) explanation: each planet rides a
small circle (the *epicycle*) whose center travels around a larger circle (the *deferent*) centered
near, but not exactly on, the Earth. This combination of circles-on-circles reproduces retrograde
motion without needing a Sun-centered system.
- **Planetary Configurations** shows the Sun-centered (heliocentric) explanation: both bodies orbit the
Sun on simple ellipses (circular in this sim), and retrograde motion is just the geometric effect of
Earth periodically overtaking (or being overtaken by) a slower or faster planet. This screen also
identifies and schedules the recurring alignments — opposition, conjunction, greatest elongation —
that Earth and the other planet form as they orbit.

## Quantities and units
Students can compare the two models directly: the same retrograde behavior an observer sees from Earth
falls out of very different underlying geometries.

*List the primary modeled quantities, their symbols, units (SI where applicable), and ranges.*
## Quantities and units

| Quantity | Symbol | Units | Range |
|---|---|---|---|
| *(example)* time | t | s | 0 – ∞ |
| Epicycle size (Ptolemaic) | R_e | deferent radii | 0 – 1 |
| Eccentricity (Ptolemaic) | ecc | deferent radii | 0 – 0.5 |
| Motion rate (Ptolemaic) | — | °/day | 0 – 4.5 |
| Apogee angle (Ptolemaic) | — | degrees | 0 – 360 |
| Elapsed time (Ptolemaic) | t | days | 0 – ∞ |
| Semimajor axis (Configurations) | a₁, a₂ | astronomical units (AU) | 0.1 – 15 |
| Orbital period (Configurations) | P | years | derived from a (Kepler) |
| Elongation | — | degrees, signed (− = East, + = West) | −180 – 180 |
| Elapsed time (Configurations) | t | years | 0 – ∞ |

## Governing equations

*State the equations or rules that drive the model, with a sentence explaining each. Use a smaller
fixed time step than the screen default if the integration requires it; the model makes no assumption
about frame rate.*
### Ptolemaic System — deferent, epicycle, and equant

The deferent has a fixed radius (normalized to 1) but is offset from Earth by the eccentricity, along
the apogee direction:

```
deferentCenter = eccentricity · (cos apogeeAngle, sin apogeeAngle)
```

The *equant* is the historical device that keeps the deferent's motion uniform even though it is
off-center from Earth: it sits twice as far from Earth as the deferent's center, on the same line.
Motion around the deferent is uniform **as seen from the equant**, not from Earth or from the deferent's
own center — this is what let Ptolemy's model match observations without needing an off-center Earth to
also be off-center in its rotation.

Which angle drives the deferent depends on whether the planet is superior (Mars, Jupiter, Saturn) or
inferior (Mercury, Venus) relative to Earth's orbit:

- **Superior planets**: the deferent (the "slow" circle) is driven by the planet's own orbital angle
(`anomaly`), and the epicycle (the "fast" circle) is locked to the Sun's angle.
- **Inferior planets**: it's reversed — the deferent follows the Sun's angle, and the epicycle follows
the planet's own orbital angle.

This swap is what produces retrograde motion at the right cadence for each class of planet: once per
epicycle revolution, the planet's position as seen from Earth briefly reverses direction along the
zodiac.

### Planetary Configurations — Kepler orbits and synodic events

Both bodies move on circular orbits around the Sun. Kepler's third law ties each orbit's period to its
radius (in AU and years, the constant of proportionality is 1):

```
period = semimajorAxis^1.5
```

An observer on one planet (typically Earth) sees the other planet's apparent position relative to the
Sun — its *elongation* — cycle through recognizable configurations as the two planets' angular
positions drift in and out of alignment. Which configurations are geometrically possible depends on
which orbit is smaller:

- If the **observer's** orbit is the inner one, the target planet can reach **opposition** (directly
opposite the Sun in the sky) and **conjunction** (behind the Sun), with two quadratures in between.
- If the **observer's** orbit is the outer one, the target planet (now moving faster than the observer)
passes through **inferior conjunction** (between Earth and the Sun) and **superior conjunction**
(behind the Sun), with two greatest-elongation events in between.

The time between repeats of the same configuration is the **synodic period** — how long it takes the
faster planet to "lap" the slower one as seen from the Sun. It depends only on the two orbital periods,
not on where either planet currently is:

```
synodicPeriod = 1 / (1/innerPeriod − 1/outerPeriod)
```

Within each synodic cycle, the four named events recur at fixed offsets from a reference time, so the
whole schedule can be predicted and displayed on a timeline rather than only observed as time passes.

## Simplifications and assumptions

*Note anything intentionally idealized or omitted relative to the real-world phenomenon (e.g. no air
resistance, point masses, instantaneous response), so educators can set expectations.*
- All orbits (Ptolemaic deferents and epicycles, and Configurations orbits) are **circular**, not
elliptical — a deliberate simplification shared with the original NAAP labs, since eccentricity's
effect on apparent motion is already the pedagogical point of the *equant*, not orbital ellipticity.
- The Configurations screen models exactly two bodies (an observer and a target) orbiting a fixed Sun;
it does not model mutual gravitational perturbation between planets.
- Distances and angles are normalized model quantities (deferent radii for Ptolemaic geometry, AU for
Configurations), not literal solar-system scale — the Ptolemaic Sun-orbit radius, for instance, is
chosen for a legible diagram, not astronomical accuracy.

## References

*Optional: textbook sections, papers, or standards the model is based on.*
- NAAP *Solar System Models* lab: `NAAP/astroUNL/naap/ssm/modeling.html`,
`NAAP/astroUNL/naap/ssm/naap_ssm_sg.pdf` (student guide).
- Original Flash simulators this sim ports: *Ptolemaic System Simulator* (`ptolemaic.swf`) and
*Planetary Configurations Simulator* (`configurationsSimulator.swf`).
Loading
Loading