Skip to main content
Version: Next

Types Reference

These types are defined in @canvas-tile-engine/core and re-exported by the @canvas-tile-engine/react and @canvas-tile-engine/react-native bindings (which also add EngineHandle). Import them from whichever package your app already depends on — a React or React Native app does not need a direct core dependency for types.

// Vanilla / server: import from core
import type { Rect, Circle, Text, Line, PathItem, PathStyle, ImageItem, Coords } from "@canvas-tile-engine/core";

// React / React Native: import the same types (plus EngineHandle) from the binding
import type { Rect, PathItem, PathCommand, LineStyle, DrawHandle, EngineHandle } from "@canvas-tile-engine/react";

Draw Objects​

Coords​

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

Rect​

type Rect = {
x: number;
y: number;
size?: number;
width?: number;
height?: number;
sizePx?: number;
widthPx?: number;
heightPx?: number;
origin?: { mode?: "cell" | "self"; x?: number; y?: number };
style?: {
fillStyle?: string;
strokeStyle?: string;
lineWidth?: number;
lineWidthPx?: number;
lineDash?: number[];
lineDashPx?: number[];
};
rotate?: number;
radius?: number | number[];
};

size, width, height, radius, style.lineWidth, and style.lineDash are world units and scale with zoom, so borders, corner rounding, and dash patterns stay proportional to the shape. sizePx, widthPx, heightPx, style.lineWidthPx and style.lineDashPx are zoom-independent screen-pixel variants and take precedence over their world counterparts (the same pattern as Text's size/fontPx). Per axis the specific field wins over the shared one, so the full order is widthPx → sizePx → width → size; the static variants ignore the pixel fields because their cache replays at a recorded scale. Dash patterns follow Canvas2D setLineDash semantics; omit them for a solid border. rotate is degrees, clockwise.

Circle​

type Circle = {
x: number;
y: number;
size?: number;
origin?: { mode?: "cell" | "self"; x?: number; y?: number };
style?: {
fillStyle?: string;
strokeStyle?: string;
lineWidth?: number;
lineWidthPx?: number;
lineDash?: number[];
lineDashPx?: number[];
};
};

The style fields follow the same unit convention as Rect.

Text​

type Text = {
x: number;
y: number;
text: string;
size?: number;
style?: {
fillStyle?: string;
fontFamily?: string;
textAlign?: "center" | "end" | "left" | "right" | "start";
textBaseline?: "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top";
};
rotate?: number;
};

size is a world-unit text size. Renderers currently draw the actual font at size * scale * 0.3, matching the existing Canvas2D behavior.

Line And Path​

type Line = {
from: Coords;
to: Coords;
style?: LineStyle; // per-item override of drawLine's call-level style
data?: TData; // app data, returned on hitTest results
};

type PathItem<TData = unknown> = {
commands?: PathCommand[]; // free-form Canvas2D-style commands (curves, arcs, holes)
points?: Coords[]; // polyline vertices in world units (one of the two required)
closed?: boolean; // join the last point back to the first (points form)
fillRule?: "nonzero" | "evenodd"; // fill rule, default "nonzero"
style?: PathStyle; // per-item fill/stroke/dash/corner styling
data?: TData; // app data, returned on hitTest results
};

type LineStyle = {
strokeStyle?: string;
lineWidth?: number; // world units, scales with zoom
lineWidthPx?: number; // screen pixels, wins over lineWidth
lineDash?: number[]; // dash pattern in world units, anchored to the world
lineDashPx?: number[]; // dash pattern in screen pixels, wins over lineDash
};

PathItem describes a free-form path (open polyline, closed outline, or filled shape); PathStyle extends the LineStyle fields with fillStyle and cornerRadius/cornerRadiusPx. drawLine takes a LineStyle as its second argument as the batch default; a Line item's own style overrides it per item, unit pair by unit pair (an item that sets either width or dash field replaces that whole pair, so a world-unit value is never shadowed by the batch's *Px value). Because item styles are registration-time, they may change lineWidth/lineWidthPx — hit testing follows the item's own width. Dash patterns follow Canvas2D setLineDash semantics (odd-length patterns repeat) and flow continuously around path corners.

ImageItem<TImage>​

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

type ImageItem<TImage = HTMLImageElement> = {
x: number;
y: number;
size?: number;
origin?: { mode?: "cell" | "self"; x?: number; y?: number };
rotate?: number;
img: TImage;
sprite?: SpriteRect;
};

TImage depends on the renderer:

RendererImage type
Canvas2D / WebGLHTMLImageElement
Skia / React NativeSkImage
Server@napi-rs/canvas Image

sprite crops a sub-rectangle from a spritesheet image before drawing.

DrawOptions​

type DrawOptions = {
id?: string;
};

Optional last parameter of every draw method. id gives the registration a stable identity: re-registering with the same id replaces the previous registration (draw callback plus hit-test entries) instead of accumulating. Ids share one namespace across draw kinds and layers; static draw methods use their cacheKey as the id instead.

StyleOf and Decoration Styles​

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

type ShapeDecorationStyle = NonNullable<DrawObject["style"]>; // Rect / Circle
type TextDecorationStyle = NonNullable<Text["style"]>;
type LineDecorationStyle = Omit<LineStyle, "lineWidth" | "lineWidthPx">;
type PathDecorationStyle = Omit<PathStyle, "lineWidth" | "lineWidthPx" | "cornerRadius" | "cornerRadiusPx">;

The dynamic draw methods additionally accept styleOf in their options (RectDrawOptions, CircleDrawOptions, TextDrawOptions, LineDrawOptions, PathDrawOptions — each extends DrawOptions). The callback runs per item on every frame at paint time; returned fields overlay the item's own style for that frame, undefined leaves it untouched. Line and path decorations exclude stroke width (and corner radius), because those feed hit-test geometry resolved at registration time.

VisibleOf and InteractiveOf​

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

Per-item siblings of StyleOf, accepted in the same options objects and read live the same way. visibleOf returning false skips the item for the frame — it is neither painted nor hit-testable. interactiveOf returning false keeps the item painted but transparent to hitTest/hitTestFirst/hitTestRect (the per-item counterpart of hitTest: false); queries fall through to items below. true/undefined keeps the default in both. A hidden item never hit-tests, regardless of interactiveOf. visibleOf exists on all six dynamic draw options (including ImageDrawOptions); interactiveOf on the hit-tested five (TextDrawOptions has no interactiveOf — text never enters hit testing). ImageDrawOptions carries no styleOf: images have no style, appearance changes go through item fields like opacity (read live at paint time; mutate + render()).

Sprite Helpers​

type SpriteSheetOptions = {
frameWidth: number;
frameHeight: number;
columns?: number;
margin?: number;
spacing?: number;
};

type SpriteAnimation = {
frames: SpriteRect[];
fps: number;
loop?: boolean;
};

Use SpriteSheet for frame math and SpriteAnimator for imperative animation. React and React Native also provide <CanvasTileEngine.Sprite>.

Callback Types​

Pointer callbacks share one shape:

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

Aliases:

type onClickCallback = MouseEventCallback;
type onRightClickCallback = MouseEventCallback;
type onHoverCallback = MouseEventCallback;
type onMouseDownCallback = MouseEventCallback;
type onMouseUpCallback = MouseEventCallback;
type onMouseLeaveCallback = MouseEventCallback;
type onZoomCallback = (scale: number) => void;

coords.raw is the exact world coordinate. coords.snapped is floored to the grid cell.

onWheelCallback And WheelInfo​

Fires for wheel (desktop) and pinch (touch) zoom gestures (requires eventHandlers.zoom). The first three arguments match the pointer callbacks; a fourth describes the gesture:

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

type WheelInfo = {
deltaY: number; // negative = zoom in; synthesized for pinch
direction: "in" | "out";
source: "wheel" | "pinch";
};

onDrawCallback​

type onDrawCallback = (
ctx: unknown,
coords: Coords, // top-left world coordinate of the viewport
config: Required<CanvasTileEngineConfig>, // live scale and size
transform: DrawTransform, // { worldToScreen, screenToWorld }
) => void;

The signature mirrors addDrawFunction callbacks, so custom drawing code can move between the two hooks unchanged.

ctx is renderer-specific:

  • CanvasRenderingContext2D for RendererCanvas.
  • The WebGL renderer's 2D overlay context for RendererWebGL.
  • SkCanvas for RendererSkia.
  • SKRSContext2D for RendererServer.

Engine Handles​

React packages expose safe handles from useCanvasTileEngine(). Methods no-op or return defaults before mount, and engine.isReady tells you when the core instance is attached.

Common methods:

engine.render();
engine.getCenter();
engine.getVisibleBounds();
engine.setCenter({ x: 0, y: 0 });
engine.goCenter(10, 10, 500);
engine.setScale(64);
engine.goScale(64, 500);
engine.zoomIn();
engine.zoomOut();
engine.setBounds({ minX: 0, maxX: 100, minY: 0, maxY: 100 });
engine.setEventHandlers({ drag: false, hover: true });
engine.loadImage("/sprite.png");