npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

grid-canvas-system

v0.1.3

Published

A library for creating canvas-based grids

Downloads

72

Readme

Grid System for Canvas

This library allows you to create managed grids on an HTML5 canvas and then draw on top of them through a small high-level API.

In addition to the grid itself, the library now includes reusable drawing helpers, coordinate labels, line primitives, circular sectors, Pac-Man, ghosts, projectiles, configurable spaceship shapes, persistent asteroid shapes, HUD-style overlays, collision/motion utilities, keyboard tracking, lightweight scene helpers, and an optional animation runtime.

In my professional use, I have found this tool very useful for education and game development. Students or animators can position elements precisely and visualize their coordinates.

Installation

To install the library, you can follow these steps:

Installation via CDN

<script src="https://cdn.jsdelivr.net/npm/grid-canvas-system/dist/grid-canvas-system.umd.js"></script>

Installation with NPM

npm install grid-canvas-system

Installation with pnpm

pnpm install grid-canvas-system

Usage

To use the library, you can follow these steps:

Usage with 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>

Usage with NPM

import GridCanvasSystem from "grid-canvas-system";

const newCanvas = new GridCanvasSystem("canvas");

Layers

The library is now organized around three simple layers:

  1. Core canvas layer: initialization, DOM validation, sizing, HiDPI setup, canvas, ctx, and options.
  2. Drawing layer: grid configuration plus reusable drawing methods like drawPacman(), drawShip(), drawProjectile(), and HUD-style overlays.
  3. Optional runtime layer: animation, input, simple physics, and scene helpers through GridCanvasSystem.runtime.

Usage with options

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,
});

Preferred encapsulated usage

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);

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 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,
      },
    );
  },
});

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

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 to 400)
  • height: The height of the canvas. (Optional, defaults to 400)
  • options: Optional configuration object for styles, spacing, and HiDPI behavior.

Available options:

  • width: Logical canvas width in CSS pixels. Defaults to 400.
  • height: Logical canvas height in CSS pixels. Defaults to 400.
  • 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 to 10px sans-serif.
  • coordinateFont: Coordinate label font. Defaults to 10px sans-serif.
  • font: Legacy alias that applies the same font to both kinds of labels.
  • gridLabelTextAlign: Grid label alignment. Defaults to start.
  • coordinateTextAlign: Default alignment for drawCoordinate(), drawText(), and text-based overlay helpers. Defaults to start.
  • gridLabelTextBaseline: Grid label baseline. Defaults to alphabetic.
  • coordinateTextBaseline: Default baseline for drawCoordinate(), drawText(), and text-based overlay helpers. Defaults to alphabetic.
  • cellSize: Space between grid lines. Defaults to 10.
  • majorStep: Distance between emphasized lines and numeric labels. Defaults to 50.
  • minorLineWidth: Width of regular grid lines. Defaults to 0.25.
  • majorLineWidth: Width of emphasized grid lines. Defaults to 0.5.
  • devicePixelRatio: Pixel ratio used for HiDPI rendering. Defaults to window.devicePixelRatio when 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;
  • width or height are invalid values;
  • numeric options such as cellSize or majorStep are invalid;
  • majorStep is not a multiple of cellSize.

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.
  • drawLine(start, end, options?): Draws a line without manipulating ctx directly.
  • 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): Lightweight requestAnimationFrame loop with elapsed seconds.
  • MassBody: Reusable physics/movement body with update, push, twist, speed, and movementAngle.
  • createKeyTracker(target, options?): Tracks pressed keys on a specific target.
  • 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, those helpers also remain mirrored as direct static properties on GridCanvasSystem.

Advanced Usage

The preferred path for common drawing is the encapsulated API: drawText, 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.

  • canvas lets you integrate the instance with DOM or sizing logic outside the library.
  • ctx lets 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.

TypeScript

The package exports:

  • GridCanvasAsteroidOptions
  • GridCanvasAsteroidShape
  • GridCanvasBarIndicatorOptions
  • GridCanvasClearOptions
  • GridCanvasCircleSectorOptions
  • GridCanvasGhostOptions
  • GridCanvasAnimationLoop
  • GridCanvasAnimationLoopOptions
  • GridCanvasBounds
  • GridCanvasCircleLike
  • GridCanvasCollisionTarget
  • GridCanvasParticle
  • GridCanvasParticleBurstOptions
  • GridCanvasParticleStepOptions
  • GridCanvasKeyTracker
  • GridCanvasKeyTrackerOptions
  • GridCanvasMassBodyOptions
  • GridCanvasMessageOptions
  • GridCanvasPacmanOptions
  • GridCanvasProjectileOptions
  • GridCanvasRectangleLike
  • GridCanvasShipOptions
  • GridCanvasSize
  • GridCanvasStackAlign
  • GridCanvasStackDirection
  • GridCanvasStackLayoutOptions
  • GridCanvasSystem
  • GridCanvasPoint
  • GridCanvasShapeOptions
  • GridCanvasStrokeOptions
  • GridCanvasPolylineOptions
  • GridCanvasSystemOptions
  • GridCanvasSystemResolvedOptions
  • GridCanvasTextOptions
  • GridCanvasValueLabelOptions

Testing

npm test
npm run test:visual
npm run test:visual:update

When 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 test

Examples

<!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:

Output

Image preview image

Ideas

  • Build reusable shapes like Pac-Man on top of drawCircleSector().
  • Add arcade overlays with drawBarIndicator(), drawValueLabel(), and drawMessage().
  • Generate persistent asteroid shape data once and redraw it with different noise values.
  • Drive small scenes with MassBody plus createAnimationLoop() instead of hand-rolled timers.
  • Reuse polarToCartesian() and drawShip() to prototype Asteroids-style actors.
  • Use drawProjectile() together with MassBody or 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 ctx only for advanced custom work.

License

This project is licensed under the MIT License

Author