scmJS docs

api.events

EventsApi

Listeners are notifications: they run after the change, in the order the plugins were activated, and cannot veto or reorder one another. A listener that rewrites the map in response (through document.sections) simply raises a fresh "document" event with reason "replace", which every other listener sees in turn.

Members

on

on(event: "document", listener: (event: DocumentEvent) => void): Disposable;
api.events.on("document", (e) => {
  if (e.reason === "open") api.ui.status(`Opened ${e.fileName ?? "a map"}`);
});
const selection = api.events.on("selection", () => api.log(`${api.selection.units().length} units selected`));
// Stop listening early; otherwise the listener goes when the plugin is turned off.
setTimeout(() => selection.dispose(), 60_000);
Try it

on

on(event: "commit", listener: (event: CommitEvent) => void): Disposable;

on

on(event: PluginEvent, listener: () => void): Disposable;

Types

Declarations only this group names.

CommitReasontype

type CommitReason = "edit" | "undo" | "redo" | "tables" | "whole" | "remote";

Why the map changed: an edit recorded in the history, an undo or redo of one, a dialog writing its tables (settings, triggers, strings), a change to the whole document (resize, tileset change, raw section edit), or other people's edits on a shared map.

CommitPartsinterface

interface CommitParts

Which parts of the map one commit touched.

terrain: boolean
isom: boolean
units: boolean
doodads: boolean
sprites: boolean
locations: boolean
fog: boolean
settings: boolean
triggers: boolean

Localetype

type Locale = "en" | "ko";

LanguagePreferencetype

type LanguagePreference = "auto" | Locale;

"auto" follows the browser (or the desktop app's system language).

HotkeyOverridestype

type HotkeyOverrides = Record<string, string[]>;

What Preferences.hotkeys holds: the commands the user changed, each with its whole list ([] = no keys).

RemasteredEffectsinterface

interface RemasteredEffects

The adjustable part of Remastered's moving water and lava (viewport/effectPass.ts). How far the picture bends and how the ripple layers drift are the game's own figures; how large the ripples lie on the map and how fast their pictures change are not in its files, so these start from values set by eye and can be moved.

bend: number

How far water bends the ground under it, as a multiple of the game's amount. 0 leaves it still.

glint: number

How much the ripples catch the light. 0 is none.

large: number

The size of the large, slow ripples and of the fine ones over them, in map pixels a repeat.

fine: number
rate: number

How many ripple pictures go by a second.

heat: number

How far lava's heat reaches, in map pixels at its strongest. 0 leaves it still.

Preferencesinterface

interface Preferences
language: LanguagePreference

The editor's own language: "auto" follows the browser's (the system's, in the desktop app), else one of LOCALES. Applied live.

splash: boolean

Show the splash while the game data loads; off starts straight on the editor.

confirmClose: boolean

Ask before closing or replacing a map with unsaved changes.

multipleMaps: boolean

Open each map beside the ones already open, in its own tab, rather than in place of the open one. Off is StarEdit's one map at a time: Open and New replace the map, asking about unsaved changes first. Either way the blank map the editor starts on, untouched, is replaced by the first map opened rather than kept beside it.

newMap: { tileset: TilesetId; width: number; height: number; version: NewMapVersion; }

What File ▸ New and the startup map start with. version is the file's revision: Brood War (VER 205, what every build reads) or Remastered (206, 32-bit strings).

startup: { reopenLast: boolean; recents: number; }

Startup: reopenLast opens the most recent file again in place of the blank map (the desktop app straight away; a browser needs a click first, so it asks in a notice), and recents is how many File ▸ Open Recent keeps.

save: { start: "asOpened" | "everything" | "smallest"; compression: "asOpened" | ArchiveCompression; backup: boolean; }

What the Save dialog starts from: the options the file was opened with ("asOpened", the default), or one of its presets. compression is for a map with no origin — new, or opened from a bare .chk — where there is nothing to follow; "asOpened" there means StarEdit's PKWARE. backup keeps the file a save writes over: <name>.bak beside it in the desktop app, the browser's storage otherwise (services/previousVersions.ts).

recovery: { enabled: boolean; minutes: number; }

Recovery copies (hooks/useRecovery.ts): while a map has unsaved changes, a copy of it is kept in the browser's storage every minutes and when the editor goes to the background, and dropped when the map is saved or closed. What a session that ended without saving left behind is offered back at the next start. Off stops the copies and drops this session's; copies left by earlier sessions are still offered.

undoLevels: number

How many edits Undo keeps per map (SCMDraft keeps 200).

view: { wheel: "scroll" | "zoom"; zoomToCursor: boolean; }

The mouse wheel over the map: scrolling, with Ctrl+wheel zooming (the default), or zooming, with Shift+wheel scrolling sideways. zoomToCursor keeps the tile under the pointer in place when the wheel zooms; the menu and keyboard keep the centre.

placement: { owner: number; brushSize: number; locationTiles: number; }

What the palettes start on: the owner of placed units and sprites (0 = player 1), the brush size (1–7), and the size of a location the Locations palette's New makes, in tiles.

animateWater: boolean

Initial View ▸ Animate Water / Animate Units.

animateUnits: boolean
hdGraphics: boolean

Initial View ▸ Remastered Graphics: the 2x terrain and sprites, where the data set in use has them.

remasteredEffects: RemasteredEffects

How Remastered's water and lava move — the part of the effect the game's files do not fix.

animateWaterSpeed: number

How fast the two animations run, as a multiple of the game's own speed (1 = the game's "Fastest"). One of ANIMATION_SPEEDS; applied live, not just at startup.

animateUnitsSpeed: number
classicText: boolean

Preview the <XX> colour codes in strings the way 1.16.1 drew them: the colour resets at every line break. Off is Remastered's rule, which carries a colour onto the next line — see editor/textColors.ts. It changes only what the editor draws, never the map, and every preview in the chrome reads it.

testMap: { launch: boolean; dir: string; }

Tools ▸ Test Map: whether to start the game after writing the map (desktop build), and the game folder to use when the desktop build should not search ("" = search). The browser's folder is a handle in IndexedDB (services/handleStore.ts), not here.

updates: { checkOnStart: boolean; nightly: boolean; }

The desktop build's in-app updates (editor/updates.ts, desktop/updater.ts); the browser build shows none of this, having nothing to update. checkOnStart asks GitHub for a newer version a few seconds after launch and raises a toast when there is one. nightly follows the nightly channel instead of the numbered releases — one-way in practice, since going back to a stable release is a downgrade the updater will not offer.

plugins: { updates: PluginUpdateMode; }

What to do when an installed plugin has a newer release than the one running (plugins/updates.ts). notify looks a few seconds after the plugins start and raises a notice with a button to the rows offering the update; manual asks nothing until Check for update is pressed on a row; auto installs what it finds, for the plugins the user added — a default moves with the editor's own releases and is only ever named in the notice. Every mode leaves the confirmation on a row's button alone.

hotkeys: HotkeyOverrides

Preferences ▸ Hotkeys: the commands whose keys the user changed, by command id (editor/commands.ts), each with its whole list — [] leaves it with none. A command not here has the keys it ships with.

statusBar: StatusBarCells

Which cells the status bar shows (Preferences ▸ View). The message, the symmetry badge while a mode is on, and the plugins' items always show.

StatusBarCellsinterface

interface StatusBarCells

See Preferences.statusBar, in the order the bar draws them.

tile: boolean
pixel: boolean
tileId: boolean
size: boolean
tileset: boolean
layer: boolean
zoom: boolean
revision: boolean

PluginUpdateModetype

type PluginUpdateMode = "notify" | "manual" | "auto";

See Preferences.plugins.updates.

NewMapVersiontype

type NewMapVersion = Extract<MapVersion, "broodwar" | "remastered">;

The revisions a new map can start on; the two older ones are for opening old files, not making new ones.

PluginEventtype

type PluginEvent = 
/** A map was opened, closed or replaced. */
"document"
/** A change was committed to the map in front; the listener gets a `CommitEvent` saying what and where. */
 | "commit"
/** The editor's language changed (Preferences ▸ Display): re-label what is showing through `api.i18n.t`. */
 | "language"
/** Any committed edit (every `document.edit`, stroke, undo and redo bumps it, terrain or not), and a fog edit. */
 | "terrain" | "units" | "doodads" | "locations" | "settings" | "triggers" | "layer"
/** THG2 sprites — the same bump doodad edits make. */
 | "sprites" | "selection"
/** The marked area or the clip on the clipboard changed. */
 | "clipboard"
/** The viewport scrolled, zoomed, or a View menu tick moved. */
 | "view"
/** A map tool or a map pick started or stopped. */
 | "tool"
/** The map's unsaved-changes flag changed. */
 | "modified"
/** A palette's pick changed: terrain brush, unit and owner, sprite, doodad, fog players. */
 | "palette"
/** An editing option moved: symmetry, placement rules, doodad rules, location snap, the fog view player, clip parts and paste mode, locked layers, the grid look, Preferences. */
 | "options"
/** The document's file changed: its name or handle after a Save, the save options, the archive extras, the recent list. */
 | "file"
/** A plugin registered or removed a command — how a plugin learns that one it calls by id has arrived. */
 | "commands"
/** A plugin provided or withdrew a service — `services.watch` is the usual way to hear this for one name. */
 | "services"
/** A dialog opened or closed — `ui.openDialogs()` says which are open. */
 | "dialogs"
/** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
 | "gameData";

CommitEventinterface

interface CommitEvent

What the "commit" event hands its listeners: one change to the map in front, after it is in the scenario. Every stroke, document.edit, undo and redo is one commit; so is a dialog's OK or a document.update (reason "tables"), a resize, tileset change or raw section edit ("whole"), and a batch of other people's edits on a shared map ("remote"). A dialog that writes both settings and triggers may send two. Opening, closing and switching maps are not commits — the "document" event says those.

id: number | null

document.id() of the map it happened to (always the one in front).

reason: CommitReason
label: string

The history label — the words Edit ▸ Undo shows, in the editor's language; for an undo or redo, the label of the entry taken back or put back. The update's label for a document.update, the operation's name for "whole", and "" for a built-in dialog's OK and for other people's edits.

area: Rect | null

The tiles the change fell on, far edges exclusive: every changed tile, and the tile under each moved, placed or removed object's position (its picture reaches further — widen the rect by the largest picture you draw). Null when the change has no place on the map ("tables") or may have touched all of it ("whole", "remote").

parts: CommitParts

Which parts changed. All of them for "whole" and "remote", which do not say.

// Flash where each change landed, and log what kind of change it was.
api.events.on("commit", (e) => {
  if (e.area) api.view.flash({ rect: e.area, kind: "attention" });
  const parts = Object.entries(e.parts).filter(([, changed]) => changed).map(([part]) => part);
  api.log(e.reason, e.label, parts);
});
Try it

DocumentChangeReasontype

type DocumentChangeReason = 
/** File ▸ Open, drag-and-drop, `document.open`: a file the user chose. */
"open"
/** File ▸ New (the startup map included). */
 | "new"
/** File ▸ Close: `document.isOpen()` is now false. */
 | "close"
/** The open map parsed again from edited bytes — a `document.sections` write, by any plugin. */
 | "replace"
/**
 * Another open map came to the front — a tab clicked, `document.activate`, or the map
 * in front closed with others still open. Nothing was read or written; the map that
 * was in front is still open behind, as it was. `id` says which map is in front now.
 */
 | "switch";

Why the document changed.

DocumentEventinterface

interface DocumentEvent
reason: DocumentChangeReason
fileName: string | null
id: number | null

document.id() after the change: the map now in front, or null after a close.

Seen in

scmJS 0.7.3 + main@e2d8ba5 · Generated from the repository. The source is under the MIT license, which does not cover what ATTRIBUTION.md lists. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.