vccs
Composable charting components for Vue 3, ported from Recharts
A typescript app and go gRPC server that simulates rocket testing data and visualizes telemetry data in real-time. 2026
DataTypeScript · GoGitHub @josh-W42OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
A Go service that streams simulated rocket-engine test-stand telemetry over
Connect/gRPC, and a React + TypeScript app that plots it live while staying
smooth at millions of points.
See SPEC.md for the full design and milestone plan, and
NOTES.md for the design decisions and the performance measurements
behind them.Read the full README ↗A Go service that streams simulated rocket-engine test-stand telemetry over Connect/gRPC, and a React + TypeScript app that plots it live while staying smooth at millions of points.
See SPEC.md for the full design and milestone plan, and NOTES.md for the design decisions and the performance measurements behind them.
All milestones complete (M0–M6). Four channels at 1 kHz stream from Go into a Web Worker, which holds ten minutes in fixed ring buffers, downsamples each visible window with LTTB, and evaluates threshold rules on every sample. The main thread only ever sees a few thousand already-reduced points.
Measured: 2,399,800 points held at 120 fps with zero long tasks, against a naive main-thread chart that saturates at 85,600 points in 22 seconds.
Two ways to run it, on two different ports — worth getting straight before you go looking for it on the wrong one:
| How | URL | What is serving the page |
|---|---|---|
just server + just web | http://localhost:5173 | Vite, calling the Go API on :8080 |
docker run ... -p 8080:8080 | http://localhost:8080 | the Go binary, serving page and API together |
There is no Vite in the container. That is the point of the single-origin design: the deployed binary serves the app itself, so :5173 does not exist there.
Either way, it streams as soon as it loads.
NOTES.md.An idle or hidden page holds no subscription. Disconnect, or switch tabs, and the server's subscriber count returns to zero — a page that keeps a stream open while discarding every batch costs the server 4,000 samples a second for nothing. With nobody subscribed the simulator stops generating entirely, and resumes exactly in phase, because it is a pure function of the sample index.
A new visitor sees the test sequence from the beginning. Arriving at an idle rig restarts the run at idle, so you watch it chill down and ignite rather than landing at a random point in a 72-second loop. Tabbing away and back resumes instead — the client says which it is, because tearing the stream down makes both look identical to the server.
proto/telemetry/v1/ the API, and the single source of truth
server/ Go service
internal/sim/ simulator: test sequence, noise, injected faults
internal/stream/ Connect handlers and the fan-out broadcaster
gen/ generated Go — committed, do not edit
web/ Vite + React + TypeScript client
src/worker/ ring buffers, LTTB view building, anomaly rules
src/render/ the three ChartRenderer implementations
src/components/ presentational UI
src/store/ Redux slices — UI state only, never samples
src/bench/ the measurement harness behind NOTES.md
src/gen/ generated TypeScript — committed, do not edit
go (1.25+), node (22+), buf, and
just. The codegen plugins are pinned by tool
directives in server/go.mod and by web/package-lock.json, so there is
nothing else to install.
Alternatively, open the repo in the dev container (.devcontainer/) and get the
whole toolchain without touching your host.
just # list recipes
just install # install web deps (reproducible, no package scripts)
just gen # regenerate Go + TypeScript from proto/
just server # Go API on :8080
just web # Vite dev server on :5173
just test # Go + web tests
just cover # Go tests with a coverage total
just lint # buf lint, go vet, tsc
just gen-check # fail if committed codegen is stale
Run just server and just web in two shells, then open
http://localhost:5173.
One container serves the app and the API from a single origin. docker build
compiles the web bundle, embeds it in a static Go binary, and runs it on
distroless — a 13 MB image, non-root, no shell.
docker build -t telemetry .
docker run --rm -p 8080:8080 -e ALLOWED_ORIGIN= telemetry
Then open http://localhost:8080 — not :5173, which is the Vite dev server and is not running inside the container.
| Variable | Default | Meaning |
|---|---|---|
PORT | 8080 | Injected by most platforms |
ALLOWED_ORIGIN | http://localhost:5173 | Empty disables CORS entirely |
MAX_SUBSCRIBERS | 25 | Concurrent streams; 0 is unlimited |
Why one origin rather than a static host plus an API. A CDN-instant page that then sits on "connecting" while a backend wakes reads as broken; one page that takes a moment and then works reads as slow. Same wait, very different impression. It also removes CORS from the deployment: the browser never makes a cross-origin request, so there is no preflight and no origin to configure at either end.
render.yaml describes the service, so the deployment is reviewable in the
repo rather than clicked into a dashboard. The image is deliberately portable —
nothing in it is platform-specific.
Generated code is committed. The repo builds on clone without buf
installed, and the generated API is browsable on GitHub. The cost is noisier
diffs when the proto changes.
Codegen is pinned, not ambient. buf.gen.yaml invokes the Go plugins
through go tool, so their versions come from server/go.mod rather than from
whatever happens to be on PATH. just gen-check fails if the committed
generated code has drifted from the protos.
connect-es v2 uses one plugin. Service codegen was folded into
@bufbuild/protoc-gen-es; there is no separate protoc-gen-connect-es in v2.
Supply chain. just install runs npm ci --ignore-scripts, which installs
exactly what the lockfile pins and does not execute package lifecycle hooks.
.github/workflows/ci.yml runs on every push to main and every pull request.
check (ubuntu) runs the same just recipes you run locally — install,
lint, test, cover, gen-check — so CI and a developer machine cannot drift.windows job builds and generates on Windows. Codegen is the most
platform-sensitive part of this repo: the TypeScript plugin is invoked through
a shim that differs by platform, and line endings can make generated output
drift. This job catches both.buf and just are installed by pinned version (just against a recorded
SHA-256) rather than through third-party actions, so the CI toolchain is
auditable from the workflow file alone.
The day-to-day loop runs on the host: just server, just web, just test and the
rest use your locally installed Go, Node and buf. The dev container is a parity check,
not the working environment — use it to confirm something builds and generates identically
on Linux before pushing:
docker build -f .devcontainer/Dockerfile -t telemetry-dev .
docker run --rm -v "$PWD:/workspaces/telemetry" -v /workspaces/telemetry/web/node_modules \
telemetry-dev bash -c "just install && just lint && just test && just gen-check"
The container only applies when the project is opened in it (VS Code Dev Containers or the
devcontainer CLI) or when invoked explicitly as above. Running just in a normal shell
never touches it.
The main supply-chain risk is covered on the host regardless: just install runs
npm ci --ignore-scripts, so package lifecycle hooks never execute. What the host does not
sandbox is go build and go test, which compile and run dependency code directly.
Benchmarks are host-measured. The M2 and M3 performance numbers must come from the same
environment to be comparable, so both are taken on the host with the server and Vite running
locally. Record the machine alongside the numbers in NOTES.md.
server/go.mod requires Go 1.26+, because connect-go 1.21 does. If your local
Go is older, GOTOOLCHAIN=auto will download a newer one automatically — but
those downloaded toolchains omit some prebuilt tools, and go test -cover fails
with no such tool "covdata". Install Go 1.26 or newer natively to avoid it.