Search any team, event or match; read OPR breakdowns and trends; ask the prediction lab who wins a what-if alliance or how likely a team is to advance from any event — and check the public track record of how often those predictions came true.
Sister app of Control Point (team management).
Same design language, and the same prediction engine: both apps run
@control-scout/predict-engine, one versioned
package, so predictions can never be better in one app than the other.
| Home | Team page |
|---|---|
![]() |
![]() |
Scout
- Instant search across every team, event and match
- Team pages with full season history and event results
- Event pages with rankings, matches and insights
Analyze
- OPR breakdowns (auto, teleop, endgame) computed by least squares over quals only
- Season trends and per-event performance charts
- Stat tables with sorting and CSV export
Predict
- Prediction lab: what-if alliances, head-to-head win odds
- Advancement likelihood for any team at any event
- Public calibration ledger — every prediction scored against reality
Access
- Free forever, no paywall
- No account needed for core features; personal data stays on your device
- Offline data packs (lite < 10 MB for predictions, full packs per season)
| Layer | Choice | Why |
|---|---|---|
| Server | Node 22+ · Express · TypeScript run by tsx |
Same as Control Point: one runtime, one mental model, no build step for the server. |
| Database | SQLite through @libsql/client |
A local file in development and on a single box; the same client talks to Turso if hosting ever needs a networked database. Zero ops. |
| Web | React 19 · Vite · Tailwind v4 · Radix (shadcn-style components copied into src/components/ui) · Motion · Recharts |
Control Point's exact UI stack and theme tokens, so the two apps feel like family. |
| Predictions | packages/predict-engine (pure TS) |
Runs identically on the server and in the browser — offline predictions from the lite pack need no server. |
| Deploy | Plain Node on the Oracle VM (Dockerfile too) | Portable: the VM or a Mac mini cluster are all just "run the app". |
npm install
cp .env.example .env # add FIRST Events API credentials (optional but recommended)
npm run seed:scout # optional: import a local FTC Scout cache for instant history
npm run sync # pull events/teams/matches from FIRST (resumable)
npm run stats # compute OPR + ratings + calibration ledger
npm run packs # optional: build the offline packs served at /packs
npm run dev # API on :3000, web on :5173npm test runs every test; npm run lint type-checks.
npm run sync needs FIRST credentials (it lists events from FIRST, and falls
back to FTC Scout per event when FIRST has no data for one). Without them, the
app still starts but shows empty states until data arrives via seed:scout or
a copied database. Without a Resend key, sign-in is hidden and everything
personal stays on the device.
| Command | What it does |
|---|---|
npm run shots -- /teams/18360 --both |
Screenshots for PRs (real servers, 2x, waits for data). See AGENTS.md. |
npm run audit |
The self-audit sweep: every route at desktop + mobile, console, overflow, labels, loading and API-down states (docs/self-audit.md). |
npm run db:export |
A consistent single-file copy of the database (for moving it to a server). |
- https://controlscout.org runs on the Oracle VM next to Control Point:
docs/deploy.md (deploys, rollback, alerts). A
Dockerfileruns anywhere else. (Render was retired on 2026-10-14.)
FIRST Events API (primary) ─┐
FTC Scout API (fallback) ──┴─> sync job ─> SQLite ─> stats job ─┬─> REST API ─> web app
├─> prediction ledger (track record)
└─> pack builder ─> /packs/*.db + latest.json
- Sync is idempotent and resumable. Finished seasons are frozen once complete; only the current season refreshes (daily, every 15 min on event days on the VM).
- Stats recomputes per-team, per-event OPR (least squares, quals only, surrogates excluded) and the engine's rating book; it also writes a prediction for every not-yet-played match into the calibration ledger before the match happens, and scores it afterwards.
- Packs: a lite pack (team ratings, < 10 MB) runs predictions fully offline;
per-season full packs hold every event, match and team.
Downloaded online, run only offline: returning visitors get the lite pack
in the background (
src/lib/packSync.tsx, rules insrc/lib/packPolicy.ts) and "Save offline" stores a season, but both only store bytes. Nothing opens, decodes or queries a pack (and sql.js never loads) while the server answers; the app switches to them only when the browser is offline or a read the pack could answer gets a network error or no answer within 4 s, shows an "Offline, showing saved data" badge, and switches back on the next server answer (src/lib/api.ts).
packages/predict-engine/ shared prediction engine (Control Scout + Control Point)
server/ API, sync, stats, ledger, auth
src/ web app
scripts/ one-off and scheduled jobs (sync, stats, packs, backtests)
docs/ methodology and runbooks
DECISIONS.md every judgment call made without the product owner
GPL-3.0-only, same as Control Point. Data © FIRST and FTC Scout contributors; see the About page for attribution.


