api.ui
UiApi
Everything a plugin puts on the screen: the status line, toasts, dialogs, floating
panels, confirm / alert / prompt / progress, a map tool that owns the pointer,
a passive overlay drawn over the map, and picking an area or a tile.
- status
- statusText
- toast
- saveFile
- dialog
- panel
- mapTool
- overlay
- pickFiles
- pickArea
- pickTile
- loadImage
- readClipboardImage
- confirm
- alert
- prompt
- progress
- el
- widgets
- open
- ask
- repaint
Members
toast
toast(toast: { kind?: Toast["kind"]; title: string; detail?: string; ttl?: number; }): void;
A short notice over the map that leaves by itself — how Save reports; ttl 0 keeps it until dismissed.
saveFile
saveFile(data: Blob | Uint8Array, fileName: string): Promise<{ route: "picker" | "download"; fileName: string; } | null>;
Write a file to disk the way the editor's own exports do: into the file the browser's save dialog picks, or as a download where there is no dialog. Resolves with where it went, or null when the user dismissed the dialog.
dialog
dialog(spec: DialogSpec): DialogHandle;
panel
panel(spec: PanelSpec): PanelHandle;
Open a floating panel over the map. As many as you like; each closes with the plugin.
mapTool
mapTool(spec: MapToolSpec): MapToolHandle;
Take over the pointer on the map until stop(), Esc, a right-click, a map change
or another tool. One tool runs at a time — starting one stops the previous — and a
pickArea / pickTile in progress is served first.
overlay
overlay(spec: OverlaySpec): OverlayHandle;
A picture over the map the user can switch on and off (View ▸ Overlays, the Layers panel) and that stays while they work on any layer. It draws at every repaint and hears the pointer, but never takes it. As many as you like; they go with the plugin.
pickFiles
pickFiles(options?: PickFilesOptions): Promise<File[]>;
The browser's file picker; resolves with an empty list on cancel.
pickArea
pickArea(options?: PickOptions): Promise<Rect | null>;
Let the user drag a rectangle on the map. The viewport switches to a crosshair, draws
the marquee and takes the gesture ahead of the active layer's tools; resolves with
the tile rect (exclusive x1 / y1), or null when the user pressed Esc or
right-clicked, no map is open, the map was replaced, or the plugin was disabled.
Only one pick runs at a time — a new one cancels the previous. A modal dialog
covers the map, so close yours first and reopen it with the result.
pickTile
pickTile(options?: PickOptions): Promise<{ x: number; y: number; } | null>;
As pickArea, for a single click: the tile under it.
loadImage
loadImage(source: Blob | string): Promise<ImageBitmap>;
Decode a picture: a File / Blob, a data: URL, or an http(s) URL (fetched, and
when the site refuses cross-origin reads, loaded through an <img> with
crossOrigin — a site that allows neither rejects with a message saying so).
readClipboardImage
readClipboardImage(): Promise<Blob | null>;
The image on the system clipboard, if the browser lets the page read it (a permission prompt may appear); null otherwise.
confirm
confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
Ask a yes/no question; resolves false on Cancel, Escape or the ×.
alert
alert(message: string, options?: ConfirmOptions): Promise<void>;
Say something with a single OK.
prompt
prompt(message: string, options?: PromptOptions): Promise<string | null>;
Ask for a line of text; null when the user cancelled.
progress
progress(label: string, options?: ProgressOptions): ProgressHandle;
A progress bar over the map for long work, with an optional Cancel.
el
el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Record<string, unknown>, ...children: WidgetChild[]): HTMLElementTagNameMap[K];
el("div", { className: "row" }, …): the DOM helper the widgets are built from.
open
open(dialog: DialogId, payload?: Record<string, unknown>): void;
Open a built-in dialog (fire and forget; ask waits for one that answers).
ask
ask(dialog: DialogId, payload?: Record<string, unknown>): Promise<boolean>;
Open a built-in dialog that answers — "saveAs", "confirmClose", "newMap" — and
resolve true when it went through, false when it was dismissed.
repaint
repaint(): void;
Ask the viewport to repaint (a transaction does this by itself). Raises no event.
Types
Declarations only this group names.
Toastinterface
interface Toast
A short notice over the map that leaves by itself — what a save says when it is done, since the status bar line is easy to miss and the menubar dot only stops glowing.
id: number | |
|---|---|
kind: "ok" | "info" | "warn" | "error" | |
title: string | |
detail?: string | |
ttl: number | Milliseconds before it leaves on its own; 0 keeps it until dismissed. |
action?: { label: string; run: () => void; } | One button beside the text, for a notice that is really a question — the update check's "Download". Pressing it dismisses the toast as well as running this. |
DialogSizetype
type DialogSize = "sm" | "md" | "lg" | "xl" | "full";
DialogButtoninterface
interface DialogButton
label: string | |
|---|---|
primary?: boolean | |
run?: (dialog: DialogHandle) => void | boolean | Promise<void | boolean> | Return |
closes?: boolean | Close after |
DialogTransferinterface
interface DialogTransfer
What a paste or a drop brought into a dialog.
files: File[] | |
|---|---|
text: string |
DialogSpecinterface
interface DialogSpec
title: string | |
|---|---|
size?: DialogSize | |
tall?: boolean | |
mount(body: HTMLElement, dialog: DialogHandle): void | (() => void) | Fill |
buttons?: DialogButton[] | Footer buttons, left to right; a single Close when omitted. |
onPaste?: (transfer: DialogTransfer, dialog: DialogHandle) => void | Ctrl+V anywhere in the dialog (while it is the topmost one). Files come from the
clipboard's items — a screenshot pastes as one |
onDrop?: (transfer: DialogTransfer, dialog: DialogHandle) => void | Something dropped onto the dialog body. |
keepOpenOnEscape?: (target: EventTarget | null) => boolean | Escape normally closes the dialog. Answer true to keep it open for this press — when the key was meant for something inside the dialog that handles Escape itself (a code editor dismissing its own popups), judged by the element it landed on. |
DialogHandleinterface
interface DialogHandle
close(): void | |
|---|---|
isOpen(): boolean | Whether the dialog is still on screen. |
setTitle(title: string): void | Change the title strip's text. |
PanelSpecinterface
interface PanelSpec
A panel floats over the map and does not block it: the user keeps drawing, scrolling
and using hotkeys while it is open (except while typing in one of its fields). It
is dragged by its title bar and closed with the × or close().
title: string | |
|---|---|
width?: number | In CSS pixels; 260 by default. The panel is as tall as its content, up to the map's height. |
mount(body: HTMLElement, panel: PanelHandle): void | (() => void) | Fill |
onClose?: () => void | The panel closed, whichever way. |
PanelHandleinterface
interface PanelHandle
close(): void | |
|---|---|
isOpen(): boolean | |
setTitle(title: string): void |
MapPointerinterface
interface MapPointer
The pointer over the map, in the map's own units. A tile is 32 × 32 pixels.
px: number | Map pixels. Kept inside the map while a button is held, as the built-in brushes do. |
|---|---|
py: number | |
tx: number | The tile under the pointer. |
ty: number | |
inMap: boolean | False once the pointer has left the map with no button held. |
down: boolean | Whether the primary button is held. |
shift: boolean | |
ctrl: boolean | |
alt: boolean |
MapViewinterface
interface MapView
Map pixels to canvas pixels, for a tool's draw.
zoom: number | |
|---|---|
tilePx: number | Canvas pixels per tile. |
x(px: number): number | A map pixel's x on the canvas. |
y(py: number): number | |
visible: Rect | The tiles on screen. |
MapToolStopReasontype
type MapToolStopReason =
/** `handle.stop()`. */
"stopped"
/** Esc or a right-click, and `onCancel` did not keep the tool. */
| "cancelled"
/** The map was closed or replaced. */
| "document"
/** Another tool started. */
| "replaced"
/** The plugin was disabled. */
| "disabled";
MapToolSpecinterface
interface MapToolSpec
A tool owns the pointer over the map: the viewport hands it every press, move and release ahead of the active layer's own tools, hides the layer's brush ghost, and lets it draw an overlay. The map stays visible and scrollable, and a panel can stay open beside it — which is how a plugin gets a drawing mode of its own.
name: string | Shown in the viewport's HUD and the status bar while the tool runs. |
|---|---|
hint?: string | After the name: |
cursor?: string | CSS cursor over the map; |
onDown?(p: MapPointer): void | |
onMove?(p: MapPointer): void | Every pointer move over the map, button held or not, and once with |
onUp?(p: MapPointer): void | |
onCancel?(): boolean | void | Esc or a right-click. Return |
draw?(ctx: CanvasRenderingContext2D, view: MapView): void | Draw over the map, after everything else, each time the viewport repaints. |
onStop?(reason: MapToolStopReason): void | The tool is no longer running, for whatever reason (once). |
MapToolHandleinterface
interface MapToolHandle
stop(): void | |
|---|---|
isActive(): boolean | |
redraw(): void | Repaint the viewport — and so call |
OverlayAbovetype
type OverlayAbove =
/** Over the terrain and grid, under doodad footprints, units, sprites and locations (the default). */
"terrain"
/** Over units, sprites and locations, under fog of war. */
| "objects"
/** Over everything but a running map tool's own drawing. */
| "everything";
Where in the viewport's paint pass an overlay draws.
OverlaySpecinterface
interface OverlaySpec
An overlay is a picture drawn over the map that the user can turn on and off: it
is listed under View ▸ Overlays and in the Layers panel, stays while the user works
on any layer, and never takes the pointer — clicks go to the active layer's tools
as usual. It hears the pointer through onHover, which is how a readout follows the
mouse while the user places units. Register one at activation and keep the handle;
it goes away with the plugin.
name: string | Shown in View ▸ Overlays and the Layers panel. Unique per plugin. |
|---|---|
visible?: boolean | Start visible; true by default. What the user last set for this name wins for the session. |
above?: OverlayAbove | Where the picture goes in the paint pass; |
draw(ctx: CanvasRenderingContext2D, view: MapView): void | Draw in canvas pixels through |
onHover?(p: MapPointer | null): void | The pointer over the map while the overlay is visible, on every layer and while a
map tool runs; |
onToggle?(visible: boolean): void | The overlay was shown or hidden, by the user in the chrome or by your handle. |
OverlayHandleinterface
interface OverlayHandle
show(): void | |
|---|---|
hide(): void | |
toggle(): void | |
isVisible(): boolean | |
redraw(): void | Repaint the viewport — and so call |
remove(): void | Take the overlay out of the chrome for good; |
PickOptionsinterface
interface PickOptions
prompt?: string | Shown in the viewport's HUD while the user picks; also the status line. |
|---|
PickFilesOptionsinterface
interface PickFilesOptions
accept?: string |
|
|---|---|
multiple?: boolean |
ConfirmOptionsinterface
interface ConfirmOptions
title?: string | |
|---|---|
confirmLabel?: string | The primary button; |
cancelLabel?: string | |
danger?: boolean | Paint the primary button as a destructive action. |
PromptOptionsinterface
interface PromptOptions
value?: string | |
|---|---|
placeholder?: string | |
multiline?: boolean | A multi-line field. |
ProgressOptionsinterface
interface ProgressOptions
title?: string | |
|---|---|
cancellable?: boolean | Show a Cancel button; |
ProgressHandleinterface
interface ProgressHandle
A progress panel over the map. It does not block the editor — the user can still
scroll and look — so a plugin doing long work should report often and check
cancelled() in its loop.
report(fraction: number, text?: string): void | How far along (0…1), and optionally a line under the bar. |
|---|---|
cancelled(): boolean | True once the user pressed Cancel or closed the panel. Poll it inside a loop. |
readonly signal: AbortSignal | The same answer as a signal, for work that takes one: aborted when the user
cancels, so |
done(): void | |
isOpen(): boolean |
WidgetChildtype
type WidgetChild = Node | string | number | null | undefined | false;
Anything the widget builders accept as a child: a node, text, or nothing.
ButtonOptionsinterface
interface ButtonOptions
primary?: boolean | |
|---|---|
danger?: boolean | |
ghost?: boolean | |
onClick?: (event: MouseEvent) => void |
CheckboxOptionsinterface
interface CheckboxOptions
value?: boolean | |
|---|---|
radio?: boolean | A radio button instead; give the group a |
name?: string | |
onChange?: (value: boolean) => void |
CheckboxElementtype
type CheckboxElement = HTMLLabelElement & {
input: HTMLInputElement;
};
The <label> a checkbox is, with its <input> on it so you can read or set the value.
TextFieldOptionsinterface
interface TextFieldOptions
value?: string | |
|---|---|
placeholder?: string | |
password?: boolean | |
onChange?: (value: string) => void |
NumberFieldOptionsinterface
interface NumberFieldOptions
value?: number | |
|---|---|
min?: number | |
max?: number | |
step?: number | |
onChange?: (value: number) => void |
SelectOptioninterface
interface SelectOption
value: string | number | |
|---|---|
label: string | |
disabled?: boolean |
SelectOptionsinterface
interface SelectOptions
value?: string | number | |
|---|---|
onChange?: (value: string) => void |
ListIteminterface
interface ListItem
label: string | |
|---|---|
value: T | |
hint?: string | Dimmed text at the end of the row. |
index?: number | A number in the row's gutter, as the editor's own lists show indices. |
title?: string |
ListOptionsinterface
interface ListOptions
selected?: number | Which row starts selected. |
|---|---|
height?: number | Maximum height in pixels; the list scrolls past it. |
className?: string | |
onPick?: (value: T, index: number) => void |
WidgetsApiinterface
interface WidgetsApi
Buttons, fields, forms and lists in the editor's own styles, as plain DOM. A plugin
dialog built from these looks like a built-in one; el is the escape hatch for
anything they do not cover.
button(label: string, options?: ButtonOptions): HTMLButtonElement | |
|---|---|
checkbox(label: string, options?: CheckboxOptions): CheckboxElement | |
text(options?: TextFieldOptions): HTMLInputElement | |
number(options?: NumberFieldOptions): HTMLInputElement | |
select(items: SelectOption[], options?: SelectOptions): HTMLSelectElement | |
form(rows: (FormRow | null | undefined | false)[]): HTMLElement | A two-column grid of labelled fields. |
group(title: string, ...children: WidgetChild[]): HTMLElement | A titled box (a |
row(...children: WidgetChild[]): HTMLDivElement | |
column(...children: WidgetChild[]): HTMLDivElement | |
hint(text: string): HTMLElement | Small dimmed explanatory text. |
separator(): HTMLElement | |
list<T>(items: ListItem<T>[], options?: ListOptions<T>): HTMLElement |