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://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-control-mechanisms.md

Game Control Mechanisms

This reference covers the primary control mechanisms available for web-based games, including mobile touch, desktop keyboard and mouse, gamepad controllers, and unconventional input methods.

Mobile Touch Controls

Mobile touch controls are essential for web-based games targeting mobile devices. A mobile-first approach ensures games are accessible on the most widely used platform for HTML5 games.

Key Events and APIs

The core touch events available in the browser are:

EventDescription
touchstartFired when the user places a finger on the screen
touchmoveFired when the user moves a finger while touching the screen
touchendFired when the user lifts a finger from the screen
touchcancelFired when a touch is cancelled or interrupted (e.g., finger moves off-screen)

Registering touch event listeners:

const canvas = document.querySelector("canvas");
canvas.addEventListener("touchstart", handleStart);
canvas.addEventListener("touchmove", handleMove);
canvas.addEventListener("touchend", handleEnd);
canvas.addEventListener("touchcancel", handleCancel);

Touch event properties:

  • e.touches[0] -- Access the first touch point (zero-indexed for multitouch).

  • e.touches[0].pageX / e.touches[0].pageY -- Touch coordinates relative to the page.

  • Always subtract canvas offset to get position relative to the canvas element.

Code Examples

Pure JavaScript touch handler:

document.addEventListener("touchstart", touchHandler);
document.addEventListener("touchmove", touchHandler);

function touchHandler(e) {
  if (e.touches) {
    playerX = e.touches[0].pageX - canvas.offsetLeft - playerWidth / 2;
    playerY = e.touches[0].pageY - canvas.offsetTop - playerHeight / 2;
    e.preventDefault();
  }
}

Phaser framework pointer system:

Phaser manages touch input through "pointers" representing individual fingers:

// Access pointers
this.game.input.activePointer;       // Most recently active pointer
this.game.input.pointer1;            // First pointer
this.game.input.pointer2;            // Second pointer

// Add more pointers (up to 10 total)
this.game.input.addPointer();

// Global input events
this.game.input.onDown.add(itemTouched, this);
this.game.input.onUp.add(itemReleased, this);
this.game.input.onTap.add(itemTapped, this);
this.game.input.onHold.add(itemHeld, this);

Draggable sprite for ship movement:

const player = this.game.add.sprite(30, 30, "ship");
player.inputEnabled = true;
player.input.enableDrag();
player.events.onDragStart.add(onDragStart, this);
player.events.onDragStop.add(onDragStop, this);

function onDragStart(sprite, pointer) {
  console.log(`Dragging at: ${pointer.x}, ${pointer.y}`);
}

Invisible touch area for shooting (right half of screen):

this.buttonShoot = this.add.button(
  this.world.width * 0.5, 0,
  "button-alpha",    // transparent image
  null,
  this
);
this.buttonShoot.onInputDown.add(this.goShootPressed, this);
this.buttonShoot.onInputUp.add(this.goShootReleased, this);

Virtual gamepad plugin:

this.gamepad = this.game.plugins.add(Phaser.Plugin.VirtualGamepad);
this.joystick = this.gamepad.addJoystick(100, 420, 1.2, "gamepad");
this.button = this.gamepad.addButton(400, 420, 1.0, "gamepad");
Best Practices
  • Always call preventDefault() on touch events to avoid unwanted scrolling and default browser behavior.

  • Use invisible button areas rather than visible buttons to avoid covering gameplay.

  • Leverage natural touch gestures like dragging, which are more intuitive than on-screen buttons.

  • Subtract canvas offset and account for object dimensions when calculating positions.

  • Make touchable areas large enough for comfortable interaction.

  • Plan for multitouch support. Phaser supports up to 10 simultaneous pointers.

  • Use a framework like Phaser for automatic desktop and mobile compatibility.

  • Consider virtual gamepad/joystick plugins for advanced touch control UI.

Desktop with Mouse and Keyboard

Desktop keyboard and mouse controls provide precise input for web games and are the default control scheme for desktop browsers.

Key Events and APIs

Keyboard events:

document.addEventListener("keydown", keyDownHandler);
document.addEventListener("keyup", keyUpHandler);
  • event.code returns readable key identifiers such as "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown".

  • Use requestAnimationFrame() for continuous frame updates.

Phaser keyboard API:

this.cursors = this.input.keyboard.createCursorKeys();  // Arrow key objects
this.keyLeft = this.input.keyboard.addKey(Phaser.KeyCode.A);  // Custom key binding
// Check key state with .isDown property
// Listen for press events with .onDown.add()

Phaser mouse API:

this.game.input.mousePointer;                    // Mouse position and state
this.game.input.mousePointer.isDown;             // Is any mouse button pressed
this.game.input.mousePointer.x;                  // Mouse X coordinate
this.game.input.mousePointer.y;                  // Mouse Y coordinate
this.game.input.mousePointer.leftButton.isDown;  // Left mouse button
this.game.input.mousePointer.rightButton.isDown; // Right mouse button
this.game.input.activePointer;                   // Platform-independent (mouse + touch)
Code Examples

Pure JavaScript keyboard state tracking:

let rightPressed = false;
let leftPressed = false;
let upPressed = false;
let downPressed = false;

function keyDownHandler(event) {
  if (event.code === "ArrowRight") rightPressed = true;
  else if (event.code === "ArrowLeft") leftPressed = true;
  if (event.code === "ArrowDown") downPressed = true;
  else if (event.code === "ArrowUp") upPressed = true;
}

function keyUpHandler(event) {
  if (event.code === "ArrowRight") rightPressed = false;
  else if (event.code === "ArrowLeft") leftPressed = false;
  if (event.code === "ArrowDown") downPressed = false;
  else if (event.code === "ArrowUp") upPressed = false;
}

Game loop with input handling:

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  if (rightPressed) playerX += 5;
  else if (leftPressed) playerX -= 5;
  if (downPressed) playerY += 5;
  else if (upPressed) playerY -= 5;

  ctx.drawImage(img, playerX, playerY);
  requestAnimationFrame(draw);
}

Dual control support (Arrow keys + WASD) in Phaser:

this.cursors = this.input.keyboard.createCursorKeys();
this.keyLeft = this.input.keyboard.addKey(Phaser.KeyCode.A);
this.keyRight = this.input.keyboard.addKey(Phaser.KeyCode.D);
this.keyUp = this.input.keyboard.addKey(Phaser.KeyCode.W);
this.keyDown = this.input.keyboard.addKey(Phaser.KeyCode.S);

// In update:
if (this.cursors.left.isDown || this.keyLeft.isDown) {
  // move left
} else if (this.cursors.right.isDown || this.keyRight.isDown) {
  // move right
}
if (this.cursors.up.isDown || this.keyUp.isDown) {
  // move up
} else if (this.cursors.down.isDown || this.keyDown.isDown) {
  // move down
}

Multiple fire buttons:

this.keyFire1 = this.input.keyboard.addKey(Phaser.KeyCode.X);
this.keyFire2 = this.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);

if (this.keyFire1.isDown || this.keyFire2.isDown) {
  // fire the weapon
}

Device-specific instructions:

if (this.game.device.desktop) {
  moveText = "Arrow keys or WASD to move";
  shootText = "X or Space to shoot";
} else {
  moveText = "Tap and hold to move";
  shootText = "Tap to shoot";
}
Best Practices
  • Support multiple input methods: provide both arrow keys and WASD for movement, and multiple fire buttons (e.g., X and Space).

  • Use activePointer instead of mousePointer to support both mouse and touch input seamlessly.

  • Detect device type and display appropriate control instructions to the player.

  • Use requestAnimationFrame() for smooth animation and check key states in the game loop rather than reacting to individual key presses.

  • Allow keyboard shortcuts to skip non-gameplay screens (e.g., Enter to start, any key to skip intro).

  • Use Phaser or a similar framework for cross-browser compatibility, as they handle edge cases and browser differences automatically.

Desktop with Gamepad

The Gamepad API enables web games to detect and respond to gamepad and controller input, bringing console-like experiences to the browser.

Key Events and APIs

Core events:

window.addEventListener("gamepadconnected", gamepadHandler);
window.addEventListener("gamepaddisconnected", gamepadHandler);

Gamepad object properties:

  • controller.id -- Device identifier string.

  • controller.buttons[] -- Array of button objects, each with a .pressed boolean property.

  • controller.axes[] -- Array of analog stick values ranging from -1 to 1.

Standard button/axes mapping (Xbox 360 layout):

InputIndexType
A Button0Button
B Button1Button
X Button2Button
Y Button3Button
D-Pad Up12Button
D-Pad Down13Button
D-Pad Left14Button
D-Pad Right15Button
Left Stick Xaxes[0]Axis
Left Stick Yaxes[1]Axis
Right Stick Xaxes[2]Axis
Right Stick Yaxes[3]Axis
Code Examples

Pure JavaScript connection handler:

let controller = {};
let buttonsPressed = [];

function gamepadHandler(e) {
  controller = e.gamepad;
  console.log(`Gamepad: ${controller.id}`);
}

window.addEventListener("gamepadconnected", gamepadHandler);

Polling button states each frame:

function gamepadUpdateHandler() {
  buttonsPressed = [];
  if (controller.buttons) {
    for (const [i, button] of controller.buttons.entries()) {
      if (button.pressed) {
        buttonsPressed.push(i);
      }
    }
  }
}

function gamepadButtonPressedHandler(button) {
  return buttonsPressed.includes(button);
}

Game loop integration:

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  gamepadUpdateHandler();

  if (gamepadButtonPressedHandler(12)) playerY -= 5;  // D-Pad Up
  else if (gamepadButtonPressedHandler(13)) playerY += 5;  // D-Pad Down
  if (gamepadButtonPressedHandler(14)) playerX -= 5;  // D-Pad Left
  else if (gamepadButtonPressedHandler(15)) playerX += 5;  // D-Pad Right
  if (gamepadButtonPressedHandler(0)) alert("BOOM!");  // A Button

  ctx.drawImage(img, playerX, playerY);
  requestAnimationFrame(draw);
}

Reusable GamepadAPI library with hold vs press detection:

const GamepadAPI = {
  active: false,
  controller: {},

  connect(event) {
    GamepadAPI.controller = event.gamepad;
    GamepadAPI.active = true;
  },

  disconnect(event) {
    delete GamepadAPI.controller;
    GamepadAPI.active = false;
  },

  update() {
    GamepadAPI.buttons.cache = [...GamepadAPI.buttons.status];
    GamepadAPI.buttons.status = [];

    const c = GamepadAPI.controller || {};
    const pressed = [];

    if (c.buttons) {
      for (let b = 0; b < c.buttons.length; b++) {
        if (c.buttons[b].pressed) {
          pressed.push(GamepadAPI.buttons.layout[b]);
        }
      }
    }

    const axes = [];
    if (c.axes) {
      for (const ax of c.axes) {
        axes.push(ax.toFixed(2));
      }
    }

    GamepadAPI.axes.status = axes;
    GamepadAPI.buttons.status = pressed;
    return pressed;
  },

  buttons: {
    layout: ["A", "B", "X", "Y", "LB", "RB", "LT", "RT",
             "Back", "Start", "LS", "RS",
             "DPad-Up", "DPad-Down", "DPad-Left", "DPad-Right"],
    cache: [],
    status: [],
    pressed(button, hold) {
      let newPress = false;
      if (GamepadAPI.buttons.status.includes(button)) {
        newPress = true;
      }
      if (!hold && GamepadAPI.buttons.cache.includes(button)) {
        newPress = false;
      }
      return newPress;
    }
  },

  axes: {
    status: []
  }
};

window.addEventListener("gamepadconnected", GamepadAPI.connect);
window.addEventListener("gamepaddisconnected", GamepadAPI.disconnect);

Analog stick movement with deadzone threshold:

if (GamepadAPI.axes.status) {
  if (GamepadAPI.axes.status[0] > 0.5) playerX += 5;       // Right
  else if (GamepadAPI.axes.status[0] < -0.5) playerX -= 5; // Left
  if (GamepadAPI.axes.status[1] > 0.5) playerY += 5;       // Down
  else if (GamepadAPI.axes.status[1] < -0.5) playerY -= 5; // Up
}

Context-aware control display:

if (this.game.device.desktop) {
  if (GamepadAPI.active) {
    moveText = "DPad or left Stick to move";
    shootText = "A to shoot, Y for controls";
  } else {
    moveText = "Arrow keys or WASD to move";
    shootText = "X or Space to shoot";
  }
} else {
  moveText = "Tap and hold to move";
  shootText = "Tap to shoot";
}
Best Practices
  • Always check GamepadAPI.active before processing gamepad input.

  • Differentiate between "hold" (continuous) and "press" (single new press) by caching previous frame button states.

  • Apply a deadzone threshold (e.g., 0.5) for analog stick values to avoid unintentional drift input.

  • Create a button mapping system because different devices may have different button layouts.

  • Poll gamepad state every frame by calling the update function inside requestAnimationFrame.

  • Display an on-screen indicator when a gamepad is connected, along with appropriate control instructions.

  • Browser support is approximately 63% globally; always provide fallback keyboard/mouse controls.

Other Control Mechanisms

Unconventional control mechanisms can provide unique gameplay experiences and leverage emerging hardware beyond traditional input devices.

TV Remote Controls

Description: Smart TV remotes emit standard keyboard events, allowing web games to run on TV screens without modification.

Key Events and APIs:

  • Remote directional buttons map to standard arrow key codes.

  • Custom remote buttons have manufacturer-specific key codes.

Code Example:

// Standard arrow key controls work automatically with TV remotes
this.cursors = this.input.keyboard.createCursorKeys();
if (this.cursors.right.isDown) {
  // move player right
}

// Discover manufacturer-specific remote key codes
window.addEventListener("keydown", (event) => {
  console.log(event.keyCode);
});

// Handle custom remote buttons (codes vary by manufacturer)
window.addEventListener("keydown", (event) => {
  switch (event.keyCode) {
    case 8:   // Pause (Panasonic example)
      break;
    case 588: // Custom action
      break;
  }
});

Best Practices:

  • Log key codes to the console during development to discover remote button mappings.

  • Reuse existing keyboard control implementations since remotes emit keyboard events.

  • Refer to manufacturer documentation or cheat sheets for key code mappings.

Leap Motion (Hand Gesture Recognition)

Description: Detects hand position, rotation, and grip strength for gesture-based control without physical contact using the Leap Motion sensor.

Key Events and APIs:

  • Leap.loop() -- Frame-based hand tracking callback.

  • hand.roll() -- Horizontal rotation in radians.

  • hand.pitch() -- Vertical rotation in radians.

  • hand.grabStrength -- Grip strength as a float from 0 (open hand) to 1 (closed fist).

Code Example:

<script src="https://js.leapmotion.com/leap-0.6.4.min.js"></script>
const toDegrees = 1 / (Math.PI / 180);
let horizontalDegree = 0;
let verticalDegree = 0;
const degreeThreshold = 30;
let grabStrength = 0;

Leap.loop({
  hand(hand) {
    horizontalDegree = Math.round(hand.roll() * toDegrees);
    verticalDegree = Math.round(hand.pitch() * toDegrees);
    grabStrength = hand.grabStrength;
  },
});

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  if (horizontalDegree > degreeThreshold) playerX -= 5;
  else if (horizontalDegree < -degreeThreshold) playerX += 5;

  if (verticalDegree > degreeThreshold) playerY += 5;
  else if (verticalDegree < -degreeThreshold) playerY -= 5;

  if (grabStrength === 1) fireWeapon();

  ctx.drawImage(img, playerX, playerY);
  requestAnimationFrame(draw);
}

Best Practices:

  • Use a degree threshold (e.g., 30 degrees) to filter out minor hand movements and noise.

  • Output diagnostic data during development to calibrate sensitivity.

  • Limit to simple actions like steering and shooting rather than complex multi-input schemes.

  • Requires Leap Motion drivers to be installed.

Doppler Effect (Microphone-Based Gesture Detection)

Description: Detects hand movement direction and magnitude by analyzing frequency shifts in sound waves picked up by the device microphone. An emitted tone bounces off the user's hand, and the frequency difference indicates movement direction.

Key Events and APIs:

  • Uses a Doppler effect detection library.

  • bandwidth.left and bandwidth.right provide frequency analysis values.

Code Example:

doppler.init((bandwidth) => {
  const diff = bandwidth.left - bandwidth.right;
  // Positive diff = movement in one direction
  // Negative diff = movement in the other direction
});

Best Practices:

  • Best suited for simple one-axis controls such as scrolling or up/down movement.

  • Less precise than Leap Motion or gamepad input.

  • Provides directional information through left/right frequency difference comparison.

Makey Makey (Physical Object Controllers)

Description: Connects conductive objects (bananas, clay, drawn circuits, water, etc.) to a board that emulates keyboard and mouse input, enabling creative physical interfaces for games.

Key Events and APIs (via Cylon.js for custom hardware):

  • makey-button driver for custom setups with Arduino or Raspberry Pi.

  • "push" event listener for button activation.

  • The Makey Makey board itself works over USB and emits standard keyboard events without requiring custom code.

Code Example (custom setup with Cylon.js):

const Cylon = require("cylon");

Cylon.robot({
  connections: {
    arduino: { adaptor: "firmata", port: "/dev/ttyACM0" },
  },
  devices: {
    makey: { driver: "makey-button", pin: 2 },
  },
  work(my) {
    my.makey.on("push", () => {
      console.log("Button pushed!");
      // Trigger game action
    });
  },
}).start();

Best Practices:

  • The Makey Makey board connects via USB and emits standard keyboard events, so existing keyboard controls work out of the box.

  • Use a 10 MOhm resistor for GPIO connections on custom setups.

  • Enables creative physical gaming experiences that are particularly good for exhibitions and installations.

General Recommendations for Unconventional Controls
  • Implement multiple control mechanisms to reach the broadest possible audience.

  • Build on a keyboard and gamepad foundation since most unconventional controllers emulate or complement standard input.

  • Use threshold values to filter noise and accidental inputs from imprecise hardware.

  • Provide visual diagnostics during development with console output and on-screen values.

  • Match control complexity to the game's needs. Not all mechanisms suit all games.

  • Test hardware setup thoroughly before implementing game logic on top of it.

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