- manager: surface worker_thread errors/exit to clients and tear the sim
down (issue 001); cache last status/state and replay on attach so a
reconnecting client sees current state even when paused (issue 002)
- web socket: capped exponential reconnect backoff + bounded command queue
(issue 003); derive ws/wss URL from page origin (issue 004)
- runner: build replacement engine before freeing the old one (issue 005)
- remove dead VesselConfig message path across types/api/web (issue 006)
Tests added for each fix. Full monorepo suite green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Single engine now lives on the server. Delete the simulation Web Worker,
the JS mock (mock-wasm), apps/web/public/wasm, and retire WorkerMessageDTO
and the wasm|mock SimulationEngine union from @ymir/types. Drop the
COOP/COEP headers and worker.format from vite config (were only for
in-browser WASM).
Task: task_08. Verified: web typecheck + unit suite green (83%), types
100%, api build clean, no dangling references. E2E against a live server
is validated separately (requires the running apps/api + web).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Package the physics engine as an internal @ymir/wasm workspace package
that runs in Node (worker_threads). Parametrize the Emscripten build
(YMIR_WASM_ENVIRONMENT=node, output dir override) so the same C++ core
builds for the server. Expose SimulationEngine interface +
createSimulationEngine() loader mirroring YmirBindings.cpp.
Task: task_01. Tests: 8 passing against the real WASM engine, 100% coverage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add-only network contract for the server-side simulation: ClientMessage
(commands) and ServerMessage (events) TypeBox unions, reusing
SimulationStateDTO/VesselConfigDTO. Adds ScenarioDraftVesselDTO and
ScenarioInputDTO. WorkerMessageDTO left intact (removed in a later task).
Task: task_02. Tests: 45 passing, 100% coverage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
InitialCondition.vesselId held the per-scenario instance id, losing which vessel
TYPE each body was — so a saved scenario could not reload the right vessel config.
Add instanceId (engine body id) and keep vesselId as the type id; emit both from
the scenario store. (Resolves the flagged DTO ambiguity.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 of the Figma "[INSTRUTOR]" port plus hardening found during testing.
Design system
- theme/tokens.ts + global.css: Figma palette, type scale, spacing, radii,
shadows; injected as CSS vars at boot.
- ui/: 11 themed primitives (Button, IconButton, TopBar, Panel, Tabs, Card,
Slider, Field, Modal/AlertDialog, SimulationControl, MapActions), each tested.
App shell (Layout do instrutor)
- features/shell/AppShell.tsx: TopBar (logo + breadcrumb, gated center actions,
Sair/Salvar), full-bleed map, bottom-center Build/Play/Stop pill, bottom-right
zoom, no-ownship AlertDialog. Replaces ScenarioCreatorPage.
- stores/mapStore.ts exposes the Leaflet instance so the zoom pill can drive it;
AreaMapView registers it and drops Leaflet's default zoom control.
Physics truth
- Worker reports which engine loaded (real WASM vs JS mock); surfaced as a
status badge/warning so the instructor never mistakes the mock for real
dynamics. SimulationControls is now a status-only strip (actions moved to the
pill).
Tests
- 229 passing, coverage gate green. New: tokens, all 11 primitives, AppShell,
VesselPanel, vesselPanelStore. Fixed GeralTab to read draft by instanceId.
Docs
- docs/specs/features/instructor-ui/: extracted screen specs, reference maps,
phased PLAN.md, and DYNAMICS-GAP.md (MATLAB↔Ymir physics parity).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Environmental Conditions feature:
- C++ EnvironmentTimeline: time-series current/wind data, JSON serialization
- WASM bindings: loadEnvironment(), World integration
- TypeScript types: CurrentSeries, WindSeries, EnvironmentPayload
- Zustand environmentStore with React panel (EnvironmentConditionPanel)
- Mock WASM current drift physics: nautical→body-frame velocity applied in step()
Bug fixes:
- Vessel instanceId: unique auto-increment ID per scenario instance prevents duplicate
vesselId crash when adding two vessels of same type
- vesselPanelStore: separate vesselTypeId field so config fetch uses correct type ID
(not instanceId) after the instanceId/vesselId split
- VesselMarker stable eventHandlers: useMemo + useRef pattern prevents react-leaflet
from re-registering Leaflet listeners every 50ms tick, fixing panel clicks during
active simulation
Tests:
- Playwright regression suite (e2e/regression.spec.ts): 8 tests covering panel open
during simulation, multi-click consistency, two VLCC no error, dual marker render,
individual panel open, remove-one behavior, current drift, no-drift baseline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces the Area entity: geographic origin (lat/lng = simulation 0,0),
GeoJSON polygon boundary, and environmental constants (gravity, water/air
density, magnetic correction). A simulation cannot run outside its area.
- areas table with origin, polygon (GeoJSON), and environment constants
- Auto-seed from area.json on startup (Baía de Guanabara)
- GET/POST/DELETE /areas endpoints (route → service → repository)
- scenarios.area_id FK — nullable for existing rows, idempotent ALTER migration
- AreaDTO + CreateAreaDTO in @ymir/types; ScenarioDTO gains optional areaId
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds 6 supplementary SQLite tables (physical_props, current, connection_points,
rudders, thrusters, waves) to hold all hydrodynamic data for the VLCC
VLCC_L350_B63_T230 (L=350m, B=63m, T=23m).
- Auto-seed at startup: reads vessel1.json into all tables when DB is empty
- GET /vessels/:id/config endpoint returns full physics config for simulation
- Refactored vessels route to use service + repository layer pattern
- Expanded @ymir/types with VesselConfigDTO and all sub-component schemas
- Simulation worker fetches vessel config on init, passes to WASM loadConfig()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add dist/, *.profraw, .wasm-stage/ to .gitignore
- Remove apps/api/dist/, apps/web/dist/, packages/types/dist/ from git
(generated on build, should not be versioned)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>