Game Engine
GitHubOfficialFirst committed by jhaugaDistributed by GitHub
- Skill
- Tool integration
- Software development
- MIT
- No issues found
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
Download the skill as a ZIP:
https://autogineer.com/agent-skills/github/game-engine/downloadUnzip 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:
Process Input - Read keyboard, mouse, touch, or gamepad input
Update State - Update game object positions, physics, AI, and logic
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
Set up an HTML file with a
<canvas>elementGet the 2D rendering context
Implement the game loop using
requestAnimationFrameCreate game objects with position, velocity, and size properties
Handle keyboard/mouse input for player control
Implement collision detection between game objects
Add scoring, lives, and win/lose conditions
Add sound effects and music
Building a 3D Game
Choose a framework (Three.js, Babylon.js, A-Frame, or PlayCanvas)
Set up the scene, camera, and renderer
Load or create 3D models and textures
Implement lighting and shaders
Add physics and collision detection
Implement player controls and camera movement
Add audio and visual effects
Publishing a Game
Optimize assets (compress images, minify code)
Test across browsers and devices
Choose distribution platform (web, app stores, game portals)
Implement monetization if needed
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.
| Template | Description |
|---|---|
paddle-game-template.md | 2D Breakout-style game with pure JavaScript |
2d-maze-game.md | Maze game with device orientation controls |
2d-platform-game.md | Platformer game using Phaser framework |
gameBase-template-repo.md | Game base template repository structure |
simple-2d-engine.md | Simple 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.
| Reference | Topics Covered |
|---|---|
basics.md | Game development introduction and anatomy |
web-apis.md | Canvas, WebGL, Web Audio, Gamepad, and other web APIs |
techniques.md | Collision detection, tilemaps, async scripts, audio |
3d-web-games.md | 3D theory, frameworks, shaders, WebXR |
game-control-mechanisms.md | Touch, keyboard, mouse, and gamepad controls |
game-publishing.md | Distribution, promotion, and monetization |
algorithms.md | Raycasting, collision, physics, vector math |
terminology.md | Game development glossary |
game-engine-core-principles.md | Core design principles for game engines |
Troubleshooting
| Issue | Solution |
|---|---|
| Canvas is blank | Check that you are calling drawing methods after getting the context and inside the game loop |
| Game runs at different speeds | Use delta time in update calculations instead of fixed values |
| Collision detection is inconsistent | Use continuous collision detection or reduce time steps for fast-moving objects |
| Audio does not play | Browsers require user interaction before playing audio; trigger playback from a click handler |
| Performance is poor | Profile with browser dev tools, reduce draw calls, use object pooling, and optimize asset sizes |
| Touch controls are unresponsive | Prevent default touch behavior and handle touch events separately from mouse events |
| WebGL context lost | Handle the webglcontextlost event and restore state on webglcontextrestored |
Files
- ATTRIBUTION.mdAdded by AutoGineer851 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md6.2 KiB
- assets/2d-maze-game.md13.0 KiB
- assets/2d-platform-game.md58.2 KiB
- assets/gameBase-template-repo.md9.9 KiB
- assets/paddle-game-template.md38.4 KiB
- assets/simple-2d-engine.md14.0 KiB
- references/3d-web-games.md23.9 KiB
- references/algorithms.md24.5 KiB
- references/basics.md10.9 KiB
- references/game-control-mechanisms.md19.1 KiB
- references/game-engine-core-principles.md21.6 KiB
- references/game-publishing.md13.7 KiB
- references/techniques.md27.4 KiB
- references/terminology.md19.4 KiB
- references/web-apis.md51.4 KiB
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.
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, streamingSeparation 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 / HardwareCircular 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
-> GroundEnemyProblems 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:
Scene traversal -- Walk the scene graph or query ECS for renderable entities.
Frustum culling -- Discard objects outside the camera's view.
Occlusion culling -- Discard objects hidden behind other geometry.
Sorting -- Order objects by material, depth, or transparency requirements.
Batching -- Group objects with the same material to minimize draw calls and state changes.
Vertex processing -- Transform vertices from model space to screen space (vertex shader).
Rasterization -- Convert triangles to fragments (pixels).
Fragment processing -- Compute final pixel color using lighting, textures, and effects (fragment shader).
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:
Hardware Layer -- Receives raw events from the OS (key pressed, mouse moved, button down).
Mapping Layer -- Translates raw inputs into named actions via configurable bindings (e.g., "Space" maps to "Jump", "W" maps to "MoveForward").
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:
| Concern | Examples |
|---|---|
| Windowing | Win32, X11, Cocoa, SDL, GLFW |
| Graphics API | OpenGL, Vulkan, DirectX, Metal, WebGL |
| File I/O | POSIX, Win32, virtual file systems |
| Threading | pthreads, Win32 threads, Web Workers |
| Audio output | WASAPI, CoreAudio, ALSA, Web Audio |
| Input devices | DirectInput, 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:
Core systems (logging, memory, configuration)
Platform layer (window creation, input devices)
Rendering system (graphics context, default resources)
Audio system
Physics system
Resource manager (load default/shared assets)
Scene manager
Scripting system
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
| Principle | Description |
|---|---|
| Modularity | Independent subsystems with clean interfaces |
| Separation of concerns | Each system has a single responsibility |
| Data-driven design | Behavior controlled by data, not hard-coded logic |
| Composition over inheritance | ECS pattern for flexible entity construction |
| Minimal dependencies | Clean, hierarchical dependency graph |
| Platform abstraction | Uniform interfaces over platform-specific code |
| Fixed timestep physics | Deterministic simulation independent of frame rate |
| Event-driven communication | Decoupled interaction through publish-subscribe |
| Data-oriented performance | Optimize memory layout for access patterns |
| Measure before optimizing | Profile 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
jhauga
- 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