Generated banner for Game Engine
Generated logo for Game Engine

Game Engine

GitHubOfficialFirst committed by jhaugaDistributed by GitHub

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Expert skill for building web-based game engines and games using HTML5, Canvas, WebGL, and JavaScript. Use when asked to create games, build game engines, implement game physics, handle collision detection, set up game loops, manage sprites, add game controls, or work with 2D/3D rendering. Covers techniques for platformers, breakout-style games, maze games, tilemaps, audio, multiplayer via WebRTC, and publishing games.
— the description by jhauga

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The Game Engine skill provides a structured approach to developing interactive 2D and 3D games for the web. It covers the entire lifecycle of game development, from core engine architecture—such as the game loop and rendering pipelines—to specific implementations of physics, collision detection, and input handling. The skill includes reference documentation on web APIs, algorithms, and 3D theory, alongside practical templates for common game types like platformers and maze games.

What it does

  • Provides workflows for building game engines and games from scratch.
  • Explains core concepts like game loops, rendering, and physics.
  • Offers reference material for WebGL, Canvas, and Web Audio APIs.
  • Includes starter templates for 2D platformers and breakout-style games.
  • Covers advanced topics like raycasting, collision detection, and multiplayer networking.
  • Guides users through asset optimization and game publishing.

When to use it

  • When you need to build a web-based game or a custom game engine.
  • When implementing game mechanics like physics, collision, or input controls.
  • When you need to understand 3D rendering pipelines or WebGL fundamentals.
  • When you are looking for starter code for 2D or 3D web game projects.
  • When you need to optimize game performance or handle cross-browser audio issues.

Advantages

  • Centralizes essential game development knowledge for the web.
  • Provides ready-to-use templates to accelerate project setup.
  • Offers clear, step-by-step procedures for common game development tasks.
  • Includes troubleshooting guides for common rendering and performance issues.
  • Supports both 2D (Canvas) and 3D (WebGL/Three.js) development workflows.

Usage examples

“How do I set up a basic game loop using requestAnimationFrame?”
The agent provides a code structure that initializes a canvas, defines an update function for game logic, and a render function for drawing, tied together by a recursive requestAnimationFrame call.
“Can you help me implement AABB collision detection for my 2D platformer?”
The agent explains the Axis-Aligned Bounding Box algorithm and provides a JavaScript function to check if two rectangular objects overlap.
“What are the steps to publish my web game?”
The agent outlines a checklist including asset compression, code minification, cross-browser testing, and choosing a distribution platform.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/github/game-engine/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip game-engine.zip -d .agents/skills

Documentation by jhauga

Game Engine Skill

Build web-based games and game engines using HTML5 Canvas, WebGL, and JavaScript. This skill includes starter templates, reference documentation, and step-by-step workflows for 2D and 3D game development with frameworks such as Phaser, Three.js, Babylon.js, and A-Frame.

When to Use This Skill

  • Building a game engine or game from scratch using web technologies

  • Implementing game loops, physics, collision detection, or rendering

  • Working with HTML5 Canvas, WebGL, or SVG for game graphics

  • Adding game controls (keyboard, mouse, touch, gamepad)

  • Creating 2D platformers, breakout-style games, maze games, or 3D experiences

  • Working with tilemaps, sprites, or animations

  • Adding audio to web games

  • Implementing multiplayer features with WebRTC or WebSockets

  • Optimizing game performance

  • Publishing and distributing web games

Prerequisites

  • Basic knowledge of HTML, CSS, and JavaScript

  • A modern web browser with Canvas/WebGL support

  • A text editor or IDE

  • Optional: Node.js for build tooling and local development servers

Core Concepts

The following concepts form the foundation of every web-based game engine.

Game Loop

Every game engine revolves around the game loop -- a continuous cycle of:

  1. Process Input - Read keyboard, mouse, touch, or gamepad input

  2. Update State - Update game object positions, physics, AI, and logic

  3. Render - Draw the current game state to the screen

Use requestAnimationFrame for smooth, browser-optimized rendering.

Rendering
  • Canvas 2D - Best for 2D games, sprite-based rendering, and tilemaps

  • WebGL - Hardware-accelerated 3D and advanced 2D rendering

  • SVG - Vector-based graphics, good for UI elements

  • CSS - Useful for DOM-based game elements and transitions

Physics and Collision Detection
  • 2D Collision Detection - AABB, circle, and SAT-based collision

  • 3D Collision Detection - Bounding box, bounding sphere, and raycasting

  • Velocity and Acceleration - Basic Newtonian physics for movement

  • Gravity - Constant downward acceleration for platformers

Controls
  • Keyboard - Arrow keys, WASD, and custom key bindings

  • Mouse - Click, move, and pointer lock for FPS-style controls

  • Touch - Mobile touch events and virtual joysticks

  • Gamepad - Gamepad API for controller support

Audio
  • Web Audio API - Programmatic sound generation and spatial audio

  • HTML5 Audio - Simple audio playback for music and sound effects

Step-by-Step Workflows

Creating a Basic 2D Game
  1. Set up an HTML file with a <canvas> element

  2. Get the 2D rendering context

  3. Implement the game loop using requestAnimationFrame

  4. Create game objects with position, velocity, and size properties

  5. Handle keyboard/mouse input for player control

  6. Implement collision detection between game objects

  7. Add scoring, lives, and win/lose conditions

  8. Add sound effects and music

Building a 3D Game
  1. Choose a framework (Three.js, Babylon.js, A-Frame, or PlayCanvas)

  2. Set up the scene, camera, and renderer

  3. Load or create 3D models and textures

  4. Implement lighting and shaders

  5. Add physics and collision detection

  6. Implement player controls and camera movement

  7. Add audio and visual effects

Publishing a Game
  1. Optimize assets (compress images, minify code)

  2. Test across browsers and devices

  3. Choose distribution platform (web, app stores, game portals)

  4. Implement monetization if needed

  5. Promote through game communities and social media

Game Templates

Starter templates are available in the assets/ folder. Each template provides a complete, working example that can be used as a starting point for a new project.

TemplateDescription
paddle-game-template.md2D Breakout-style game with pure JavaScript
2d-maze-game.mdMaze game with device orientation controls
2d-platform-game.mdPlatformer game using Phaser framework
gameBase-template-repo.mdGame base template repository structure
simple-2d-engine.mdSimple 2D platformer engine with collisions

Reference Documentation

Detailed reference material is available in the references/ folder. Consult these files for in-depth coverage of specific topics.

ReferenceTopics Covered
basics.mdGame development introduction and anatomy
web-apis.mdCanvas, WebGL, Web Audio, Gamepad, and other web APIs
techniques.mdCollision detection, tilemaps, async scripts, audio
3d-web-games.md3D theory, frameworks, shaders, WebXR
game-control-mechanisms.mdTouch, keyboard, mouse, and gamepad controls
game-publishing.mdDistribution, promotion, and monetization
algorithms.mdRaycasting, collision, physics, vector math
terminology.mdGame development glossary
game-engine-core-principles.mdCore design principles for game engines

Troubleshooting

IssueSolution
Canvas is blankCheck that you are calling drawing methods after getting the context and inside the game loop
Game runs at different speedsUse delta time in update calculations instead of fixed values
Collision detection is inconsistentUse continuous collision detection or reduce time steps for fast-moving objects
Audio does not playBrowsers require user interaction before playing audio; trigger playback from a click handler
Performance is poorProfile with browser dev tools, reduce draw calls, use object pooling, and optimize asset sizes
Touch controls are unresponsivePrevent default touch behavior and handle touch events separately from mouse events
WebGL context lostHandle the webglcontextlost event and restore state on webglcontextrestored

Files

references/game-engine-core-principles.md

Game Engine Core Design Principles

A comprehensive reference on the fundamental architecture and design principles behind building a game engine. Covers modularity, separation of concerns, core subsystems, and practical implementation guidance.

Source: https://www.gamedev.net/articles/programming/general-and-gameplay-programming/making-a-game-engine-core-design-principles-r3210/


Why Build a Game Engine

A game engine is a reusable software framework that abstracts the common systems needed to build games. Rather than writing rendering, physics, input, and audio code from scratch for every project, a well-designed engine provides these as modular, configurable subsystems.

Key motivations:

  • Reusability -- Use the same codebase across multiple game projects.

  • Separation of engine code from game code -- Engine developers and game designers can work independently.

  • Maintainability -- Well-structured code is easier to debug, extend, and optimize.

  • Scalability -- Add new features or platforms without rewriting existing systems.


Core Design Principles

Modularity

Every major system in the engine should be an independent module with a well-defined interface. Modules should communicate through clean APIs rather than reaching into each other's internals.

Why it matters:

  • Swap implementations without affecting other systems (e.g., replace OpenGL renderer with Vulkan).

  • Test individual systems in isolation.

  • Allow teams to work on different modules in parallel.

Example structure:

engine/
  core/           -- Memory, logging, math, utilities
  platform/       -- OS abstraction, windowing, file I/O
  renderer/       -- Graphics API, shaders, materials
  physics/        -- Collision, rigid body dynamics
  audio/          -- Sound playback, mixing, spatial audio
  input/          -- Keyboard, mouse, gamepad, touch
  scripting/      -- Scripting language bindings
  scene/          -- Scene graph, entity management
  resources/      -- Asset loading, caching, streaming
Separation of Concerns

Each system should have a single, clearly defined responsibility. Avoid mixing rendering logic with physics, or input handling with game state management.

Practical guidelines:

  • The renderer should not know about game mechanics.

  • The physics engine should not know how entities are rendered.

  • Input processing should translate raw device events into abstract actions that game code can consume.

  • The game logic layer sits on top of the engine and uses engine services without modifying them.

Data-Driven Design

Wherever possible, behavior should be controlled by data rather than hard-coded logic. This allows designers and artists to modify game behavior without recompiling code.

Examples of data-driven approaches:

  • Level layouts defined in data files (JSON, XML, binary) rather than code.

  • Entity properties and behaviors configured through component data.

  • Shader parameters exposed as material properties editable in tools.

  • Animation state machines defined in configuration rather than imperative code.

Minimize Dependencies

Each module should depend on as few other modules as possible. The dependency graph should be a clean hierarchy, not a tangled web.

Game Code
    |
    v
Engine High-Level Systems (Scene, Entity, Scripting)
    |
    v
Engine Low-Level Systems (Renderer, Physics, Audio, Input)
    |
    v
Engine Core (Memory, Math, Logging, Platform Abstraction)
    |
    v
Operating System / Hardware

Circular dependencies between modules are a sign of poor architecture and should be eliminated.


The Entity-Component-System (ECS) Pattern

ECS is a widely adopted architectural pattern in modern game engines that favors composition over inheritance.

Core Concepts
  • Entity -- A unique identifier (often just an integer ID) that represents a game object. An entity has no behavior or data of its own.

  • Component -- A plain data container attached to an entity. Each component type stores one aspect of an entity's state (position, velocity, sprite, health, etc.).

  • System -- A function or object that processes all entities with a specific set of components. Systems contain the logic; components contain the data.

Why ECS Over Inheritance

Traditional object-oriented inheritance creates rigid, deep hierarchies:

GameObject
  -> MovableObject
    -> Character
      -> Player
      -> Enemy
        -> FlyingEnemy
        -> GroundEnemy

Problems with this approach:

  • Adding a new entity type that combines traits from multiple branches requires restructuring the hierarchy or using multiple inheritance.

  • Deep hierarchies are fragile; changes to base classes ripple through all descendants.

  • Classes accumulate unused behavior over time.

ECS solves these problems through composition:

// An entity is just an ID
const player = world.createEntity();

// Attach components to define what it is
world.addComponent(player, new Position(100, 200));
world.addComponent(player, new Velocity(0, 0));
world.addComponent(player, new Sprite("player.png"));
world.addComponent(player, new Health(100));
world.addComponent(player, new PlayerInput());

// A "flying enemy" is just a different combination of components
const flyingEnemy = world.createEntity();
world.addComponent(flyingEnemy, new Position(400, 50));
world.addComponent(flyingEnemy, new Velocity(0, 0));
world.addComponent(flyingEnemy, new Sprite("bat.png"));
world.addComponent(flyingEnemy, new Health(30));
world.addComponent(flyingEnemy, new AIBehavior("patrol_fly"));
world.addComponent(flyingEnemy, new Flying());
Systems Process Components
// Movement system: processes all entities with Position + Velocity
function movementSystem(world, deltaTime) {
  for (const [entity, pos, vel] of world.query(Position, Velocity)) {
    pos.x += vel.x * deltaTime;
    pos.y += vel.y * deltaTime;
  }
}

// Render system: processes all entities with Position + Sprite
function renderSystem(world, context) {
  for (const [entity, pos, sprite] of world.query(Position, Sprite)) {
    context.drawImage(sprite.image, pos.x, pos.y);
  }
}

// Gravity system: only affects entities with Velocity but NOT Flying
function gravitySystem(world, deltaTime) {
  for (const [entity, vel] of world.query(Velocity).without(Flying)) {
    vel.y += 9.8 * deltaTime;
  }
}
Benefits of ECS
  • Flexible composition -- Create any entity type by mixing components without modifying code.

  • Cache-friendly data layout -- Storing components contiguously in memory improves CPU cache performance.

  • Parallelism -- Systems that operate on different component sets can run in parallel.

  • Easy serialization -- Components are plain data, making save/load straightforward.


Core Engine Subsystems

Memory Management

Custom memory management is critical for game engine performance. The default allocator (malloc/new) is general-purpose and not optimized for game workloads.

Common allocation strategies:

  • Stack Allocator -- Fast LIFO allocations for temporary, frame-scoped data. Reset the stack pointer at the end of each frame.

  • Pool Allocator -- Fixed-size block allocation for objects of the same type (entities, components, particles). Zero fragmentation.

  • Frame Allocator -- A linear allocator that resets every frame. Ideal for per-frame temporary data.

  • Double-Buffered Allocator -- Two frame allocators that alternate each frame, allowing data from the previous frame to persist.

// Conceptual frame allocator
class FrameAllocator {
    char* buffer;
    size_t offset;
    size_t capacity;

public:
    void* allocate(size_t size) {
        void* ptr = buffer + offset;
        offset += size;
        return ptr;
    }

    void reset() {
        offset = 0;  // All allocations freed instantly
    }
};
Resource Management

The resource manager handles loading, caching, and lifetime management of game assets.

Key responsibilities:

  • Asynchronous loading -- Load assets in background threads to avoid stalling the game loop.

  • Reference counting -- Track how many systems use an asset; unload when no longer referenced.

  • Caching -- Keep recently used assets in memory to avoid redundant disk reads.

  • Hot reloading -- Detect asset changes on disk and reload them at runtime during development.

  • Resource handles -- Use handles (IDs or smart pointers) rather than raw pointers to reference assets.

class ResourceManager {
  constructor() {
    this.cache = new Map();
    this.loading = new Map();
  }

  async load(path) {
    // Return cached resource if available
    if (this.cache.has(path)) {
      return this.cache.get(path);
    }

    // Avoid duplicate loads
    if (this.loading.has(path)) {
      return this.loading.get(path);
    }

    // Start async load
    const promise = this._loadFromDisk(path).then(resource => {
      this.cache.set(path, resource);
      this.loading.delete(path);
      return resource;
    });

    this.loading.set(path, promise);
    return promise;
  }

  unload(path) {
    this.cache.delete(path);
  }
}
Rendering Pipeline

The rendering subsystem translates the game's visual state into pixels on screen.

Typical rendering pipeline stages:

  1. Scene traversal -- Walk the scene graph or query ECS for renderable entities.

  2. Frustum culling -- Discard objects outside the camera's view.

  3. Occlusion culling -- Discard objects hidden behind other geometry.

  4. Sorting -- Order objects by material, depth, or transparency requirements.

  5. Batching -- Group objects with the same material to minimize draw calls and state changes.

  6. Vertex processing -- Transform vertices from model space to screen space (vertex shader).

  7. Rasterization -- Convert triangles to fragments (pixels).

  8. Fragment processing -- Compute final pixel color using lighting, textures, and effects (fragment shader).

  9. Post-processing -- Apply screen-space effects like bloom, tone mapping, and anti-aliasing.

Render command pattern:

Rather than making draw calls directly, build a list of render commands that can be sorted and batched before submission:

class RenderCommand {
  constructor(mesh, material, transform, sortKey) {
    this.mesh = mesh;
    this.material = material;
    this.transform = transform;
    this.sortKey = sortKey;
  }
}

class Renderer {
  constructor() {
    this.commandQueue = [];
  }

  submit(command) {
    this.commandQueue.push(command);
  }

  flush(context) {
    // Sort by material to minimize state changes
    this.commandQueue.sort((a, b) => a.sortKey - b.sortKey);

    for (const cmd of this.commandQueue) {
      this._bindMaterial(cmd.material);
      this._setTransform(cmd.transform);
      this._drawMesh(cmd.mesh, context);
    }

    this.commandQueue.length = 0;
  }
}
Physics Integration

The physics subsystem simulates physical behavior and detects collisions.

Key design considerations:

  • Fixed timestep -- Physics should update at a fixed rate (e.g., 50 Hz) independent of the rendering frame rate. This ensures deterministic simulation behavior.

  • Collision phases -- Use a broad phase (spatial partitioning, bounding volume hierarchies) to quickly eliminate non-colliding pairs, followed by a narrow phase for precise intersection testing.

  • Physics world separation -- The physics world should maintain its own representation of objects (physics bodies) separate from game entities. A synchronization step maps between them.

class PhysicsWorld {
  constructor(fixedTimestep = 1 / 50) {
    this.fixedTimestep = fixedTimestep;
    this.accumulator = 0;
    this.bodies = [];
  }

  update(deltaTime) {
    this.accumulator += deltaTime;

    while (this.accumulator >= this.fixedTimestep) {
      this.step(this.fixedTimestep);
      this.accumulator -= this.fixedTimestep;
    }
  }

  step(dt) {
    // Integrate velocities
    for (const body of this.bodies) {
      body.velocity.y += body.gravity * dt;
      body.position.x += body.velocity.x * dt;
      body.position.y += body.velocity.y * dt;
    }

    // Detect and resolve collisions
    this.broadPhase();
    this.narrowPhase();
    this.resolveCollisions();
  }
}
Input System

The input system translates raw hardware events into game-meaningful actions.

Layered design:

  1. Hardware Layer -- Receives raw events from the OS (key pressed, mouse moved, button down).

  2. Mapping Layer -- Translates raw inputs into named actions via configurable bindings (e.g., "Space" maps to "Jump", "W" maps to "MoveForward").

  3. Action Layer -- Exposes abstract actions that game code queries, completely decoupled from specific hardware inputs.

class InputManager {
  constructor() {
    this.bindings = new Map();
    this.actionStates = new Map();
  }

  bind(action, key) {
    this.bindings.set(key, action);
  }

  handleKeyDown(event) {
    const action = this.bindings.get(event.code);
    if (action) {
      this.actionStates.set(action, true);
    }
  }

  handleKeyUp(event) {
    const action = this.bindings.get(event.code);
    if (action) {
      this.actionStates.set(action, false);
    }
  }

  isActionActive(action) {
    return this.actionStates.get(action) || false;
  }
}

// Usage
const input = new InputManager();
input.bind("Jump", "Space");
input.bind("MoveLeft", "KeyA");
input.bind("MoveRight", "KeyD");

// In game update:
if (input.isActionActive("Jump")) {
  player.jump();
}
Event System

An event system enables decoupled communication between engine subsystems and game code without direct references.

Publish-subscribe pattern:

class EventBus {
  constructor() {
    this.listeners = new Map();
  }

  on(eventType, callback) {
    if (!this.listeners.has(eventType)) {
      this.listeners.set(eventType, []);
    }
    this.listeners.get(eventType).push(callback);
  }

  off(eventType, callback) {
    const callbacks = this.listeners.get(eventType);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index !== -1) callbacks.splice(index, 1);
    }
  }

  emit(eventType, data) {
    const callbacks = this.listeners.get(eventType);
    if (callbacks) {
      for (const callback of callbacks) {
        callback(data);
      }
    }
  }
}

// Usage
const events = new EventBus();

events.on("collision", (data) => {
  console.log(`${data.entityA} collided with ${data.entityB}`);
});

events.on("entityDestroyed", (data) => {
  spawnExplosion(data.position);
  addScore(data.points);
});

// Emit from physics system
events.emit("collision", { entityA: player, entityB: wall });

Deferred events:

For performance and determinism, events can be queued during a frame and dispatched at a specific point in the update cycle:

class DeferredEventBus extends EventBus {
  constructor() {
    super();
    this.eventQueue = [];
  }

  queue(eventType, data) {
    this.eventQueue.push({ type: eventType, data });
  }

  dispatchQueued() {
    for (const event of this.eventQueue) {
      this.emit(event.type, event.data);
    }
    this.eventQueue.length = 0;
  }
}
Scene Management

The scene manager organizes game content into logical groups and manages transitions between different game states.

Common patterns:

  • Scene graph -- A hierarchical tree of nodes where child transforms are relative to parent transforms. Moving a parent moves all children.

  • Scene stack -- Scenes can be pushed and popped. A pause menu pushes on top of gameplay; dismissing it pops back to gameplay.

  • Scene loading -- Scenes define which assets and entities to load. The scene manager coordinates loading, initialization, and cleanup.

class SceneManager {
  constructor() {
    this.scenes = new Map();
    this.activeScene = null;
  }

  register(name, scene) {
    this.scenes.set(name, scene);
  }

  async switchTo(name) {
    if (this.activeScene) {
      this.activeScene.onExit();
      this.activeScene.unloadResources();
    }

    this.activeScene = this.scenes.get(name);
    await this.activeScene.loadResources();
    this.activeScene.onEnter();
  }

  update(deltaTime) {
    if (this.activeScene) {
      this.activeScene.update(deltaTime);
    }
  }

  render(context) {
    if (this.activeScene) {
      this.activeScene.render(context);
    }
  }
}

Platform Abstraction

A well-designed engine abstracts platform-specific code behind a uniform interface. This enables the engine to run on multiple operating systems, graphics APIs, and hardware configurations.

Areas requiring abstraction:

ConcernExamples
WindowingWin32, X11, Cocoa, SDL, GLFW
Graphics APIOpenGL, Vulkan, DirectX, Metal, WebGL
File I/OPOSIX, Win32, virtual file systems
Threadingpthreads, Win32 threads, Web Workers
Audio outputWASAPI, CoreAudio, ALSA, Web Audio
Input devicesDirectInput, XInput, evdev, Gamepad API
// Abstract file system interface
class FileSystem {
  async readFile(path) { throw new Error("Not implemented"); }
  async writeFile(path, data) { throw new Error("Not implemented"); }
  async exists(path) { throw new Error("Not implemented"); }
}

// Web implementation
class WebFileSystem extends FileSystem {
  async readFile(path) {
    const response = await fetch(path);
    return response.arrayBuffer();
  }
}

// Node.js implementation
class NodeFileSystem extends FileSystem {
  async readFile(path) {
    const fs = require("fs").promises;
    return fs.readFile(path);
  }
}

Initialization and Shutdown Order

Engine subsystems must be initialized in dependency order and shut down in reverse order.

Typical initialization sequence:

  1. Core systems (logging, memory, configuration)

  2. Platform layer (window creation, input devices)

  3. Rendering system (graphics context, default resources)

  4. Audio system

  5. Physics system

  6. Resource manager (load default/shared assets)

  7. Scene manager

  8. Scripting system

  9. Game-specific initialization

Shutdown reverses this order to ensure systems are cleaned up before the systems they depend on.

class Engine {
  async initialize() {
    this.logger = new Logger();
    this.config = new Config("engine.json");
    this.platform = new Platform();
    await this.platform.createWindow(this.config.window);

    this.renderer = new Renderer(this.platform.canvas);
    this.audio = new AudioSystem();
    this.physics = new PhysicsWorld();
    this.resources = new ResourceManager();
    this.input = new InputManager(this.platform.window);
    this.events = new EventBus();
    this.scenes = new SceneManager();

    this.logger.info("Engine initialized");
  }

  shutdown() {
    this.scenes.cleanup();
    this.resources.unloadAll();
    this.input.cleanup();
    this.physics.cleanup();
    this.audio.cleanup();
    this.renderer.cleanup();
    this.platform.cleanup();
    this.logger.info("Engine shutdown complete");
  }

  run() {
    let lastTime = performance.now();

    const loop = (currentTime) => {
      const deltaTime = (currentTime - lastTime) / 1000;
      lastTime = currentTime;

      this.input.poll();
      this.physics.update(deltaTime);
      this.scenes.update(deltaTime);
      this.events.dispatchQueued();
      this.scenes.render(this.renderer);
      this.renderer.present();

      requestAnimationFrame(loop);
    };

    requestAnimationFrame(loop);
  }
}

Performance Principles

Avoid Premature Abstraction

While modularity is important, over-engineering interfaces before understanding real requirements leads to unnecessary complexity. Start with simple, concrete implementations and refactor toward abstraction when actual use cases demand it.

Profile Before Optimizing

Measure actual performance bottlenecks using profiling tools before spending time on optimization. Intuition about where time is spent is frequently wrong.

Data-Oriented Design

Organize data by how it is accessed rather than by object-oriented abstractions. Storing components of the same type contiguously in memory (Structure of Arrays rather than Array of Structures) dramatically improves CPU cache hit rates.

// Array of Structures (cache-unfriendly for position-only iteration)
const entities = [
  { position: {x: 0, y: 0}, sprite: "hero.png", health: 100 },
  { position: {x: 5, y: 3}, sprite: "bat.png", health: 30 },
];

// Structure of Arrays (cache-friendly for position-only iteration)
const positions = { x: [0, 5], y: [0, 3] };
const sprites = ["hero.png", "bat.png"];
const healths = [100, 30];
Minimize Allocations in Hot Paths

Avoid creating new objects or allocating memory during per-frame updates. Pre-allocate buffers, use object pools, and reuse temporary objects.

Batch Operations

Group similar operations together to reduce overhead from context switching, draw call setup, and cache misses. Process all entities of a given type before moving to the next type.


Summary of Key Principles

PrincipleDescription
ModularityIndependent subsystems with clean interfaces
Separation of concernsEach system has a single responsibility
Data-driven designBehavior controlled by data, not hard-coded logic
Composition over inheritanceECS pattern for flexible entity construction
Minimal dependenciesClean, hierarchical dependency graph
Platform abstractionUniform interfaces over platform-specific code
Fixed timestep physicsDeterministic simulation independent of frame rate
Event-driven communicationDecoupled interaction through publish-subscribe
Data-oriented performanceOptimize memory layout for access patterns
Measure before optimizingProfile to identify actual bottlenecks

Requirements and compatibility

Written for: GitHub Copilot

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

First committed by
GitHub avatar of jhaugajhauga
Publisher
GitHub (Official)
Distributed by
GitHub
Source
github/awesome-copilot · skills/game-engine · commit 797337f
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Contributors
jhauga

AutoGineer is not affiliated with or endorsed by jhauga or GitHub.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download game-engine.zip