Live Demo
This page explains the demo as a working integration blueprint.
If you are integrating Potree and mapprism-2d in one app, demo/index.html is the reference implementation.
What this demo teaches
The demo shows how to run two renderers in one host layout:
- Potree in
panel-3d MapPrism2Dinpanel-2d- A shared header that controls view mode and active panel
- Runtime synchronization between 3D and 2D view state
In practical terms, it answers:
- how to initialize both viewers from one bootstrap script
- how to hide/show panels without breaking MapLibre sizing
- how to keep context when users move between 3D and 2D
- how to ship usable built-in 2D controls (layers, HUD, measurement) on day one
Runtime architecture at a glance
demo/index.html is intentionally monolithic so you can trace the full flow in one file:
- Load Potree and related global scripts
- Load
MapPrism2Das an ES module - Create the dual-panel DOM structure (
panel-3d,panel-2d) - Start Potree (
window.viewer) - Start
MapPrism2D(window.map2d) with sync enabled against Potree - Wire UI state transitions (split/alternating + panel switch)
Think of it as a host app skeleton. You can later split this into framework components, but the integration order should stay similar.
UI state model (the part most teams need)
The demo keeps UI logic simple and explicit:
viewMode:"alternate"or"split"activePanel:"3d"or"2d"(only relevant in alternating mode)PANELSmetadata object: maps panel ids to labels and switch targets
Two small functions drive almost all behavior:
setViewMode(nextMode)applies mode classes and updates header/buttonssetActivePanel(next)toggles which panel is visible in alternating mode
Important integration detail: after any panel/mode change, it calls:
window.map2d.resize()
This is required because MapLibre must recalculate the canvas when its container visibility/size changes.
Potree bootstrap (3D side)
The demo creates Potree first and exposes it globally:
window.viewer = new Potree.Viewer(...)- sets FOV, point budget, and GUI options
- loads point cloud:
Piney DamEPT source - calls
viewer.fitToScreen(...)after load
Why this matters: MapPrism2D sync receives the Potree viewer reference, so Potree must exist before the 2D map is initialized.
MapPrism2D bootstrap (2D side)
The demo then creates:
window.map2d = new MapPrism2D(document.getElementById("panel-2d"), config)
The config is close to real integration defaults:
initialView: center + zoom + bearingbasemap: "uai"layerPanel: truehud: truetools.measurement.controls: truelayers: raster + PMTiles stack
This gives you a production-like starting point where users can immediately inspect layers and measurements without custom UI code.
3D <-> 2D sync wiring
The demo enables continuous sync using:
sync.enabled: truesync.potree.viewer: window.viewersync.potree.throttleMs: 50
That setup keeps both views spatially coherent while users navigate either panel.
If your product does not need continuous coupling, start with transition-time handoff (getView() / setView()) and enable continuous sync later.
Measurement tools and debug instrumentation
The measurement UI is enabled through tools.measurement.controls: true.
The demo also adds a debug helper:
window.measureDebug
It wraps measurement method calls and logs drawings after each action. This is useful while integrating custom toolbars or validating keyboard finalize/cancel behavior (Enter / Escape).
How to adapt this demo into your app
Use demo/index.html as your migration checklist:
- Keep the same container contract (
panel-3d,panel-2d) or equivalent sized regions. - Preserve initialization order: Potree first, then
MapPrism2Dwith Potree reference. - Keep explicit view state (
viewMode,activePanel) in your host state store. - Call
map2d.resize()whenever panel visibility or layout changes. - Start with built-in controls; replace with custom controls only after behavior is stable.
- Replace demo layer URLs with your environment-specific sources.
Local run
npm install
npm run dev:siteThen open /demo/index.html and keep this guide next to demo/index.html while reading the source.