Fieldwork ยท Electrophysics
An interactive 3D learning lab built with TypeScript, Vite, Three.js, and KaTeX.
PLAN.md controls the subject scope. The only implemented subject is Electric flux and charge.
Run locally
Use Node 22 (at least 22.12.0), as specified in .nvmrc.
npm install
npm run dev
Open the local URL printed by Vite. npm run build type-checks and builds the app into dist/; npm run preview serves that build. npm run typecheck runs TypeScript separately.
No test scripts or test files were created for this implementation. The pre-existing test commands and dependencies in package.json are retained, but there is no test suite in the current working tree.
The experiment
- Change a point charge from โ5 to +5 nC and move it along the x-axis.
- Choose a sphere or cube and change its radius or half side length.
- Compare enclosed charge, surface area, and exact net flux.
- Try positive, negative, and external-charge presets.
- Toggle the surface, field lines, and outward normals.
- Drag to orbit; scroll to zoom. Focus the canvas and use arrow keys to orbit,
+/โto zoom, andHometo reset. All other controls are native keyboard-operable inputs.
The model assumes a stationary ideal point charge in vacuum. The imaginary Gaussian surface is centered at the origin. Geometry uses metres, physics uses SI units, and the interface presents charge in nanocoulombs. A nonzero charge exactly on the surface produces an undefined enclosed-charge/flux result because its field is singular there. The visible marker's radius does not change the point-charge model. Sampled lines and fixed-size arrows illustrate field direction; total flux is calculated analytically, never by counting those lines.
Reference: docs/theory/3Electric flux and charge.pdf, sections 3.2โ3.4. Lesson copy and graphics are original, based on these definitions.
Add another 3D model
- Enable its subject in
PLAN.mdfirst. - Create
src/models/<model-id>/with separate physics, state, scene, and view modules. - Implement
ModelDefinitionfromsrc/core/model.ts.mount(host, { i18n })renders into its host and returns aModelInstancewhosedispose()releases listeners, GPU resources, and observers. - Add its title, controls, explanations, accessibility text, and messages to
src/i18n/en.ts. - Register a lazy-loading definition in
src/models/registry.ts. The current shell mounts its first entry. Add model selection to the shell when a second enabled model is implemented; each model's physics and scene remain independent.
src/models/electric-flux/physics.ts has no dependency on DOM, Three.js, or translations. Rendering consumes physical field directions; it does not own the equations or measurement state. Scenes render only when controls, state, or viewport size changes.
Add a language
English (en) is the default and fallback. User-facing copy is in src/i18n/en.ts, accessed through stable typed keys. Messages accept named parameters and numbers use Intl.NumberFormat.
To support another language, add its catalog and register its BCP 47 locale in src/i18n/index.ts. Pass that locale to createI18n in the shell. Missing messages fall back to English. No physics or model components need rewriting. Add a language selector only once another language has been requested and supplied.
Layout
src/core/ Shared model lifecycle contract
src/i18n/ English catalog, locale registry, formatting
src/models/registry.ts Enabled, lazy-loaded models
src/models/electric-flux/ Pure physics, state, Three.js scene, lesson view
src/ui/ Shared interface graphics
src/main.ts Application shell
src/style.css Responsive presentation