A Progressive Web App (PWA) for FIRST Robotics Competition scouting with QR code data output and offline support.
β
JSON-Driven Configuration - Loads field definitions from config.json
β
Offline Support - Works without internet using service workers
β
Schedule Management - Auto-fills data from uploaded schedules
β
QR Code Generation - Generates scannable QR codes for data transfer
β
Dark Theme - Optimized for low-light competition environments
β
Reactive & Fast - Built with React and TypeScript
β
Four-Phase Data Entry - PREMATCH, AUTONOMOUS, TELEOP, ENDGAME tabs
β
Multiple Field Types - Text, Number, Dropdown, Switch, Counter
npm install
npm run devnpm run build
npm run preview- App loads with default schedule from
sample_schedule.txt - Select your Scouter ID from the dropdown
- View your assigned matches
- PREMATCH Tab: Verify/enter match info (auto-filled from schedule)
- AUTONOMOUS Tab: Record autonomous period actions
- TELEOP Tab: Record teleoperated period
- ENDGAME Tab: Record end-game and commit data
- Click "COMMIT DATA" to generate QR code
- Scan QR with external scanner app
- Or click "Copy Info" to paste into spreadsheets
- Click "RESET FORM" to clear fields
- Select next match from dropdown
- Form auto-fills with new match data
Located in /public/config.json. Defines all form fields.
{
"PREMATCH": [
{
"label": "Field Label",
"key": "data_key",
"type": "text|number|dropdown|switch|counter",
"options": ["Option1", "Option2"]
}
],
"AUTONOMOUS": [...],
"TELEOP": [...],
"ENDGAME": [...]
}Supported Field Types:
text- Free text inputnumber- Numeric inputdropdown- Selection from options arrayswitch- Boolean toggle (Yes/No)counter- Increment/decrement buttons
Event: Event Name
ScouterID, Match Number, Position, Team Number
ANA, 1, Blue 1, 1234
LEO, 2, Red 2, 5678
Flexible Parsing:
- Separators: commas, tabs, or multiple spaces
- Comments: lines starting with
# - Case-insensitive positions
The app uses Service Workers to cache:
- All application code and assets
- Config files (
config.json,sample_schedule.txt) - User-uploaded schedules and configs
Once loaded, the app works completely offline!
- Click π icon in header
- Select
.txtschedule file - Choose your Scouter ID
- Matches auto-populate
- Click π icon in header
- Select custom
.jsonconfig file - Form rebuilds with new fields
Tab-separated values matching config field order:
ScouterName\tMatchNum\tPosition\tTeam\tField1\tField2\t...\tFieldN
Comma-separated column headers:
Scouter,Match,Position,Team,Field1,Field2,...,FieldN
- React 19 - UI framework
- TypeScript - Type safety
- Vite - Build tool and dev server
- qrcode.react - QR code generation
- Workbox - Service worker and PWA support
- Chrome/Edge (recommended)
- Firefox
- Safari
- Any modern browser with PWA support
NewOvertureQR-Scout/
βββ public/
β βββ config.json # Field definitions
β βββ sample_schedule.txt # Default schedule
β βββ manifest.json # PWA manifest
βββ src/
β βββ components/
β β βββ FieldComponents.tsx # Text, Number, Dropdown, Switch, Counter
β β βββ QRModal.tsx # QR code display modal
β β βββ *.css
β βββ utils/
β β βββ scheduleParser.ts # Schedule file parser
β βββ types.ts # TypeScript interfaces
β βββ App.tsx # Main app component
β βββ main.tsx # App entry point
βββ package.json
βββ vite.config.ts # Vite & PWA config
Edit /public/config.json and reload the app. No code changes needed!
- Build:
npm run build - Preview:
npm run preview - Open in browser
- Turn off wifi/network
- App continues to work
Edit CSS custom properties in:
src/index.css- Global stylessrc/App.css- Layout and structuresrc/components/*.css- Component styles
Purple accent: #9c27b0
Dark background: #121212
This project is open source for FRC teams.
For issues or questions, check the MVP.txt specification document.
Built for FIRST Robotics Competition Teams π€
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel (or oxc when used in rolldown-vite) for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])