Add a framework-free HTML/CSS/JS labeling UI: set/session/status
filters, a frame browser, drag-to-draw/move/resize bounding boxes with
a per-set class picker, per-frame status control, and Left/Right frame
navigation. No login - a locally cached username is sent for
attribution only, matching the backend's get-or-create user model.
Backend additions the frontend needed: serve frame images from a
configurable FRAMES_ROOT via a /images static mount, permissive CORS
(internal tool, not publicly exposed), and a GET /sets/{id}/frames
endpoint returning frames joined with their per-set label status
(defaulting missing rows to unlabeled) for the frame browser.
Verified the full call chain end-to-end against a running backend +
static frontend server (set/class creation, frame ingest, image
serving, label CRUD, status updates, CORS preflight) - every field
name the JS reads matches the API responses. 18/18 backend tests
pass. Not yet verified: actual interactive browser use (no browser
tooling available here) - try drag-to-draw/resize locally.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2.7 KiB
Labeling Tool — Frontend
UI for the bounding-box labeling tool: pick a label set, browse its frames, draw/ edit/delete boxes, assign classes, and mark per-frame status.
See CLAUDE.md §3.2 for full requirements.
Status: core labeling UI implemented — plain HTML/CSS/JS, no framework, no
build step (matches "simple frontend — functionality over polish"). Not yet
implemented: dataset-version browsing/promotion (backend doesn't have it yet
either — see labeling/backend/README.md), multi-box copy/paste, and any kind of
zoom/pan (assumes the fixed 1280x720 capture resolution fits on screen).
How it works
index.html/style.css— layout: top bar (set/session/status filters), a frame view with an absolutely-positioned box overlay, and a class-picker sidebar.app.js— everything else: talks to the backend viafetch, renders boxes as DOMdivs scaled to the displayed image size, and handles drawing (drag on empty space), moving (drag a box), resizing (drag its corner handle), selecting and deleting (click, then Delete/Backspace), and frame navigation (buttons or Left/Right arrow keys).- No login: a username is captured once via a prompt on first use, cached in
localStorage, and sent ascreated_by/updated_byon writes purely for attribution (see the backend's multi-user notes). - Each sub-class gets a stable color derived from its id (
colorForIdinapp.js), reused consistently across the class picker and the boxes.
Running it
This is static files — any static file server works, e.g. Python's stdlib one:
cd labeling/frontend
python3 -m http.server 5500
Then open http://127.0.0.1:5500. The backend must be running separately (see
labeling/backend/README.md); the frontend defaults to
http://127.0.0.1:8000 and the backend allows all CORS origins (it's an
internal tool, not exposed publicly), so no extra configuration is needed for the
default setup. To point at a different backend, set
window.SPELUNKAI_API_BASE = "http://host:port" in a <script> tag before
app.js loads in index.html.
You'll also need at least one label set with classes and some ingested frames to
see anything — create those via the backend's API (/docs has interactive
Swagger UI once it's running) until there's a bulk-ingest script.
Testing
No JS test framework/build step is set up (matches the "no build step" choice above). Verified so far: the full backend API contract this UI relies on is covered by the backend's pytest suite, and the static files + wiring (image serving, CORS, correct field names) were checked end-to-end via curl against a running backend. Not yet verified: actual interactive use in a browser (drag-to-draw, drag-to-resize) — try it locally and report anything that feels off.