Learn How Stuff is Built

Peek behind the curtain and see the magic (code) that powers modern digital experiences. Interactive demos and real code snippets reveal our technical craft.

Pac-Man Game

Classic Pac-Man style game with ghosts, pellets and maze navigation

pacman-game.jsJavaScript
const canvas = document
  .getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Game settings
const cellSize = 20;
const cols = Math.floor(
  canvas.width / cellSize
);
const rows = Math.floor(
  canvas.height / cellSize
);

// Game state
let score = 0;
let gameOver = false;
let isRunning = true;

// Pacman properties
let pacman = {
  x: 5,
  y: 5,
  direction: 'right',
  nextDirection: 'right',
  mouth: 0.2,
  mouthDirection: 1
};

// Ghost properties
let ghosts = [
  { 
    x: 15, 
    y: 15, 
            color: '#FFEB3B', 
    direction: 'left' 
  },  // Red ghost
  { 
    x: 14, 
    y: 15, 
            color: '#00d4ff', 
    direction: 'up' 
  },    // Pink ghost
  { 
    x: 16, 
    y: 15, 
    color: '#00FFFF', 
    direction: 'right' 
  }, // Cyan ghost
  { 
    x: 15, 
    y: 14, 
            color: '#fbb604', 
    direction: 'down' 
  }   // Orange ghost
];

// Maze layout
let grid = [];
initializeMaze();

function initializeMaze() {
  // Create maze with walls and dots
  for (let y = 0; y < rows; y++) {
    grid[y] = [];
    for (let x = 0; x < cols; x++) {
      // Border walls
      if (x === 0 || x === cols - 1 || 
          y === 0 || y === rows - 1) {
        grid[y][x] = 'wall';
      } else if ((x % 2 === 0 && 
                  y % 2 === 0) && 
                 (Math.random() < 0.3)) {
        // Some inner walls
        grid[y][x] = 'wall';
      } else {
        // Dots (food)
        grid[y][x] = 'dot';
      }
    }
  }
  
  // Clear area around pacman
  const clearRadius = 2;
  for (let y = Math.max(
         0, pacman.y - clearRadius
       ); 
       y <= Math.min(
         rows - 1, 
         pacman.y + clearRadius
       ); y++) {
    for (let x = Math.max(
           0, pacman.x - clearRadius
         ); 
         x <= Math.min(
           cols - 1, 
           pacman.x + clearRadius
         ); x++) {
      if (grid[y][x] !== 'wall') {
        grid[y][x] = 'empty';
      }
    }
  }
}

Snake Game

Classic Snake game where you collect food to grow while avoiding walls and yourself

snake-game.jsJavaScript
const canvas = document
  .getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Game settings
const cellSize = 15;
const cols = Math.floor(
  canvas.width / cellSize
);
const rows = Math.floor(
  canvas.height / cellSize
);

// Game state
let score = 0;
let gameOver = false;

// Snake state
let snake = [
  {
    x: Math.floor(cols / 2), 
    y: Math.floor(rows / 2)
  },
  {
    x: Math.floor(cols / 2) - 1, 
    y: Math.floor(rows / 2)
  },
  {
    x: Math.floor(cols / 2) - 2, 
    y: Math.floor(rows / 2)
  }
];
let direction = 'right';
let nextDirection = 'right';

// Food position
let food = { x: 0, y: 0 };
placeFood();

// Handle keyboard input
document.addEventListener('keydown', 
  (e) => {
    switch(e.key.toLowerCase()) {
      case 'w':
        if (direction !== 'down') {
          nextDirection = 'up';
        }
        break;
      case 's':
        if (direction !== 'up') {
          nextDirection = 'down';
        }
        break;
      case 'a':
        if (direction !== 'right') {
          nextDirection = 'left';
        }
        break;
      case 'd':
        if (direction !== 'left') {
          nextDirection = 'right';
        }
        break;
    }
  }
);

// Place food at a random position
function placeFood() {
  let foodPosition;
  let isOnSnake;
  
  do {
    isOnSnake = false;
    foodPosition = {
      x: Math.floor(
        Math.random() * cols
      ),
      y: Math.floor(
        Math.random() * rows
      )
    };
    
    // Check if food is on the snake
    for (let segment of snake) {
      if (segment.x === foodPosition.x && 
          segment.y === foodPosition.y) {
        isOnSnake = true;
        break;
      }
    }
  } while (isOnSnake);
  
  food = foodPosition;
}

// Draw the snake
function drawSnake() {
  for (let i = 0; i < snake.length; 
       i++) {
    const segment = snake[i];
    
    if (i === 0) {
      // Head
      ctx.fillStyle = '#50fa7b';
    } else {
      // Body
      ctx.fillStyle = i % 2 === 0 
        ? '#3ae374' 
        : '#32ff7e';
    }
    
    ctx.fillRect(
      segment.x * cellSize,
      segment.y * cellSize,
      cellSize - 1,
      cellSize - 1
    );
  }
}

Player vs AI Pong Game

Interactive Pong game where you control the right paddle with W/S keys and face off against an AI opponent

pong-game.jsJavaScript
const canvas = document
  .getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Game settings
const paddleHeight = 60;
const paddleWidth = 10;
const ballRadius = 8;

// Game state
let ballX = canvas.width / 2;
let ballY = canvas.height / 2;
let ballSpeedX = 3;
let ballSpeedY = 2;
let leftPaddleY = canvas.height / 2 - 
  paddleHeight / 2;
let rightPaddleY = canvas.height / 2 - 
  paddleHeight / 2;
let leftScore = 0;
let rightScore = 0;
let isRunning = true;

// Handle keyboard input for player
document.addEventListener('keydown', 
  (e) => {
    if (e.key === 'ArrowUp') {
      rightPaddleY = Math.max(
        0, rightPaddleY - 15
      );
    } else if (e.key === 'ArrowDown') {
      rightPaddleY = Math.min(
        canvas.height - paddleHeight, 
        rightPaddleY + 15
      );
    }
  }
);

// Reset ball to center after scoring
function resetBall() {
  ballX = canvas.width / 2;
  ballY = canvas.height / 2;
  // Randomize direction
  ballSpeedX = (Math.random() > 0.5 
    ? 1 
    : -1) * 3;
  ballSpeedY = (Math.random() * 2 - 1) * 2;
}

// Draw a paddle at specified position
function drawPaddle(x, y) {
  ctx.fillStyle = '#ffffff';
  ctx.fillRect(
    x, y, 
    paddleWidth, paddleHeight
  );
}

// Draw the ball
function drawBall() {
  ctx.beginPath();
  ctx.arc(
    ballX, ballY, 
    ballRadius, 
    0, Math.PI * 2
  );
        ctx.fillStyle = '#FFEB3B';
  ctx.fill();
  ctx.closePath();
}

// Draw the score
function drawScore() {
  ctx.fillStyle = '#ffffff';
  ctx.font = '20px Arial';
  ctx.textAlign = 'center';
  ctx.fillText(
    leftScore, 
    canvas.width / 4, 
    30
  );
  ctx.fillText(
    rightScore, 
    canvas.width * 3 / 4, 
    30
  );
}

// Update paddle positions
function updatePaddles() {
  // Left paddle AI
  const leftPaddleCenter = 
    leftPaddleY + paddleHeight / 2;
  if (ballX < canvas.width / 2) {
    if (ballY > leftPaddleCenter + 10) {
      leftPaddleY += 3;
    } else if (ballY < 
               leftPaddleCenter - 10) {
      leftPaddleY -= 3;
    }
  }
  
  // Keep paddles in bounds
  leftPaddleY = Math.max(
    0, 
    Math.min(
      leftPaddleY, 
      canvas.height - paddleHeight
    )
  );
}

// Update ball position and collisions
function updateBall() {
  // Wall collisions (top and bottom)
  if (ballY - ballRadius < 0 || 
      ballY + ballRadius > 
        canvas.height) {
    ballSpeedY = -ballSpeedY;
    // Add slight randomization
    ballSpeedY += 
      (Math.random() * 0.4) - 0.2;
  }
  
  // Paddle collisions
  if (ballX - ballRadius < paddleWidth && 
      ballY > leftPaddleY && 
      ballY < leftPaddleY + paddleHeight) {
    // Left paddle hit
    ballSpeedX = -ballSpeedX;
    // Add angle based on hit position
    const relativeIntersect = 
      (leftPaddleY + paddleHeight / 2) - 
      ballY;
    ballSpeedY = -relativeIntersect * 0.1;
  } else if (
      ballX + ballRadius > 
        canvas.width - paddleWidth && 
      ballY > rightPaddleY && 
      ballY < rightPaddleY + paddleHeight
  ) {
    // Right paddle hit
    ballSpeedX = -ballSpeedX;
    // Add angle based on hit position
    const relativeIntersect = 
      (rightPaddleY + paddleHeight / 2) - 
      ballY;
    ballSpeedY = -relativeIntersect * 0.1;
  }
  
  // Score detection
  if (ballX < 0) {
    // Right scores
    rightScore++;
    resetBall();
  } else if (ballX > canvas.width) {
    // Left scores
    leftScore++;
    resetBall();
  }
  
  // Update ball position
  ballX += ballSpeedX;
  ballY += ballSpeedY;
}