Skip to content
Draft

V2.0 #37

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d7f020c
initial go work
guyfleeman Sep 3, 2026
f9644f3
svelte fe migration
guyfleeman Sep 8, 2026
8f1a879
add SPA routes, tests, and vscode tools
guyfleeman Sep 8, 2026
d409a72
initial proto wiring
guyfleeman Sep 8, 2026
fd4440f
major UI updates
guyfleeman Sep 22, 2026
b080617
add load/save/save-as, clean up vfield
guyfleeman Sep 22, 2026
9e40705
make corner picker persistent
guyfleeman Sep 25, 2026
3cb7d85
make pb generated code transient
guyfleeman Sep 25, 2026
7a38b0a
cleanup after code review
guyfleeman Sep 25, 2026
166706c
update docs
guyfleeman Sep 25, 2026
7749c3c
minor docs correction
guyfleeman Sep 25, 2026
d963b4e
dimension view layout updates
guyfleeman Sep 26, 2026
6d9df06
clean default pane
guyfleeman Sep 26, 2026
f3908e0
Merge branch 'v2.0-alpha' into dev/will/frontend_initial
guyfleeman Sep 27, 2026
eab8145
color picker prototype
guyfleeman Sep 29, 2026
7674fb4
flowbite component cleanup, layout cleanup
guyfleeman Oct 3, 2026
2d286df
unify config, overhaul save/load, confirm dialogue
guyfleeman Oct 3, 2026
a242adf
network config added, network display, if filtering
guyfleeman Oct 4, 2026
a4963a6
initial live video working, test data
guyfleeman Oct 4, 2026
0b07a69
camera config windows, driver selection
guyfleeman Oct 4, 2026
9e888dc
review pass for all flowbite elements, style matching with GC
guyfleeman Oct 4, 2026
7508f3b
initial pass at field level camera assignment
guyfleeman Oct 5, 2026
175083d
add missing advanced configs, abstract all long text into dedicated f…
guyfleeman Oct 6, 2026
c1d0934
code review of camera assignment, view matrix, and advanced settings
guyfleeman Oct 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 27 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,51 +34,50 @@ jobs:
make -C build -j"$(nproc)" vision_processor geometry_benchmark blob_benchmark
'

python:
name: Python (wrapper_backend)
gui-go:
name: Go (gui)
runs-on: ubuntu-latest
steps:
# gui/internal/{vision,gamecontroller} are generated, not committed (see
# gui/buf.gen.yaml) -- the proto/ submodule and a `buf generate` (via
# `make .proto`, local plugins, no network needed) are needed before
# anything here builds.
- uses: actions/checkout@v4
with:
submodules: recursive

- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

# Importing wrapper_backend runs protoc against the submodule and
# generates wrapper_backend/proto/, which mypy needs on its path even
# though it excludes the generated files themselves.
- name: Lint and type check
- name: Format, vet, build, test
run: |
nix develop --command bash -c '
uv sync --locked
uv run python -c "import wrapper_backend"
uv run ruff check wrapper_backend/
uv run ruff format --check wrapper_backend/
uv run mypy
cd gui
make .proto
test -z "$(gofmt -l .)" || { gofmt -l .; exit 1; }
make vet
make build
make go-test
'

frontend:
name: Frontend (wrapper-frontend)
name: Frontend (gui/frontend)
runs-on: ubuntu-latest
defaults:
run:
working-directory: wrapper-frontend
steps:
# frontend/src/proto is generated, not committed (see gui/buf.gen.yaml)
# -- this job now needs the proto/ submodule and buf/go (hence nix,
# same as gui-go) to produce it before npm can build against it.
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: wrapper-frontend/package-lock.json

- run: npm ci

- run: npm run lint

- run: npm run format:check
submodules: recursive

- run: npm run check
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

- run: npm run build
- name: Lint, check, build
run: |
nix develop --command bash -c '
cd gui
make frontend-test
make frontend
'
27 changes: 26 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
/src/cl_kernels.S
/src/proto
/python/proto
/wrapper_backend/proto
/gui/internal/vision
/gui/internal/gamecontroller
/gui/frontend/src/proto
__pycache__

# Cam viewer
Expand All @@ -12,11 +14,31 @@ __pycache__
# Debug and test image directories
/img
/test-data
*.log

# Config files are local: only the read-only references in config/ are
# tracked (see config/README.md). Copy one to the repo root and edit the copy;
# git ignores it wherever it lives, so `git add -A` can't sweep in a venue's
# config or calibration.
*.yml
!/config/**/*.yml
# Not configs: test fixtures, CI, and vision_processor's default robot height
# table, which it reads from the working directory.
!**/testdata/**/*.yml
!/.gitlab-ci.yml
!/.github/**/*.yml
!/robot-heights.yml

#Output binaries
vision_processor
blob_benchmark
geometry_benchmark
/gui/bin
/gui/ssl-vision-processor-gui

# Makefile sentinels for the frontend build and protobuf codegen
/gui/.frontend
/gui/.proto

#CMake files
/build
Expand All @@ -33,3 +55,6 @@ CMakeCache.txt
/.cache
/build*
/.zed

# AI Files
.mcp.json
23 changes: 4 additions & 19 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.12
hooks:
- id: ruff
args: [--fix]
files: ^wrapper_backend/
- id: ruff-format
files: ^wrapper_backend/
- repo: local
hooks:
- id: mypy
name: mypy
entry: uv run mypy
language: system
types: [python]
files: ^wrapper_backend/
pass_filenames: false
- id: eslint
name: eslint
entry: npm --prefix wrapper-frontend run lint
entry: npm --prefix gui/frontend run lint
language: system
files: ^wrapper-frontend/
files: ^gui/frontend/
pass_filenames: false
- id: prettier
name: prettier
entry: npm --prefix wrapper-frontend run format:check
entry: npm --prefix gui/frontend run format:check
language: system
files: ^wrapper-frontend/
files: ^gui/frontend/
pass_filenames: false
13 changes: 13 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"recommendations": [
"golang.go",
"svelte.svelte-vscode",
"esbenp.prettier-vscode",
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"ms-python.python",
"charliermarsh.ruff",
"jnoortheen.nix-ide",
"bufbuild.vscode-buf"
]
}
22 changes: 22 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"[go]": {
"editor.defaultFormatter": "golang.go",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"[svelte]": {
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.formatOnSave": true
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"go.vetOnSave": "package"
}
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ The geometry publisher `geom_publisher.py` publishes the field geometry
for all vision_processors, teams and the game controller.
`cam_viewer.py` opens the `mpv` video player with the camera streams from the vision_processor instances.

## Wrapper
## GUI

A modular replacement for `geom_publisher.py` plus a browser UI:
A Go host plus a browser UI, replacing `geom_publisher.py` for anyone running it:

- `wrapper_backend/` — async Python (uv-managed). Owns the field geometry, absorbs incoming calibrations, exposes the bus over WebSocket. Run with `./start_wrapper.sh` (defaults to `geometry-divB.yml`). See [`wrapper_backend/README.md`](wrapper_backend/README.md).
- `wrapper-frontend/` — Svelte 5 + TypeScript + Vite. Connects to the backend's WebSocket and renders the operator UI. Run with `cd wrapper-frontend && npm install && npm run dev`. See [`wrapper-frontend/README.md`](wrapper-frontend/README.md).
- `gui/` — Go host (`cmd/ssl-vision-processor-gui`). Owns the field geometry, absorbs calibrations from vision processors over multicast, and serves the embedded frontend, JSON API, a WebSocket for live updates, and debug snapshot images all on one port. Run with `cd gui && make run` (defaults to `geometry-divB.yml`). See [`gui/README.md`](gui/README.md) for development and [`gui/ARCHITECTURE.md`](gui/ARCHITECTURE.md) for its design.
- `gui/frontend/` — Svelte 5 + TypeScript + Vite, embedded into the Go binary. Run standalone with `cd gui && make proto && cd frontend && npm install && npm run dev` (proxies `/api` and `/ws` to the Go host), or serve it from the Go host directly with `make run`. `make proto` regenerates the protobuf bindings the frontend imports (not committed to git; needs `buf`, or use `nix develop`, see [`gui/CLAUDE.md`](gui/CLAUDE.md)) and only needs to be rerun after the `proto/` submodule changes. See [`gui/frontend/README.md`](gui/frontend/README.md).

## Dependency installation and compilation

Expand Down Expand Up @@ -65,7 +65,8 @@ Installation with PIP: `pip install protobuf pyyaml`
## Setup

1. Complete the dependency installation and compilation section.
2. Configure one `config-minimal.yml` or `config.yml` for each camera, skip the `geometry` section for now.
2. Copy `config/legacy/config-minimal.yml` or `config/legacy/config.yml` to the repo root as a
`config[X].yml` for each camera, and fill it in. Skip the `geometry` section for now.
The camera ids are assigned like in ssl-vision:
![Camera id pattern](camera_ids.png)
3. Start `build/vision_processor config[X].yml` for each camera.
Expand All @@ -78,13 +79,19 @@ Installation with PIP: `pip install protobuf pyyaml`
Subsequent edits to thresholds, tracking limits and color references in `config[X].yml`
are picked up live (within ~0.5 s) without a restart; camera, geometry, network and stream
sections still require a restart.
7. Modify `geometry[X].yml` to match your field geometry.
7. Copy `config/legacy/geometry-divA.yml` or `config/legacy/geometry-divB.yml` to `geometry[X].yml`
and modify it to match your field geometry.
(for simple use cases configuring the field size, penalty area and goal will suffice)
8. Start `python/geom_publisher.py geometry[X].yml`.
The calibration is successful when the reprojected livestream views are parallel to the image frame.
If the calibration is unsuccessful, restart the geom_publisher for a new geometry calibration.
For setups with multiple cameras it is recommended to tune the calibration by hand.

The reference configs live in [config/](config/README.md) and are read-only: copy one and edit the
copy. Every other `.yml` config, wherever it is (your `config[X].yml`/`geometry[X].yml`, the GUI's
`vision.yml`), is gitignored and won't be committed. If you need to track a variant anyway, `git add -f`
it.


## Troubleshooting

Expand Down
41 changes: 41 additions & 0 deletions config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Reference configuration

Read-only reference files. Copy one to the repo root under your own name and
edit the copy; git ignores config files outside this directory, so local
configs never get committed by accident.

| File | What it is |
| --- | --- |
| `vision.yml` | The unified config the GUI host owns: field, shared and per-camera settings, locked calibrations. Start here. |
| `legacy/config.yml` | vision_processor's own config, with every setting and its default documented. The GUI generates one of these per local camera from `vision.yml`. |
| `legacy/config-minimal.yml` | The smallest vision_processor config: just what has no usable default. |
| `legacy/geometry-divA.yml` | Division A field (12 x 9 m). The GUI's Division A preset. |
| `legacy/geometry-divB.yml` | Division B field (9 x 6 m). The GUI's Division B preset. |

## Getting started

```sh
cp config/vision.yml vision.yml
./gui/bin/vision-processor-gui -config vision.yml
```

For a vision_processor run by hand, without the GUI:

```sh
cp config/legacy/config.yml config.yml
./build/vision_processor config.yml
```

## Read-only

These files are `chmod 444`, and the GUI refuses to write any file without
write permission, so a `config_path` or Save As pointed here fails instead of
overwriting a reference. Git doesn't record read-only permissions, so a fresh
clone needs:

```sh
chmod 444 config/*.yml config/legacy/*.yml
```

The GUI's tests parse every file here, so a reference that stops matching
what the code accepts fails `make test`.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading