Skip to content
peterlodri-secPublic

About

Live WebGPU 4D visualization of a Tailscale tailnet (space × time × direction × channel)

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tailscope cover art — a bright cyan-white central node with luminous particle streams radiating to smaller glowing orbs in teal, amber, magenta and violet on a deep-space background

Cover art — AI-generated concept art, not a screenshot. Real frames from the live renderer are in the gallery below.

tailscope

A single-page WebGPU visualization of a live Tailscale tailnet, rendered as a living 4D graph. GPU-driven particle flows stream between your nodes in real time, derived from tailscale status --json.

tailscope — live tailnet flow, this node at the center with particle streams to active peers

A real screenshot of the running app — this node (dev-cx53) at the center, live particle flows to active peers.

Tailnet-only. It reads the local tailnet and is meant to be served over the tailnet (via tailscale serve, which also gives you the HTTPS that WebGPU requires).

Quick start

On any machine in your tailnet that runs the Tailscale daemon:

git clone https://github.com/peterlodri-sec/tailscope
cd tailscope

python3 server.py &                        # serves 127.0.0.1:8799 — stdlib only, no deps
sudo tailscale serve --bg --https=443 8799 # expose it over the tailnet with HTTPS

tailscale serve prints the URL, e.g. https://<node>.<your-tailnet>.ts.net/. Open it from any tailnet device in a WebGPU browser (recent Chrome / Edge, or Safari 18+) and you'll see your tailnet come alive.

Plain http://… over the LAN will not work — WebGPU requires a secure context, which tailscale serve provides automatically (it terminates TLS with a valid *.ts.net cert).

Stop it:

sudo tailscale serve --https=443 off && pkill -f server.py

The four dimensions

axis encoding
space nodes laid out in 3D, clustered by DERP relay region; this node at the origin
time particles stream continuously; the graph breathes as live byte-rates change
direction warm particles leave this node (tx), cool particles arrive (rx)
channel hue = DERP relay region (or direct), on a perceptual OKLCH wheel; particle size + speed ∝ byte-rate

Rates are computed client-side from deltas between RxBytes/TxBytes snapshots, so no packet capture or elevated privileges are needed — it visualizes exactly what the Tailscale daemon already reports.

Gallery

Real frames captured from the live renderer (this node = dev-cx53) — every image in this section is an actual screenshot of the running WebGPU app, not a mock-up or concept render.

overview flow close-up
tailnet overview particle stream close-up
orbit view of the full tailnet zoomed-in view of a bright cross-tailnet flow

The bright stream in these shots is a live flow (~3–7 K/s) between two nodes; offline peers fade to grey, and each ring is tinted by its DERP region. The HUD (top-left) and the flowing through <region> readout (bottom) update live as byte-rates change.

Concept art

AI-generated concept art — not screenshots. These illustrate tailscope's four dimensions in the ENTHEA palette; the real renderer is in the gallery above.

channels — relay regions direction — tx vs rx
clusters of nodes each tinted its own DERP-region hue on a perceptual OKLCH wheel warm-orange streams leaving a node, cool-cyan streams arriving

a living 4D graph — luminous nodes and particle rivers streaming along glowing edges in an aurora void

space · time · direction · channel — the living 4D graph. Generated with gpt-image-1.

Look & feel

The chrome is tuned toward the ENTHEA visual synthesizer: the graph floats in a slow-breathing OKLab aurora void, channel hues are spaced on a perceptual OKLCH wheel, nodes bloom in time with their live byte-rate, and the HUD is a glass console with a centered status pill that names the busiest channel. A vignette + scanline + film-grain pass gives it a dithered, instrument-panel texture. Motion respects prefers-reduced-motion.

Controls

drag orbit · scroll zoom · L labels · Space pause · R recenter

How it works

  • server.py — dependency-free HTTP server (Python stdlib). Serves the page and /api/tailnet, a compact transform of tailscale status --json (per-peer rx/tx, online, OS, DERP relay), cached ~1s so polls are cheap.
  • index.html — the whole app in one file: WebGPU (a WGSL compute pass advances ~6k particles along edges each frame; instanced render passes draw nodes, edges, and particles with additive glow), an orbit camera, and a projected-label / HUD overlay. Polls the API every 1.5 s and diffs byte counters into live rates.

Notes

tailscale status exposes per-peer cumulative byte counters, online state, OS, and the DERP relay region — not per-packet type. So "packet type" is approximated honestly by direction × relay-region × rate; the color/size system is built around what the daemon truly reports. Swapping in a real per-packet feed (e.g. a tailscale0 capture streamed over a WebSocket) is a natural extension — the renderer already keys everything off the edge buffer.

Built with 🤖 Claude Code.

About

Live WebGPU 4D visualization of a Tailscale tailnet (space × time × direction × channel)

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages