Standalone point cloud viewer for COPC, Potree, and EPT data. Renders via Potree, which streams points on-demand based on the camera view. Designed to be served as static files — works locally or on Cloudflare Pages.
python3 -m http.server 5504
# open http://localhost:5504The Potree build artifacts (build/, libs/, laz-perf.wasm) are committed to the repo, so no build step is needed. To re-fetch them from upstream Potree, run ./setup.sh — it overwrites build/ and libs/ with a fresh build.
Auto-detected from the URL:
| URL ends with | Format | Notes |
|---|---|---|
.copc.laz |
COPC | Cloud Optimized Point Cloud — single self-contained file |
metadata.json |
Potree 2.0 | Converted octree, directory of many files |
cloud.js |
Potree 1.x | Legacy Potree format |
ept.json |
EPT | Entwine Point Tile |
| (anything else) | → treated as COPC | data.copc.laz is appended as a convention |
All four run through the same Potree viewer, so rendering, navigation, and settings are identical.
Three ways:
- Sample buttons — chips at the top of the panel, one per verified public dataset (COPC Autzen, EPT Red Rocks). Adding a Potree 2.0 sample requires a stable public host — none was reliable at port time. Edit the
PRESETSarray inindex.htmlto add more. - URL — paste any URL ending in
.copc.laz/metadata.json/cloud.js/ept.jsonand click Load. Or open the page with?url=...to auto-load:http://localhost:5504/?url=https://example.com/data.copc.laz - Drag & drop — drag a
.copc.lazfile from your file manager onto the page. COPC is single-file so this works locally; Potree 2.0 / EPT are multi-file directories and need a URL.
- Scroll wheel — zoom toward cursor (Earth Controls switch on after load)
- Double-click — focus on a point
- Left drag — orbit around the focal point
- Right drag — pan
- WASD — fly; hold Shift to go much faster
- R — reset view
- Q / E — down / up
Move speed is auto-scaled to dataset size, so WASD stays responsive on city-sized clouds.
If the data has RGB attributes, Potree renders them directly. Otherwise the viewer falls back to elevation-based coloring.
OpenLayers only knows EPSG:4326 and EPSG:3857 natively. Potree uses proj4 to reproject. This viewer pre-registers 19 Japanese plane-rectangular CRS (EPSG:6669–6687) before Potree looks them up — otherwise an Uncaught EPSG:6676 (or similar) error fires when loading data in those CRS.
To add more CRS, edit the <script> block near the top of index.html that calls proj4.defs(...), and add your projection there before Potree.loadPointCloud runs.
# one-time
npx wrangler login
# deploy current directory as a Pages project
npx wrangler pages deploy .wrangler.toml already sets pages_build_output_dir = ".", so the project root is uploaded as the static site.
The _headers file:
- forces
Content-Type: application/wasmon.wasmfiles (some CDNs serve them asapplication/octet-stream, which preventsWebAssembly.instantiateStreamingfrom initializing laz-perf) - adds long-lived immutable caching to
build/andlibs/.
Total deployed size: ~40 MB across ~390 files — well within Cloudflare Pages' limits (25 MB per file, 20,000 files).
- 404 for
sources.json— optional Potree 2.0 file. Ignore. - 404 for
attributes.json— same.
The actual point data lives in metadata.json / hierarchy.bin / octree.bin. If those load, the viewer renders.
- Check the URL in DevTools → Network — is Potree getting 200 responses for
metadata.json/ept.json/.copc.laz? - Check CRS — the File Info panel should show a sensible EPSG. If it's
unknownor mismatched, Potree may place the cloud off-screen. Add the CRS toproj4.defs(...). - Check the console —
Uncaught EPSG:XXXXmeans a CRS isn't registered. - Try double-clicking the map background —
fitToScreenis called after load but can fail on edge cases. - The on-page status bar now reports HTTP status / CORS errors / parse errors with the detected format label.
- Potree: https://github.com/potree/potree
- COPC spec: https://copc.io/
- EPT spec: https://entwine.io/
- Cloudflare Pages: https://developers.cloudflare.com/pages/
