Inspiration

Track 3's brief puts it plainly: "Every decision about people's safety stays with a person." We pictured Mo, Riverside's safety lead, on foot with an earpiece and a phone in their pocket. Mo can't watch a dashboard all day. Festival-goers and volunteers see problems first, but a report can disappear between a radio call, a group chat and someone's memory.

What stuck with us is that "someone saw it", "someone accepted it", "someone is there" and "it's fixed" are four different states. Most tools blur them, so a report looks handled when nobody is actually with the person. And if every small report pings Mo, Mo stops listening.

What it does

Hi-Vis makes sure every festival safety report reaches a person, and stays open until someone confirms it's fixed.

  • Anyone can report: festival-goers without signing in, volunteers and Mo after signing in. The original words are saved and shown to Mo before any AI runs.
  • AI triages: TypeSafe Jev suggests a category and urgency, and screens chat messages for possible safety incidents. A language model (Nemotron 3 Super via OpenRouter) summarises reports and answers everyday questions, using only what that person is allowed to see. A safety message in chat becomes a report draft the person must confirm, not a chatbot reply.
  • A person responds: the nearest volunteer who has opted in to location sharing gets one offer at a time, with a 60-second window before it moves to the next nearest. Accepting and arriving are separate steps.
  • Only a person closes it: Mo, the assigned volunteer or the original reporter must explicitly confirm. No timer and no AI can close an incident.

How we built it

A deliberately small stack: plain HTML, CSS and JavaScript in the browser, and a Node.js server with no dependencies, storing data in a JSON file. There's no build step and no database; for an MVP, one file was enough.

  • Real accounts and permissions enforced on the server: password hashing (scrypt), signed cookies and protection against forged requests (CSRF). Mo, volunteer and event-goer views can run side by side in separate tabs.
  • Live updates via Server-Sent Events. The server sends only a "something changed" signal, and each browser re-fetches its own permission-filtered view, so no data leaks across roles.
  • AI calls happen only on the server. Every result is validated against fixed categories, can only raise urgency, and is discarded if malformed. Calls have timeouts and a capped allowance so testing can't drain credits.
  • Nearest volunteer is plain code, not AI: the straight-line (haversine) distance between two GPS points,

$$ d = 2R \arcsin!\left(\sqrt{\sin^2!\frac{\Delta\varphi}{2} + \cos\varphi_1 \cos\varphi_2 \sin^2!\frac{\Delta\lambda}{2}}\right), \quad R \approx 6371\text{ km} $$

where $\varphi$ is latitude and $\lambda$ is longitude.

We used Codex and Claude Code as AI coding assistants. All data in the demo is fictional.

Challenges we ran into

  • Two designs for the same problem. In parallel, we built a roster-and-zone-coverage assignment system and a GPS nearest-volunteer system. Both wrote to the same assignment field, so we had to choose. The team kept GPS matching and set the roster design aside.
  • Subtle bugs from "harmless" features. Our demo reset reused incident IDs, so a stale screen could act on a different incident. We fixed it by never reusing IDs, even across restarts.
  • Location in real browsers. Location requests timed out in some browsers, so the app now explains each kind of failure (permission denied, unavailable, timeout, too inaccurate) instead of failing silently.
  • Spending AI credits safely. We gated every live call behind explicit flags and a capped call allowance, and test with simulated providers by default.

Accomplishments that we're proud of

  • No lost reports, by design. The report is saved before any AI call, so an AI outage or bad output never hides a report from Mo.
  • Clear AI boundaries, enforced on the server. The AI can suggest and raise urgency, but can't assign anyone, close an incident or see records that person isn't allowed to see.
  • "Accepted" isn't "arrived", and "arrived" isn't "fixed". Each step is a separate human action, recorded with who did it and when.
  • A working end-to-end flow: chat message, safety draft, confirmed request, nearest-volunteer offer, accept, arrive, explicit resolution. It's backed by an automated test suite covering permissions, failures and edge cases.

What we learned

  • The hardest design work wasn't the AI. It was deciding what the AI must never do, then enforcing that on the server rather than trusting the interface.
  • Saving the report before calling the AI turns an outage into an inconvenience instead of a lost report.
  • Small, tested steps and frequent merges beat big checkpoints, especially with three people and AI coding agents working at the same time.

What's next for Hi-Vis

  • Voice reports for volunteers, with an editable transcript, so hands-busy staff can report quickly.
  • A zone map with cluster alerts, so Mo sees when several reports build up in one area (we've prototyped zone counts and cluster detection).
  • Testing on real phones on site, including GPS accuracy and the hosted HTTPS version.
  • Skills-aware matching, for example sending first-aid-trained volunteers to medical reports.

Before submitting:

  • "Accomplishments": I left out the exact test count. Check the current number with npm test if you want to quote one.
  • "What's next" mentions the zone-count prototype. It's on your armaan-roster-offers branch, not on main. Keep that wording, or remove the line if you'd rather not mention it.
  • AI tools list: add any chat assistants teammates used.

Built With

Share this project:

Updates

Submission history