camera.up defaulted to three.js's Y-up while the actual data (ROS/FAST-
LIVO2) and WALK mode are Z-up. Orbiting with the pole misaligned from the
cloud's real vertical made yaw look like a diagonal tumble instead of a
clean spin around what's visually "up" in the rendered cloud. Set Z-up at
camera creation and on WALK exit (previously reverted to Y-up).
OrbitControls only tracks 1-2 simultaneous touches — a 3rd pointer makes
it go idle rather than doing anything. Added a three-finger pan on top,
replicating OrbitControls' own (private, unexported) screen-space pan math
so it feels identical to the existing right-drag/two-finger-pan.
- The MENU toggle now works at any viewport width, not just small screens —
desktop/tablet default to the panel open, phones default to closed, and
crossing the 768px breakpoint resets to that side's default. The canvas
already spans the full window behind the panel, so hiding it needs no
resize. The empty-state "open a file" prompt re-centers when the panel
is hidden.
- Android's WebView renders the page in a separate process with its own
memory ceiling, independent of the app's Java heap (android:largeHeap
wouldn't help). A 1.35GB .pcd blew through it and crashed the renderer,
taking the whole app down with no catchable JS exception — confirmed via
a device tombstone: "Render process crash wasn't handled by all
associated webviews, triggering application crash." openFile() now
blocks anything over 300MB on Android (empirical: 233MB survived, 1.35GB
didn't) with a clear in-app message instead of a silent kill. Desktop is
unaffected — it has far more headroom.
- Two-finger touch now free-rotates (any drag direction, not locked to one
axis) while pinch still zooms (OrbitControls' DOLLY_ROTATE instead of the
default DOLLY_PAN). Trades away two-finger panning, which double-click
to recenter mostly substitutes for.
Verified on a physical Galaxy Z Fold.
targetSdk 36 (Android 15+) forces edge-to-edge, so the fixed-position
top rail was drawing behind the status bar clock/battery icons on a
real device (title and DARK/LIGHT toggle both obscured) — invisible on
desktop since there's no inset there. Add env(safe-area-inset-top) via
a --rail-h variable used everywhere the rail's height was hardcoded as
42px, plus viewport-fit=cover so the inset actually gets populated.
Verified on a physical Galaxy Z Fold over adb.
Covers the rustup requirement (Homebrew rust can't cross-compile to
Android), env vars needed for cargo tauri android build, install via
adb, and the cleartext-traffic gotcha for release builds against ws://
rosbridge endpoints.
Restructure src-tauri into lib+bin (Tauri 2's mobile requirement — Android
embeds the app as a JNI cdylib, which needs a [lib] target with
tauri::mobile_entry_point) and scaffold gen/android/ via `cargo tauri
android init`. Builds and packages cleanly to a debug APK/AAB.
pcd_viewer.html: the 284px docked sidebar becomes a slide-in drawer under
768px viewport width (toggled from the rail, closes on backdrop tap), the
rail sheds its subtitle and secondary telemetry chips under 480px, and the
camera panel caps its width to the viewport. Also disables native pinch-zoom
(the canvas has its own via OrbitControls) and sets overscroll-behavior:none
for a full-bleed touch surface.
Lets the cross-section plane sweep back and forth between two positions
like a CT scan, so registration drift between passes shows up as the
section moves through the cloud instead of needing manual dragging.
The .app bundle's binary doesn't auto-update on rebuild without tauri-cli
(not installed on the dev machine) — document the manual sync step so a
fresh clone doesn't hit the "changes aren't showing up" trap.
Orphan branch with no history — includes the Tauri shell (src-tauri/) and
vendored Three.js (vendor/) that were never pushed before, so a fresh clone
can actually build the native app. Drops the large .pcd sample captures and
editor cruft (.obsidian, .DS_Store); they aren't needed to build or run the
app (point clouds load via drag-and-drop, not bundling).