Reworks the console's look away from generic dark-mode defaults: the
neutral ramp carries a faint violet cast, and the signal palette now
distinguishes connection topology by colour — mint for live agents,
iris for direct connections, copper for consent-required machines.
Type contrast comes from pairing the platform mono against the platform
sans rather than a webfont, since the box this runs on has no internet.
particles.js draws a proximity-linked node field: full strength on the
login and public pages, frozen static in the console, and entirely
absent from the viewer, where every frame belongs to the remote desktop.
It caps DPR at 2, scales node count to viewport area, throttles to 30fps,
cancels rAF when the tab is hidden, and honours prefers-reduced-motion.
app.js and viewer.js are unchanged; the particle layer mounts itself and
tracks the console via MutationObserver on #app.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Browser-based remote control (noVNC) with invite links, per-user access
control, garagedoor SSO and a persisted client list.
The hub proxies RFB rather than pointing the browser at a VNC server. That
is what lets it authenticate upstream with a stored password the browser
never sees, and enforce view-only by dropping input messages on the
client->server stream instead of hiding buttons.
Machines are reachable two ways: direct TCP for LAN hosts, or an outbound
agent tunnel for anything behind NAT. Node 22's global WebSocket keeps the
agent dependency-free, and node:sqlite keeps the image free of native
builds.
Ships with an end-to-end suite that boots the real server against a fake
VNC server and a fake auth service (72 assertions), plus Gitea Actions
CI/CD to Portainer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>