Building a Secure Snake Game with Terminal Aesthetic

Adding games to a developer portfolio creates an engaging way to showcase technical skills while providing interactive entertainment. Today, I'll walk through how we built and integrated a security-hardened Snake game that perfectly matches our terminal aesthetic.

Project Requirements

Our goals were clear from the start:

  • Security first: No vulnerabilities or backdoors
  • Terminal aesthetic: Match the existing 90s BBS styling
  • Zero dependencies: Self-contained, no external libraries
  • Performance optimized: Smooth 60fps gameplay
  • Responsive design: Works on desktop and mobile
  • Portfolio integration: Seamless navigation experience

Security Architecture

Security was our top priority, implementing multiple layers of protection:

Strict Mode JavaScript

(() => {   'use strict';   // All code runs in strict mode to prevent common security issues })();

Secure Random Generation

Instead of Math.random(), we use cryptographically secure randomness:

function secureRandom(min, max) {   const range = max - min + 1;   const array = new Uint32Array(1);   crypto.getRandomValues(array);   return Math.floor((array[0] / (0xFFFFFFFF + 1)) * range) + min; }

Input Validation and Sanitization

All user inputs are validated with strict bounds checking:

function updateSpeed(newSpeed) {   const speed = parseInt(newSpeed, 10);   if (speed >= 1 && speed <= 50) { // Security: validate range     gameState.speed = speed;     gameState.stepMs = 1000 / speed;   } }

DOM Element Validation

We validate all DOM references exist before use:

for (const [key, element] of Object.entries(elements)) {   if (!element) {     console.error(`Critical element missing: ${key}`);     return;   } }

Terminal Aesthetic Implementation

The visual design follows our strict terminal color palette and typography conventions.

Color System

:root {   --terminal-green: #55ff55;   --terminal-amber: #ff8855;   --terminal-cyan: #55ffff;   --terminal-magenta: #ff55ff;   --terminal-bg: #000000;   --terminal-gray: #c9c9c9;   --terminal-dark-gray: #333333; }

Typography and Layout

All text uses our monospace font stack:

font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;

Visual elements include:

  • Grid-based game board with terminal-style borders
  • ASCII key representations for controls ([↑], [Space], [R])
  • Glowing effects on food items
  • Terminal window styling for overlays and banners

Game Engine Architecture

The game engine uses a clean, modular architecture optimized for performance and maintainability.

Game State Management

const gameState = {   status: 'idle', // 'idle' | 'running' | 'paused' | 'gameover'   wrapMode: false,   speed: 8,   stepMs: 125,   score: 0,   snake: [],   dir: {x: 1, y: 0},   nextDir: {x: 1, y: 0},   food: {x: 0, y: 0} };

Game Loop Implementation

The game loop uses requestAnimationFrame for smooth 60fps performance:

function gameLoop(timestamp) {   if (gameState.status !== 'running') return;     const deltaTime = timestamp - gameState.last;   gameState.last = timestamp;   gameState.acc += deltaTime;    while (gameState.acc >= gameState.stepMs) {     gameStep();     gameState.acc -= gameState.stepMs;   }     draw();   gameState.rafId = requestAnimationFrame(gameLoop); }

Advanced Features

Collision Detection

The collision system prevents self-collision while allowing tail movement:

const selfCollision = gameState.snake.some((segment, index) => {   if (!willEat && index === gameState.snake.length - 1 &&        segment.x === tail.x && segment.y === tail.y) {     return false;   }   return index > 0 && segment.x === headX && segment.y === headY; });

Touch Controls

Mobile support with gesture recognition:

function handleTouchMove(e) {   const dx = touch.clientX - gameState.touchStart.x;   const dy = touch.clientY - gameState.touchStart.y;   const threshold = 30;     if (Math.abs(dx) > Math.abs(dy)) {     queueTurn(dx > 0 ? 1 : -1, 0);   } else {     queueTurn(0, dy > 0 ? 1 : -1);   } }

Rendering System

The canvas rendering system includes grid visualization and visual effects:

function drawCell(gridX, gridY, color, glow = false) {   const x = gridX * CELL + 2;   const y = gridY * CELL + 2;   const size = CELL - 4;    ctx.fillStyle = color;   ctx.fillRect(x, y, size, size);    if (glow) {     ctx.shadowColor = color;     ctx.shadowBlur = 10;     ctx.fillRect(x, y, size, size);     ctx.shadowBlur = 0;   } }

Portfolio Integration

Navigation Integration

We added the Snake game to the main navigation menu:

const navItems = [   { label: "Home", href: "#hero" },   { label: "Experience", href: "#experience" },   { label: "Projects", href: "#projects" },   { label: "Skills", href: "#skills" },   { label: "Education", href: "#education" },   { label: "Blog", href: "/blog", external: true },   { label: "Snake", href: "/snake.html", external: true }, // New addition   { label: "Analytics", href: "/analytics.html", external: true },   { label: "Contact", href: "#contact" } ];

File Structure

public/ ├── snake.html          # Self-contained game file └── favicon.ico  src/components/ └── Navigation.tsx       # Updated with Snake link

Performance Optimizations

Memory Management

  • Object pooling for game entities
  • Efficient collision detection with early exits
  • Minimal DOM manipulation during gameplay
  • RequestAnimationFrame for smooth rendering

Code Size Optimization

The entire game fits in a single HTML file under 50KB:

  • No external dependencies
  • Minified CSS embedded inline
  • Optimized JavaScript with no libraries
  • Compressed assets and efficient algorithms

Security Testing Results

Our security audit revealed zero vulnerabilities:

  • No XSS vectors - all user input sanitized
  • No injection risks - no eval() or dynamic code execution
  • Safe localStorage usage - properly sanitized data storage
  • Input validation - all user inputs bounded and validated
  • No external dependencies - zero attack surface from third-party code

Technical Specifications

  • File size: <50KB total
  • Performance: 60fps consistent gameplay
  • Browser support: All modern browsers
  • Mobile support: Full touch controls
  • Accessibility: Keyboard navigation and ARIA labels
  • Security: Multiple layers of input validation and sanitization

Lessons Learned

Building this game reinforced several important principles:

  1. Security by design - implementing security from the ground up is easier than retrofitting
  2. Performance matters - smooth gameplay requires careful optimization
  3. Aesthetic consistency - maintaining visual coherence across portfolio sections
  4. Mobile-first thinking - touch controls are just as important as keyboard input
  5. Code organization - clean architecture makes maintenance easier

Future Enhancements

Potential improvements for future iterations:

  • Sound effects with terminal-style beeps and bleeps
  • High score leaderboard with persistent storage
  • Multiple game modes like timed challenges or obstacles
  • Power-ups that fit the terminal aesthetic
  • Multiplayer support via WebSocket connections

Conclusion

This project demonstrates how to build secure, performant games while maintaining strict aesthetic guidelines. The combination of security-first development, terminal styling, and smooth gameplay creates an engaging portfolio piece that showcases both technical skills and attention to detail.

The Snake game now serves as both entertainment and a demonstration of our development capabilities, seamlessly integrated into the portfolio experience while maintaining our commitment to security and performance.

View the live game at /snake.html and explore the source code to see these techniques in action.