1D Pong
A two-player reaction game played on a single strip of WS2812B LEDs. Players compete by pressing their button at the right moment when the ball enters their zone.
Features
- Fast-paced two-player gameplay
- Dynamic difficulty: zones shrink after each point
- Early-hit bonus: hit the ball as it enters your zone for extra speed
- 13 attract mode animations to draw players in
- Modular animation system for easy customization
- Visual feedback for hits, misses, and scoring
- Configurable game parameters
Hardware Requirements
Components
| Component | Specification | Quantity |
|---|---|---|
| Microcontroller | WEMOS D1 Mini ESP32 | 1 |
| LED Strip | WS2812B, 55 LEDs | 1 |
| Buttons | Momentary push button | 2 |
| Power Supply | 5V, 3A rec⦠|
1D Pong
A two-player reaction game played on a single strip of WS2812B LEDs. Players compete by pressing their button at the right moment when the ball enters their zone.
Features
- Fast-paced two-player gameplay
- Dynamic difficulty: zones shrink after each point
- Early-hit bonus: hit the ball as it enters your zone for extra speed
- 13 attract mode animations to draw players in
- Modular animation system for easy customization
- Visual feedback for hits, misses, and scoring
- Configurable game parameters
Hardware Requirements
Components
| Component | Specification | Quantity |
|---|---|---|
| Microcontroller | WEMOS D1 Mini ESP32 | 1 |
| LED Strip | WS2812B, 55 LEDs | 1 |
| Buttons | Momentary push button | 2 |
| Power Supply | 5V, 3A recommended | 1 |
| Wires | Jumper wires | As needed |
Schematic
Pin Connections
| Component | ESP32 Pin |
|---|---|
| LED Data | GPIO 5 |
| Left Button | GPIO 17 |
| Right Button | GPIO 18 |
| Left Button LED | GPIO 25 (PWM) |
| Right Button LED | GPIO 26 (PWM) |
| LED Power | 5V |
| LED Ground | GND |
| Buttons | GND (active LOW with internal pull-up) |
Photos
Installation
Prerequisites
Setup
Clone the repository:
git clone https://github.com/yourusername/1d-pong.git
cd 1d-pong
Open the project in VS Code:
code .
Build the project:
- Click the checkmark icon in the PlatformIO toolbar, or
- Press
Ctrl+Alt+B
Upload to your ESP32:
- Connect your ESP32 via USB
- Click the arrow icon in the PlatformIO toolbar, or
- Press
Ctrl+Alt+U
Configuration
Edit include/config.h to customize:
// Hardware
#define NUM_LEDS 55 // Number of LEDs in your strip
#define LED_PIN 5 // Data pin for LED strip
#define BUTTON_LEFT_PIN 17 // Left player button
#define BUTTON_RIGHT_PIN 18 // Right player button
// Button LEDs (PWM capable pins)
#define BUTTON_LED_LEFT_PIN 25 // Left button LED
#define BUTTON_LED_RIGHT_PIN 26 // Right button LED
#define BUTTON_LED_PWM_FREQ 5000 // 5kHz PWM frequency
#define BUTTON_LED_PWM_RES 8 // 8-bit resolution (0-255)
// Game Parameters
#define ZONE_SIZE_START 10 // Initial zone size (LEDs)
#define ZONE_SIZE_MIN 5 // Minimum zone size
#define SCORE_TO_WIN 5 // Points to win a match
// Speed
#define BALL_INITIAL_DELAY_MS 60 // Starting ball speed (lower = faster)
// Animation
#define ANIMATION_DURATION_MS 10000UL // Duration per animation (ms)
How to Play
Starting a Game
- When idle, the LED strip displays attract mode animations
- Either player presses their button to start a match
- The ball spawns in the center after a countdown
Gameplay
- The ball (white LED) travels toward one playerβs zone
- When the ball enters your zone (colored section), press your button to return it
- The ball speeds up with each successful return
- Score a point when your opponent misses
Scoring
- Miss: Ball exits the strip = opponent scores
- Early press: Pressing outside your zone = opponent scores
- First to 5 points wins the match
Advanced Mechanics
- Early-hit bonus: Hitting the ball as it enters your zone (not waiting until itβs about to exit) adds extra speed, making it harder for your opponent
- Shrinking zones: After each point, both zones shrink by 1 LED, increasing difficulty
Game State Machine
stateDiagram-v2
[*] --> IDLE
IDLE --> SERVE : Button Press
SERVE --> BALL_MOVING : Countdown Complete
BALL_MOVING --> BALL_MOVING : Successful Hit
BALL_MOVING --> CHECK_GAME_OVER : Miss or Penalty
CHECK_GAME_OVER --> SERVE : Score < 5
CHECK_GAME_OVER --> GAME_OVER : Score β₯ 5
GAME_OVER --> IDLE : Win Animation Complete
note right of IDLE
Attract mode animations
Button LED breathing & pulses
end note
note right of SERVE
Countdown with visual pulse
Zone shrinks after each point
end note
note right of BALL_MOVING
Active gameplay
Button LEDs indicate active zones
Flash on hit, blink on miss
end note
note right of GAME_OVER
Display winner animation
First to 5 points wins
end note
Loading
States
| State | Description |
|---|---|
IDLE | Attract mode - cycling through animations, waiting for player |
SERVE | Countdown before ball launch, zones displayed |
BALL_MOVING | Active gameplay - ball moving, checking for hits |
CHECK_GAME_OVER | Evaluate if a player has won |
GAME_OVER | Display winner animation, then return to idle |
Adding Custom Animations
The animation system uses auto-registration - simply create a new .cpp file in src/animations/ and it will be automatically included.
Step-by-Step
Copy the template:
cp src/animations/_template.cpp.example src/animations/my_animation.cpp
Edit your new file:
#include "animation.h"
class MyAnimation : public Animation {
public:
MyAnimation(const char* name) : Animation(name) {}
void reset() override {
// Initialize state when animation starts
_lastUpdate = 0;
}
void update(CRGB* leds, uint8_t numLeds) override {
// Non-blocking timing
if (millis() - _lastUpdate < 50) return;
_lastUpdate = millis();
// Your animation logic here
fill_solid(leds, numLeds, CRGB::Black);
// ...
FastLED.show();
}
private:
uint32_t _lastUpdate = 0;
};
// Register with a display name
REGISTER_ANIMATION(MyAnimation, "My Animation");
Build and upload - your animation is now in the rotation!
Animation Guidelines
- Non-blocking: Never use
delay()- usemillis()for timing - Call
FastLED.show(): Required to display your changes - Use
reset(): Initialize state variables when animation starts - Available helpers:
fill_solid(),CHSV(),sin8(),qadd8(),qsub8(), etc.
Included Animations
| Animation | Description |
|---|---|
| Rainbow Dot | Rainbow background with bouncing white dot |
| Pong Demo | Simulated game demonstration |
| Plasma Comet | Plasma background with white comet trail |
| Cylon | Scanning red eye effect |
| Fire | Flames from both player zones |
| Sparkle | Twinkling stars with shooting stars |
| Duel Chase | Blue/green dots colliding |
| Heartbeat | Pulsing red heartbeat |
| Ocean Wave | Blue sine waves with foam |
| Bouncing Balls | Physics-based bouncing balls |
| Matrix Rain | Green digital rain |
| Lightning Storm | Random flashes with thunder |
| Color Breathing | Slow color pulsing |
Troubleshooting
LEDs not lighting up
- Check power supply voltage (5V) and amperage (3A recommended for 55 LEDs)
- Verify data pin connection (GPIO 5 by default)
- Ensure correct LED type in config (
WS2812B) - Check color order setting (
GRBfor most WS2812B strips)
Buttons not responding
- Verify button connections to correct GPIO pins
- Buttons should connect between GPIO and GND (uses internal pull-up)
- Check for loose connections
Upload fails
- Try holding BOOT button on ESP32 while uploading
- Check USB cable (some are power-only)
- Verify correct board selected in
platformio.ini
Game too fast/slow
- Adjust
BALL_INITIAL_DELAY_MSinconfig.h - Higher values = slower ball
- Recommended range: 40-80ms
Project Structure
1d-pong/
βββ platformio.ini # PlatformIO configuration
βββ include/
β βββ config.h # Game and hardware configuration
β βββ animation.h # Animation base class
βββ src/
β βββ main.cpp # Game logic and state machine
β βββ animation.cpp # Animation manager
β βββ animations/ # Animation implementations
β βββ _template.cpp.example
β βββ rainbow_dot.cpp
β βββ fire.cpp
β βββ ...
βββ README.md
Development Note
This project was developed with assistance from AI tools (Claude, ChatGPT, etc.). All code has been reviewed and tested by the author.
Contributing
Contributions are welcome! Hereβs how you can help:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-animation) - Commit your changes (
git commit -m 'Add amazing animation') - Push to the branch (
git push origin feature/amazing-animation) - Open a Pull Request
Ideas for Contributions
- New attract mode animations
- Sound effects support (buzzer/speaker)
- Web-based configuration interface
- Score persistence (EEPROM)
- Tournament mode (best of N matches)
- Single-player mode with AI
Future Improvements
-
Add sound effects for hits and misses
-
Web interface for configuration
-
Bluetooth controller support
-
High score tracking
-
Adjustable difficulty modes
-
More visual feedback options
-
Button LED integration for gameplay feedback and attract animations
-
Note: Button LEDs have integrated resistors for 5V operation and require level shifters or transistors/MOSFETs to drive from ESP32
Credits
This project was inspired by a 1D Pong game seen at 38C3 (38th Chaos Communication Congress).
Built with:
- FastLED - LED control library
- PlatformIO - Development platform
- Arduino-ESP32 - ESP32 Arduino core
License
This project is licensed under the MIT License - see below for details.
MIT License
Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.