Newbury Exhibit v3

Fan-made shared multi-viewer AR experience for a physical LEGO® Hidden Side™ town display (tribute project — not affiliated with the LEGO Group). Multiple phones detect printed "Newbury Crests" (ArUco markers) and see the same server-driven ghosts anchored to real-world positions, each from their own viewpoint.

v3 = v2 with the tracking core replaced. Everything else — playlist engine, residents/tracks, character editor, admin suite, dev error overlay, password- protected final mode, deployment — carries over unchanged.

What changed in v3

The per-marker POS-IT → confidence-weighted fusion pipeline is replaced by a joint multi-marker board solve (public/js/ar/solve-cv.js, OpenCV.js):

  • Every detected crest corner becomes a 3D world point (from data/scene.json anchors, same anchorWorldMatrix convention as v2) and one solvePnP call recovers the camera pose. No per-marker fusion, no slerp base, no area buckets.
  • Stability scales with marker spread. Synthetic validation at 0.5px corner noise: ~0.06 cm position / 0.03° rotation error on the full 5-crest board (single-marker POS-IT on the same test: ~2.6 cm / 0.9°).
  • The wall crest makes the point set non-coplanar, which removes the POS-IT planar ambiguity (the flip problem) outright whenever it's visible.
  • Single visible crest still works: SQPNP/IPPE cold start, then iterative refine warm-started from the previous frame (temporal continuity resolves flips).
  • A reprojection-error gate (mean px, shown in the dev HUD) rejects poisoned frames before they reach the 1€ filter.

OpenCV.js (~13 MB WASM) is fetched at Docker build time (pinned @techstark/opencv-js@4.12.0-release.1) and lazy-loaded on the client after Start. If it fails to load, the app falls back to the v2 engine automatically.

Dual engines (on-table A/B)

The complete v2 pipeline (detect.jspose.jsfuse.js) ships alongside the new one until the board solve is confirmed on the real table.

Dev HUD overlay tap zones (thirds):

zone opencv engine posit engine
top switch engine switch engine
middle axis mode (std/ymirror) rotation mode (fr/…)
bottom camera correction (none/…)

Engine choice persists in localStorage (nbx.engine). Optional per-device horizontal FOV override: localStorage nbx.hfovDeg (default 60, both engines).

axis ymirror exists as on-device insurance: if the world appears mirrored / camera under the table in opencv mode, tap the middle third once.

First-time load (in place of v2)

git clone https://gitea.hideawaygaming.com.au/jessikitty/newbury-exhibit-v3.git ~/newbury-exhibit-v3
cd ~/newbury-exhibit-v3 && bash load-v3.sh

load-v3.sh imports the unchanged v2 base files into this repo (one commit, pushed — set GITEA_TOKEN=… if the machine has no git credentials), copies .env and any locally-dropped public/models from the v2 checkout, stops the v2 container, and brings v3 up on the same host port, container name, and exhibit-live volume — live scene/playlist/character state carries over.

  • Future deploys: cd ~/newbury-exhibit-v3 && bash deploy.sh (same as v2).
  • Rollback any time: cd ~/newbury-exhibit && docker compose up -d --build.

Conventions (unchanged from v2)

  • World units cm; origin front-left table corner; +X right, +Z back, +Y up.
  • Marker print sizes stay in mm (sizeMM); single mm→cm conversion at the solver boundary.
  • data/*.json are committed seeds; data/live/ (volume) is runtime state.
  • maxHammingDistance: 0 — hamming-1 detections are 100% phantoms here.

LEGO® and Hidden Side™ are trademarks of the LEGO Group, which does not sponsor, authorise or endorse this project.

S
Description
Newbury Exhibit v3 — shared multi-viewer AR for the LEGO Hidden Side tribute display. v3 replaces per-marker POS-IT + fusion with a joint multi-marker OpenCV board solve.
Readme
354 KiB
Languages
HTML 55.6%
JavaScript 43.1%
Shell 1.1%
Dockerfile 0.2%