@canvas-tile-engine/core
v0.11.0
Published
Lightweight library for building interactive 2D grid-based maps and visualizations with Canvas
Maintainers
Readme
@canvas-tile-engine/core
The renderer-agnostic engine behind Canvas Tile Engine. Use it when you want direct TypeScript control over a zoomable 2D grid surface without React or another UI wrapper.
@canvas-tile-engine/core owns the camera, coordinate math, event callbacks, layers, draw helpers, static caches, sprites, and viewport culling. You bring a renderer: Canvas2D, WebGL, React Native Skia, server-side Node.js, or your own implementation of the IRenderer contract.
Install
Canvas2D web app:
npm install @canvas-tile-engine/core @canvas-tile-engine/renderer-canvasOther renderer choices:
npm install @canvas-tile-engine/core @canvas-tile-engine/renderer-webgl
npm install @canvas-tile-engine/core @canvas-tile-engine/renderer-serverQuick Start
<div id="map">
<canvas></canvas>
</div>import { CanvasTileEngine, type CanvasTileEngineConfig } from "@canvas-tile-engine/core";
import { RendererCanvas } from "@canvas-tile-engine/renderer-canvas";
const wrapper = document.getElementById("map") as HTMLDivElement;
const config: CanvasTileEngineConfig = {
scale: 48,
size: { width: 800, height: 500 },
backgroundColor: "#0f172a",
eventHandlers: { drag: true, zoom: true, hover: true, click: true },
coordinates: { enabled: true, shownScaleRange: { min: 16, max: 96 } },
};
const engine = new CanvasTileEngine(wrapper, config, new RendererCanvas(), { x: 0, y: 0 });
engine.drawGridLines(1, 1, "#1e293b", 0);
engine.drawRect({ x: 0, y: 0, size: 1, radius: 4, style: { fillStyle: "#22c55e" } }, 1);
engine.drawText(
{
x: 0,
y: -1,
text: "Spawn",
size: 0.35,
style: { fillStyle: "#e2e8f0", fontFamily: "sans-serif", textAlign: "center" },
},
2,
);
engine.onClick = (coords) => {
console.log("Clicked tile:", coords.snapped);
};
engine.render();What Core Handles
- Camera state: pan, zoom, bounds, smooth movement, resize-aware center updates.
- Coordinate transforms: screen/pointer coordinates to raw and snapped world coordinates.
- Event callbacks: click, right-click, hover, mouse/touch down, mouse/touch up, leave, zoom, resize.
- Layered drawing: lower layers draw first, higher layers draw on top.
- Draw helpers: rect, circle, image, text, line, path, grid lines, static rect/circle/image, and custom draw functions.
- Performance basics: viewport culling, RBush spatial indexing for large item sets, and static draw caches where the renderer supports them.
- Sprite utilities:
SpriteSheetframe calculation andSpriteAnimatorframe scheduling.
Renderers
Core does not draw by itself. It delegates to an injected renderer:
import { CanvasTileEngine } from "@canvas-tile-engine/core";
import { RendererCanvas } from "@canvas-tile-engine/renderer-canvas";
import { RendererWebGL } from "@canvas-tile-engine/renderer-webgl";
new CanvasTileEngine(wrapper, config, new RendererCanvas());
new CanvasTileEngine(wrapper, config, new RendererWebGL());
new CanvasTileEngine(wrapper, config, new MyCustomRenderer());Official renderers:
| Package | Surface |
| ----------------------------------------------------------- | ------------------------------ |
| @canvas-tile-engine/renderer-canvas | HTML Canvas2D |
| @canvas-tile-engine/renderer-webgl | WebGL with a 2D overlay |
| @canvas-tile-engine/renderer-skia | React Native Skia |
| @canvas-tile-engine/renderer-server | Headless Node.js image buffers |
Useful APIs
| API | Purpose |
| --------------------------------------------------- | --------------------------------------------------------------------- |
| engine.render() | Render the current scene. |
| engine.setCenter({ x, y }) | Move the camera center immediately. |
| engine.goCenter(x, y, durationMs) | Animate the camera center. |
| engine.setScale(scale) / zoomIn() / zoomOut() | Control zoom programmatically. |
| engine.getVisibleBounds() | Read the visible world bounds for culling, lazy loading, or UI state. |
| engine.setBounds(bounds) | Clamp camera movement. |
| engine.setEventHandlers(partial) | Enable or disable interactions at runtime. |
| engine.clearLayer(layer) / clearAll() | Replace dynamic content safely. |
| engine.images.load(src) | Load platform-specific image handles through the active renderer. |
Sprites
import { SpriteSheet, SpriteAnimator } from "@canvas-tile-engine/core";
const sheet = new SpriteSheet({ frameWidth: 32, frameHeight: 32, columns: 8 });
const player = { x: 4, y: 2, size: 1, img, sprite: sheet.frame(0, 0) };
engine.drawImage(player, 2);
const animator = new SpriteAnimator({ frames: sheet.framesInRow(0, 0, 5), fps: 8 });
animator.start((frame) => {
player.sprite = frame;
engine.render();
});Documentation
- Full docs: canvastileengine.dev
- Repository: github.com/enesyukselx/canvas-tile-engine
- Issues: GitHub Issues
License
MIT
