GENERATED by tools/embed_viewer.py from views/viewer.html — do not edit. The viewer page, embedded so an installed binary needs no views/ directory on disk (--page FILE overrides). Chunked because released nurlc stack-overflows on string literals past ~48 KB.
@ viewer_html_chunks → i@ viewer_html_chunk i k → spackages/ply/src/view.nu — look at the cloud.
Serves two things on localhost: the viewer page, and the bytes of a PLY file.
GET / the viewer, one self-contained WebGL document GET /cloud the PLY, verbatim
The page is compiled into the binary (viewer_html_data.nu, generated by tools/embed_viewer.py) because nurlpkg install ships a binary and nothing else — a views/ path next to the executable can never resolve for an installed tool. A page_override file path replaces it while editing the page.
The cloud is read into memory once and handed out on every request. A large scene is ~100+ MB, which is a lot to hold but exactly what the browser is about to hold anyway, and it means the file can be replaced underneath a running viewer without the server noticing a half-written one.
( vw_serve path host port page_override quiet tls ) → i exit code
host is the BIND address: 127.0.0.1 stays private to the machine, 0.0.0.0 serves every interface, a specific address (192.168.1.30) serves exactly that adapter. tls != 0 generates a fresh self-signed P-256 certificate at startup (std/x509_gen) and serves HTTPS — the browser warns once, but the bytes cross the LAN encrypted.
: VwState: VwState {
String page
String name
( Vec u ) cloud
}
: ~ i g_vw 0@ vw_page s override → StringThe page as compiled in. --page FILE reads from disk instead, which is the only way to iterate on the viewer without rebuilding.
@ h_vw_index HttpRequest req Params p → HttpResponse@ h_vw_cloud HttpRequest req Params p → HttpResponse@ vw_serve s path s host i port s page_override i quiet i tls → iServe path until interrupted. Returns a process exit code.
packages/ply/src/ply.nu — a streaming PLY point-cloud writer.
The property layout is the one every viewer reads and the bundled viewer parses: x, y, z as float32 and red, green, blue as uchar — 15 bytes a vertex in binary_little_endian, one line a vertex in ascii.
The vertex count is usually not known until the last point is pushed, so the header is written with a fixed-width zero-padded placeholder and patched in place at the end, rather than holding the whole cloud in memory:
( ply_create path ascii comment ) → !*PlyW String ( ply_vertex w x y z r g b ) → v buffered; flushes itself ( ply_count w ) → i vertices pushed so far ( ply_finish w ) → b flush, patch the count, close
ply_finish frees the handle either way; its F means the file could not be finished and should not be trusted.
Writes are buffered ~4 KB at a time — a vertex is 15 bytes, and a write per vertex would make the file the slowest part of a pipeline that computes millions of them.
: i PLY_COUNT_WIDTH 12The count field is fixed-width so the header keeps its byte length when the real number is patched in. 12 digits holds any cloud a filesystem holds.
: i PLY_FLUSH_AT 4096: PlyW: PlyW {
File f
i n
i ascii
i cnt_off // where the count field starts, for the patch at the end
String abuf
( Vec u ) bbuf
}
@ ply_create s path i ascii s comment → !*PlyW StringOpen path and write the header. comment goes in as one comment line ("" for none) — a place for provenance, not for structure.
@ ply_count * PlyW w → i@ ply_flush * PlyW w → bWrite out whatever is buffered. Idempotent; ply_vertex calls it on its own past PLY_FLUSH_AT bytes.
@ ply_vertex * PlyW w f x f y f z i r i g i b → vPush one vertex. Colour components are clamped to 0..255.
@ ply_finish * PlyW w → bFlush, rewind to the count field, overwrite it in place, close, free.
packages/ply/src/main.nu — the ply CLI.
ply view <cloud.ply> [--port n] [--host a] [--tls] [--page f] ply info <cloud.ply> print the header ply <cloud.ply> shorthand for view
The viewer serves one self-contained WebGL page on localhost and the cloud next to it; nothing is installed, nothing leaves the machine.
@ main → i