Table of Contents

Mapper

Generated from smudgy v0.5.4-dev (smudgy-core.d.ts @ a1c9d1939ffb, smudgy-mapper.d.ts @ 5d586b4dc546). Index: scriptref.

The map API: import { mapper } from "smudgy:core". The map types (Area, Room, …) need no import; import the Area value only for runtime instanceof checks.

For common workflows and coordinate conventions, see Work with maps.

The mapper

mapper

export const mapper: Mapper;

The current session's map API (see Mapper).

Area

export const Area: {
  readonly prototype: Area;
  [Symbol.hasInstance](value: unknown): boolean;
};

The runtime area constructor, for checks such as area instanceof Area. Areas are created by the mapper; the constructor is not a creation API.

Mapper contract

Mapper

interface Mapper {
    refreshAreas(): Promise<void>;
    createArea(name: string, options?: CreateAreaOptions): Promise<Area>;
    listAtlases(): Promise<Atlas[]>;
    createAtlas(name: string, options: CreateAtlasOptions): Promise<Atlas>;
    copyAreas(areas: (Area | AreaId)[], destination: MapDestination): Promise<Area[]>;
    moveAreas(areas: (Area | AreaId)[], destination: MapDestination): Promise<Area[]>;
    copyArea(area: Area | AreaId, destination: MapDestination): Promise<Area>;
    moveArea(area: Area | AreaId, destination: MapDestination): Promise<Area>;
    copyAtlas(atlas: Atlas | AtlasId, storage: "local" | "cloud"): Promise<Atlas>;
    moveAtlas(atlas: Atlas | AtlasId, storage: "local" | "cloud"): Promise<Atlas>;
    setCurrentLocation(areaId: AreaId, roomNumber?: RoomNumber): void;
    getCurrentLocation(): { area: AreaId; room?: RoomNumber } | undefined;
    readonly areas: Area[];
    getAreaById(id: AreaId): Area;
    mutateArea(
        area: Area | AreaId,
        callback: (mutation: AreaMutator) => void | Promise<void>,
        options?: MutateAreaOptions,
    ): Promise<OperationId[]>;
    getPathBetweenRooms(
        fromAreaId: AreaId,
        fromRoomNumber: RoomNumber,
        toAreaId: AreaId,
        toRoomNumber: RoomNumber,
    ): [AreaId, RoomNumber][];
    listRoomsByTitleAndDescription(title: string, description: string): (Room | undefined)[];
    listRoomsByTitleDescriptionAndVisibleExits(
        title: string,
        description: string,
        visibleExitDirections: string[],
    ): (Room | undefined)[];
    renameArea(area: Area | AreaId, name: string): Promise<void>;
    deleteArea(area: Area | AreaId): Promise<void>;
    setRoomTitle(area: Area | AreaId, room: Room | RoomNumber, title: string): Promise<OperationId | null>;
    setRoomDescription(area: Area | AreaId, room: Room | RoomNumber, description: string): Promise<OperationId | null>;
    setRoomColor(area: Area | AreaId, room: Room | RoomNumber, color: string): Promise<OperationId | null>;
    setRoomLevel(area: Area | AreaId, room: Room | RoomNumber, level: number): Promise<OperationId | null>;
    setRoomX(area: Area | AreaId, room: Room | RoomNumber, x: number): Promise<OperationId | null>;
    setRoomY(area: Area | AreaId, room: Room | RoomNumber, y: number): Promise<OperationId | null>;
    setRoomProperty(area: Area | AreaId, room: Room | RoomNumber, name: string, value: string): Promise<OperationId | null>;
    setAreaProperty(area: Area | AreaId, name: string, value: string): Promise<OperationId | null>;
    addRoomTag(area: Area | AreaId, room: Room | RoomNumber, tag: string): Promise<OperationId | null>;
    removeRoomTag(area: Area | AreaId, room: Room | RoomNumber, tag: string): Promise<OperationId | null>;
    findNearestRoomWithTag(from: Room, tag: string): Room | undefined;
    findNearestRoomWithTags(
        from: Room,
        filter: { all?: string[]; none?: string[] },
    ): Room | undefined;
    findNearestRoomInArea(from: Room, area: Area | AreaId): Room | undefined;
    findRoomByExternalId(externalId: string): Room | undefined;
    rescueRoomByExternalId(externalId: string): boolean;
    setRoomExternalId(area: Area | AreaId, room: Room | RoomNumber, externalId: string): Promise<OperationId | null>;
    createRoom(area: Area | AreaId, params: CreateRoomParams): Promise<RoomNumber>;
    updateRoom(area: Area | AreaId, room: Room | RoomNumber, fields: UpdateRoomParams): Promise<OperationId | null>;
    updateRooms(area: Area | AreaId, updates: [RoomNumber, UpdateRoomParams][]): Promise<OperationId[]>;
    createRoomExit(area: Area | AreaId, room: Room | RoomNumber, exit: ExitArgs): Promise<ExitId>;
    setRoomExit(area: Area | AreaId, room: Room | RoomNumber, exitId: ExitId, exit: ExitUpdates): Promise<OperationId | null>;
    mergeRooms(area: Area | AreaId, keep: Room | RoomNumber, remove: Room | RoomNumber): Promise<OperationId | null>;
    deleteRoom(area: Area | AreaId, room: Room | RoomNumber): Promise<OperationId | null>;
    deleteRoomExit(area: Area | AreaId, room: Room | RoomNumber, exitId: ExitId): Promise<OperationId | null>;
    createLink(area: Area | AreaId, link: LinkCreateArgs): Promise<ConnectionId>;
    setConnection(area: Area | AreaId, connectionId: ConnectionId, updates: ConnectionUpdates): Promise<OperationId | null>;
    unlinkRoomExit(area: Area | AreaId, exitId: ExitId): Promise<ConnectionId>;
    pairConnections(area: Area | AreaId, keepConnectionId: ConnectionId, mergeConnectionId: ConnectionId): Promise<OperationId | null>;
    deleteLink(area: Area | AreaId, connectionId: ConnectionId): Promise<OperationId | null>;
    createLabel(area: Area | AreaId, label: LabelArgs): Promise<LabelId>;
    createShape(area: Area | AreaId, shape: ShapeArgs): Promise<ShapeId>;
    deleteLabel(area: Area | AreaId, labelId: LabelId): Promise<OperationId | null>;
    deleteShape(area: Area | AreaId, shapeId: ShapeId): Promise<OperationId | null>;
    setLabel(area: Area | AreaId, labelId: LabelId, updates: LabelUpdates): Promise<OperationId | null>;
    setShape(area: Area | AreaId, shapeId: ShapeId, updates: ShapeUpdates): Promise<OperationId | null>;
    exportArea(area: Area | AreaId): Promise<AreaJson>;
    importAreas(areas: AreaJson[]): Promise<AreaId[]>;
    importArea(area: AreaJson): Promise<AreaId>;
    importAreasIfAbsent(areas: AreaJson[]): Promise<AreasImportedIfAbsent>;
}

The map API for the current session. Each session has its own current location; changes to persistent areas sync to the cloud in the background.

Atlases & storage

Atlas

interface Atlas {
    readonly id: AtlasId;
    readonly name: string;
    readonly storage: MapStorage;
    toString(): string;
}

An atlas (map folder). Session storage does not support atlases.

AtlasId

type AtlasId = readonly [number, number];

An atlas (map folder) identifier, opaque like AreaId.

CreateAtlasOptions

interface CreateAtlasOptions {
    storage: "local" | "cloud";
}

MapStorage

type MapStorage = "session" | "local" | "cloud";

Where a map is stored. Session maps disappear when the session closes.

MapDestination

interface MapDestination {
    storage: MapStorage;
    atlas?: Atlas | AtlasId;
}

A destination used by map copy and move operations.

AreaMutator

interface AreaMutator {
    createRoom(params: CreateRoomParams): Promise<RoomNumber>;
    updateRoom(room: Room | RoomNumber, fields: UpdateRoomParams): Promise<void>;
    updateRooms(updates: [RoomNumber, UpdateRoomParams][]): Promise<void>;
    setRoomTitle(room: Room | RoomNumber, title: string): Promise<void>;
    setRoomDescription(room: Room | RoomNumber, description: string): Promise<void>;
    setRoomColor(room: Room | RoomNumber, color: string): Promise<void>;
    setRoomLevel(room: Room | RoomNumber, level: number): Promise<void>;
    setRoomX(room: Room | RoomNumber, x: number): Promise<void>;
    setRoomY(room: Room | RoomNumber, y: number): Promise<void>;
    setRoomExternalId(room: Room | RoomNumber, externalId: string): Promise<void>;
    setRoomProperty(room: Room | RoomNumber, name: string, value: string): Promise<void>;
    setAreaProperty(name: string, value: string): Promise<void>;
    addRoomTag(room: Room | RoomNumber, tag: string): Promise<void>;
    removeRoomTag(room: Room | RoomNumber, tag: string): Promise<void>;
    createRoomExit(room: Room | RoomNumber, exit: ExitArgs): Promise<ExitId>;
    setRoomExit(room: Room | RoomNumber, exitId: ExitId, exit: ExitUpdates): Promise<void>;
    deleteRoom(room: Room | RoomNumber): Promise<void>;
    deleteRoomExit(room: Room | RoomNumber, exitId: ExitId): Promise<void>;
    createLink(link: LinkCreateArgs): Promise<ConnectionId>;
    setConnection(connectionId: ConnectionId, updates: ConnectionUpdates): Promise<void>;
}

Callback-scoped collector used by Mapper.mutateArea. Calls update a callback-local draft and are submitted only after the callback completes.

MutateAreaOptions

interface MutateAreaOptions {
    description?: string;
}

OperationId

type OperationId = readonly [number, number];

A queued mapper mutation's identifier, opaque like ExitId.

Areas & rooms

Area

interface Area {
    readonly id: AreaId;
    readonly uuid: string;
    readonly name: string;
    readonly room_numbers: RoomNumber[];
    readonly isEphemeral: boolean;
    readonly storage: MapStorage;
    readonly next_room_number: RoomNumber;
    room(roomNumber: number): Room | undefined;
    data(key: string): string | undefined;
    readonly labels: Label[];
    readonly shapes: Shape[];
    readonly connections: Connection[];
    toString(): string;
}

A map area. You get areas from the mapper (mapper.areas, mapper.getAreaById), never by constructing one. For a runtime check, import the constructor: import { Area } from "smudgy:core".

Room

interface Room {
    readonly room_number: RoomNumber;
    readonly area_id: AreaId;
    readonly title: string;
    readonly externalId: string | undefined;
    readonly description: string;
    readonly level: number;
    readonly x: number;
    readonly y: number;
    readonly color: string;
    readonly exits: Exit[];
    data(key: string): string | undefined;
    readonly tags: string[];
    hasTag(tag: string): boolean;
    update(fields: UpdateRoomParams): Promise<OperationId | null>;
    toString(): string;
}

A room read from the map. Obtain one via area.room(n) or the listRooms* helpers.

Exit

interface Exit {
    readonly id: ExitId;
    readonly from_direction: ExitDirection;
    readonly from_area_id: AreaId;
    readonly from_room_number: RoomNumber;
    readonly to_direction: ExitDirection | null;
    readonly to_area_id: AreaId | null;
    readonly to_room_number: RoomNumber | null;
    readonly is_hidden: boolean;
    readonly is_closed: boolean;
    readonly is_locked: boolean;
    readonly weight: number;
    readonly command: string | null;
}

One exit read back from a room (room.exits). Optional links are present but null when unset (not omitted).

CreateAreaOptions

interface CreateAreaOptions {
    storage?: MapStorage;
    atlas?: Atlas | AtlasId;
    ephemeral?: boolean;
}

Options for Mapper.createArea.

CreateRoomParams

interface CreateRoomParams {
    title?: string;
    description?: string;
    level?: number;
    x?: number;
    y?: number;
    color?: string;
    externalId?: string;
}

Fields accepted when creating a room (mapper.createRoom). Any omitted field takes its default.

UpdateRoomParams

type UpdateRoomParams = CreateRoomParams;

Fields accepted when updating a room (mapper.updateRoom/Room.update): the same set as creation. Any omitted field is left unchanged.

ExitArgs

interface ExitArgs {
    from_direction: ExitDirection;
    to_direction?: ExitDirection;
    to_area_id?: AreaId;
    to_room_number?: RoomNumber;
    is_hidden?: boolean;
    is_closed?: boolean;
    is_locked?: boolean;
    weight?: number;
    command?: string;
}

Fields accepted when creating an exit (mapper.createRoomExit). Only from_direction is required. Visual appearance (routing, dash, color, thickness) lives on the shared Connection, not the exit.

ExitUpdates

interface ExitUpdates {
    from_direction?: ExitDirection;
    to_direction?: ExitDirection;
    to_area_id?: AreaId;
    to_room_number?: RoomNumber;
    is_hidden?: boolean;
    is_closed?: boolean;
    is_locked?: boolean;
    weight?: number;
    command?: string;
}

Fields accepted when updating an exit (mapper.setRoomExit). Any omitted field is left unchanged.

AreaJson

type AreaJson = Record<string, unknown>;

A portable area export, produced by Mapper.exportArea and consumed by Mapper.importArea/Mapper.importAreas. Treat it as opaque: export it, store it, import it back, but do not depend on its internal shape.

AreasImportedIfAbsent

interface AreasImportedIfAbsent {
    readonly added: AreaId[];
    readonly skipped: string[];
}

The outcome of Mapper.importAreasIfAbsent.

Connections

Connection

interface Connection {
    readonly id: ConnectionId;
    readonly endpoint_a: ConnectionEndpoint;
    readonly endpoint_b: ConnectionEndpoint | null;
    readonly kind: ConnectionKind;
    readonly routing: ConnectionRouting;
    readonly segment_shape: ConnectionSegmentShape;
    readonly corner: ConnectionCorner;
    readonly route_points: MapPoint[];
    readonly dash: ConnectionDash;
    readonly color: string;
    readonly thickness: number;
}

Shared topology, route, and appearance for one or two member Exits.

ConnectionEndpoint

interface ConnectionEndpoint {
    room_number: RoomNumber;
    side: RoomSide;
    port_offset: number;
    port_mode: PortMode;
}

A Connection's wall attachment on one room.

MapPoint

interface MapPoint {
    x: number;
    y: number;
}

One interior Connection centerline vertex in area coordinates.

ConnectionUpdates

interface ConnectionUpdates {
    endpoint_a?: ConnectionEndpoint;
    endpoint_b?: ConnectionEndpoint;
    routing?: ConnectionRouting;
    segment_shape?: ConnectionSegmentShape;
    corner?: ConnectionCorner;
    route_points?: MapPoint[];
    dash?: ConnectionDash;
    color?: string;
    thickness?: number;
}

Geometry/appearance fields accepted by Mapper.setConnection.

LinkTraversalArgs

interface LinkTraversalArgs extends ExitArgs {
    room_number: RoomNumber;
}

One directed Exit to create as a member of a new Connection.

LinkCreateArgs

interface LinkCreateArgs extends ConnectionUpdates {
    endpoint_a: ConnectionEndpoint;
    endpoint_b?: ConnectionEndpoint;
    traversals: LinkTraversalArgs[];
}

One atomic link creation: Connection first, followed by one or two traversals.

Labels & shapes

Label

interface Label {
    readonly id: LabelId;
    readonly level: number;
    readonly x: number;
    readonly y: number;
    readonly width: number;
    readonly height: number;
    readonly horizontal_alignment: LabelHorizontalAlign;
    readonly vertical_alignment: LabelVerticalAlign;
    readonly text: string;
    readonly color: string;
    readonly background_color: string;
    readonly font_size: number;
    readonly font_weight: number;
}

A text label read back from an area (area.labels).

LabelArgs

interface LabelArgs {
    x: number;
    y: number;
    width: number;
    height: number;
    text: string;
    level?: number;
    horizontal_alignment?: LabelHorizontalAlign;
    vertical_alignment?: LabelVerticalAlign;
    color?: string;
    background_color?: string;
    font_size?: number;
    font_weight?: number;
}

Fields accepted when creating a label (mapper.createLabel). Position, size, and text are required; any omitted field takes its default.

LabelUpdates

interface LabelUpdates {
    x?: number;
    y?: number;
    width?: number;
    height?: number;
    text?: string;
    level?: number;
    horizontal_alignment?: LabelHorizontalAlign;
    vertical_alignment?: LabelVerticalAlign;
    color?: string;
    background_color?: string;
    font_size?: number;
    font_weight?: number;
}

Fields accepted when updating a label (mapper.setLabel). Any omitted field is left unchanged.

Shape

interface Shape {
    readonly id: ShapeId;
    readonly level: number;
    readonly x: number;
    readonly y: number;
    readonly width: number;
    readonly height: number;
    readonly background_color: string | null;
    readonly stroke_color: string | null;
    readonly shape_type: ShapeKind;
    readonly border_radius: number;
    readonly stroke_width: number;
}

A graphical shape read back from an area (area.shapes).

ShapeArgs

interface ShapeArgs {
    x: number;
    y: number;
    width: number;
    height: number;
    level?: number;
    background_color?: string;
    stroke_color?: string;
    shape_type?: ShapeKind;
    border_radius?: number;
    stroke_width?: number;
}

Fields accepted when creating a shape (mapper.createShape). Position and size are required; any omitted field takes its default.

ShapeUpdates

interface ShapeUpdates {
    x?: number;
    y?: number;
    width?: number;
    height?: number;
    level?: number;
    background_color?: string;
    stroke_color?: string;
    shape_type?: ShapeKind;
    border_radius?: number;
    stroke_width?: number;
}

Fields accepted when updating a shape (mapper.setShape). Any omitted field is left unchanged.

Identifiers & enums

AreaId

type AreaId = readonly [number, number];

An area's identifier. Treat it as opaque: take it from one mapper call and pass it back to another, unchanged. Careful: this is not the same as the UUID string the map:room event delivers; mapper calls accept only the pair. Real ids carry BigInt halves (see ConnectionId), which JSON.stringify rejects — so mapper-issued ids cannot travel session-store writes or store bindings. Where an area scope must ride JSON — store-bound MapView apply arrays — use the UUID string spelling instead: MapStyleApplication.area in smudgy:widgets accepts either form.

RoomNumber

type RoomNumber = number;

A room number within an area (a 32-bit integer).

ExitId

type ExitId = readonly [number, number];

An exit's identifier: a 2-element [hi, lo] pair, like AreaId. Opaque.

ConnectionId

type ConnectionId = readonly [number, number];

A Connection's identifier, opaque like ExitId.

Careful: the [hi, lo] halves are 64-bit UUID halves. Values beyond Number.MAX_SAFE_INTEGER (essentially always for real ids) are delivered as BigInt, so despite this type's spelling the halves are bigint at runtime. JSON.stringify throws on BigInt, which means these ids cannot travel session-store writes or store bindings, and coercing a half with Number() rounds it and will silently never match. Pass ids straight back to mapper calls; for widget-facing selection use room + direction exit refs instead (see MapExitRef in smudgy:widgets).

LabelId

type LabelId = readonly [number, number];

A label's identifier: a 2-element [hi, lo] UUID pair, like AreaId. Opaque.

ShapeId

type ShapeId = readonly [number, number];

A shape's identifier: a 2-element [hi, lo] UUID pair, like AreaId. Opaque.

ExitDirection

type ExitDirection =
| "North"
| "East"
| "South"
| "West"
| "Up"
| "Down"
| "Northeast"
| "Northwest"
| "Southeast"
| "Southwest"
| "In"
| "Out"
| "Special"
| "Other";

A compass/special exit direction (the canonical PascalCase names).

RoomSide

type RoomSide = "North" | "East" | "South" | "West";

One of the four walls where a Connection attaches to a room.

PortMode

type PortMode = "AutoPinned" | "Manual";

Whether a port follows automatic wall redistribution or keeps an author-selected offset.

ConnectionKind

type ConnectionKind = "Internal" | "SelfLoop" | "Dangling" | "External" | "CrossLevel";

The topology represented by a Connection.

ConnectionRouting

type ConnectionRouting = "Stub" | "Simple" | "Manual" | "Automatic";

How a Connection's centerline is produced and stored.

ConnectionSegmentShape

type ConnectionSegmentShape = "Direct" | "Orthogonal";

Whether routed segments may be diagonal or must remain axis-aligned.

ConnectionCorner

type ConnectionCorner = "Sharp" | "Rounded";

How turns between Connection segments are drawn.

ConnectionDash

type ConnectionDash = "Solid" | "Dashed" | "Dotted";

The repeating stroke pattern used to draw a Connection.

LabelHorizontalAlign

type LabelHorizontalAlign = "Left" | "Center" | "Right";

Horizontal alignment of a label's text.

LabelVerticalAlign

type LabelVerticalAlign = "Top" | "Center" | "Bottom";

Vertical alignment of a label's text.

ShapeKind

type ShapeKind = "Rectangle" | "RoundedRectangle";

A shape's kind.


Script API reference · ← smudgy:widgets — Canvas · smudgy:params → · Scripting manual