Shared MapLibre and Cesium application state
This deterministic browser fixture runs a real MapLibre Map and a real Cesium Viewer in one page against one renderer-neutral Honua state synchronizer. Nothing here hand-rolls a port: the two bindings are the SDK's shipped createMapLibreStateSyncPort() and createCesiumStateSyncPort(), and CesiumJS is reached through the bare cesium specifier the page's import map resolves — the same lazy peer path the Cesium port uses internally.
Every fact the fixture reports is read back out of a renderer, not out of a dictionary it kept for itself:
| What crosses | Read back from |
|---|---|
| camera, 2D → 3D | viewer.camera.positionCartographic, viewer.camera.heading/pitch |
| camera, 3D → 2D | map.getCenter(), map.getZoom(), map.getBearing(), map.getPitch() |
| selection, 2D → 3D | viewer.selectedEntity |
| selection, 3D → 2D | map.getFeatureState(...) |
| filters | map.getFilter("incidents"), viewer.entities.getById(...).show |
| time | map.getFilter("incidents"), viewer.clock.currentTime / shouldAnimate |
| detail | map.getFeatureState(...), and the globe's unsupported-target refusal |
| attribution | the shared snapshot, derived from live style credits and primitive attribution |
It also drives one globe pose a Web Mercator plane cannot hold (latitude 88, near-horizon pitch) to show the clamps being reported as typed degradations while the shared 3D state is left intact.
Build the SDK and serve the repository root so /dist, /node_modules, and this directory share an origin. The browser assertions live in test/playwright/shared-renderer-state.spec.mjs, which recomputes the expected camera values from the SDK's own exported correspondence (mapLibreZoomToCameraHeight / mapLibreCameraHeightToZoom) against the viewport the live map reported. No MapLibre or Cesium dependency is statically imported by the SDK entrypoint; both remain optional peer/runtime choices owned by the application.