Why this simulator is structured like a laboratory instrument (not a toy)
Most simulators start with UI and “make the math fit”. This project intentionally does the opposite: we treat the solver as the instrument, and the interface as a thin control surface.
Physics first. Rendering second. UI last.
Strict architectural direction:
state → core → physics → metrics → panels → rendering → ui → main
No circular imports.
No hidden coupling.
No solver logic inside UI.
Rule: Dependencies may only flow downward. Upstream layers must never import downstream layers.
Every layer is allowed to depend only on layers to its left. Nothing “downstream” may be imported “upstream”. This prevents circular imports and prevents accidental feedback loops.
| Layer | Responsibility | May depend on |
|---|---|---|
| state | Mutable runtime parameters (inputs) | — |
| core | Pure helpers (τ, Rtotal, periods, duty) | state |
| physics | Closed-form kernels (RL/RLC waveforms) | state, core |
| metrics | Measurement math (P/Q/S, energy per period, validation) | state, core, physics |
| panels | Formatting + presentation synthesis (numbers → UI) | metrics |
| rendering | Canvas drawing (scope, field, helix) | physics (via wave builder), panels (readouts) |
| ui | Event binding (sliders, toggles, focus mode) | state (write), rendering hooks (callbacks only) |
| main | Orchestration + lifecycle (init + loop) | everything (as a coordinator) |
If solver logic lives in UI code, then:
Instead, UI is restricted to two safe actions:
Rendering is downstream. It consumes already-computed waves/metrics and draws them.
This is why the simulator stays defensible: even if you export a PNG, pause the view, or drop to 15 FPS, the computed values are unchanged — only the presentation changes.
Hidden coupling is when two parts of the app affect each other without an explicit interface. Examples we avoid:
Instead, data flows in one direction: inputs → state → physics/metrics → panels/render → pixels.
The math must remain correct if the UI is deleted.
The UI must remain functional if the renderer is replaced.
Rendering must never change physics.