grid-canvas-system
v1.1.0
Published
Build small interactive Canvas scenes with grids, pixel art, sprites, animation, input, collisions and lightweight runtime helpers.
Downloads
242
Maintainers
Readme
Grid Canvas System
Grid Canvas System is a grid-first Canvas library for pixel art, motion, input, HUD overlays and arcade-ready interactive scenes.
Start with a visible grid and a crisp HiDPI canvas. Then add reusable drawing primitives, pixel sprites, sprite animation, state machines, pointer helpers, collisions and optional audio only when the scene needs more range.
It is built for small interactive products, education demos, toy engines, game prototypes, visual experiments and any Canvas workflow where you want fast feedback without adopting a heavyweight framework.
Why teams pick it
- Grid-first defaults with predictable sizing, visible coordinates and HiDPI rendering.
- Reusable pixel and arcade primitives like sprites, Pac-Man, ghosts, ships, asteroids, projectiles and HUD overlays.
- Lightweight runtime helpers for animation, state, pointer tracking, collisions and scene logic.
- Optional audio lanes: browser-native retro cues, Howler asset playback and Tone-powered music.
- Vanilla examples, CDN support and published TypeScript types.
Quick links
Current release
The package is currently at 1.1.0.
1.1.0 adds a reactive, framework-friendly runtime for long-lived Canvas components:
- Accepts either a canvas id or an
HTMLCanvasElement. - Adds
createCanvasRuntime()with DPR-aware resize,renderOnce, pointer events and cleanup. - Extends animation loops, sprite animators and state machines with lifecycle and observable events.
- Publishes the tree-shakeable
grid-canvas-system/runtimesubpath. - Keeps audio available through subpaths and legacy runtime aliases compatible.
Installation
CDN
<script src="https://cdn.jsdelivr.net/npm/grid-canvas-system/dist/grid-canvas-system.umd.js"></script>npm
npm install grid-canvas-systempnpm
pnpm install grid-canvas-systemOptional audio addons
grid-canvas-system/audio-arcade ships with no extra dependencies and is the fastest way to add retro browser audio.
grid-canvas-system/audio opens richer audio workflows and expects the peer dependencies you plan to use:
pnpm add tone howlerQuick start
CDN
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Grid Canvas System</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/grid-canvas-system/dist/grid-canvas-system.umd.js"></script>
<script>
const newCanvas = new GridCanvasSystem("canvas");
newCanvas.drawCoordinate(25, 60);
</script>
</body>
</html>npm
import GridCanvasSystem from "grid-canvas-system";
const newCanvas = new GridCanvasSystem("canvas");Layers
The package stays intentionally small and splits cleanly into three layers:
- Core canvas layer: initialization, DOM validation, sizing, HiDPI setup,
canvas,ctx, andoptions. - Drawing layer: grid configuration plus reusable drawing methods like
drawPixelSprite(),drawPacman(),drawShip(),drawProjectile(), and HUD-style overlays. - Optional runtime layer: animation, sprite animation, state machines, input, grid coordinate conversion, simple physics, and scene helpers through
GridCanvasSystem.runtime.
Audio Addons
Audio stays outside the root export so the main Canvas layer remains small, while scenes that need sound can opt into the right lane.
The audio subpaths remain usable in 1.0.0, but they are classified as Experimental in the public API contract while browser autoplay, adapter coverage and richer examples keep maturing.
Arcade audio addon
grid-canvas-system/audio-arcade provides browser-only retro SFX and lightweight 8-bit loops for instant arcade feedback.
import { createArcadeAudio } from "grid-canvas-system/audio-arcade";
const arcadeAudio = createArcadeAudio({
masterVolume: 0.75,
});
await arcadeAudio.playShoot();
const loopId = await arcadeAudio.playLoop("patrol");
arcadeAudio.stopLoop(loopId);Adapter addon
grid-canvas-system/audio exposes async factories for howler asset playback and tone music when you want a bigger sound palette.
import { createHowlerAssetAudio, createToneMusicAudio } from "grid-canvas-system/audio";
const assetAudio = await createHowlerAssetAudio({
laser: {
src: ["/audio/laser.wav"],
volume: 0.45,
},
});
const musicAudio = await createToneMusicAudio({
bpm: 132,
instruments: {
lead: "synth",
bass: "membrane",
},
});
musicAudio.registerSequence("theme", {
loop: true,
steps: [
{ instrumentId: "lead", note: "C4", time: 0, duration: "8n" },
{ instrumentId: "bass", note: "C2", time: "0:1:0", duration: "4n" },
],
});Browser note
Start audio from a user gesture such as a click or keypress because browsers usually block autoplay until the page has been interacted with.
Configuration example
import GridCanvasSystem from "grid-canvas-system";
const newCanvas = new GridCanvasSystem("canvas", {
width: 800,
height: 500,
backgroundColor: "#101820",
gridColor: "#5eead4",
gridLabelColor: "#5eead4",
coordinateLabelColor: "#ccfbf1",
gridLabelFont: "11px monospace",
coordinateFont: "13px serif",
gridLabelTextAlign: "start",
coordinateTextAlign: "end",
gridLabelTextBaseline: "alphabetic",
coordinateTextBaseline: "top",
cellSize: 20,
majorStep: 100,
minorLineWidth: 0.5,
majorLineWidth: 1.25,
devicePixelRatio: window.devicePixelRatio,
});Encapsulated drawing example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 800,
height: 500,
});
grid.drawPolyline(
[
{ x: 100, y: 200 },
{ x: 120, y: 300 },
{ x: 250, y: 150 },
],
{
color: "#ffffff",
lineWidth: 2,
},
);
grid.drawCoordinate(100, 200);
grid.drawCoordinate(120, 300);
grid.drawCoordinate(250, 150);Pixel art example
drawPixelSprite() draws declarative pixel art at absolute canvas coordinates. It is strict by design: rows must have the same length, pixelSize must be positive, and every sprite character must exist in the palette.
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 200,
height: 160,
});
grid.drawPixelSprite(
["00111100", "01122110", "11222211", "12233221", "11222211", "01111110", "00100100"],
{
x: 60,
y: 45,
pixelSize: 10,
palette: {
0: "transparent",
1: "#38bdf8",
2: "#f8fafc",
3: "#0f172a",
},
},
);Compiled pixel sprite example
Use compiled sprites when the same matrix is drawn repeatedly inside an animation loop. The compile step validates palette coverage once, then drawCompiledPixelSprite() reuses the cached pixels.
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas");
const pointer = GridCanvasSystem.runtime.createPointerTracker(grid.canvas);
const sprite = ["010", "111", "010"];
const palette = GridCanvasSystem.createPixelPalette({
0: "transparent",
1: "#facc15",
});
const compiled = GridCanvasSystem.compilePixelSprite(sprite, palette);
const tinted = GridCanvasSystem.tintPixelSprite(compiled, "#38bdf8");
grid.drawCompiledPixelSprite(tinted, {
x: 80,
y: 60,
pixelSize: 12,
opacity: 0.9,
});
const bounds = GridCanvasSystem.getPixelSpriteBounds(tinted, {
x: 80,
y: 60,
pixelSize: 12,
});
const point = pointer.position();
const hit =
point !== null &&
GridCanvasSystem.hitTestPixelSprite(point, tinted, {
x: 80,
y: 60,
pixelSize: 12,
});Pac-Man example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 220,
height: 220,
});
grid.drawPacman(110, 110, 70, 1, {
fillColor: "#FFFF00",
strokeColor: "#000000",
lineWidth: 2,
});Spaceship example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 240,
height: 240,
});
grid.drawShip({ x: 120, y: 120 }, 70, {
rotation: -Math.PI / 2,
curve1: 0.45,
curve2: 0.8,
guide: true,
});Asteroid example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 260,
height: 260,
});
const shape = grid.createAsteroidShape(14);
grid.drawAsteroid({ x: 130, y: 130 }, 75, shape, {
noise: 0.4,
rotation: Math.PI / 10,
guide: true,
});Ghost example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 240,
height: 240,
});
grid.drawGhost({ x: 120, y: 130 }, 70, {
feet: 5,
fillColor: "#ff0000",
strokeColor: "#ffffff",
});HUD example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 320,
height: 180,
});
grid.drawShip({ x: 160, y: 112 }, 38, {
rotation: -Math.PI / 2,
curve1: 0.45,
curve2: 0.8,
thruster: true,
});
grid.drawBarIndicator("health", 8, 8, 110, 12, 78, 100);
grid.drawValueLabel("score", 2450, 312, 18, {
textAlign: "end",
});
grid.drawMessage("GAME OVER", "Press space to play again", { x: 160, y: 62 });Runtime loop example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 420,
height: 260,
});
const body = new GridCanvasSystem.runtime.MassBody({
x: 210,
y: 130,
mass: 10,
radius: 20,
});
const keys = GridCanvasSystem.runtime.createKeyTracker(grid.canvas, {
autoFocus: true,
preventDefaultKeys: ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"],
});
let time = 0;
GridCanvasSystem.runtime.createAnimationLoop({
autoStart: true,
update(elapsed) {
time += elapsed;
if (keys.isPressed("ArrowLeft")) body.angle -= Math.PI * 1.5 * elapsed;
if (keys.isPressed("ArrowRight")) body.angle += Math.PI * 1.5 * elapsed;
if (keys.isPressed("ArrowUp")) body.push(body.angle, 1200, elapsed);
body.update(elapsed, {
width: grid.options.width,
height: grid.options.height,
});
},
draw() {
grid.clearCanvas();
grid.drawPacman(
body.x,
body.y,
body.radius,
GridCanvasSystem.runtime.oscillate01(time, 2),
{
direction: body.angle,
},
);
},
});Use createAnimationLoop() for visual motion that can scale with elapsed time. Use createFixedStepLoop() when collisions, tile movement or deterministic gameplay should advance in equal simulation steps.
const fixedLoop = GridCanvasSystem.runtime.createFixedStepLoop({
autoStart: true,
step: 1 / 60,
maxUpdatesPerFrame: 5,
update(step) {
player.update(step);
},
draw(alpha) {
grid.clearCanvas();
player.draw(alpha);
},
});
fixedLoop.stop();
fixedLoop.start();Canvas runtime example
import { createCanvasRuntime, createSpriteAnimator } from "grid-canvas-system/runtime";
const canvas = document.querySelector("canvas");
const animator = createSpriteAnimator({
initial: "idle",
animations: {
idle: { frames: ["idle-1", "idle-2"], fps: 6, loop: true },
flash: { frames: ["flash-1", "flash-2"], fps: 12, loop: false },
},
});
const runtime = createCanvasRuntime({
canvas,
logicalWidth: 160,
logicalHeight: 160,
pixelRatio: "auto",
imageSmoothing: false,
pauseWhenHidden: true,
update(deltaMs) {
animator.update(deltaMs / 1000);
},
render(context) {
context.clearRect(0, 0, 160, 160);
drawFrame(context, animator.getFrame());
},
});
runtime.onPointerDown(() => {
animator.play("flash", {
restart: true,
onComplete: () => animator.play("idle"),
});
});
runtime.renderOnce();
runtime.start();Sprite animation and state example
import GridCanvasSystem from "grid-canvas-system";
const animator = GridCanvasSystem.runtime.createSpriteAnimator({
animations: {
idle: ["idle-1", "idle-2"],
happy: ["happy-1", "happy-2"],
},
initial: "idle",
fps: 6,
});
const machine = GridCanvasSystem.runtime.createStateMachine({
initial: "idle",
transitions: {
idle: ["happy"],
happy: ["idle"],
},
});
machine.transition("happy");
animator.play(machine.getState());
animator.update(1 / 60);
const frame = animator.getFrame();Scene manager example
const scenes = GridCanvasSystem.runtime.createSceneManager({
initial: "menu",
scenes: {
menu: {
draw: () => grid.drawMessage("READY", "Press enter", { x: 160, y: 90 }),
},
game: {
enter: () => resetGame(),
update: (elapsed) => updateGame(elapsed),
draw: () => drawGame(),
exit: () => saveScore(),
},
pause: {
draw: () => grid.drawMessage("PAUSED", "Press enter", { x: 160, y: 90 }),
},
},
});
scenes.transition("game");
scenes.update(1 / 60);
scenes.draw();Tilemap example
const wall = GridCanvasSystem.compilePixelSprite(["11", "11"], {
1: "#22c55e",
});
const map = ["11111", "10001", "10201", "11111"];
GridCanvasSystem.runtime.drawTileMap(
map,
{
1: wall,
2: "#facc15",
},
{
grid,
origin: { x: 40, y: 40 },
tileSize: 24,
},
);
const playerHitsWall = GridCanvasSystem.runtime.hitTestTileMap(
{ x: player.x, y: player.y, width: 14, height: 14 },
map,
["1"],
{ origin: { x: 40, y: 40 }, tileSize: 24 },
);Grid coordinate helpers example
The drawing API uses absolute canvas coordinates. The runtime helpers make grid-cell conversion explicit when you want tile-like logic.
import GridCanvasSystem from "grid-canvas-system";
const options = {
cellSize: 20,
origin: { x: 0, y: 0 },
};
const cell = GridCanvasSystem.runtime.canvasToGrid({ x: 42, y: 58 }, options);
// { column: 2, row: 2 }
const topLeft = GridCanvasSystem.runtime.gridToCanvas({ column: 2, row: 2 }, options);
// { x: 40, y: 40 }
const snapped = GridCanvasSystem.runtime.snapPointToGrid({ x: 42, y: 58 }, options);
// { x: 40, y: 40 }Pointer tracker example
import GridCanvasSystem from "grid-canvas-system";
const grid = new GridCanvasSystem("canvas", {
width: 320,
height: 220,
});
const pointer = GridCanvasSystem.runtime.createPointerTracker(grid.canvas, {
preventDefault: true,
});
GridCanvasSystem.runtime.createAnimationLoop({
autoStart: true,
draw() {
grid.clearCanvas();
const position = pointer.position();
if (position !== null) {
grid.drawCoordinate(position.x, position.y);
}
},
});Collision helpers example
import GridCanvasSystem from "grid-canvas-system";
const pointHitsGhost = GridCanvasSystem.runtime.hitTestPoint(
{ x: 120, y: 130 },
{ x: 120, y: 130, radius: 24 },
);
const rectanglesOverlap = GridCanvasSystem.runtime.hitTestRectangle(
{ x: 20, y: 20, width: 40, height: 30 },
{ x: 50, y: 30, width: 60, height: 20 },
);
const shipTouchesWall = GridCanvasSystem.runtime.hitTestCircleRectangle(
{ x: 110, y: 110, radius: 18 },
{ x: 140, y: 80, width: 30, height: 80 },
);Scene helpers example
import GridCanvasSystem from "grid-canvas-system";
let trail = [];
trail = GridCanvasSystem.runtime.appendTrailPoint(trail, { x: 140, y: 90 }, 12);
const particles = GridCanvasSystem.runtime.createParticleBurst({ x: 140, y: 90 }, 6, {
angle: -Math.PI / 2,
spread: Math.PI / 3,
speed: 90,
life: 0.8,
size: 3,
});
const nextParticles = GridCanvasSystem.runtime.stepParticles(particles, 1 / 60, {
gravityY: 40,
drag: 0.15,
});
const hudSlots = GridCanvasSystem.runtime.layoutStack(
{ x: 312, y: 12 },
[
{ width: 92, height: 16 },
{ width: 70, height: 16 },
],
{
align: "end",
gap: 8,
},
);Documentation
- Documentation index
- Examples guide
- Technical study
- Findings and improvements
- Innovation and scaling research
- Changelog
Parameters
The library accepts the following parameters:
id: The ID of the canvas where the grid will be drawn. (Required)width: The width of the canvas. (Optional, defaults to400)height: The height of the canvas. (Optional, defaults to400)options: Optional configuration object for styles, spacing, and HiDPI behavior.
Available options:
width: Logical canvas width in CSS pixels. Defaults to400.height: Logical canvas height in CSS pixels. Defaults to400.backgroundColor: Canvas background color. Defaults to#000000.gridColor: Grid line color. Defaults to#00FF00.gridLabelColor: Grid label text color. Defaults to#009900.coordinateLabelColor: Coordinate label text color. Defaults to#009900.labelColor: Legacy alias that applies the same color to both kinds of labels.gridLabelFont: Grid label font. Defaults to10px sans-serif.coordinateFont: Coordinate label font. Defaults to10px sans-serif.font: Legacy alias that applies the same font to both kinds of labels.gridLabelTextAlign: Grid label alignment. Defaults tostart.coordinateTextAlign: Default alignment fordrawCoordinate(),drawText(), and text-based overlay helpers. Defaults tostart.gridLabelTextBaseline: Grid label baseline. Defaults toalphabetic.coordinateTextBaseline: Default baseline fordrawCoordinate(),drawText(), and text-based overlay helpers. Defaults toalphabetic.cellSize: Space between grid lines. Defaults to10.majorStep: Distance between emphasized lines and numeric labels. Defaults to50.minorLineWidth: Width of regular grid lines. Defaults to0.25.majorLineWidth: Width of emphasized grid lines. Defaults to0.5.devicePixelRatio: Pixel ratio used for HiDPI rendering. Defaults towindow.devicePixelRatiowhen available.
The constructor throws an error when:
- the element does not exist;
- the element exists but is not a
canvas; - the 2D context cannot be created;
widthorheightare invalid values;- numeric options such as
cellSizeormajorStepare invalid; majorStepis not a multiple ofcellSize.
Methods
The library has the following methods:
drawText(text, x, y, options?): Draws text using the managed canvas state.drawGhost(center, radius, options?): Draws a configurable ghost silhouette with optional feet and eyes.drawProjectile(center, radius, life, options?): Draws a projectile with life-based default coloring.polarToCartesian(center, radius, angle): Converts polar coordinates into a canvas point.createAsteroidShape(segments, random?): Creates persistent asteroid shape data that can be reused across renders.drawCircleSector(center, radius, startAngle, endAngle, options?): Draws a filled sector or wedge shape.drawPacman(x, y, radius, mouthOpen, options?): Draws a Pac-Man shape over the managed grid.drawAsteroid(center, radius, shape, options?): Draws a configurable asteroid from persisted shape data.drawShip(center, radius, options?): Draws a configurable spaceship with optional guide overlays, rotation, and thruster flame.drawValueLabel(label, value, x, y, options?): Draws a formatted numeric label for score, fps, level, or similar overlays.drawBarIndicator(label, x, y, width, height, value, max, options?): Draws a label plus a proportional status bar.drawMessage(mainText, subText, center, options?): Draws a two-line centered message overlay.drawPixelSprite(sprite, options): Draws matrix/string-based pixel art with a strict palette and absolute canvas coordinates.drawCompiledPixelSprite(compiled, options): Draws a precompiled pixel sprite withx,y,pixelSize, and optionalopacity.drawLine(start, end, options?): Draws a line without manipulatingctxdirectly.drawPolyline(points, options?): Draws a polyline or closed path through a high-level API.drawCoordinate(x, y, options?): Draws the coordinate label at the provided position.clearCanvas(options?): Clears the canvas and can optionally skip redrawing the grid for animation-oriented flows.
Runtime And Utilities
Static utilities exposed on the optional runtime layer GridCanvasSystem.runtime:
createAnimationLoop(options): LightweightrequestAnimationFrameloop with elapsed seconds.createFixedStepLoop(options): Deterministic loop that advances update logic in fixed simulation steps.createSceneManager(options): Small scene flow helper withenter,update,draw,exit, andtransition.createSpriteAnimator(options): Pure sprite animation helper that advances frame IDs by elapsed seconds.createStateMachine(options): Small finite state machine helper with boolean transition results.MassBody: Reusable physics/movement body withupdate,push,twist,speed, andmovementAngle.createKeyTracker(target, options?): Tracks pressed keys on a specific target.createPointerTracker(target, options?): Tracks pointer position and down state relative to a target.canvasToGrid(point, options): Converts absolute canvas coordinates into{ column, row }.gridToCanvas(cell, options): Converts a grid cell into its top-left absolute canvas point.snapPointToGrid(point, options): Snaps a canvas point to the top-left of its containing grid cell.drawTileMap(map, tileset, options): Draws simple character tilemaps with color, raw sprite or compiled sprite tiles.getTileAt(point, map, options): Reads the tile under an absolute canvas point.setTileAt(map, cell, value): Returns a new map with one tile changed.tileToBounds(cell, options): Converts a tile cell into an absolute canvas rectangle.hitTestTileMap(rect, map, solidTiles, options): Checks a rectangle against solid tile IDs.appendTrailPoint(trail, point, maxPoints): Keeps a bounded point trail without mutating the original array.createParticleBurst(origin, count, options?): Creates a simple particle burst with angle, spread, speed, size, and lifetime controls.hitTestPoint(point, target): Checks a point against either a circle or an axis-aligned rectangle.hitTestRectangle(a, b): Checks overlap between two axis-aligned rectangles.hitTestCircleRectangle(circle, rectangle): Checks a circle against an axis-aligned rectangle.layoutStack(origin, itemSizes, options?): Computes reusable positions for vertical or horizontal overlay stacks.normalizeKeyIdentifier(key): Normalizes modern keys and legacy key codes.stepParticles(particles, elapsed, options?): Advances simple particles with optional gravity and drag.vectorFromAngle(angle, magnitude?): Converts an angle and magnitude to{ x, y }.angleToPoint(from, to): Calculates the angle from one point to another.oscillate01(time, frequency?): Produces a 0..1 oscillation useful for repeated animation cycles.distanceBetweenPoints(a, b): Calculates Euclidean distance.circlesIntersect(a, b): Detects circular collision overlap.wrapPoint(point, bounds, radius?): Applies wrap-around positioning inside rectangular bounds.
For backward compatibility, runtime helpers shipped before 1.0.0 also remain mirrored as direct static properties on GridCanvasSystem. New runtime helpers stay only under GridCanvasSystem.runtime.
Advanced Usage
The preferred path for common drawing is the encapsulated API: drawText, drawPixelSprite, drawGhost, drawProjectile, polarToCartesian, createAsteroidShape, drawCircleSector, drawPacman, drawAsteroid, drawShip, drawValueLabel, drawBarIndicator, drawMessage, drawLine, drawPolyline, drawCoordinate, and clearCanvas().
canvas and ctx remain intentionally exposed as advanced extension points.
canvaslets you integrate the instance with DOM or sizing logic outside the library.ctxlets you draw your own shapes on top of the grid.- Both references are treated as part of the supported public API.
- If you mutate the rendering context state directly, the visual result becomes your responsibility.
Why not Phaser, PixiJS or Konva?
Those projects are excellent when you need a full game framework, a high-performance renderer, or a large interactive object model. grid-canvas-system is intentionally smaller: it gives you a visible grid, fast drawing primitives, lightweight runtime helpers and readable examples that get small scenes moving quickly. The goal is not to replace larger engines, but to make grid-aware Canvas work feel direct and shippable.
TypeScript
The package exports:
GridCanvasAsteroidOptionsGridCanvasAsteroidShapeGridCanvasBarIndicatorOptionsGridCanvasClearOptionsGridCanvasCircleSectorOptionsGridCanvasGhostOptionsGridCanvasAnimationLoopGridCanvasAnimationLoopOptionsGridCanvasBoundsGridCanvasCircleLikeGridCanvasCollisionTargetGridCanvasCompiledPixelGridCanvasCompiledPixelSpriteGridCanvasCompiledPixelSpriteDrawOptionsGridCanvasFixedStepLoopGridCanvasFixedStepLoopOptionsGridCanvasGridCellGridCanvasGridOptionsGridCanvasParticleGridCanvasParticleBurstOptionsGridCanvasParticleStepOptionsGridCanvasKeyTrackerGridCanvasKeyTrackerOptionsGridCanvasPointerTrackerGridCanvasPointerTrackerOptionsGridCanvasMassBodyOptionsGridCanvasMessageOptionsGridCanvasPacmanOptionsGridCanvasPixelPaletteGridCanvasPixelSpriteGridCanvasPixelSpriteDrawOptionsGridCanvasPixelSpriteGeometryOptionsGridCanvasProjectileOptionsGridCanvasRectangleLikeGridCanvasSceneGridCanvasSceneManagerGridCanvasSceneManagerOptionsGridCanvasShipOptionsGridCanvasSizeGridCanvasStackAlignGridCanvasStackDirectionGridCanvasStackLayoutOptionsGridCanvasSpriteAnimatorGridCanvasSpriteAnimatorOptionsGridCanvasStateMachineGridCanvasStateMachineOptionsGridCanvasSystemGridCanvasPointGridCanvasShapeOptionsGridCanvasStrokeOptionsGridCanvasPolylineOptionsGridCanvasSystemOptionsGridCanvasSystemResolvedOptionsGridCanvasTextOptionsGridCanvasTileDefinitionGridCanvasTileMapGridCanvasTileMapDrawOptionsGridCanvasTileMapDrawRendererGridCanvasTileMapOptionsGridCanvasTileObjectDefinitionGridCanvasTileSetGridCanvasVelocityGridCanvasValueLabelOptions
The audio subpaths export their own focused types such as ArcadeSequence,
HowlerAssetMap, ToneInstrumentKind, and ToneSequence.
Testing
These commands reflect the current workspace setup ([email protected] in package.json).
Format the complete workspace before running the test suite:
pnpm run format
pnpm run format:checkpnpm testpnpm run test:visualpnpm run test:visual:updateWhen a visual snapshot fails, the test runner now writes expected, actual, and diff PNG artifacts into tests/__artifacts__/ to make regressions easier to inspect.
pnpm install --frozen-lockfile
pnpm testContributing
See CONTRIBUTING.md for the development workflow, formatting contract, and pull-request checklist.
Examples
The vanilla examples are the fastest way to evaluate the library as a product: plain HTML, readable source and focused scenarios.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Grid Canvas System</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/grid-canvas-system/dist/grid-canvas-system.umd.js"></script>
<script>
const grid = new GridCanvasSystem("canvas");
grid.drawPolyline(
[
{ x: 100, y: 200 },
{ x: 120, y: 300 },
{ x: 250, y: 150 },
],
{
color: "#FFFFFF",
lineWidth: 2,
},
);
grid.drawCoordinate(100, 200);
grid.drawCoordinate(120, 300);
grid.drawCoordinate(250, 150);
</script>
</body>
</html>See also:
- Example setup and authoring guide
- Asteroid example
- Audio arcade example
- Audio adapters example
- Collision course example
- Ghost example
- Grid Buddy example
- Interactive character runtime example
- HUD example
- Pac-Man example
- Projectile example
- Runtime example
- Sprite animator and state machine example
- Spaceship example
Output
Preview

What to build
- Build reusable shapes like Pac-Man on top of
drawCircleSector(). - Add arcade overlays with
drawBarIndicator(),drawValueLabel(), anddrawMessage(). - Draw declarative pixel characters with
drawPixelSprite(). - Combine
createSpriteAnimator()andcreateStateMachine()for small reactive actors. - Use Grid Buddy as a showcase for a Tamagotchi-like companion built on generic APIs, not as core pet logic.
- Convert between canvas points and grid cells with
canvasToGrid(),gridToCanvas(), andsnapPointToGrid(). - Use
createPointerTracker()for click, drag, hover, or tap-driven scenes without wiring raw DOM listeners each time. - Generate persistent asteroid
shapedata once and redraw it with differentnoisevalues. - Drive small scenes with
MassBodypluscreateAnimationLoop()instead of hand-rolled timers. - Reuse
polarToCartesian()anddrawShip()to prototype Asteroids-style actors. - Use
drawProjectile()together withMassBodyor your own motion state for lightweight shooter prototypes. - Use
createKeyTracker()to scope keyboard input to the canvas instead of the whole page. - Combine
drawPacman()with loops or randomization to generate simple scenes. - Use
clearCanvas({ redrawGrid: false })as a simpler base for custom animation loops. - Use the encapsulated API for most drawing, and drop to
ctxonly for advanced custom work.
License
This project is licensed under the MIT License
