Remember that classic Chrome Dino game you play when your internet goes down? What if I told you that you could build your own pocket-sized version using an Arduino and a tiny OLED display? In this comprehensive guide, we’ll walk through every step of creating this nostalgic game from scratch, complete with jumping mechanics, obstacle avoidance, and score tracking.
Table of Contents
Introduction: Bringing a Browser Classic to the Physical World
The Chrome Dino game has become an iconic part of the internet experience. Its simple yet addictive gameplay has entertained millions during frustrating connection moments. By recreating it on Arduino, we’re not just building a game—we’re learning about display graphics, physics simulation, input handling, and game state management, all on a microcontroller.
This project is perfect for beginners who have some basic Arduino knowledge and want to dive into creating an interactive project. By the end of this guide, you’ll have a fully functional handheld game that you can proudly show off to friends and family.
Required components
Let’s gather all the required components to build our google chrome Dino game:
- Arduino Uno or Nano(or similar): Any Arduino-compatible board will work.
- SSD1306 OLED Display (128×64 pixels): This tiny screen will bring our game to life. We’re using the I2C version for simplicity.
- Push Button: For controlling the dino’s jump. A momentary tactile switch works perfectly.
- Breadboard: For easy prototyping without soldering.
- Jumper Wires: To connect everything together.
- USB Cable: To upload the code and power our Arduino.
The Hardware Setup: Wiring Your Game
Now connect all the required components as shown in the below simple circuit diagram. A Proper wiring is crucial for the project to work.

- OLED Display Connection (I2C) with Arduino:
- Connect the OLED’s VCC pin to Arduino’s 5V
- Connect the OLED’s GND pin to Arduino’s GND
- Connect the OLED’s SDA pin to Arduino’s A4
- Connect the OLED’s SCL pin to Arduino’s A5
- Button Connection:
- Connect one leg of the push button to Arduino pin 2
- Connect the other leg to Arduino’s GND
We’ll be using the Arduino’s internal pull-up resistor for the button, which means we don’t need an external resistor. This simplifies our wiring and makes the button more reliable.
Bringing the Chrome Dino game to life on a breadboard is an exhilarating first step for any maker. Seeing the pixelated dinosaur jump across the OLED screen for the first time is a moment of pure triumph. But a tangle of jumper wires and a loose button isn’t the final vision. To transform this prototype into a durable, pocket-sized gaming gadget, you need to bridge the gap between idea and finished product.
PCBWay: Your One-Stop Digital Manufacturing Partner
Transform your electronics projects from concept to reality with PCBWay’s comprehensive manufacturing services. Beyond high-quality PCB fabrication—including standard, advanced, flexible, and rigid-flex options—PCBWay offers end-to-end solutions for engineers and innovators worldwide.
Assembly Services streamline production with SMT, through-hole, and mixed assembly capabilities. Choose from turnkey, kitted, or consigned options, with component sourcing, BGA assembly, and functional testing available. Customize further with conformal coating, firmware loading, or box-build assembly .
Rapid Prototyping accelerates development via CNC machining (3-, 4-, and 5-axis milling and turning), 3D printing (FDM, SLA, SLS, MJF, DMLS, and PolyJet), and vacuum casting. Sheet metal fabrication supports laser cutting, bending, and post-processing, while injection molding enables rapid tooling and multi-cavity molds.
Enhanced Capabilities include SMT stencils, surface finishes (anodizing, bead blasting, spray painting), and specialized PCB options like HDI, aluminum, and high-frequency boards. Quality assurance is ensured through AOI, X-ray, impedance control, and UL certification.
PCBWay also provides free design tools: Gerber viewers, impedance calculators, and KiCad plugins simplify project preparation. With global support, competitive pricing, and scalable solutions for prototypes to mass production, PCBWay empowers creators to innovate faster.
Explore PCBWay’s full suite of services at pcbway.com and bring your ideas to life.
From NOV 28th to DEC 31st there are huge offers going on for Christmas, where you can get upto 50% OFF, there are special offers like 10% OFF on 3D printing materials + 20% OFF starting price, Also find free upgrades on solder masks and more. For more details and Offers page please check: https://www.pcbway.com/activity/christmas2025.html
Program Code
After connecting all the required components, we have to upload the program code to Arduino using Arduino IDE. First open Arduino IDE and install required libraries listed below, you can do it through Arduino Library manager.
Adafruit_GFX: Provides graphics functions for drawing shapes, text, and bitmapsAdafruit_SSD1306: The driver for our specific OLED display
These libraries handle the low-level communication with our display, allowing us to focus on the game logic rather than hardware protocols.
- Connect your Arduino to your computer via USB
- In the Arduino IDE:
- Select your board (Tools > Board > Arduino Uno)
- Select the correct port (Tools > Port)
- Copy and paste the code into a new sketch
- Click the Upload button
- Once uploaded, press the button to start playing!

Here’s the full code for your Arduino Dino game:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Defines
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
#define BUTTON_PIN 2 // Push button pin
#define GROUND_HEIGHT 12
#define DINO_WIDTH 25
#define DINO_HEIGHT 26
#define DINO_INIT_X 10 // Dino initial spawn location
#define DINO_INIT_Y (SCREEN_HEIGHT - GROUND_HEIGHT - DINO_HEIGHT)
#define TREE_WIDTH 11
#define TREE_HEIGHT 23
#define TREE_Y (SCREEN_HEIGHT - GROUND_HEIGHT - TREE_HEIGHT)
#define JUMP_VELOCITY -10
#define GRAVITY 0.8
#define GAME_SPEED 3
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Game variables
int dinoY = DINO_INIT_Y;
float dinoVelocity = 0;
bool isJumping = false;
int obstacleX = SCREEN_WIDTH;
int score = 0;
bool gameOver = false;
bool gameStarted = false;
int highScore = 0;
// Button state
int buttonState = 0;
int lastButtonState = 0;
// New Chrome-style dinosaur sprite
static const unsigned char PROGMEM dino1[]={
// 'dino', 25x26px - Chrome-style T-Rex
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x06, 0xff, 0x00, 0x00, 0x0e, 0xff, 0x00,
0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xc0, 0x00,
0x00, 0x0f, 0xfc, 0x00, 0x40, 0x0f, 0xc0, 0x00, 0x40, 0x1f, 0x80, 0x00, 0x40, 0x7f, 0x80, 0x00,
0x60, 0xff, 0xe0, 0x00, 0x71, 0xff, 0xa0, 0x00, 0x7f, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x80, 0x00,
0x7f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00,
0x03, 0xfc, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00,
0x01, 0x0c, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00
};
// New Chrome-style cactus sprite
static const unsigned char PROGMEM tree1[]={
// 'tree1', 11x23px - Chrome-style cactus
0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x40, 0x1f, 0xe0, 0x1f, 0xe0, 0xdf, 0xe0, 0xff, 0xe0, 0xff, 0xe0,
0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0xff, 0x00, 0xff, 0x00, 0x7f, 0x00,
0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00
};
void setup() {
// Initialize button pin
pinMode(BUTTON_PIN, INPUT_PULLUP);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
// Don't proceed, loop forever
for(;;);
}
// Show initial screen
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 10);
display.println("DINO GAME");
display.setCursor(10, 30);
display.println("Press Button to Start");
display.setCursor(20, 50);
display.println("High Score: " + String(highScore));
display.display();
// Wait for button press to start
while (digitalRead(BUTTON_PIN) == HIGH) {
delay(10);
}
gameStarted = true;
}
void loop() {
if (!gameStarted) {
// Wait for button press to restart
if (digitalRead(BUTTON_PIN) == LOW) {
resetGame();
gameStarted = true;
// Wait for button release to prevent immediate restart
while (digitalRead(BUTTON_PIN) == LOW) {
delay(10);
}
}
delay(100);
return;
}
// Read button state
buttonState = digitalRead(BUTTON_PIN);
// Check for button press (falling edge)
if (buttonState == LOW && lastButtonState == HIGH && !isJumping && !gameOver) {
dinoVelocity = JUMP_VELOCITY;
isJumping = true;
}
// Update game physics
if (!gameOver) {
// Apply gravity
dinoVelocity += GRAVITY;
// Update dino position
dinoY += dinoVelocity;
// Check if dino landed
if (dinoY >= DINO_INIT_Y) {
dinoY = DINO_INIT_Y;
isJumping = false;
dinoVelocity = 0;
}
// Update obstacle position
obstacleX -= GAME_SPEED;
// Reset obstacle if it goes off screen
if (obstacleX <= -TREE_WIDTH) {
obstacleX = SCREEN_WIDTH;
score++;
}
// Check for collision - Fixed collision detection
// Check if rectangles overlap
bool collisionX = (obstacleX < DINO_INIT_X + DINO_WIDTH) && (obstacleX + TREE_WIDTH > DINO_INIT_X);
bool collisionY = (dinoY + DINO_HEIGHT > TREE_Y) && (dinoY < TREE_Y + TREE_HEIGHT);
if (collisionX && collisionY) {
gameOver = true;
if (score > highScore) {
highScore = score;
}
}
}
// Draw everything
drawGame();
// Game over screen
if (gameOver) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(30, 10);
display.println("GAME OVER");
display.setCursor(30, 30);
display.println("Score: " + String(score));
display.setCursor(30, 40);
display.println("High: " + String(highScore));
display.setCursor(10, 55);
display.println("Press Button to Restart");
display.display();
gameStarted = false;
gameOver = false; // Reset game over flag
// Wait for button press to restart
while (digitalRead(BUTTON_PIN) == HIGH) {
delay(10);
}
// Wait for button release to prevent immediate restart
while (digitalRead(BUTTON_PIN) == LOW) {
delay(10);
}
}
// Remember button state
lastButtonState = buttonState;
// Control game speed
delay(30);
}
void drawGame() {
display.clearDisplay();
// Draw ground
display.drawLine(0, SCREEN_HEIGHT - GROUND_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - GROUND_HEIGHT, SSD1306_WHITE);
// Draw dino
display.drawBitmap(DINO_INIT_X, dinoY, dino1, DINO_WIDTH, DINO_HEIGHT, SSD1306_WHITE);
// Draw obstacle (cactus)
display.drawBitmap(obstacleX, TREE_Y, tree1, TREE_WIDTH, TREE_HEIGHT, SSD1306_WHITE);
// Draw score
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(SCREEN_WIDTH - 30, 5);
display.println(String(score));
display.display();
}
void resetGame() {
dinoY = DINO_INIT_Y;
dinoVelocity = 0;
isJumping = false;
obstacleX = SCREEN_WIDTH;
score = 0;
gameOver = false;
}
The Code Breakdown: Understanding the Game Logic
Now for the exciting part—the code! Let’s break down how our game works, piece by piece.
Game Constants and Physics
The magic of our game lies in the physics simulation. We define several constants that control how the game behaves:
#define JUMP_VELOCITY -10 // How fast the dino jumps upward
#define GRAVITY 0.8 // How quickly the dino falls back down
#define GAME_SPEED 3 // How fast obstacles move across the screen
The jump mechanics work by applying an initial upward velocity when the button is pressed, then continuously applying gravity to pull the dino back down. This creates a realistic parabolic jump arc that feels natural to players.
Game Variables and State
We track several variables to maintain the game state:
dinoY: The vertical position of our dinosaurdinoVelocity: The current speed and direction of the dinoobstacleX: The horizontal position of the cactusscore: The player’s current scoregameOver: A flag to track if the game has ended
The Game Sprites
Sprites are the visual representations of our game objects. We’ve created simple pixel art for both the dino and the cactus obstacle using binary arrays:
static const unsigned char PROGMEM dino1[]={
// 'dino', 25x26px - Chrome-style T-Rex
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x06, 0xff, 0x00, 0x00, 0x0e,
// ... more pixel data
};
The PROGMEM keyword tells Arduino to store these sprites in flash memory rather than RAM, which is important since we have limited memory on the Arduino.
The Main Game Loop
The loop() function is the heart of our game, running continuously to:
- Read button input
- Update physics (apply gravity, move the dino)
- Update obstacle positions
- Check for collisions
- Draw everything on the screen
- Handle game over state
This creates the illusion of movement and interaction through rapid updates to the display.
Collision Detection
Our collision detection is simple but effective. We check if the bounding boxes of the dino and cactus overlap:
if (obstacleX < DINO_WIDTH &&
obstacleX + OBSTACLE_WIDTH > 0 &&
dinoY + DINO_HEIGHT > SCREEN_HEIGHT - GROUND_HEIGHT - obstacleHeight) {
gameOver = true;
}
This code checks if the cactus is horizontally aligned with the dino and if the dino is low enough to hit it.
Taking It Further: Customization Ideas
Now that you have a working game, here are some ways to enhance it:
- Variable Game Speed: Increase the game speed as the score gets higher to make it progressively more challenging.
- Different Obstacles: Add flying birds or multiple cacti types that require different jump timings.
- Duck Mechanic: Add a second button to make the dino duck under flying obstacles.
- Sound Effects: Add a piezo buzzer for jump sounds and collision alerts.
- Day/Night Cycle: Change the background color periodically to simulate day and night like in the original game.
- Power-ups: Add special items that grant temporary invincibility or slow down time.
Conclusion
Congratulations! You’ve successfully built your own Chrome Dino game on Arduino with an OLED display. Through this project, you’ve learned about graphics programming, physics simulation, input handling, and game state management on a microcontroller.
This project demonstrates how even simple components can come together to create something fun and interactive. It’s a testament to the versatility of Arduino and a great stepping stone toward more complex projects.
Whether you keep it as is or expand on it with the customization ideas, you now have a unique handheld game that you built yourself. Happy tinkering, and may your high scores be ever in your favor!
