What is oniyanma
A point cloud viewer built to make bridge-inspection review work entirely inside the browser.
Convert a multi-gigabyte .las into a single .copc.laz (COPC) ahead of time, and only the LOD nodes actually in view are fetched incrementally over HTTP Range and rendered. Opening a 496 MB point cloud means no wait for a download. Walk under the girders in first person, read the real-world distance (m) between any two points, and non-destructively hide, delete, or reclassify whatever range you're concerned about.
Two things set it apart from other viewers of the same kind.
1. The UI, the AI, and MCP all call the same command layer
Every oniyanma operation, without exception, is collected into a command. UI buttons, keyboard shortcuts, the ⌘K command palette, the in-app natural-language console, and external agents via MCP — all five entry points go through the same executeCommand.
Commands are self-describing. Each one declares its own name, description, argument JSON Schema, whether it's read-only, and whether it's destructive. Because of that:
- The tool definitions handed to the AI are generated from the registry (there's no hand-written API definition)
- Permissions are decided not by a per-command ACL table but by which surface is open
- The confirmation gate for destructive operations exists as structure in the command layer, not as wording in a prompt
- The argument tables in this documentation are generated from that same definition, so they never drift from the implementation
The goal of this design is that adding one command and marking its properties is enough for the public surface, denials, tests, and documentation to follow automatically. Details: The command layer as a design.
2. Viewpoint, selection, and edits are shared live
Participants in the same room share camera viewpoint (another person's view frustum is drawn for you), selection, and non-destructive edits in real time. Sync runs on Yjs (CRDT), so simultaneous edits don't corrupt anything.
The point is that "look here" happens through sharing a selection, not describing coordinates out loud. What's shared isn't a list of point IDs but the selection's predicate (a condition such as "points inside this shape"), so the exact same points end up selected on the receiving screen too. Undo works per user and never sweeps up someone else's edits (the same behavior as Google Docs / Figma).
Details: Collaborating.
What it doesn't break
As a tool for inspection and survey, two invariants take top priority.
The source is never rewritten. Hiding, deleting, reclassifying, and recoloring are all pushed onto the Command log. The attributes that reach the GPU are rebuilt from that log every time, so even after LOD drops and reloads points, the edits come back. The .copc.laz itself is never changed. Saving happens through a sidecar (a separate file).
Numbers never silently go wrong. Measurement values are pinned to known answers in regression tests. A peer's selection whose coordinate frame doesn't match isn't drawn as a misaligned box — the reason is shown and drawing stops instead. A sidecar meant for different data is rejected as a signature mismatch. "A wrong value with no error" is the worst possible failure for an inspection tool, so whenever it's unclear, the design errs toward stopping and stating why.
Structure
| Package | Role |
|---|---|
packages/app | The viewer itself (Vite + TypeScript + three.js). WebGL and WebGPU coexist |
packages/collab | The collaboration sync server (Cloudflare Workers + Durable Objects) |
packages/server | The command relay coordinator (WS) and the MCP server (Node) |
packages/docs | This documentation |
The app is client-only with no backend of its own. Point clouds are pulled with Range requests from static hosting (R2), and AI API keys go straight from the browser to each provider. Only collaboration and the MCP relay need a server.