⚡ Instant access — No signup, no download, no install. Just click and play!
👆 Click the screenshot to launch the app
| 🎰 38+ Classic & Modern Tables | 🧠 Memory Training with Dynamic Drift |
| Addams Family, Medieval Madness, Attack from Mars, and more! | Values shift as you practice — no rote memorization! |
| 📊 Real-Time Performance Tracking | 🌐 Works 100% Offline |
| Instant feedback on accuracy with color-coded results | All data stored locally in your browser |
Memorize flipper positions • Build muscle memory • Train anywhere, anytime
📊 Project Status & Badges
Hi, I'm a competitive pinball player. Like many players, I've worked hard to improve my accuracy and aiming consistency. There are many ways to aim in pinball—some players use visual references, others use feel or timing. I personally aim by position on the flipper.
As games progress, players need to remember dozens of different shots and their optimal flipper positions. This project is my attempt to create a training tool to help develop that muscle memory and recall ability. It's designed to internalize shot accuracy recall so deeply that thinking becomes unnecessary—performance becomes instinctive under pressure during competitive play.
This is also an experiment in 100% pure AI "vibe coding"—every line of code in this project, along with the build scripts, GitHub workflows, Copilot instructions, and even this README file, has been written by AI. I just provide the prompts, review the output, and guide the direction.
I hope this tool helps improve your game. If you'd like to discuss pinball—strategy, techniques, theory, or have feedback—I'd be happy to connect.
— Gary Brown
A specialized memory training tool for pinball players to practice and improve flipper shot accuracy recall. This progressive web application helps players develop muscle memory for shot percentages for different flipper angles, with dynamic difficulty through drift mechanics and detailed performance feedback.
The trainer helps pinball players develop muscle memory for shot accuracy by:
- Defining shot configurations - Set up shots with specific base elements (Ramp, Orbit, Scoop, etc.) and locations (Left, Right, Center, etc.)
- Guessing flipper percentages - Each shot has accuracy percentages for both left and right flippers (5-95% in 5% increments, or "NP" for Not Possible)
- Testing recall - After memorizing the percentages, the app hides the true values and you must recall them from memory
- Dynamic difficulty - True values gradually "drift" within bounds as you practice, preventing rote memorization
- Performance tracking - Detailed feedback on accuracy, adjustment quality, and overall performance
- Visual playfield editor - Arrange shots spatially on an arc-based layout with visual flipper representations
- 38 pinball preset tables - Pre-configured shot layouts from classic and modern pinball machines (Addams Family, Medieval Madness, Attack from Mars, etc.)
- Custom shot creation - Setup shots using 20 base elements (Ramp, Orbit, Drops, Spinner, etc.) combined with 8 location modifiers (Left, Right, Center, Side, Top, Upper, Bottom, Lower)
- Image-based tiles - Optional visual shot element thumbnails with 80×80px tiles (extensible with WebP images in
/public/images/elements/) - Export/import - Save your custom shot configurations as JSON files
- Ordering constraints - Left flipper shots must be strictly increasing (harder shots = higher %), right flipper strictly decreasing
- "NP" = Not Possible - Special value (stored as 0) for shots that cannot be made from a specific flipper; valid percentage values are 5-95
- Drift system - Hidden truth values shift periodically within ±20% bounds to keep you on your toes
- Two practice modes:
- Manual - Pick any shot/flipper combination to practice
- Random - App randomly selects shots to reduce bias
- Four severity levels:
- Perfect (0% error) - Bright green
- Slight (5% error) - Dark green
- Fairly (10% error) - Yellow
- Very (≥15% error) - Red
- Adjustment tracking - Points awarded for correct directional adjustments on repeated attempts
- Visual feedback - Color-coded feedback pills show shot direction (early/late) with severity
- Performance metrics - Total points, average absolute error, attempt history
- Final recall test - Complete memory test of all shots at session end
- Fullscreen playfield mode - Practice with an uncluttered, immersive view; uses browser Fullscreen API to hide URL bar and navigation on mobile
- Progressive Web App (PWA) - Install to home screen for true fullscreen experience without browser chrome
- Responsive design - Works on desktop, tablet, and mobile devices with safe-area support for notched screens
- Visual shot lines - See percentage markers on flippers during practice
- Drag-and-drop reordering - Reorganize shot sequences in setup (with visual insertion indicators)
- Mental model tracking - Optional display of your evolving accuracy guesses
- Persistent state - All data saved to localStorage (no backend required)
- React 19.1.1 - Single-page application with functional components and hooks
- Vite 7.1.6 - Lightning-fast build tool with Hot Module Replacement (HMR)
- Tailwind CSS 4.1.13 - Utility-first styling with Vite plugin integration
- No backend - 100% client-side, offline-capable with localStorage persistence
- Single-file app -
src/app.jsx(~5000 lines) containing all logic - Functional helpers - Pure functions for percentage snapping, ordering, drift calculations
- Custom hooks -
useLocalStoragefor automatic state persistence - Isotonic regression - Mathematical constraint solver for maintaining shot order during randomization/drift
- Portal-based modals - Using React's
createPortalfor modal dialogs
All values snap to 5% increments. Valid values are 0 (Not Possible) or 5, 10, 15, ..., 90, 95. The value 0 is reserved for shots that cannot be made from a specific flipper.
- Left flipper: Values must be strictly increasing top-to-bottom (index 0 < index 1 < ...)
- Right flipper: Values must be strictly decreasing top-to-bottom (index 0 > index 1 > ...)
- Constraint enforcement: Uses bounded isotonic regression when randomizing/drifting values
- Frequency: Configurable (e.g., every 4 attempts)
- Magnitude: Configurable steps (e.g., 2 steps = ±10%)
- Bounds: Each shot can drift ±20% from its base value (4 steps max)
- Order preservation: Drift maintains left-ascending/right-descending order constraints
This application is hosted on GitHub Pages and is fully compliant with GitHub's Terms of Service and Acceptable Use Policies:
- ✅ 100% client-side - No backend servers, all processing happens in the browser
- ✅ Static site hosting - Only HTML, CSS, and JavaScript files served
- ✅ Educational/training tool - Free open-source project for the pinball community
- ✅ No commercial transactions - No payments, e-commerce, or business operations
- ✅ Lightweight bandwidth - Minimal resource usage well within GitHub's soft limits
- ✅ localStorage only - All user data stored locally in browser (no external databases)
As a PWA, this application provides:
- Installable - Add to home screen on mobile devices for app-like experience
- Offline-capable - Works completely offline after first visit via Service Worker
- No app store required - Direct access via web browser, no installation barriers
- Cross-platform - Runs on any device with a modern browser (iOS, Android, Desktop)
- Automatic updates - New versions deploy automatically when you refresh
- No tracking or analytics - Your training data never leaves your device
- No accounts or sign-ins - No user registration, authentication, or personal information collected
- Local-only storage - All shot configurations and performance data stored in browser localStorage
- No cookies - Application doesn't use cookies or external tracking scripts
- GitHub Pages only logs IP addresses for security purposes (standard for all GitHub Pages sites)
This tool is intended for:
- ✅ Personal training and skill development
- ✅ Educational purposes and pinball theory learning
- ✅ Tournament preparation and competitive practice
- ✅ Community sharing of shot configurations and presets
This application does NOT:
- ❌ Collect, store, or transmit personal information
- ❌ Involve any commercial transactions or monetization
- ❌ Use excessive bandwidth or place undue load on GitHub's infrastructure
- ❌ Include spamming, malware, or malicious code
- ❌ Violate any GitHub Terms of Service or Acceptable Use Policies
- Node.js 24+ and npm
# Clone the repository
git clone <repository-url>
cd PinballAccuracyMemoryTrainer
# Install dependencies
npm install
# Start development server
npm run devThe app will be available at http://localhost:5173
# Standard Vite build (outputs to dist/)
npm run build
npm run preview
# Standalone single-file build with embedded assets
npm run build:standaloneThe build:standalone script creates a self-contained HTML file (pinball-trainer-standalone.html) with:
- All CSS and JavaScript inlined
- All shot element images embedded as base64 data URIs
- All 38 preset configurations embedded
- No external dependencies - works completely offline
- Automatic lint check before build
- Add shots - Click "+ Add Shot(s)" to create empty rows, or load a preset table
- Configure shots - Click shot type chips to select base element and location
- Set percentages - Enter left/right flipper accuracy values (must maintain ordering)
- Visual layout - Shots auto-arrange on the playfield arc
- Adjust parameters:
- Initial random steps (0-4): How far hidden values start from your guesses
- Drift every N attempts: Frequency of hidden value shifts
- Drift magnitude (0-10): Maximum distance values can drift
- Mode: Manual (you pick) or Random (app picks)
- Click "Start Session" (or press Enter)
- See the selected shot highlighted on the playfield
- Enter your percentage guess (5-95 in 5% increments, or 0 for Not Possible)
- Receive instant feedback with color-coded accuracy
- View visual feedback line showing early/late direction
- Continue practicing as hidden values drift
- Toggle "Show Mental Model" to see your evolving guesses
- Toggle "Show Attempt History" to review past attempts
- Click "End Session & Final Recall"
- Enter all shot percentages from memory
- Click "Grade Final Recall" to see your score
- Toggle "Show Truth" to compare against actual values
The app includes 38 preset pinball tables with pre-configured shot layouts:
- Classic tables: Addams Family, Medieval Madness, Twilight Zone, Funhouse
- Modern Stern: Deadpool, Godzilla, Jurassic Park, JAWS
- Williams/Bally classics: Attack from Mars, Monster Bash, White Water
- And many more!
Load presets from the "+ Add Shot(s)" popup in the setup screen.
Place WebP files in /public/images/elements/ with kebab-case filenames matching element names:
ramp.webpfor "Ramp"left-orbit.webpfor "Left Orbit"center-scoop.webpfor "Center Scoop"
Images display as 80×80px tiles with automatic fallback to text labels. The standalone build automatically embeds all images as base64 data URIs.
- Export your shot configuration via the export button (⬆ icon) in the setup table
- Place the JSON file in
/public/presets/ - Add an entry to
/public/presets/index.jsonwith the table name and filename - Preset will appear in the "+ Add Shot(s)" popup
Base Elements (20): Ramp, Standups, Orbit, Drops, Spinner, Scoop, Lane, Toy, Captive Ball, Saucer, Loop, Lock, VUK, Bumper, Deadend, Gate, Magnet, Rollover, Vari Target, Roto Target
Location Modifiers (8): Left, Right, Center, Side, Top, Upper, Bottom, Lower
Locations can be omitted for base-element-only shots.
All state persists automatically to browser localStorage:
- Shot configurations (
pinball_rows_v1) - Practice parameters (
pinball_driftEvery_v1,pinball_driftMag_v1, etc.) - Practice state (hidden values, mental model, attempts)
- UI preferences (fullscreen, panel visibility)
Clear browser data to reset the app completely.
- Attempt history capped at 200 entries to prevent unbounded growth
- Efficient re-renders via
useMemofor expensive calculations (drift, ordering, visual layout) - Single-file architecture - Optimized for this scale (~5000 LOC), no component splitting overhead
- Minimal dependencies - Only React 19, React-DOM, and Tailwind CSS
- Source maps enabled - Full debugging support in development
- Strict linting - 80+ ESLint rules enforced with zero warnings policy
- Modern browsers with ES6+ support (Chrome, Firefox, Edge, Safari)
- LocalStorage required for state persistence
- Recommended: Desktop or tablet (optimal screen size for playfield visualization)
- Tested with Brave browser in development
npm install- Install all dependenciesnpm run dev- Start Vite development server (port 5173)npm run build- Build for production (outputs todist/)npm run build:standalone- Build self-contained single HTML file with embedded assets (includes lint and test checks)npm run lint- Run ESLint with strict error checking (max warnings: 0)npm run test- Run Vitest unit tests in watch modenpm run test:run- Run Vitest unit tests oncenpm run test:ui- Run Vitest with interactive UInpm run test:coverage- Run Vitest unit tests with coverage reportnpm run test:coverage:ui- Run Vitest with interactive UI and coveragenpm run test:e2e- Run Playwright E2E testsnpm run test:e2e:ui- Run Playwright tests with interactive UInpm run test:e2e:headed- Run Playwright tests in headed mode (visible browser)npm run test:e2e:debug- Run Playwright tests in debug modenpm run preview- Preview production build locally
The project includes predefined VS Code tasks (.vscode/tasks.json):
- Install Dependencies - Runs
npm install - Lint - Runs ESLint with problem matcher integration
- Run Unit Tests - Runs Vitest unit tests (depends on Lint)
- Run E2E Tests - Runs Playwright E2E tests (depends on Unit Tests)
- Run All Tests - Runs both unit and E2E tests sequentially
- npm: dev - Starts Vite dev server (depends on all tests passing)
- npm: build:standalone - Builds standalone HTML (script includes lint and test checks)
- Stop npm dev server - PowerShell script to terminate Node.js processes for Vite
The project includes two types of tests:
- Fast, focused tests for individual functions and components
- Located in
tests/vitest/with.test.jsxextension - Run with
npm run test(watch mode) ornpm run test:run(once) - Interactive UI available with
npm run test:ui
- End-to-end tests simulating user interactions
- Located in
tests/e2e/ - Run with
npm run test:e2e - Interactive UI available with
npm run test:e2e:ui - Debug mode available with
npm run test:e2e:debug
Tests are automatically run in these scenarios:
- Before standalone builds -
npm run build:standaloneruns lint → unit tests → E2E tests → build - Before starting dev server - VS Code task runs all tests before starting Vite
- In CI/CD pipeline - GitHub Actions runs lint → unit tests → E2E tests → build → deploy
- Before commits - Using the
commit-and-pushprompt runs lint → tests → build → commit → push
All test failures block the build process to ensure code quality.
├── public/
│ ├── images/elements/ # Shot element image tiles (WebP format)
│ └── presets/ # 38 pre-configured table JSON files
├── src/
│ ├── app.jsx # Main application (~5000 lines)
│ ├── app.css # Component-specific styles
│ ├── main.jsx # React entry point
│ └── index.css # Global styles and Tailwind imports
├── config/
│ ├── build-standalone-complete.js # Standalone build script
│ ├── eslint.config.js # ESLint 9+ flat config with strict rules
│ ├── vite.config.js # Vite configuration
│ └── playwright.config.js # Playwright E2E test configuration
├── tests/
│ ├── e2e/ # Playwright E2E tests
│ └── vitest/ # Vitest unit tests
├── .vscode/
│ ├── launch.json # Debugger configuration (Brave browser)
│ └── tasks.json # VS Code task definitions
├── .github/
│ └── copilot-instructions.md # AI assistant development guidelines
├── package.json # Dependencies and scripts
└── index.html # HTML entry point
src/app.jsx- Core application logic, state management, all componentsconfig/build-standalone-complete.js- Custom build script that embeds all assets into a single HTML fileconfig/vite.config.js- Vite config with React plugin, Tailwind integration, and source mapsconfig/eslint.config.js- Strict ESLint configuration with 80+ rules for code qualityconfig/playwright.config.js- Playwright E2E test configuration.github/copilot-instructions.md- Comprehensive development guidelines for AI assistants
Use the "Brave: Vite React (Single Tab)" launch configuration in VS Code:
- Start the dev server (
npm run dev) or press F5 (task runs automatically) - Debugger launches Brave browser in app mode
- Set breakpoints in
src/app.jsx - Dev server automatically stops when debugging ends
The launch config uses:
- Brave browser in app mode (
--app=http://localhost:5173) - Ephemeral user data directory (fresh profile per session)
- Disabled extensions and session restore
- Source map support enabled
Join the discussion and connect with other pinball players:
- Ask Questions - Get help with setup, configuration, or usage
- Share Ideas - Suggest new features or preset tables
- Show Your Results - Share your training progress and accuracy improvements
- General Discussion - Talk strategy, tournament prep, and pinball theory
See .github/copilot-instructions.md for detailed development guidelines, including:
- Architectural principles (single-file design, state management)
- State model documentation (localStorage keys, data structures)
- Ordering constraint rules (left ascending, right descending)
- Performance guidelines (memoization, render optimization)
- Coding conventions (ESLint rules, formatting standards)
- Build processes (standard and standalone builds)
For contribution guidelines, see CONTRIBUTING.md.
This project doesn't accept monetary donations. The best way to support it is through your time and engagement:
- ⭐ Star the repo — It helps others discover the project
- 🐛 Report bugs — Help improve quality by reporting issues
- 💡 Share ideas — Suggest features via GitHub Discussions
- 🎰 Add presets — Contribute shot configurations for pinball tables
- 📣 Spread the word — Tell other pinball players about the trainer
Your feedback, ideas, and contributions are worth more than any donation!
Thanks goes to these wonderful people (emoji key):
Gary Brown 💻 📖 🎨 🤔 🚧 📆 |
dependabot[bot] 🚧 |
github-actions[bot] 🚇 |
This project follows the all-contributors specification. Contributions of any kind welcome!
This project is licensed under the MIT License - one of the most permissive open source licenses available.
You are free to:
- ✅ Use this software for any purpose (personal, commercial, educational)
- ✅ Modify and adapt the code to your needs
- ✅ Distribute copies of the software
- ✅ Sublicense and incorporate it into your own projects
The only requirement is that you include the original copyright notice and license text in any copies or substantial portions of the software.
See the LICENSE file for the full license text.
Built for the pinball community to help players improve their shot accuracy recall and develop better muscle memory for competitive play.
This project is free and open source - contributions, forks, and adaptations are welcome!