An interactive physical-optics simulation of the three interferometers every optics course covers — Michelson, Mach-Zehnder and Fabry-Pérot — built with SceneryStack, Vite 8, TypeScript 7, and Biome 2.
Geometric-optics simulators are common. This one is a physical optics simulator: it tracks optical path length, phase and partial coherence, and renders the interference pattern those produce rather than drawing a picture of one.
- Michelson — coarse and micrometer mirror travel, mirror tilt to drive circular fringes into straight ones, an evacuable gas cell for the classic index-of-refraction measurement, a compensator plate, a fringe counter, an intensity trace across the detector, and a visibility curve that shows the coherence envelope — flat for a laser, a needle for white light, and the sodium doublet's nulls and revivals
- Mach-Zehnder — both complementary output ports shown at once, an insertable sample slide with adjustable thickness, index and tilt, and a single-photon mode that builds the pattern one detection at a time (pausable and steppable), with a which-path marker that erases it — and a trace of both ports whose dashed total stays flat, so interference visibly moves light rather than destroying it
- Fabry-Pérot — mirror reflectance from 0.04 to 0.99, absorption, cavity spacing and a scanning mode you can pause and step onto a transmission peak, with live finesse, free spectral range and resolving power, plus a transmission spectrum showing whether two lines are resolved
- Six light sources from a helium-neon laser to white light, spanning 200 mm to 1 µm of coherence length — including the sodium doublet and its visibility beats
- Physically computed colour: white-light fringes come out with the correct achromatic centre and coloured orders, summed in linear light through CIE XYZ
- An optional Preferences overlay labelling each optical element with what it contributes to the optical path difference — including the factor of two a Michelson arm carries and a Mach-Zehnder's does not
- Full keyboard access and live screen-reader descriptions of the pattern and of both charts
- English, Spanish, and French localization via
StringManager - Default and projector color profiles
- Progressive Web App (installable, offline-capable)
- Shared GitHub Actions CI via
OpenPhysics/Baton
| Document | Contents |
|---|---|
doc/model.md |
The physics: coherence, path difference, the three instruments |
doc/implementation-notes.md |
Architecture, the renderer, the colour pipeline |
npm install
npm run icons # generate PNG icons from public/icons/icon.svg
npm start # dev server → http://localhost:5173| Command | Description |
|---|---|
npm start / npm run dev |
Start Vite dev server |
npm run build |
Type-check + production build → dist/ |
npm run preview |
Preview the production build locally |
npm test |
Run Vitest unit tests (includes memory-leak suite) |
npm run test:fuzz |
Optional Playwright fuzz smoke (?fuzz, default 15s) |
npm run test:fuzz:quick |
Shorter fuzz smoke (10s) |
npm run check |
TypeScript type check |
npm run lint |
Biome lint check |
npm run format |
Auto-format all files |
npm run fix |
Lint + auto-fix |
npm run icons |
Regenerate PNG icons from public/icons/icon.svg |
npm run clean |
Remove dist/ |
New sims start at version: "0.0.0" in package.json. Bump only when cutting a release (for example npm version patch and a matching git tag). Keep name in kebab-case; it is separate from the SceneryStack sim identifier in src/init.ts.
| Tool | Version | Purpose |
|---|---|---|
| SceneryStack | ^3.0.0 | Simulation framework |
| Vite | ^8 | Build tool + dev server |
| TypeScript | ^7 | Type-safe JavaScript |
| Biome | ^2.5 | Linting + formatting |
| vite-plugin-pwa | ^1 | PWA + service worker |
GNU Affero General Public License v3.0 — see OpenPhysics org license.
See OpenPhysics contributing guidelines. Report bugs via GitHub Issues; use org issue templates.