After making changes, always run from the totality root:
npm run checkThis runs type checking and linting and must pass.
For runtime verification, the default is the headless smoke test:
npm run sim-test -- --sim=quantum-wave-interferenceException: when you are running under claude --chrome (a live browser session), visual verification in that live Chrome session substitutes for the headless sim-test smoke test. In that mode, load the sim in the live browser, confirm it starts without console errors, and exercise the changed feature directly instead of running sim-test.
sim-test accepts a --script flag that evaluates JavaScript in the browser after the sim starts. Use this to interrogate model state, verify property values, and understand the sim at runtime.
# How many screens?
npm run sim-test -- --sim=quantum-wave-interference --script="phet.joist.sim.screens.length"
# Sim version
npm run sim-test -- --sim=quantum-wave-interference --script="phet.joist.sim.version"
# List screen names
npm run sim-test -- --sim=quantum-wave-interference --script="phet.joist.sim.screens.map(s => s.tandem.phetioID).join(', ')"# Dump key model properties from screen 0
npm run sim-test -- --sim=quantum-wave-interference --script="
const model = phet.joist.sim.screens[0].model;
const scene = model.sceneProperty.value;
JSON.stringify({
selectedScene: scene.sourceType,
isPlaying: model.isPlayingProperty.value,
wavelength: scene.wavelengthProperty.value,
intensity: scene.intensityProperty.value,
slitSetting: scene.slitSettingProperty.value,
isEmitting: scene.isEmittingProperty.value
}, null, 2)
"After modifying model code, use --script to confirm the change took effect:
# Example: verify a new property exists and has the expected default
npm run sim-test -- --sim=quantum-wave-interference --script="
const model = phet.joist.sim.screens[0].model;
JSON.stringify({ myNewProperty: model.myNewProperty.value })
"When you're not sure what properties exist, explore incrementally:
# List own property names on the model
npm run sim-test -- --sim=quantum-wave-interference --script="
Object.getOwnPropertyNames(phet.joist.sim.screens[0].model).filter(k => k.endsWith('Property')).join('\n')
"
# Then drill into a specific one
npm run sim-test -- --sim=quantum-wave-interference --script="
phet.joist.sim.screens[0].model.someProperty.value
"When working on Quantum Wave Interference, use sim-test iteratively:
- Explore -- Use
--scriptto understand the current model state before making changes. - Change -- Edit the code.
- Check -- Run
npm run checkfor type/lint errors. - Smoke test -- Run
npm run sim-test -- --sim=quantum-wave-interferenceto confirm the sim starts. - Verify -- Run sim-test with
--scriptto confirm the change has the expected runtime effect. - Repeat as needed.
See doc/implementation-notes.md for architecture details, component nickname/street-name mappings (e.g., "camera" = snapshotButton, "eye" = viewSnapshotsButton), and other helpful context.
- Screens: Experiment, High Intensity, Single Particles (in that order). Use
--screens=N(1-indexed) to load a specific screen, e.g.?screens=2for High Intensity. - Common code:
js/common/-- colors, constants, query parameters, and any code shared across two or more screens - Experiment screen:
js/experiment/-- model and view - High Intensity screen:
js/high-intensity/-- model and view - Single Particles screen:
js/single-particles/-- model and view - Entry point:
js/quantum-wave-interference-main.ts-- registers all three screens - Strings:
quantum-wave-interference-strings_en.yaml
When refactoring to share code between screens, move the shared code into js/common/ rather than importing across sibling screen directories. Never modify the Experiment screen's observable behavior when doing so.