API Reference

Canvas Tile Engine API

Package-owned public classes, methods, types, hooks, and components across 7 packages — generated from their published TypeScript declarations.

@canvas-tile-engine/core

v0.11.0npm

The renderer-agnostic engine: camera, coordinate math, gestures, layers, and the draw API. Every other package builds on core.

Classes

AnimationController

class

Manages smooth animations for camera movements, zooming, and canvas resizing. Handles animation frame scheduling and cleanup.

class AnimationController {
    constructor(camera: ICamera, viewport: ViewportState, onAnimationFrame: () => void);
}

CanvasTileEngine

class

Core engine wiring camera, config, renderer, events, and draw helpers.

class CanvasTileEngine<TMount = HTMLDivElement, TImage = HTMLImageElement> {
    canvasWrapper: TMount;
    canvas: TMount extends HTMLElement ? HTMLCanvasElement : HTMLCanvasElement | undefined;
    get images(): IImageLoader<TImage>;
    constructor(canvasWrapper: TMount, config: CanvasTileEngineConfig, renderer: IRenderer<TMount, TImage>, center?: Coords);
}

Config

class

Normalizes and stores grid engine configuration with safe defaults.

class Config {
    constructor(config: CanvasTileEngineConfig);
}

CoordinateTransformer

class

Transforms coordinates between world space and screen space using the active camera.

class CoordinateTransformer {
    constructor(camera: ICamera);
}

GestureProcessor

class

Handles gesture logic (click, hover, drag, zoom) independent of DOM/platform. Receives normalized input from renderer and performs calculations.

class GestureProcessor {
    constructor(camera: ICamera, config: Config, transformer: CoordinateTransformer, canvasBoundsGetter: () => CanvasBounds, onCameraChange: () => void);
    handleClick: (pointer: NormalizedPointer) => void;
    handleRightClick: (pointer: NormalizedPointer) => void;
    handlePointerDown: (pointer: NormalizedPointer) => void;
    handlePointerMove: (pointer: NormalizedPointer) => void;
    handlePointerUp: (pointer: NormalizedPointer) => void;
    handlePointerLeave: (pointer: NormalizedPointer) => void;
    handleTouchStart: (pointers: NormalizedPointer[]) => void;
    handleTouchMove: (pointers: NormalizedPointer[]) => void;
    handleTouchEnd: (remainingPointers: NormalizedPointer[], changedPointer?: NormalizedPointer) => void;
    handleWheel: (pointer: NormalizedPointer, deltaY: number) => void;
    get dragging(): boolean;
    get pinching(): boolean;
}

SpatialIndex

class

No API description is included in the published TypeScript declaration for SpatialIndex.

class SpatialIndex<T extends SpatialItem> {
    constructor();
}

SpriteAnimator

class

Plays a SpriteAnimation by invoking a callback whenever the current frame changes. The callback typically mutates an ImageItem's `sprite` field and triggers a render, which makes animation work identically across all renderers without renderer-specific code. The internal rAF loop only fires the callback when the frame index actually advances, so renders happen at the animation's fps, not at 60fps.

class SpriteAnimator {
    constructor(animation: SpriteAnimation);
}
Example
const sheet = new SpriteSheet({ frameWidth: 32, frameHeight: 32 });
const item = { x: 5, y: 3, img, sprite: sheet.frame(0, 0) };
engine.drawImage(item);


const animator = new SpriteAnimator({ frames: sheet.framesInRow(0, 0, 4), fps: 8 });
animator.start((frame) => {
    item.sprite = frame;
    engine.render();
});

SpriteSheet

class

Grid-based spritesheet frame calculator. Maps (col, row) or linear frame indices to pixel source rectangles (SpriteRect) inside a sheet image. Pure calculation — holds no image reference, so it is platform-agnostic and works with every renderer.

class SpriteSheet {
    constructor(options: SpriteSheetOptions);
}
Example
const sheet = new SpriteSheet({ frameWidth: 32, frameHeight: 32, columns: 5 });
engine.drawImage({ x: 5, y: 3, img, sprite: sheet.frame(3, 0) });

ViewportState

class

Holds mutable viewport size for runtime changes (resize, layout). Also tracks device pixel ratio for HiDPI/Retina display support.

class ViewportState {
    constructor(width: number, height: number);
    get dpr(): number;
}

Class methods

AnimationController.animateMoveTo()

method

Smoothly animate camera movement to target coordinates.

animateMoveTo(targetX: number, targetY: number, durationMs?: number, onComplete?: () => void): void

Parameters

targetXnumberTarget world x coordinate.
targetYnumberTarget world y coordinate.
durationMs?numberAnimation duration in milliseconds (default: 500ms). Set to 0 for instant move.
onComplete?() => voidOptional callback fired when animation completes.

Returns void

AnimationController.animateZoomTo()

method

Smoothly animate the camera scale to a target value, anchored at the viewport center (matching zoomIn/zoomOut).

animateZoomTo(targetScale: number, durationMs?: number, onZoomFrame?: (prevScale: number) => void, onComplete?: () => void): void

Parameters

targetScalenumberTarget scale. Callers should pre-clamp it to the camera's limits so the animation ends exactly at the effective value.
durationMs?numberAnimation duration in milliseconds (default: 500ms). Set to 0 for instant change.
onZoomFrame?(prevScale: number) => voidOptional callback fired after each scale step with the scale before the step, for zoom-change notifications.
onComplete?() => voidOptional callback fired when animation completes.

Returns void

AnimationController.animateResize()

method

Smoothly animate canvas size change while keeping view centered.

animateResize(targetWidth: number, targetHeight: number, durationMs: number | undefined, onApplySize: (width: number, height: number, center: Coords) => void, onComplete?: () => void): void

Parameters

targetWidthnumberNew canvas width in pixels.
targetHeightnumberNew canvas height in pixels.
durationMsnumber | undefinedAnimation duration in milliseconds (default: 500ms). Set to 0 for instant resize.
onApplySize(width: number, height: number, center: Coords) => voidCallback to apply the new size (updates wrapper, canvas, renderer).
onComplete?() => voidOptional callback fired when animation completes.

Returns void

AnimationController.cancelMove()

method

Cancel the current move animation if running.

cancelMove(): void

Returns void

AnimationController.cancelZoom()

method

Cancel the current zoom animation if running.

cancelZoom(): void

Returns void

AnimationController.cancelResize()

method

Cancel the current resize animation if running.

cancelResize(): void

Returns void

AnimationController.cancelAll()

method

Cancel all running animations.

cancelAll(): void

Returns void

AnimationController.isAnimating()

method

Check if any animation is currently running.

isAnimating(): boolean

Returns boolean

CanvasTileEngine.destroy()

method

Tear down listeners and observers.

destroy(): void

Returns void

CanvasTileEngine.render()

method

Render a frame using the active renderer.

render(): void

Returns void

CanvasTileEngine.resize()

method

Manually update canvas size (e.g., user-driven select). Keeps view centered.

resize(width: number, height: number, durationMs?: number, onComplete?: () => void): void

Parameters

widthnumberNew canvas width in pixels.
heightnumberNew canvas height in pixels.
durationMs?numberAnimation duration in ms (default 500). Use 0 for instant resize.
onComplete?() => voidOptional callback fired when resize animation completes.

Returns void

CanvasTileEngine.getSize()

method

Current canvas size.

getSize(): {
    width: number;
    height: number;
}

Returns { width: number; height: number; } — Current `{ width, height }` in pixels.

CanvasTileEngine.getScale()

method

Current canvas scale.

getScale(): number

Returns number — Current canvas scale.

CanvasTileEngine.setScale()

method

Set the canvas scale directly, clamped to min/max bounds. The change is anchored at the viewport center, matching goScale/zoomIn/zoomOut.

setScale(newScale: number): void

Parameters

newScalenumberThe desired scale value.

Returns void

CanvasTileEngine.goScale()

method

Smoothly animate the canvas scale to a target value over the given duration. The zoom is anchored at the viewport center, matching zoomIn/zoomOut.

goScale(targetScale: number, durationMs?: number, onComplete?: () => void): void

Parameters

targetScalenumberThe desired scale value, clamped to min/max bounds.
durationMs?numberAnimation duration in milliseconds (default: 500ms). Set to 0 for instant change.
onComplete?() => voidOptional callback fired when animation completes.

Returns void

CanvasTileEngine.zoomIn()

method

Zoom in by a given factor, centered on the viewport.

zoomIn(factor?: number): void

Parameters

factor?numberZoom multiplier (default: 1.5). Higher values zoom in more.

Returns void

CanvasTileEngine.zoomOut()

method

Zoom out by a given factor, centered on the viewport.

zoomOut(factor?: number): void

Parameters

factor?numberZoom multiplier (default: 1.5). Higher values zoom out more.

Returns void

CanvasTileEngine.setScaleLimits()

method

Update the minimum and maximum scale limits at runtime. The current scale is clamped into the new range immediately.

setScaleLimits(minScale: number, maxScale: number): void

Parameters

minScalenumberNew minimum scale.
maxScalenumberNew maximum scale.

Returns void

Example
// Allow zooming between 0.25x and 8x
engine.setScaleLimits(0.25, 8);

CanvasTileEngine.getConfig()

method

Snapshot of current normalized config.

getConfig(): Required<CanvasTileEngineConfig>

Returns Required<CanvasTileEngineConfig>

CanvasTileEngine.getCenter()

method

Current center of the view in world coordinates.

getCenter(): Coords

Returns Coords — Center coordinates `{ x, y }`.

CanvasTileEngine.getVisibleBounds()

method

Get the visible world coordinate bounds of the viewport. Returns floored/ceiled values representing which cells are visible.

getVisibleBounds(): {
    minX: number;
    maxX: number;
    minY: number;
    maxY: number;
}

Returns { minX: number; maxX: number; minY: number; maxY: number; } — Visible bounds with min/max coordinates.

Example
const bounds = engine.getVisibleBounds();
// { minX: 0, maxX: 10, minY: 0, maxY: 10 }


// Use for random placement within visible area
const x = bounds.minX + Math.floor(Math.random() * (bounds.maxX - bounds.minX));

CanvasTileEngine.setCenter()

method

Move the view center to new world coordinates instantly.

setCenter(newCenter: Coords): void

Parameters

newCenterCoordsThe new center coordinates.

Returns void

CanvasTileEngine.goCenter()

method

Smoothly animate the view center to target world coordinates over the given duration.

goCenter(x: number, y: number, durationMs?: number, onComplete?: () => void): void

Parameters

xnumberTarget world x.
ynumberTarget world y.
durationMs?numberAnimation duration in milliseconds (default: 500ms). Set to 0 for instant move.
onComplete?() => voidOptional callback fired when animation completes.

Returns void

CanvasTileEngine.fitBounds()

method

Fit a world-space rectangle into the viewport: centers the view on the rectangle and picks the largest scale that keeps the whole (padded) area visible, clamped to the scale limits. Animated by default; not related to setBounds, which restricts camera movement.

fitBounds(bounds: Bounds, options?: FitBoundsOptions): void

Parameters

boundsBoundsRectangle to fit. Every edge must be finite.
options?FitBoundsOptions`padding` in world units (default 0) or `paddingPx` in screen pixels (wins over `padding`), `durationMs` (default 500, 0 = instant), and `onComplete`.

Returns void

Example
// Show the whole board with one cell of margin
engine.fitBounds({ minX: 0, maxX: 32, minY: 0, maxY: 32 }, { padding: 1 });


// 24px of air around any selection, small or huge
engine.fitBounds(selectionBounds, { paddingPx: 24 });


// Jump to a selection instantly
engine.fitBounds(selectionBounds, { durationMs: 0 });

CanvasTileEngine.setEventHandlers()

method

Update event handlers at runtime. This allows you to enable or disable specific interactions dynamically.

setEventHandlers(handlers: Partial<EventHandlers>): void

Parameters

handlersPartial<EventHandlers>Partial event handlers to update.

Returns void

Example
// Disable drag temporarily
engine.setEventHandlers({ drag: false });


// Enable painting mode
engine.setEventHandlers({ drag: false, hover: true });


// Re-enable drag
engine.setEventHandlers({ drag: true });

CanvasTileEngine.setBounds()

method

Set or update map boundaries to restrict camera movement.

setBounds(bounds: {
    minX: number;
    maxX: number;
    minY: number;
    maxY: number;
}): void

Parameters

bounds{ minX: number; maxX: number; minY: number; maxY: number; }Boundary limits. Use Infinity/-Infinity to remove limits.

Returns void

Example
// Restrict map to -100 to 100 on both axes
engine.setBounds({ minX: -100, maxX: 100, minY: -100, maxY: 100 });


// Remove boundaries
engine.setBounds({ minX: -Infinity, maxX: Infinity, minY: -Infinity, maxY: Infinity });


// Only limit X axis
engine.setBounds({ minX: 0, maxX: 500, minY: -Infinity, maxY: Infinity });

CanvasTileEngine.drawRect()

method

Draw one or many rectangles in world space. Supports rotation via the `rotate` property (degrees, positive = clockwise).

drawRect<TData = unknown>(items: Rect<TData> | Array<Rect<TData>>, layer?: number, options?: RectDrawOptions<TData>): DrawHandle

Parameters

itemsRect<TData> | Array<Rect<TData>>Rectangle definitions.
layer?numberLayer order (lower draws first).
options?RectDrawOptions<TData>Optional `id` (re-registering with the same id replaces the previous registration), `styleOf` (paint-time decoration: the returned fields overlay the item's `style` each frame without re-registering — mutate your state and call `render()`), `visibleOf` (per-item show/hide, same live-read model; a hidden item neither paints nor hit-tests), and `interactiveOf` (per-item hit-test opt-out).

Returns DrawHandle

CanvasTileEngine.drawStaticRect()

method

Draw rectangles with pre-rendering cache. Renders all items once to an offscreen canvas, then blits the visible portion each frame. Ideal for large static datasets like mini-maps where items don't change. Supports rotation via the `rotate` property (degrees, positive = clockwise).

drawStaticRect(items: Array<Rect>, cacheKey: string, layer?: number, options?: StaticDrawOptions): DrawHandle

Parameters

itemsArray<Rect>Array of rectangle definitions.
cacheKeystringUnique key for this cache (e.g., "minimap-items"). Also acts as the registration id: calling again with the same key replaces the previous registration and invalidates its cache.
layer?numberLayer order (lower draws first).
options?StaticDrawOptionsOptional `hitTest: false` to keep the registration out of hit testing (decorative content).

Returns DrawHandle

CanvasTileEngine.drawStaticCircle()

method

Draw circles with pre-rendering cache. Renders all items once to an offscreen canvas, then blits the visible portion each frame. Ideal for large static datasets like mini-maps where items don't change.

drawStaticCircle(items: Array<Circle>, cacheKey: string, layer?: number, options?: StaticDrawOptions): DrawHandle

Parameters

itemsArray<Circle>Array of circle definitions.
cacheKeystringUnique key for this cache (e.g., "minimap-circles"). Also acts as the registration id: calling again with the same key replaces the previous registration and invalidates its cache.
layer?numberLayer order (lower draws first).
options?StaticDrawOptionsOptional `hitTest: false` to keep the registration out of hit testing (decorative content).

Returns DrawHandle

CanvasTileEngine.drawStaticImage()

method

Draw images with pre-rendering cache. Renders all items once to an offscreen canvas, then blits the visible portion each frame. Ideal for large static datasets like terrain tiles or static decorations. Supports rotation via the `rotate` property (degrees, positive = clockwise).

drawStaticImage(items: Array<ImageItem<TImage>>, cacheKey: string, layer?: number, options?: StaticDrawOptions): DrawHandle

Parameters

itemsArray<ImageItem<TImage>>Array of image definitions with HTMLImageElement.
cacheKeystringUnique key for this cache (e.g., "terrain-cache"). Also acts as the registration id: calling again with the same key replaces the previous registration and invalidates its cache.
layer?numberLayer order (lower draws first).
options?StaticDrawOptionsOptional `hitTest: false` to keep the registration out of hit testing (decorative content).

Returns DrawHandle

CanvasTileEngine.clearStaticCache()

method

Clear a static rendering cache.

clearStaticCache(cacheKey?: string): void

Parameters

cacheKey?stringThe cache key to clear, or undefined to clear all caches.

Returns void

CanvasTileEngine.drawLine()

method

Draw one or many lines between world points. Lines participate in hit testing: a point within half the stroke width of a segment (with a minimum tap width for hairlines) hits it.

drawLine<TData = unknown>(items: Array<Line<TData>> | Line<TData>, style?: LineStyle, layer?: number, options?: LineDrawOptions<TData>): DrawHandle

Parameters

itemsArray<Line<TData>> | Line<TData>Line segments.
style?LineStyleLine style overrides.
layer?numberLayer order.
options?LineDrawOptions<TData>Optional `id` (re-registering with the same id replaces the previous registration), `styleOf` (paint-time decoration overlaid on the call-level `style` per item — also the way to give individual lines their own color), `visibleOf` (per-item show/hide; a hidden line neither paints nor hit-tests), and `interactiveOf` (per-item hit-test opt-out). Decorations cannot change `lineWidth`: the hit-test area derives from the registration-time stroke width.

Returns DrawHandle

CanvasTileEngine.drawCircle()

method

Draw one or many circles sized in world units.

drawCircle<TData = unknown>(items: Circle<TData> | Array<Circle<TData>>, layer?: number, options?: CircleDrawOptions<TData>): DrawHandle

Parameters

itemsCircle<TData> | Array<Circle<TData>>Circle definitions.
layer?numberLayer order.
options?CircleDrawOptions<TData>Optional `id` (re-registering with the same id replaces the previous registration), `styleOf` (paint-time decoration: the returned fields overlay the item's `style` each frame without re-registering — mutate your state and call `render()`), `visibleOf` (per-item show/hide, same live-read model; a hidden item neither paints nor hit-tests), and `interactiveOf` (per-item hit-test opt-out).

Returns DrawHandle

CanvasTileEngine.drawText()

method

Draw one or many texts at world positions.

drawText<TData = unknown>(items: Array<Text<TData>> | Text<TData>, layer?: number, options?: TextDrawOptions<TData>): DrawHandle

Parameters

itemsArray<Text<TData>> | Text<TData>Text definitions with position, text, size, and style.
layer?numberLayer order.
options?TextDrawOptions<TData>Optional `id`: re-registering with the same id replaces the previous registration instead of accumulating alongside it.

Returns DrawHandle

Example
engine.drawText({
    x: 0,
    y: 0,
    text: "Hello",
    size: 1, // 1 tile height, scales with zoom
    style: { fillStyle: "black", fontFamily: "Arial" }
});


// Fixed-size label: always 14px on screen, regardless of zoom
engine.drawText({ x: 0, y: 0, text: "Ankara", fontPx: 14 });


// Multiple texts
engine.drawText([
    { x: 0, y: 0, text: "A", size: 2 },
    { x: 1, y: 0, text: "B", size: 2 }
]);

CanvasTileEngine.drawPath()

method

Draw one or many free-form paths through world points. Each `PathItem` owns its geometry and style: `points` traces the outline, `closed` joins it back to the start, `style.fillStyle` fills the interior (under `fillRule`), and stroke/dash/corner options follow the shared world-vs-`*Px` unit convention. Paths participate in hit testing: filled paths hit on their interior, unfilled paths on the stroke itself.

drawPath<TData = unknown>(items: PathItem<TData> | Array<PathItem<TData>>, layer?: number, options?: PathDrawOptions<TData>): DrawHandle

Parameters

itemsPathItem<TData> | Array<PathItem<TData>>Path item(s).
layer?numberLayer order.
options?PathDrawOptions<TData>Optional `id`: re-registering with the same id replaces the previous registration instead of accumulating alongside it.

Returns DrawHandle

Example
// Filled shape with a rounded outline
engine.drawPath({
    points: [{ x: 0, y: 0 }, { x: 4, y: 0 }, { x: 4, y: 3 }, { x: 0, y: 3 }],
    closed: true,
    style: { fillStyle: "#22c55e", strokeStyle: "#166534", lineWidthPx: 2, cornerRadius: 0.5 },
    data: { id: "zone-a" },
});


// Open route line
engine.drawPath({ points: route, style: { strokeStyle: "#3b82f6", lineWidthPx: 4 } });

CanvasTileEngine.drawImage()

method

Draw one or many images scaled in world units. Supports rotation via the `rotate` property (degrees, positive = clockwise).

drawImage<TData = unknown>(items: Array<ImageItem<TImage, TData>> | ImageItem<TImage, TData>, layer?: number, options?: ImageDrawOptions<TImage, TData>): DrawHandle

Parameters

itemsArray<ImageItem<TImage, TData>> | ImageItem<TImage, TData>Image definitions.
layer?numberLayer order.
options?ImageDrawOptions<TImage, TData>Optional `id` (re-registering with the same id replaces the previous registration), `visibleOf` (per-item show/hide, read live each frame; a hidden item neither paints nor hit-tests), and `interactiveOf` (per-item hit-test opt-out). Images carry no `style`, so there is no `styleOf` — appearance changes go through item fields like `opacity` (mutate + `render()`).

Returns DrawHandle

CanvasTileEngine.drawGridLines()

method

Draw grid lines at specified cell size.

drawGridLines(cellSize: number, lineWidth?: number, strokeStyle?: string, layer?: number, options?: DrawOptions): DrawHandle

Parameters

cellSizenumberSize of each grid cell in world units.
lineWidth?number
strokeStyle?string
layer?number
options?DrawOptionsOptional `id`: re-registering with the same id replaces the previous registration instead of accumulating alongside it.

Returns DrawHandle

Example
engine.drawGridLines(50);

CanvasTileEngine.addDrawFunction()

method

Register a custom draw function for complete rendering control. Useful for complex or one-off drawing operations.

addDrawFunction(fn: (ctx: unknown, coords: Coords, config: Required<CanvasTileEngineConfig>, transform: DrawTransform) => void, layer?: number, options?: DrawOptions): DrawHandle

Parameters

fn(ctx: unknown, coords: Coords, config: Required<CanvasTileEngineConfig>, transform: DrawTransform) => voidFunction receiving canvas context, top-left coords, config, and a `transform` helper — use `transform.worldToScreen(x, y)` to position drawing at world coordinates instead of deriving the pixel math by hand.
layer?numberLayer index (default 1).
options?DrawOptionsOptional `id`: re-registering with the same id replaces the previous registration instead of accumulating alongside it.

Returns DrawHandle — DrawHandle for removal.

Example
engine.addDrawFunction((ctx, coords, config, transform) => {
    const c = ctx as CanvasRenderingContext2D;
    const p = transform.worldToScreen(5, 3); // center of cell (5, 3)
    c.fillStyle = "red";
    c.fillRect(p.x - 4, p.y - 4, 8, 8);
}, 4);

CanvasTileEngine.removeDrawHandle()

method

Remove a specific draw callback by handle. Does not clear other callbacks on the same layer.

removeDrawHandle(handle: DrawHandle): void

Parameters

handleDrawHandle

Returns void

CanvasTileEngine.clearLayer()

method

Clear all draw callbacks from a specific layer. Use this before redrawing dynamic content to prevent accumulation.

clearLayer(layer: number): void

Parameters

layernumberLayer index to clear.

Returns void

Example
engine.clearLayer(1);
engine.drawRect(newRects, 1);
engine.render();

CanvasTileEngine.clearAll()

method

Clear all draw callbacks from all layers. Useful for complete scene reset.

clearAll(): void

Returns void

Example
engine.clearAll();
// Redraw everything from scratch

CanvasTileEngine.hitTest()

method

All rect/circle/image/path/line items under a world point, highest visual priority first (higher layer, then later registration, then later item within a draw call). Pass the `coords.raw` value from event callbacks - origin anchoring, image aspect fit, and rotation are handled internally. Line, Path, and Text items are not hit-testable. Like rendering, results reflect item positions as of the draw call: mutating an item's position requires re-registration (style mutation is fine). `padding` (world units) and `paddingPx` (screen pixels, zoom independent) expand every item's hit geometry outward - generous touch targets around small markers without invisible helper items. `TData` types the `data` field of returned items — it is an assertion, not checked at runtime, so only pass it when every hit-testable item carries that data shape (or narrow per hit).

hitTest<TData = unknown>(point: Coords, opts?: HitTestOptions): HitResult<TImage, TData>[]

Parameters

pointCoordsWorld coordinates (e.g. `coords.raw` from onClick/onHover).
opts?HitTestOptionsOptional filters, e.g. `{ layer: 2, padding: 0.5 }`.

Returns HitResult<TImage, TData>[]

Example
engine.onClick = (coords) => {
    // Accept clicks up to 0.6 world units around each station dot
    const hit = engine.hitTestFirst<Station>(coords.raw, { padding: 0.6 });
    if (hit?.item.data) openPanel(hit.item.data);
};

CanvasTileEngine.hitTestFirst()

method

The topmost item under a world point, or `undefined`. See hitTest for semantics.

hitTestFirst<TData = unknown>(point: Coords, opts?: HitTestOptions): HitResult<TImage, TData> | undefined

Parameters

pointCoords
opts?HitTestOptions

Returns HitResult<TImage, TData> | undefined

CanvasTileEngine.hitTestRect()

method

All items whose geometry intersects (default) or lies fully inside a world rectangle — the marquee/box-selection query. Corners may be passed in any order (a drag can travel in any direction); build them from event `coords.raw` values, like `hitTest`. Region tests run on item GEOMETRY — stroke widths are not expanded — and filled paths count interior overlap with holes excluded.

hitTestRect<TData = unknown>(rect: Bounds, opts?: HitTestRectOptions): HitResult<TImage, TData>[]

Parameters

rectBounds
opts?HitTestRectOptions

Returns HitResult<TImage, TData>[]

Example
// Marquee selection between drag start and end (raw coords)
const hits = engine.hitTestRect(
    { minX: start.x, minY: start.y, maxX: end.x, maxY: end.y },
    { layer: 2, mode: "contain" },
);
select(hits.map((h) => h.item.data));

Config.get()

method

Get the current configuration as an immutable snapshot. The returned object is deeply frozen and shared — do not mutate it. Runtime updates (`updateEventHandlers`, `updateBounds`) replace the snapshot with a new frozen object, so previously returned references keep their old values. Returning the frozen instance avoids the deep copy this method used to make on every call (it runs on every pointer event and every rendered frame).

get(): Readonly<Required<CanvasTileEngineConfig>>

Returns Readonly<Required<CanvasTileEngineConfig>> — Normalized configuration snapshot e.g. `{ scale: 1, size: { width: 800, height: 600 }, ... }`.

Config.updateEventHandlers()

method

Update event handlers at runtime.

updateEventHandlers(handlers: Partial<EventHandlers>): void

Parameters

handlersPartial<EventHandlers>Partial event handlers to update.

Returns void

Config.updateScaleLimits()

method

Update scale limits at runtime.

updateScaleLimits(minScale: number, maxScale: number): void

Parameters

minScalenumberNew minimum scale.
maxScalenumberNew maximum scale.

Returns void

Config.updateBounds()

method

Update map bounds at runtime.

updateBounds(bounds: {
    minX: number;
    maxX: number;
    minY: number;
    maxY: number;
}): void

Parameters

bounds{ minX: number; maxX: number; minY: number; maxY: number; }New boundary limits. Use Infinity/-Infinity to remove limits on specific axes.

Returns void

CoordinateTransformer.worldToScreen()

method

Convert a world grid coordinate to screen pixels, accounting for camera offset and scale.

worldToScreen(worldX: number, worldY: number): Coords

Parameters

worldXnumberGrid X in world space (tile index).
worldYnumberGrid Y in world space (tile index).

Returns Coords — Screen-space coordinates in pixels. e.g., (e.g. `{ x: 100.5, y: 200.5 }`).

CoordinateTransformer.screenToWorld()

method

Convert screen pixel coordinates back to world space grid coordinates.

screenToWorld(screenX: number, screenY: number): Coords

Parameters

screenXnumberX coordinate in screen space (pixels).
screenYnumberY coordinate in screen space (pixels).

Returns Coords — World-space grid coordinates. (e.g. `{ x: 10, y: 20 }`).

SpatialIndex.load()

method

Bulk load items into the R-Tree (much faster than individual inserts)

load(items: T[]): void

Parameters

itemsT[]

Returns void

SpatialIndex.query()

method

Query all items within a rectangular range

query(minX: number, minY: number, maxX: number, maxY: number): T[]

Parameters

minXnumber
minYnumber
maxXnumber
maxYnumber

Returns T[]

SpatialIndex.clear()

method

Clear all items

clear(): void

Returns void

SpatialIndex.fromArray()

method

Create SpatialIndex from array of items

static fromArray<T extends SpatialItem>(items: T[]): SpatialIndex<T>

Parameters

itemsT[]

Returns SpatialIndex<T>

SpriteAnimator.frameIndexAt()

method

Frame index for a given elapsed time since the animation started. Pure timing math; exposed for tests and manual stepping.

frameIndexAt(elapsedMs: number): number

Parameters

elapsedMsnumber

Returns number

SpriteAnimator.frameAt()

method

Frame source rect for a given elapsed time since the animation started.

frameAt(elapsedMs: number): SpriteRect

Parameters

elapsedMsnumber

Returns SpriteRect

SpriteAnimator.start()

method

Start playback. Restarts from the first frame if already running.

start(onFrame: (frame: SpriteRect, index: number) => void, onComplete?: () => void): void

Parameters

onFrame(frame: SpriteRect, index: number) => voidCalled with the new frame whenever the frame changes (including once immediately with the first frame).
onComplete?() => voidCalled when a non-looping animation reaches its last frame.

Returns void

SpriteAnimator.stop()

method

Stop playback. The last applied frame stays drawn.

stop(): void

Returns void

SpriteAnimator.isRunning()

method

Whether the animation loop is currently scheduled.

isRunning(): boolean

Returns boolean

SpriteSheet.frame()

method

Source rectangle of the frame at grid position (col, row).

frame(col: number, row: number): SpriteRect

Parameters

colnumber
rownumber

Returns SpriteRect

SpriteSheet.frameByIndex()

method

Source rectangle of a frame by linear index (left-to-right, top-to-bottom). Requires `columns` to be set.

frameByIndex(index: number): SpriteRect

Parameters

indexnumber

Returns SpriteRect

SpriteSheet.framesInRow()

method

Consecutive frames of a single row, from `startCol` to `endCol` inclusive. Useful as an animation frame list, e.g. `framesInRow(0, 0, 4)` for the frames (0,0) through (4,0).

framesInRow(row: number, startCol: number, endCol: number): SpriteRect[]

Parameters

rownumber
startColnumber
endColnumber

Returns SpriteRect[]

ViewportState.getSize()

method

No API description is included in the published TypeScript declaration for ViewportState.getSize.

getSize(): {
    width: number;
    height: number;
}

Returns { width: number; height: number; }

ViewportState.setSize()

method

No API description is included in the published TypeScript declaration for ViewportState.setSize.

setSize(width: number, height: number): void

Parameters

widthnumber
heightnumber

Returns void

ViewportState.updateDpr()

method

Update DPR (useful when window moves between displays).

updateDpr(): void

Returns void

Events

CanvasTileEngine.onCoordsChange

event

Callback when center coordinates change (pan or zoom).

onCoordsChange?: (coords: Coords) => void
Example
engine.onCoordsChange = (coords) => {
    console.log(`Center: ${coords.x}, ${coords.y}`);
};

CanvasTileEngine.onClick

event

Callback when a tile is clicked (mouse or touch tap).

get onClick(): onClickCallback | undefined
set onClick(cb: onClickCallback | undefined)

Parameters

cbonClickCallback | undefined
Example
engine.onClick = (coords, mouse, client) => {
    console.log(`Clicked tile: ${coords.snapped.x}, ${coords.snapped.y}`);
};

CanvasTileEngine.onRightClick

event

Callback when a tile is right-clicked.

get onRightClick(): onRightClickCallback | undefined
set onRightClick(cb: onRightClickCallback | undefined)

Parameters

cbonRightClickCallback | undefined
Example
engine.onRightClick = (coords) => {
    showContextMenu(coords.snapped.x, coords.snapped.y);
};

CanvasTileEngine.onHover

event

Callback when hovering over tiles.

get onHover(): onHoverCallback | undefined
set onHover(cb: onHoverCallback | undefined)

Parameters

cbonHoverCallback | undefined
Example
engine.onHover = (coords) => {
    setHoveredTile({ x: coords.snapped.x, y: coords.snapped.y });
};

CanvasTileEngine.onMouseDown

event

Callback on mouse/touch down.

get onMouseDown(): onMouseDownCallback | undefined
set onMouseDown(cb: onMouseDownCallback | undefined)

Parameters

cbonMouseDownCallback | undefined
Example
engine.onMouseDown = (coords) => {
    startPainting(coords.snapped.x, coords.snapped.y);
};

CanvasTileEngine.onMouseUp

event

Callback on mouse/touch up.

get onMouseUp(): onMouseUpCallback | undefined
set onMouseUp(cb: onMouseUpCallback | undefined)

Parameters

cbonMouseUpCallback | undefined
Example
engine.onMouseUp = (coords) => {
    stopPainting();
};

CanvasTileEngine.onMouseLeave

event

Callback when mouse/touch leaves the canvas.

get onMouseLeave(): onMouseLeaveCallback | undefined
set onMouseLeave(cb: onMouseLeaveCallback | undefined)

Parameters

cbonMouseLeaveCallback | undefined
Example
engine.onMouseLeave = () => {
    clearHoveredTile();
};

CanvasTileEngine.onDraw

event

Callback after each draw frame, on top of all layers. Same signature as `addDrawFunction` callbacks: platform context, top-left world coords, live config, and coordinate transform helpers.

get onDraw(): onDrawCallback | undefined
set onDraw(cb: onDrawCallback | undefined)

Parameters

cbonDrawCallback | undefined
Example
engine.onDraw = (ctx, coords, config, transform) => {
    const c = ctx as CanvasRenderingContext2D;
    c.fillStyle = "red";
    c.fillText(`Scale: ${config.scale}`, 10, 20);
};

CanvasTileEngine.onResize

event

Callback on canvas resize.

get onResize(): (() => void) | undefined
set onResize(cb: (() => void) | undefined)

Parameters

cb(() => void) | undefined
Example
engine.onResize = () => {
    console.log("Canvas resized:", engine.getSize());
};

CanvasTileEngine.onZoom

event

Callback when zoom level changes (wheel or pinch).

get onZoom(): ((scale: number) => void) | undefined
set onZoom(cb: ((scale: number) => void) | undefined)

Parameters

cb((scale: number) => void) | undefined
Example
engine.onZoom = (scale) => {
    console.log(`Zoom level: ${scale}`);
};

CanvasTileEngine.onWheel

event

Callback for wheel (desktop) and pinch (touch) zoom gestures. Requires `eventHandlers.zoom`; fires even when the scale is clamped at a limit. Unlike `onZoom` (which reports the resulting scale, including programmatic changes), this reports the input gesture itself with its position. For pinch, the coordinates describe the pinch midpoint and `deltaY` is the wheel delta that would produce the same zoom factor.

get onWheel(): onWheelCallback | undefined
set onWheel(cb: onWheelCallback | undefined)

Parameters

cbonWheelCallback | undefined
Example
engine.onWheel = (coords, mouse, client, wheel) => {
    console.log(`${wheel.source} zoom ${wheel.direction} at`, coords.snapped);
};

GestureProcessor.onClick

event

Event callback exposed by GestureProcessor.

onClick?: onClickCallback

GestureProcessor.onRightClick

event

Event callback exposed by GestureProcessor.

onRightClick?: onRightClickCallback

GestureProcessor.onHover

event

Event callback exposed by GestureProcessor.

onHover?: onHoverCallback

GestureProcessor.onMouseDown

event

Event callback exposed by GestureProcessor.

onMouseDown?: onMouseDownCallback

GestureProcessor.onMouseUp

event

Event callback exposed by GestureProcessor.

onMouseUp?: onMouseUpCallback

GestureProcessor.onMouseLeave

event

Event callback exposed by GestureProcessor.

onMouseLeave?: onMouseLeaveCallback

GestureProcessor.onZoom

event

Event callback exposed by GestureProcessor.

onZoom?: onZoomCallback

GestureProcessor.onWheel

event

Event callback exposed by GestureProcessor.

onWheel?: onWheelCallback

Functions

computeOriginOffset()

function

Top-left offset of a `w`x`h` box anchored at `pos`. - "cell": nudges the box from the cell center by `origin.x`/`origin.y` (0 to 1) across a `cellSize`-wide cell, independent of the box's own size. - "self": anchors within the box's own `w`/`h`; `cellSize` is unused. `pos`, `w`, `h`, and `cellSize` must share the same unit — screen pixels for renderers (`cellSize` = `camera.scale`), or world units for hit testing (`cellSize` = 1, a cell is exactly one world unit wide).

function computeOriginOffset(pos: Coords, w: number, h: number, origin: Origin, cellSize: number): Coords

Parameters

posCoords
wnumber
hnumber
originOrigin
cellSizenumber

Returns Coords

cornerArc()

function

Compute the rounding arc for the corner `prev → v → next` with the desired `radiusPx`. The radius is clamped so the arc's tangent points never pass the midpoint of either adjacent segment (matching what `ctx.arcTo` would need to stay well-formed on short segments). Returns `null` for degenerate corners: zero-length segments, collinear continuation, or a fold-back.

function cornerArc(prev: Coords, v: Coords, next: Coords, radiusPx: number): CornerArc | null

Parameters

prevCoords
vCoords
nextCoords
radiusPxnumber

Returns CornerArc | null

fitScale()

function

The scale (pixels per world unit) at which `bounds` exactly fits a `size`-pixel viewport — the math `fitBounds` uses to pick its target scale, exposed as a pure function for config-time use (the `gridToSize` of free-form content). Use it to derive scale limits from content instead of hand-tuning constants: the fit scale tracks the content automatically, and only `maxScale` — a content-resolution quality cap that no bounds can imply — stays a deliberate choice.

function fitScale(bounds: Bounds, size: {
    width: number;
    height: number;
}, options?: FitScaleOptions): number

Parameters

boundsBoundsRectangle to fit. Every edge must be finite.
size{ width: number; height: number; }Viewport size in logical pixels.
options?FitScaleOptions`padding` in world units or `paddingPx` in screen pixels (wins over `padding`).

Returns number — The fitting scale; unclamped — apply your own min/max policy.

Example
const fit = fitScale(WORLD_BOUNDS, { width: 800, height: 600 }, { paddingPx: 24 });
const config = {
    size: { width: 800, height: 600 },
    scale: fit, // open showing everything
    minScale: fit * 0.8, // small overview slack — your policy
    maxScale: 64, // quality cap — intentionally hand-picked
};

flattenPathCommands()

function

Flattens a Canvas2D-style command list into polyline subpaths, following Canvas2D path semantics: each `moveTo` starts a new subpath; `lineTo`/ curves with no open subpath implicitly move first; `arc` draws a connecting line from the current point to the arc start; after `closePath` the current point is the closed subpath's start. All consumers of flattened geometry (hit testing, WebGL, culling) share this one implementation so they agree exactly. `maxSegment` is the max spacing between samples, in the same unit as the coordinates — callers flatten in world units with `ARC_SEGMENT_LENGTH / scale` to sample at the renderers' screen-pixel density.

function flattenPathCommands(commands: PathCommand[], maxSegment: number): Subpath[]

Parameters

commandsPathCommand[]
maxSegmentnumber

Returns Subpath[]

gridToSize()

function

Convert grid-based dimensions to pixel-based config plus the board center. Integers are cell centers (cell k spans [k-0.5, k+0.5]), so a board of cells 0..N-1 is centered at (N-1)/2 on each axis. Pass the returned `center` to the engine so the board exactly fills the viewport.

function gridToSize(options: {
    columns: number;
    rows: number;
    cellSize: number;
}): Pick<CanvasTileEngineConfig, "size" | "scale"> & {
    center: Coords;
}

Parameters

options{ columns: number; rows: number; cellSize: number; }Grid configuration with columns, rows, and cell size.

Returns Pick<CanvasTileEngineConfig, "size" | "scale"> & { center: Coords; } — Config `size`/`scale` plus the `center` of a 0-based board.

Example
const { center, ...board } = gridToSize({ columns: 8, rows: 8, cellSize: 60 });
// board.size = { width: 480, height: 480 }, board.scale = 60
// center = { x: 3.5, y: 3.5 }


const engine = new CanvasTileEngine(
    wrapper,
    { ...board, gridAligned: true },
    new RendererCanvas(),
    center,
);

overlayLineStyle()

function

Overlay one line style on another, unit-pair by unit-pair. A plain field-by-field spread breaks the world/px precedence rule across layers: a base `lineWidthPx` would survive the merge and shadow an overlay that only sets the world `lineWidth`. Instead, a layer that sets either field of a pair (`lineWidth`/`lineWidthPx`, `lineDash`/`lineDashPx`) replaces the whole pair — the `*Px`-wins rule applies within one layer, never across layers. Used for `Line.style` over the call-level style, and for `styleOf` decorations over both.

function overlayLineStyle<T extends OverlayableLineStyle>(base: T | undefined, over: Partial<T> | undefined): T

Parameters

baseT | undefined
overPartial<T> | undefined

Returns T

pathCommandsBounds()

function

Conservative world-space bounds of a command list from its control-point hull: every endpoint and control point, and each arc's full center±radius box. Curves never leave their control hull, so this over-approximates — cheap, camera-independent, and safe for culling. Returns null for an empty list.

function pathCommandsBounds(commands: PathCommand[]): {
    minX: number;
    minY: number;
    maxX: number;
    maxY: number;
} | null

Parameters

commandsPathCommand[]

Returns { minX: number; minY: number; maxX: number; maxY: number; } | null

resolveCornerRadiusPx()

function

Effective Path corner-rounding radius in screen pixels; 0 disables rounding. `cornerRadiusPx` wins; `cornerRadius` is world units.

function resolveCornerRadiusPx(style: CornerRadiusStyle | undefined, scale: number): number

Parameters

styleCornerRadiusStyle | undefined
scalenumber

Returns number

resolveLineDashPx()

function

Effective dash pattern in screen pixels, or `undefined` for a solid line. Follows Canvas2D `setLineDash` semantics: an odd-length pattern is repeated (doubled), and a pattern that is empty, contains a negative or non-finite value, or sums to zero yields a solid line.

function resolveLineDashPx(style: LineDashStyle | undefined, scale: number): number[] | undefined

Parameters

styleLineDashStyle | undefined
scalenumber

Returns number[] | undefined

resolveLineWidthPx()

function

Effective stroke width in screen pixels. `lineWidthPx` wins; `lineWidth` is world units (multiplied by `scale`); neither given falls back to a 1px hairline.

function resolveLineWidthPx(style: StrokeWidthStyle | undefined, scale: number): number

Parameters

styleStrokeWidthStyle | undefined
scalenumber

Returns number

resolveOrigin()

function

Fills in the "cell"/0.5/0.5 defaults for an item's `origin` field.

function resolveOrigin(origin?: RawOrigin): Origin

Parameters

origin?RawOrigin

Returns Origin

resolveRadiusPx()

function

Border radius in screen pixels. `radius` is world units; single values and per-corner arrays are both supported.

function resolveRadiusPx(radius: number | number[] | undefined, scale: number): number | number[] | undefined

Parameters

radiusnumber | number[] | undefined
scalenumber

Returns number | number[] | undefined

resolveSizePx()

function

Effective drawn size in screen pixels. `sizePx` wins; else `size * scale`; default 1 world unit.

function resolveSizePx(item: SizedItem, scale: number): number

Parameters

itemSizedItem
scalenumber

Returns number

resolveSizeWorld()

function

Effective size in world units at the current scale. Note that a `sizePx` item's world extent GROWS as the camera zooms out — culling and hit queries must re-evaluate this per frame instead of caching it.

function resolveSizeWorld(item: SizedItem, scale: number): number

Parameters

itemSizedItem
scalenumber

Returns number

roundedPolyline()

function

Replace each interior vertex of a polyline with its rounding arc, flattened into short segments. Uses cornerArc for the exact same clamped geometry the Canvas2D/Skia renderers feed to their native tangent-arc APIs, so flattened consumers (WebGL, hit testing) agree with them. Because the result is a plain (denser) polyline, dash tessellation and distance tests run over it unchanged. Radius, points, and `maxSegment` share one unit (pixels or world).

function roundedPolyline(points: Coords[], radius: number, maxSegment?: number): Coords[]

Parameters

pointsCoords[]
radiusnumber
maxSegment?number

Returns Coords[]

roundedRing()

function

Closed-ring variant of roundedPolyline: every vertex is a corner with cyclic neighbors, including the joins of the closing segment. The result is still an implicit ring — consumers connect the last sample back to the first.

function roundedRing(points: Coords[], radius: number, maxSegment?: number): Coords[]

Parameters

pointsCoords[]
radiusnumber
maxSegment?number

Returns Coords[]

traceCommands()

function

Replays a PathCommand list into a Canvas2D-style sink, converting world coordinates to screen pixels and degrees to radians at this one boundary so every renderer traces identical geometry. The world→screen transform is uniform (one scale for both axes), so curves and arcs map exactly.

function traceCommands(ctx: CommandTraceTarget, commands: PathCommand[], worldToScreen: (x: number, y: number) => Coords, scale: number): void

Parameters

ctxCommandTraceTarget
commandsPathCommand[]
worldToScreen(x: number, y: number) => Coords
scalenumber

Returns void

traceRoundedPath()

function

Traces one path item's outline (screen-pixel points) into a Canvas2D-style sink, applying corner rounding via cornerArc so every renderer produces identical geometry. Open paths round interior vertices only; closed paths round every vertex, including the joins of the closing segment. Degenerate corners (collinear, fold-back, zero radius) fall back to straight joins.

function traceRoundedPath(ctx: PathTraceTarget, pts: Coords[], closed: boolean, radiusPx: number): void

Parameters

ctxPathTraceTarget
ptsCoords[]
closedboolean
radiusPxnumber

Returns void

Interfaces

Bounds

interface

No API description is included in the published TypeScript declaration for Bounds.

interface Bounds {
    minX: number;
    maxX: number;
    minY: number;
    maxY: number;
}

CanvasBounds

interface

Canvas bounds for zoom calculation. Compatible with DOMRect subset needed by Camera.zoom

interface CanvasBounds {
    left: number;
    top: number;
    width: number;
    height: number;
    x: number;
    y: number;
    bottom: number;
    right: number;
}

CircleDrawOptions

interface

Options for CanvasTileEngine.drawCircle.

interface CircleDrawOptions<TData = unknown> extends DrawOptions {
    /** Paint-time decoration; see {@link StyleOf}. */
    styleOf?: StyleOf<Circle<TData>, ShapeDecorationStyle>;
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<Circle<TData>>;
    /** Per-item hit-test opt-out; see {@link InteractiveOf}. */
    interactiveOf?: InteractiveOf<Circle<TData>>;
}

CommandTraceTarget

interface

Full Canvas2D-shaped sink for command replay: PathTraceTarget plus the curve methods. DOM and

interface CommandTraceTarget extends PathTraceTarget {
    quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
    bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
}

CornerArc

interface

Geometry of one rounded polyline corner, in screen pixels. All renderers derive their corner arcs from this single computation so the rounding is identical everywhere: Canvas2D/Skia feed `radius` to their native tangent arc APIs, WebGL flattens the arc from `center`/angles.

interface CornerArc {
    /** Arc radius after per-corner clamping. */
    radius: number;
    /** Tangent point on the incoming segment (arc start). */
    t1: Coords;
    /** Tangent point on the outgoing segment (arc end). */
    t2: Coords;
    /** Arc center. */
    center: Coords;
    /** Angle of `t1` around the center, radians. */
    startAngle: number;
    /** Angle of `t2` around the center, radians. */
    endAngle: number;
    /** Sweep from start to end, radians; negative = counterclockwise. */
    sweep: number;
}

DrawHandle

interface

No API description is included in the published TypeScript declaration for DrawHandle.

interface DrawHandle {
    readonly id: symbol;
    readonly layer: number;
}

DrawOptions

interface

Options accepted by the engine draw helpers (`drawRect`, `drawCircle`, ...).

interface DrawOptions {
    /**
     * Stable identity for this registration. Calling any draw method again
     * with the same id atomically replaces the previous registration: the old
     * draw callback and its hit-test entries are removed (and, for static
     * draws, the offscreen cache is invalidated) before the new one is added.
     * Ids share a single namespace across draw kinds and layers; static draw
     * helpers use their `cacheKey` as the id. Without an id, every call adds
     * a new registration (remove with the returned handle or `clearLayer`).
     */
    id?: string;
    /**
     * Set to `false` to keep this registration out of hit testing — the
     * `pointer-events: none` of the draw API. Decorative content (floor
     * tiles, background images, zone overlays) declared once at registration
     * stops leaking into every `hitTest`/`hitTestFirst`/`hitTestRect` query,
     * and large decorative sets skip hit-registry bookkeeping entirely.
     * Default `true`. Text and custom draw functions never enter hit testing
     * regardless of this flag.
     */
    hitTest?: boolean;
}

DrawTransform

interface

Coordinate transform helpers handed to custom draw callbacks (`addDrawFunction` / `onDraw`), so user code never re-derives the `(world - topLeft) * scale` formula or the cell-center offset.

interface DrawTransform {
    /**
     * Item-space world coordinate → canvas pixel position. Integers are cell
     * centers (the same space item `x`/`y` live in), so `worldToScreen(k, k)`
     * is the pixel at the center of cell `k`.
     */
    worldToScreen(x: number, y: number): Coords;
    /**
     * Canvas pixel position → raw (corner-space) world coordinate — the same
     * space event payloads report as `coords.raw`.
     */
    screenToWorld(x: number, y: number): Coords;
}

FitBoundsOptions

interface

Options for the engine's `fitBounds` method.

interface FitBoundsOptions {
    /**
     * Extra world-unit margin added on every side of the rectangle. Scales
     * with the content: 10x larger bounds need a 10x larger padding for the
     * same framing. Ignored when {@link paddingPx} is set. Default 0.
     */
    padding?: number;
    /**
     * Screen-pixel margin kept free on every side of the viewport,
     * independent of the content's world size — "20px of air" frames a
     * 3-cell selection and a 10k-cell board identically. Takes precedence
     * over {@link padding}. A value too large for the viewport is clamped so
     * the fit stays valid.
     */
    paddingPx?: number;
    /** Animation duration in ms (default 500). Use 0 for an instant jump. */
    durationMs?: number;
    /** Fired when the fit completes (synchronously when instant). */
    onComplete?: () => void;
}

FitScaleOptions

interface

Options for fitScale. The same pair `fitBounds` accepts.

interface FitScaleOptions {
    /**
     * Extra world-unit margin added on every side of the rectangle; scales
     * with the content. Ignored when {@link paddingPx} is set. Default 0.
     */
    padding?: number;
    /**
     * Screen-pixel margin kept free on every side of the viewport,
     * independent of the content's world size. Takes precedence over
     * {@link padding}. A value too large for the viewport is clamped so the
     * result stays valid.
     */
    paddingPx?: number;
}

ICamera

interface

No API description is included in the published TypeScript declaration for ICamera.

interface ICamera {
    readonly x: number;
    readonly y: number;
    readonly scale: number;
    pan(dx: number, dy: number): void;
    zoom(screenX: number, screenY: number, deltaY: number, bounds: ViewportBounds): void;
    zoomByFactor(factor: number, centerX: number, centerY: number): void;
    setScale(scale: number): void;
    setScaleLimits(minScale: number, maxScale: number): void;
    setCenter(center: Coords, viewportWidth: number, viewportHeight: number): void;
    getCenter(viewportWidth: number, viewportHeight: number): Coords;
    getVisibleBounds(viewportWidth: number, viewportHeight: number): Bounds;
    setBounds(bounds: Bounds): void;
    adjustForResize(dw: number, dh: number): void;
}

IDrawAPI

interface

No API description is included in the published TypeScript declaration for IDrawAPI.

interface IDrawAPI<TImage = HTMLImageElement> {
    addDrawFunction(fn: (ctx: unknown, coords: Coords, config: Required<CanvasTileEngineConfig>, transform: DrawTransform) => void, layer?: number): DrawHandle;
    drawRect(items: Rect | Rect[], layer?: number, options?: RendererDrawOptions<Rect, ShapeDecorationStyle>): DrawHandle;
    drawCircle(items: Circle | Circle[], layer?: number, options?: RendererDrawOptions<Circle, ShapeDecorationStyle>): DrawHandle;
    drawLine(items: Line | Line[], style?: LineStyle, layer?: number, options?: RendererDrawOptions<Line, LineDecorationStyle>): DrawHandle;
    drawText(items: Text | Text[], layer?: number, options?: RendererDrawOptions<Text, TextDecorationStyle>): DrawHandle;
    drawImage(items: ImageItem<TImage> | ImageItem<TImage>[], layer?: number, options?: RendererImageDrawOptions<TImage>): DrawHandle;
    /** Receives fully normalized items: the engine converts every accepted
     * `drawPath` input (including the legacy `Coords[]` forms) before
     * delegating, so renderers only implement the item form. */
    drawPath(items: PathItem[], layer?: number, options?: RendererDrawOptions<PathItem, PathDecorationStyle>): DrawHandle;
    drawGridLines(cellSize: number, style: {
        lineWidth: number;
        strokeStyle: string;
    }, layer?: number): DrawHandle;
    drawStaticRect(items: Rect[], cacheKey: string, layer?: number): DrawHandle;
    drawStaticCircle(items: Circle[], cacheKey: string, layer?: number): DrawHandle;
    drawStaticImage(items: ImageItem<TImage>[], cacheKey: string, layer?: number): DrawHandle;
    removeDrawHandle(handle: DrawHandle): void;
    clearLayer(layer: number): void;
    clearAll(): void;
    clearStaticCache(cacheKey?: string): void;
}

IImageLoader

interface

Platform-agnostic image loader interface. Each renderer implements this with platform-specific image handling.

interface IImageLoader<TImage = HTMLImageElement> {
    /**
     * Load an image from URL, with caching.
     * @param src Image URL.
     * @param retry Retry count on failure.
     */
    load(src: string, retry?: number): Promise<TImage>;
    /**
     * Get a cached image without loading.
     */
    get(src: string): TImage | undefined;
    /**
     * Check if an image is already cached.
     */
    has(src: string): boolean;
    /**
     * Clear all cached images.
     */
    clear(): void;
    /**
     * Register a callback fired when a new image finishes loading.
     * @returns Unsubscribe function.
     */
    onLoad(cb: () => void): () => void;
}

IRenderer

interface

No API description is included in the published TypeScript declaration for IRenderer.

interface IRenderer<TMount = HTMLDivElement, TImage = HTMLImageElement> {
    init(deps: RendererDependencies<TMount>): void;
    render(): void;
    resize(width: number, height: number): void;
    resizeWithAnimation(width: number, height: number, durationMs: number, onComplete?: () => void): void;
    destroy(): void;
    getDrawAPI(): IDrawAPI<TImage>;
    getImageLoader(): IImageLoader<TImage>;
    setupEvents(): void;
    onClick?: onClickCallback;
    onRightClick?: onRightClickCallback;
    onHover?: onHoverCallback;
    onMouseDown?: onMouseDownCallback;
    onMouseUp?: onMouseUpCallback;
    onMouseLeave?: onMouseLeaveCallback;
    onZoom?: onZoomCallback;
    onWheel?: onWheelCallback;
    onResize?: () => void;
    onCameraChange?: () => void;
    onDraw?: onDrawCallback;
}

ImageDrawOptions

interface

Options for CanvasTileEngine.drawImage. Images carry no `style`, so there is no `styleOf` — appearance changes go through item fields like `opacity` (read live at paint time; mutate + `render()`).

interface ImageDrawOptions<TImage = unknown, TData = unknown> extends DrawOptions {
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<ImageItem<TImage, TData>>;
    /** Per-item hit-test opt-out; see {@link InteractiveOf}. */
    interactiveOf?: InteractiveOf<ImageItem<TImage, TData>>;
}

LineDrawOptions

interface

Options for CanvasTileEngine.drawLine. `styleOf` overlays the call-level `style` per item, which also makes it the way to give individual lines their own color.

interface LineDrawOptions<TData = unknown> extends DrawOptions {
    /** Paint-time decoration; see {@link StyleOf}. */
    styleOf?: StyleOf<Line<TData>, LineDecorationStyle>;
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<Line<TData>>;
    /** Per-item hit-test opt-out; see {@link InteractiveOf}. */
    interactiveOf?: InteractiveOf<Line<TData>>;
}

LineStyle

interface

No API description is included in the published TypeScript declaration for LineStyle.

interface LineStyle {
    strokeStyle?: string;
    /**
     * Line thickness in world units; scales with zoom.
     * Ignored when {@link lineWidthPx} is set. Default: 1px hairline.
     */
    lineWidth?: number;
    /**
     * Line thickness in screen pixels, independent of zoom.
     * Takes precedence over {@link lineWidth}.
     */
    lineWidthPx?: number;
    /**
     * Dash pattern in world units (dashes are anchored to the world and scale
     * with zoom). Follows Canvas2D `setLineDash` semantics. Ignored when
     * {@link lineDashPx} is set. Omit for a solid line.
     */
    lineDash?: number[];
    /**
     * Dash pattern in screen pixels, independent of zoom.
     * Takes precedence over {@link lineDash}.
     */
    lineDashPx?: number[];
}

NormalizedPinch

interface

Normalized multi-pointer input for pinch gestures.

interface NormalizedPinch {
    /** First pointer */
    pointer1: NormalizedPointer;
    /** Second pointer */
    pointer2: NormalizedPointer;
}

NormalizedPointer

interface

Normalized pointer input - renderer-agnostic format. All coordinates should be canvas-relative.

interface NormalizedPointer {
    /** X position relative to canvas */
    x: number;
    /** Y position relative to canvas */
    y: number;
    /** X position relative to viewport (for callbacks) */
    clientX: number;
    /** Y position relative to viewport (for callbacks) */
    clientY: number;
}

Origin

interface

Normalized origin: `mode` defaults to "cell", `x`/`y` default to 0.5 (center).

interface Origin {
    mode: "cell" | "self";
    x: number;
    y: number;
}

OverlayableLineStyle

interface

The stroke fields overlayLineStyle understands.

interface OverlayableLineStyle extends StrokeWidthStyle, LineDashStyle {
    strokeStyle?: string;
}

PathDrawOptions

interface

Options for CanvasTileEngine.drawPath.

interface PathDrawOptions<TData = unknown> extends DrawOptions {
    /**
     * Paint-time decoration; see {@link StyleOf}. Note: hit testing keeps the
     * registration-time semantics — decorating an unfilled path with a
     * `fillStyle` paints a fill but does not switch hit testing from
     * stroke to interior.
     */
    styleOf?: StyleOf<PathItem<TData>, PathDecorationStyle>;
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<PathItem<TData>>;
    /** Per-item hit-test opt-out; see {@link InteractiveOf}. */
    interactiveOf?: InteractiveOf<PathItem<TData>>;
}

PathTraceTarget

interface

Minimal Canvas2D-shaped path sink. Both DOM and

interface PathTraceTarget {
    moveTo(x: number, y: number): void;
    lineTo(x: number, y: number): void;
    arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
    closePath(): void;
}

ProcessedCoords

interface

Processed coordinate result for callbacks.

interface ProcessedCoords {
    coords: {
        raw: Coords;
        snapped: Coords;
    };
    mouse: {
        raw: Coords;
        snapped: Coords;
    };
    client: {
        raw: Coords;
        snapped: Coords;
    };
}

RectDrawOptions

interface

Options for CanvasTileEngine.drawRect.

interface RectDrawOptions<TData = unknown> extends DrawOptions {
    /** Paint-time decoration; see {@link StyleOf}. */
    styleOf?: StyleOf<Rect<TData>, ShapeDecorationStyle>;
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<Rect<TData>>;
    /** Per-item hit-test opt-out; see {@link InteractiveOf}. */
    interactiveOf?: InteractiveOf<Rect<TData>>;
}

RendererDependencies

interface

Dependencies injected into a renderer's `init`. `TMount` is the platform-specific mount target the engine is constructed with. It defaults to `HTMLDivElement` so existing DOM renderers stay source- and type-compatible; non-DOM renderers (e.g. React Native / Skia) parameterize it with their own mount type.

interface RendererDependencies<TMount = HTMLDivElement> {
    wrapper: TMount;
    camera: ICamera;
    viewport: ViewportState;
    config: Config;
    transformer: CoordinateTransformer;
}

RendererDrawOptions

interface

Paint-time options the engine threads into a renderer's `IDrawAPI` draw methods. Only `styleOf` and `visibleOf` reach renderers — registration concerns (`id`) and hit-test concerns (`interactiveOf`) are resolved in the engine.

interface RendererDrawOptions<TItem, TStyle> {
    styleOf?: StyleOf<TItem, TStyle>;
    visibleOf?: VisibleOf<TItem>;
}

RendererImageDrawOptions

interface

Paint-time options for `drawImage` — images carry no `style`, so only `visibleOf` reaches renderers.

interface RendererImageDrawOptions<TImage> {
    visibleOf?: VisibleOf<ImageItem<TImage>>;
}

SpriteAnimation

interface

A frame-based sprite animation definition.

interface SpriteAnimation {
    /** Frames to cycle through, in play order (e.g. `SpriteSheet.framesInRow(...)`). */
    frames: SpriteRect[];
    /** Playback speed in frames per second. */
    fps: number;
    /** Restart from the first frame after the last one (default: true). */
    loop?: boolean;
}

SpriteSheetOptions

interface

No API description is included in the published TypeScript declaration for SpriteSheetOptions.

interface SpriteSheetOptions {
    /** Width of a single frame in sheet pixels. */
    frameWidth: number;
    /** Height of a single frame in sheet pixels. */
    frameHeight: number;
    /** Number of columns in the sheet. Required for index-based lookups. */
    columns?: number;
    /** Outer offset from the sheet edges in pixels (default: 0). */
    margin?: number;
    /** Gap between adjacent frames in pixels (default: 0). */
    spacing?: number;
}

StaticDrawOptions

interface

Options for the static draw helpers (`drawStaticRect`, ...). Their `cacheKey` already plays the registration-id role, so only the hit-test opt-out applies.

interface StaticDrawOptions {
    /** Set to `false` to keep this registration out of hit testing; see
     * {@link DrawOptions.hitTest}. */
    hitTest?: boolean;
}

Subpath

interface

One flattened subpath: a polyline plus whether it closes back to its start.

interface Subpath {
    points: Coords[];
    closed: boolean;
}

TextDrawOptions

interface

Options for CanvasTileEngine.drawText. Text never enters hit testing, so there is no `interactiveOf`.

interface TextDrawOptions<TData = unknown> extends DrawOptions {
    /** Paint-time decoration; see {@link StyleOf}. */
    styleOf?: StyleOf<Text<TData>, TextDecorationStyle>;
    /** Per-item visibility; see {@link VisibleOf}. */
    visibleOf?: VisibleOf<Text<TData>>;
}

ViewportBounds

interface

No API description is included in the published TypeScript declaration for ViewportBounds.

interface ViewportBounds {
    left: number;
    top: number;
    width: number;
    height: number;
}

WheelInfo

interface

Details of the zoom gesture that triggered an onWheel callback.

interface WheelInfo {
    /**
     * Vertical wheel delta in pixels (negative = zoom in). For pinch this is
     * synthesized: the wheel delta that would produce the same zoom factor,
     * so both sources read on the same axis.
     */
    deltaY: number;
    /** Zoom direction implied by the gesture. */
    direction: "in" | "out";
    /** Input source: mouse wheel or two-finger pinch. */
    source: "wheel" | "pinch";
}

Types

CanvasTileEngineConfig

type

No API description is included in the published TypeScript declaration for CanvasTileEngineConfig.

type CanvasTileEngineConfig = {
    scale: number;
    maxScale?: number;
    minScale?: number;
    backgroundColor?: string;
    /**
     * When true, the initial center snaps to the nearest grid-aligned value
     * for pixel-perfect alignment: half-integers (x.5) for even tile counts,
     * integers for odd. Integers are cell centers (cell k spans
     * [k-0.5, k+0.5]); exact ties snap down so a center computed as N/2 for
     * a 0-based N-cell board lands on the true board center (N-1)/2.
     */
    gridAligned?: boolean;
    size: {
        width: number;
        height: number;
        minWidth?: number;
        minHeight?: number;
        maxWidth?: number;
        maxHeight?: number;
    };
    responsive?: "preserve-scale" | "preserve-viewport" | false;
    eventHandlers?: EventHandlers;
    bounds?: {
        minX: number;
        maxX: number;
        minY: number;
        maxY: number;
    };
    coordinates?: {
        enabled?: boolean;
        shownScaleRange?: {
            min: number;
            max: number;
        };
    };
    debug?: {
        enabled?: boolean;
        hud?: {
            enabled?: boolean;
            topLeftCoordinates?: boolean;
            coordinates?: boolean;
            scale?: boolean;
            tilesInView?: boolean;
            fps?: boolean;
        };
        eventHandlers?: {
            click?: boolean;
            hover?: boolean;
            drag?: boolean;
            zoom?: boolean;
            resize?: boolean;
        };
    };
};

Circle

type

No API description is included in the published TypeScript declaration for Circle.

type Circle<TData = unknown> = Omit<DrawObject<TData>, "rotate" | "radius"> & {
    /**
     * Fixed diameter in screen pixels, independent of zoom — the marker
     * pattern (station dots, POI markers) analog of Text's `fontPx`. Takes
     * precedence over {@link DrawObject.size}. Ignored by `drawStaticCircle`:
     * static caches replay at their recorded scale, so pixel sizing cannot
     * hold there.
     */
    sizePx?: number;
};

Coords

type

No API description is included in the published TypeScript declaration for Coords.

type Coords = {
    x: number;
    y: number;
};

DrawObject

type

No API description is included in the published TypeScript declaration for DrawObject.

type DrawObject<TData = unknown> = {
    x: number;
    y: number;
    size?: number;
    origin?: {
        mode?: "cell" | "self";
        x?: number;
        y?: number;
    };
    style?: {
        fillStyle?: string;
        strokeStyle?: string;
        /**
         * Border width in world units; scales with zoom like the item's
         * geometry. Ignored when `lineWidthPx` is set. Default: 1px hairline.
         */
        lineWidth?: number;
        /**
         * Border width in screen pixels, independent of zoom.
         * Takes precedence over `lineWidth`.
         */
        lineWidthPx?: number;
        /**
         * Border dash pattern in world units (dashes are anchored to the shape
         * and scale with zoom). Follows Canvas2D `setLineDash` semantics.
         * Ignored when `lineDashPx` is set. Omit for a solid border.
         */
        lineDash?: number[];
        /**
         * Border dash pattern in screen pixels, independent of zoom.
         * Takes precedence over `lineDash`.
         */
        lineDashPx?: number[];
    };
    /** Rotation angle in degrees (0 = no rotation, positive = clockwise) */
    rotate?: number;
    /**
     * Border radius in world units; scales with zoom so corners stay
     * proportional to the shape. Single value for all corners, or array for
     * [topLeft, topRight, bottomRight, bottomLeft].
     */
    radius?: number | number[];
    /**
     * Arbitrary app data attached to the item. Never read by the engine or
     * renderers; carried through so `hitTest` results can identify the item
     * without relying on array positions.
     */
    data?: TData;
};

EventHandlers

type

No API description is included in the published TypeScript declaration for EventHandlers.

type EventHandlers = {
    click?: boolean;
    rightClick?: boolean;
    hover?: boolean;
    drag?: boolean;
    /** Zoom behavior: `false` disables zoom, `true` is shorthand for `"pointer"`. */
    zoom?: boolean | ZoomMode;
    resize?: boolean;
};

HitKind

type

Primitive kinds that participate in hit testing.

type HitKind = "rect" | "circle" | "image" | "path" | "line";

HitResult

type

A single hit returned by `hitTest`, ordered by visual priority.

type HitResult<TImage = unknown, TData = unknown> = {
    /** The original item object passed to the draw call. */
    item: Rect<TData> | Circle<TData> | ImageItem<TImage, TData> | PathItem<TData> | Line<TData>;
    /** Which primitive kind the item was drawn as. */
    kind: HitKind;
    /** Layer the item is drawn on. */
    layer: number;
    /** Handle of the draw call that registered the item. */
    handle: DrawHandle;
    /** Position of the item inside its draw call's items array. */
    index: number;
};

HitTestOptions

type

No API description is included in the published TypeScript declaration for HitTestOptions.

type HitTestOptions = {
    /** Only test items drawn on this layer. */
    layer?: number;
    /**
     * Expand every item's hit geometry outward by this many world units -
     * generous touch targets around small markers without invisible helper
     * items. Negative values are treated as 0.
     */
    padding?: number;
    /**
     * Extra hit padding in screen pixels, independent of zoom. The engine
     * converts it with the current scale at query time and adds it to
     * `padding`. Negative values are treated as 0.
     */
    paddingPx?: number;
};

HitTestRectOptions

type

No API description is included in the published TypeScript declaration for HitTestRectOptions.

type HitTestRectOptions = {
    /** Only test items drawn on this layer. */
    layer?: number;
    /**
     * `"intersect"` (default): any overlap with the rectangle counts.
     * `"contain"`: the item's full geometry must lie inside the rectangle —
     * the usual choice for marquee seat/unit selection.
     */
    mode?: "intersect" | "contain";
};

ImageItem

type

An image to draw. `TImage` is the platform-specific image handle and defaults to `HTMLImageElement` (DOM); other renderers parameterize it (e.g. `SkImage`).

type ImageItem<TImage = HTMLImageElement, TData = unknown> = Omit<DrawObject<TData>, "style"> & {
    img: TImage;
    /**
     * Source rectangle in sheet pixels. When set, only this sub-region of
     * `img` is drawn (spritesheet frame); when omitted the whole image is drawn.
     */
    sprite?: SpriteRect;
    /**
     * Fixed size in screen pixels, independent of zoom — for marker-style
     * images that must stay readable at any zoom level. Takes precedence
     * over {@link DrawObject.size}. Ignored by `drawStaticImage`: static
     * caches replay at their recorded scale, so pixel sizing cannot hold
     * there.
     */
    sizePx?: number;
    /**
     * Mirror the image horizontally. Unlike `rotate`, flipping produces a
     * true mirror (a right-facing sprite faces left), which no rotation can.
     * Applied around the draw box center; combines with `rotate` and
     * spritesheet frames, and works in `drawStaticImage` too.
     */
    flipX?: boolean;
    /** Mirror the image vertically. See {@link flipX}. */
    flipY?: boolean;
    /**
     * Opacity from 0 (transparent) to 1 (opaque). Default: 1.
     * Useful for ghost/preview placements in editor-style apps.
     */
    opacity?: number;
};

InteractiveOf

type

Per-item hit-test opt-out — the item-level counterpart of DrawOptions.hitTest. Runs at hit-query time: return `false` to keep the item out of `hitTest`/`hitTestFirst`/`hitTestRect` while it stays painted (queries fall through to items below it); `true`/`undefined` keeps it interactive. Items hidden by `visibleOf` never hit-test, regardless of this callback. Reads external state live, like StyleOf.

type InteractiveOf<TItem> = (item: TItem) => boolean | undefined;

Line

type

No API description is included in the published TypeScript declaration for Line.

type Line<TData = unknown> = {
    from: Coords;
    to: Coords;
    /**
     * Per-item style, overlaying the call-level `style` argument field by
     * field — mixed-style batches no longer need one `drawLine` call per
     * style. Registration-time like every item style, so unlike `styleOf`
     * decorations it may change `lineWidth`/`lineWidthPx`: hit testing
     * resolves this item's own stroke width. `styleOf` decorations still
     * overlay both at paint time.
     */
    style?: LineStyle;
    /**
     * Arbitrary app data attached to the segment. Never read by the engine or
     * renderers; carried through so `hitTest` results can identify the item
     * without relying on array positions.
     */
    data?: TData;
};

LineDecorationStyle

type

Decoration fields for `Line`. Excludes `lineWidth`/`lineWidthPx`: a line's hit-test area is derived from its stroke width at registration time, so a paint-time decoration must not change it.

type LineDecorationStyle = Omit<LineStyle, "lineWidth" | "lineWidthPx">;

PathCommand

type

One drawing command of a free-form path, mirroring the Canvas2D path API. Coordinates and radii are world units (item space); angles are degrees (engine convention, like `rotate`) — renderers convert to radians.

type PathCommand = {
    type: "moveTo";
    x: number;
    y: number;
} | {
    type: "lineTo";
    x: number;
    y: number;
}
/**
 * Center-based circular arc from `startAngle` to `endAngle` (degrees,
 * 0 = +x axis, positive angles sweep clockwise in screen space). `ccw`
 * defaults to false. Like Canvas2D, a line connects the current point to
 * the arc's start when the subpath is already open.
 */
 | {
    type: "arc";
    x: number;
    y: number;
    radius: number;
    startAngle: number;
    endAngle: number;
    ccw?: boolean;
} | {
    type: "quadraticCurveTo";
    cpx: number;
    cpy: number;
    x: number;
    y: number;
} | {
    type: "bezierCurveTo";
    cp1x: number;
    cp1y: number;
    cp2x: number;
    cp2y: number;
    x: number;
    y: number;
} | {
    type: "closePath";
};

PathDecorationStyle

type

Decoration fields for `PathItem`. Excludes stroke width and corner radius: both feed hit-test geometry resolved at registration time, so a paint-time decoration must not change them.

type PathDecorationStyle = Omit<PathStyle, "lineWidth" | "lineWidthPx" | "cornerRadius" | "cornerRadiusPx">;

PathItem

type

A free-form path: either a `points` polyline or a Canvas2D-style `commands` list (curves, arcs, multiple subpaths, holes). `points` describes an open polyline; `closed` joins the last point back to the first. `commands` is fully free-form: each `moveTo` starts a new subpath, so one item can be an outline plus holes — under the `"evenodd"` fill rule any overlapping subpath punches a hole; under `"nonzero"` a hole must wind in the opposite direction of its outer ring. Setting `style.fillStyle` fills the shape (open subpaths close implicitly for filling, like Canvas2D `fill()`), and filled paths hit-test against their interior. Unfilled paths hit-test against the stroke itself.

type PathItem<TData = unknown> = {
    /**
     * Free-form command list. Mutually exclusive with {@link points}
     * when both are set, `commands` wins.
     */
    commands?: PathCommand[];
    /** Polyline vertices in world units (item space: integers are cell centers). */
    points?: Coords[];
    /**
     * Join the last point back to the first with a closing segment.
     * `points` form only — with `commands`, use a `closePath` command.
     */
    closed?: boolean;
    /**
     * Fill rule used for filling and interior hit testing, mirroring Canvas2D:
     * `"nonzero"` (default) counts winding, `"evenodd"` alternates — the
     * difference shows on self-intersecting outlines (e.g. a star polygon).
     */
    fillRule?: "nonzero" | "evenodd";
    style?: PathStyle;
    /**
     * Arbitrary app data attached to the item. Never read by the engine or
     * renderers; carried through so `hitTest` results can identify the item
     * without relying on array positions.
     */
    data?: TData;
};

PathStyle

type

Per-item styling for PathItem. Same unit convention as elsewhere: plain values are world units and scale with zoom; `*Px` variants are screen pixels and take precedence over their world counterpart.

type PathStyle = {
    /** Fill color. Setting it makes the path a filled shape: the outline is
     * implicitly closed for filling and hit testing covers the interior. */
    fillStyle?: string;
    strokeStyle?: string;
    /** Stroke width in world units; scales with zoom. Ignored when
     * {@link lineWidthPx} is set. Default: 1px hairline. */
    lineWidth?: number;
    /** Stroke width in screen pixels, independent of zoom. */
    lineWidthPx?: number;
    /** Dash pattern in world units (anchored to the world, scales with zoom).
     * Ignored when {@link lineDashPx} is set. Omit for a solid line. */
    lineDash?: number[];
    /** Dash pattern in screen pixels, independent of zoom. */
    lineDashPx?: number[];
    /** Corner rounding radius in world units, applied at every interior
     * vertex of `points` (and the closing corners when `closed`). `points`
     * form only — with `commands`, draw arcs explicitly. Ignored when
     * {@link cornerRadiusPx} is set. */
    cornerRadius?: number;
    /** Corner rounding radius in screen pixels, independent of zoom. */
    cornerRadiusPx?: number;
};

RawOrigin

type

Raw `origin` as authored on a draw item — every field optional.

type RawOrigin = {
    mode?: "cell" | "self";
    x?: number;
    y?: number;
};

Rect

type

No API description is included in the published TypeScript declaration for Rect.

type Rect<TData = unknown> = DrawObject<TData> & {
    /** Width in world units. Defaults to `size`, so square rects are unchanged. */
    width?: number;
    /** Height in world units. Defaults to `size`. */
    height?: number;
};

ShapeDecorationStyle

type

Decoration fields for `Rect`/`Circle` — the full shape style (stroke width does not feed shape hit testing, so nothing needs to be excluded).

type ShapeDecorationStyle = NonNullable<DrawObject["style"]>;

SpriteRect

type

A source rectangle inside a spritesheet image, in sheet pixels. Used to draw a sub-region (frame) of a larger image.

type SpriteRect = {
    x: number;
    y: number;
    w: number;
    h: number;
};

StyleOf

type

Paint-time decoration callback. Runs for each item on every frame; the returned fields overlay the item's own `style` for that frame only (`undefined` leaves the item untouched). Because it runs at paint time it reads external state live: mutate a selection set and call `render()` — the items are never re-registered and the spatial index never rebuilds. Identify items through `item.data` (the same convention as `hitTest` results); most items should return `undefined`.

type StyleOf<TItem, TStyle> = (item: TItem) => TStyle | undefined;

Text

type

No API description is included in the published TypeScript declaration for Text.

type Text<TData = unknown> = Omit<DrawObject<TData>, "radius" | "size"> & {
    text: string;
    /**
     * Font size in world units: the font's em box spans `size` world units, so
     * rendered pixel height is `size * scale` and text scales with zoom.
     * Ignored when {@link fontPx} is set. Default: 1
     */
    size?: number;
    /**
     * Fixed font size in CSS pixels, independent of zoom. Use for labels that
     * must stay readable at any zoom level. Takes precedence over {@link size}.
     */
    fontPx?: number;
    style?: {
        fillStyle?: string;
        /** Font family (default: "sans-serif") */
        fontFamily?: string;
        textAlign?: TextAlign;
        textBaseline?: TextBaseline;
    };
};

TextAlign

type

Horizontal text alignment. Mirrors the DOM `CanvasTextAlign` values but is declared locally so core's public types do not require the DOM lib (needed by non-DOM renderers such as React Native / Skia).

type TextAlign = "center" | "end" | "left" | "right" | "start";

TextBaseline

type

Vertical text baseline. Mirrors the DOM `CanvasTextBaseline` values; declared locally for the same platform-agnostic reason as TextAlign.

type TextBaseline = "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top";

TextDecorationStyle

type

Decoration fields for `Text` — the full text style.

type TextDecorationStyle = NonNullable<Text["style"]>;

VisibleOf

type

Per-item visibility callback. Runs at paint time on every frame (and at hit-query time for hit-tested kinds): return `false` to skip the item for that frame — it is neither painted nor hit-testable; `true`/`undefined` keeps it. Like StyleOf it reads external state live: mutate a filter set and call `render()` — the items are never re-registered and the spatial index never rebuilds.

type VisibleOf<TItem> = (item: TItem) => boolean | undefined;

ZoomMode

type

Anchor point for zoom interactions (wheel and pinch): - `"pointer"` — zoom toward the mouse cursor / pinch midpoint. - `"center"` — zoom toward the center of the canvas.

type ZoomMode = "pointer" | "center";

onClickCallback

type

No API description is included in the published TypeScript declaration for onClickCallback.

type onClickCallback = MouseEventCallback;

onDrawCallback

type

Post-frame draw hook. Mirrors the `addDrawFunction` callback signature: the platform context, the viewport's top-left world coordinate, the live normalized config (current scale and size), and the coordinate transform helpers.

type onDrawCallback = (ctx: unknown, coords: Coords, config: Required<CanvasTileEngineConfig>, transform: DrawTransform) => void;

onHoverCallback

type

No API description is included in the published TypeScript declaration for onHoverCallback.

type onHoverCallback = MouseEventCallback;

onMouseDownCallback

type

No API description is included in the published TypeScript declaration for onMouseDownCallback.

type onMouseDownCallback = MouseEventCallback;

onMouseLeaveCallback

type

No API description is included in the published TypeScript declaration for onMouseLeaveCallback.

type onMouseLeaveCallback = MouseEventCallback;

onMouseUpCallback

type

No API description is included in the published TypeScript declaration for onMouseUpCallback.

type onMouseUpCallback = MouseEventCallback;

onRightClickCallback

type

No API description is included in the published TypeScript declaration for onRightClickCallback.

type onRightClickCallback = MouseEventCallback;

onWheelCallback

type

Fired for wheel (desktop) and pinch (touch) zoom gestures. The coordinate payloads match the other pointer callbacks; for pinch they describe the pinch midpoint.

type onWheelCallback = (coords: {
    raw: Coords;
    snapped: Coords;
}, mouse: {
    raw: Coords;
    snapped: Coords;
}, client: {
    raw: Coords;
    snapped: Coords;
}, wheel: WheelInfo) => void;

onZoomCallback

type

No API description is included in the published TypeScript declaration for onZoomCallback.

type onZoomCallback = (scale: number) => void;

Constants

ARC_SEGMENT_LENGTH

constant

Default max spacing between flattened arc samples. Callers pass values in the same unit as their points: renderers use it as screen pixels, the hit tester divides by the camera scale to sample identically in world units.

const ARC_SEGMENT_LENGTH: unknown

COORDINATE_OVERLAY

constant

No API description is included in the published TypeScript declaration for COORDINATE_OVERLAY.

const COORDINATE_OVERLAY: {
    /** Coordinate overlay border width in pixels */
    readonly BORDER_WIDTH: 20;
    /** Coordinate text opacity */
    readonly TEXT_OPACITY: 0.8;
    /** Border overlay opacity */
    readonly BORDER_OPACITY: 0.1;
    /** Minimum font size for coordinate labels */
    readonly MIN_FONT_SIZE: 8;
    /** Maximum font size for coordinate labels */
    readonly MAX_FONT_SIZE: 12;
    /** Font size scale factor relative to camera scale */
    readonly FONT_SIZE_SCALE_FACTOR: 0.25;
}

DEBUG_HUD

constant

No API description is included in the published TypeScript declaration for DEBUG_HUD.

const DEBUG_HUD: {
    /** Debug HUD panel width in pixels */
    readonly PANEL_WIDTH: 160;
    /** Debug HUD padding in pixels */
    readonly PADDING: 8;
    /** Debug HUD line height in pixels */
    readonly LINE_HEIGHT: 16;
}

DEFAULT_VALUES

constant

Global constants for the canvas grid engine. Centralizes magic numbers and configuration values.

const DEFAULT_VALUES: {
    /** Default animation duration in milliseconds */
    readonly ANIMATION_DURATION_MS: 500;
    /** Pixel offset for centering cells (0.5 = center of pixel) */
    readonly CELL_CENTER_OFFSET: 0.5;
    /** Default retry count for image loading */
    readonly IMAGE_LOAD_RETRY_COUNT: 1;
    /** Maximum wheel delta value for zoom (prevents extreme zooming) */
    readonly MAX_WHEEL_DELTA: 100;
    /** Minimum wheel delta value for zoom */
    readonly MIN_WHEEL_DELTA: -100;
    /** Zoom sensitivity factor */
    readonly ZOOM_SENSITIVITY: 0.001;
}

RENDER_DEFAULTS

constant

No API description is included in the published TypeScript declaration for RENDER_DEFAULTS.

const RENDER_DEFAULTS: {
    /** Default background color */
    readonly BACKGROUND_COLOR: "#ffffff";
}

SCALE_LIMITS

constant

No API description is included in the published TypeScript declaration for SCALE_LIMITS.

const SCALE_LIMITS: {
    /** Default minimum scale multiplier */
    readonly MIN_SCALE_MULTIPLIER: 0.5;
    /** Default maximum scale multiplier */
    readonly MAX_SCALE_MULTIPLIER: 2;
}

SIZE_LIMITS

constant

No API description is included in the published TypeScript declaration for SIZE_LIMITS.

const SIZE_LIMITS: {
    /** Default minimum canvas width in pixels */
    readonly MIN_WIDTH: 100;
    /** Default minimum canvas height in pixels */
    readonly MIN_HEIGHT: 100;
    /** Default maximum width (infinity means no limit) */
    readonly MAX_WIDTH: number;
    /** Default maximum height (infinity means no limit) */
    readonly MAX_HEIGHT: number;
}

VISIBILITY_BUFFER

constant

No API description is included in the published TypeScript declaration for VISIBILITY_BUFFER.

const VISIBILITY_BUFFER: {
    /** Buffer zone for visibility culling (tiles) */
    readonly TILE_BUFFER: 1;
}