Shared types
The declarations more than one group names — everything else is documented on the page of the group that uses it.
- ChkSection
- ChkFile
- StringTable
- UnitRecord
- SpriteRecord
- DoodadRecord
- LocationRecord
- Forces
- PlayerRgb
- UnitSettings
- UnitAvailability
- UpgradeSettings
- UpgradeRestrictions
- TechSettings
- TechRestrictions
- CuwpSlot
- ConditionRecord
- ActionRecord
- TriggerRecord
- Scenario
- MapVersion
- TilesetId
- TerrainName
- Rect
- Diamond
- IsomCheck
- FogMode
- SpriteKind
- EditorLayer
- TerrainMode
- DialogId
- MapImageOptions
- UnitChange
- PlayerSlotView
- ForceView
- WeaponView
- UnitTypeView
- UpgradeLevelsView
- UpgradeView
- TechStateView
- TechView
- SoundRow
- CuwpSlotView
- Side
- PLUGIN_API_VERSION
- Disposable
- PluginManifest
- Deactivate
- PluginActivate
- PluginModule
- PluginInfo
- WidgetOptions
- pluginIdOf
ChkSectioninterface
interface ChkSection
CHK is a flat stream of chunks: 4-byte name, int32 length, then that many bytes.
StarCraft applies chunks sequentially into fixed-size buffers, so a section that
appears twice is not "last one wins" — the later copy overwrites only as many bytes
as it carries. Protected maps lean on this constantly, so the reader keeps every
occurrence in file order and layer() reproduces the overwrite semantics.
name: string | 4-character chunk name, latin1. May contain junk in protected maps. |
|---|---|
offset: number | Byte offset of the chunk's name within the CHK. |
declaredSize: number | Length field as written, which may disagree with |
data: Uint8Array | |
truncated?: boolean | Set when the declared size ran past the end of the file. |
ChkFileinterface
interface ChkFile
sections: ChkSection[] | |
|---|---|
trailing?: Uint8Array | Bytes after the last parseable chunk header, if any. |
StringTableinterface
interface StringTable
STR/STRx string table.
Index 0 means "no string" and is never stored. Indices are referenced from TRIG, MRGN, SPRP and friends — several of which we round-trip as raw bytes — so the table must keep its index space stable across a save. Entries are therefore addressed by position, never renumbered.
strings: (string | null)[] |
|
|---|---|
extended: boolean | True when the source section was STRx (Remastered, 32-bit count and offsets). |
UnitRecordinterface
interface UnitRecord
serial: number | |
|---|---|
x: number | |
y: number | |
unitId: number | |
relationType: number | |
validProperties: number | Bit set of which "special properties" fields below are meaningful. |
validStates: number | |
owner: number | |
hitPointsPercent: number | |
shieldPercent: number | |
energyPercent: number | |
resourceAmount: number | |
hangarUnits: number | |
stateFlags: number | |
unused: number | |
relatedSerial: number |
SpriteRecordinterface
interface SpriteRecord
spriteId: number | sprites.dat id for a pure sprite, units.dat id for a unit sprite (see |
|---|---|
x: number | |
y: number | |
owner: number | |
unused: number | |
flags: number |
|
DoodadRecordinterface
interface DoodadRecord
One placed doodad, as StarEdit records it (the game never reads this section: it sees
only the doodad's tiles in MTXM and its overlay in THG2). doodadId is the index into
the tileset's dddata.bin, not a CV5 group; x/y are the pixel centre of the
footprint, so the top-left tile is x / 32 - width / 2.
doodadId: number | |
|---|---|
x: number | |
y: number | |
owner: number | |
disabled: number | 0 = enabled (every doodad in Blizzard's maps), 1 = disabled. |
LocationRecordinterface
interface LocationRecord
left: number | |
|---|---|
top: number | |
right: number | |
bottom: number | |
nameIndex: number | |
elevationFlags: number | Bit 0 low ground, 1 medium, 2 high, 3 low air, 4 medium air, 5 high air. |
Forcesinterface
interface Forces
playerForce: number[] | Force index (0-3) each of the 8 playable slots belongs to. |
|---|---|
nameIndex: number[] | String index of each force's name. |
flags: number[] | Bit 0 random start, 1 allied, 2 allied victory, 3 shared vision. |
PlayerRgbinterface
interface PlayerRgb
rgb: [ number, number, number ][] |
|
|---|---|
mode: number[] | A |
UnitSettingsinterface
interface UnitSettings
useDefault: Uint8Array | 1 = the game uses units.dat / weapons.dat for this type and ignores the columns below. |
|---|---|
hitPoints: Uint32Array | Fixed point: hit points × 256, like units.dat. |
shields: Uint16Array | |
armor: Uint8Array | |
buildTime: Uint16Array | Game frames (15 per second at Fastest). |
mineralCost: Uint16Array | |
gasCost: Uint16Array | |
nameIndex: Uint16Array | String index of the custom name, 0 for the default one. |
weaponDamage: Uint16Array | Per weapons.dat id, always |
weaponBonus: Uint16Array |
UnitAvailabilityinterface
interface UnitAvailability
Which players may build which unit types. Three tables, player-major (puniIndex):
a per-player answer, the global default, and whether each player defers to it.
playerAvailable: Uint8Array | 1 = the player can build the type; read only where |
|---|---|
defaultAvailable: Uint8Array | 1 = the type is available to every player that uses the default. |
playerUsesDefault: Uint8Array | 1 = the player takes |
UpgradeSettingsinterface
interface UpgradeSettings
Research cost per upgrade: a base and a per-level factor for minerals, gas and time. Struct of arrays over 61 upgrades; the original sections only store the first 46.
useDefault: Uint8Array | 1 = the game uses upgrades.dat for this upgrade and ignores the columns below. |
|---|---|
mineralCost: Uint16Array | |
mineralFactor: Uint16Array | |
gasCost: Uint16Array | |
gasFactor: Uint16Array | |
timeCost: Uint16Array | Game frames. |
timeFactor: Uint16Array |
UpgradeRestrictionsinterface
interface UpgradeRestrictions
How far each player may research each upgrade and where they start. Player-major
tables (upgradeIndex), a global default pair, and a per-player "use the default" flag.
playerMax: Uint8Array | |
|---|---|
playerStart: Uint8Array | |
defaultMax: Uint8Array | |
defaultStart: Uint8Array | |
playerUsesDefault: Uint8Array |
TechSettingsinterface
interface TechSettings
useDefault: Uint8Array | 1 = the game uses techdata.dat for this ability. |
|---|---|
mineralCost: Uint16Array | |
gasCost: Uint16Array | |
researchTime: Uint16Array | Game frames. |
energyCost: Uint16Array |
TechRestrictionsinterface
interface TechRestrictions
Whether each player may research each ability and whether they start with it. Same shape as UpgradeRestrictions.
playerAvailable: Uint8Array | |
|---|---|
playerResearched: Uint8Array | |
defaultAvailable: Uint8Array | |
defaultResearched: Uint8Array | |
playerUsesDefault: Uint8Array |
CuwpSlotinterface
interface CuwpSlot
validProperties: number |
|
|---|---|
validFields: number |
|
owner: number | Unused by the game; StarEdit writes 0. |
hitPointsPercent: number | |
shieldsPercent: number | |
energyPercent: number | |
resources: number | |
hangar: number | |
stateFlags: number |
|
unused: number | The record's last four bytes, kept for fidelity. |
ConditionRecordinterface
interface ConditionRecord
location: number | 1-based location number, 0 = none. |
|---|---|
player: number |
|
amount: number | |
unitId: number | |
comparison: number |
|
type: number |
|
resource: number |
|
flags: number |
|
mask: number | EUD mask word; 0 in ordinary maps. |
ActionRecordinterface
interface ActionRecord
location: number | 1-based source location, 0 = none. |
|---|---|
text: number | String index for text / comment / leaderboard label, 0 = none. |
wav: number | String index of the WAV file name, 0 = none. |
time: number | Milliseconds for Wait / Transmission / Talking Portrait; WAV duration for Play WAV. |
player: number |
|
target: number | Second player / destination location / amount / AI script code, per type. |
unitId: number | Unit id / |
type: number |
|
modifier: number | Unit count (0 = all) / |
flags: number |
|
padding: number | |
mask: number | EUD mask word; 0 in ordinary maps. |
TriggerRecordinterface
interface TriggerRecord
conditions: ConditionRecord[] | |
|---|---|
actions: ActionRecord[] | |
flags: number |
|
players: number[] | 27 bytes, one per |
currentAction: number | The game's bookkeeping byte (offset 2399); StarEdit writes 0. |
Scenariointerface
interface Scenario
A parsed scenario.
chk holds every original section in file order and is the fidelity anchor: sections
we do not model are re-emitted byte for byte, so opening and saving a map we only
partly understand does not destroy the parts we don't. Only names listed in dirty
are re-encoded on save.
chk: ChkFile | |
|---|---|
dirty: Set<string> | |
warnings: string[] | |
type: string | TYPE, e.g. "RAWB" for Brood War. |
fileVersion: number | VER: 59 original, 63 hybrid, 205 Brood War, 206 Remastered. |
width: number | |
height: number | |
era: number | ERA value as stored; the meaningful tileset is |
strings: StringTable | |
nameIndex: number | |
descriptionIndex: number | |
playerTypes: number[] | |
editorPlayerTypes: number[] | null | IOWN: StarEdit's own copy of the player types — what its Player Settings dialog shows, where the game reads OWNR. The editor keeps the two in step; a file where they differ (another tool wrote one and not the other) is flagged by Check Map. Null when the file has no section. |
playerRaces: number[] | |
playerColors: number[] | |
playerRgb: PlayerRgb | null | CRGB, Remastered's per-slot colour choice; null when the file has none (every client then reads COLR). |
forces: Forces | |
unitSettings: UnitSettings | null | UNIx if the file has one, else UNIS; null when it has neither (every type on its dat defaults). |
unitAvailability: UnitAvailability | null | PUNI; null when the file has none (everything buildable by everyone). |
upgradeSettings: UpgradeSettings | null | UPGx if the file has one, else UPGS; null when it has neither (every upgrade on its dat costs). |
upgradeRestrictions: UpgradeRestrictions | null | PUPx else UPGR; null when absent (every player on the dat level caps, starting at 0). |
techSettings: TechSettings | null | TECx else TECS; null when absent. |
techRestrictions: TechRestrictions | null | PTEx else PTEC; null when absent (everything researchable, nothing researched). |
wavs: number[] | null | WAV: 512 string indices of the map's sound paths; null when the file has no section. |
cuwp: CuwpSlot[] | null | UPRP: the 64 Create Unit with Properties slots (the action names one 1-based); null when the file has no section. |
cuwpUsed: boolean[] | null | UPUS: StarEdit's "slot in use" byte per CUWP slot; null when the file has no section. |
tiles: Uint16Array | MTXM: what the game draws — terrain with the doodads stamped over it. |
editorTiles: Uint16Array | TILE: StarEdit's copy of the terrain without doodads (a doodad's cells hold the
ground it was placed on). Terrain brushes write both arrays; placing a doodad writes
only |
isom: Uint16Array | null | |
mask: Uint8Array | null | |
units: UnitRecord[] | |
sprites: SpriteRecord[] | |
doodads: DoodadRecord[] | |
locations: LocationRecord[] | |
triggers: TriggerRecord[] | TRIG, in execution order. |
briefing: TriggerRecord[] | MBRF: mission briefings, same record layout with briefing action types. |
switchNames: number[] | null | SWNM: string index per switch (0 = unnamed); null when the file has no section. |
MapVersiontype
type MapVersion = "original" | "hybrid" | "broodwar" | "remastered";
TilesetIdtype
type TilesetId = "badlands" | "platform" | "install" | "ashworld" | "jungle" | "desert" | "ice" | "twilight";
StarCraft tileset reference data.
TerrainNameinterface
interface TerrainName
One ISOM terrain type: its id is the CV5 index of the flat left/right group pair
that draws it, and the value the ISOM section stores for it.
id: number | |
|---|---|
name: string |
IsomCheckinterface
interface IsomCheck
rects: number | Rects that have tiles under them. |
|---|---|
mismatched: number | Rects whose tiles are not what their ISOM resolves to (doodad tiles are excused). |
SpriteKindtype
type SpriteKind = "pure" | "unit";
EditorLayertype
type EditorLayer = "terrain" | "doodads" | "units" | "sprites" | "locations" | "fog" | "clipboard";
The classic SCMDraft layer combo; "clipboard" is Cut / Copy / Paste.
TerrainModetype
type TerrainMode = "isom" | "rect" | "tile" | "blend";
DialogIdtype
type DialogId = "newMap" | "openMap" | "saveAs" | "exportImage" | "mapProperties" | "resizeMap" | "mapRevision" | "playerSettings" | "forceSettings" | "playerColors" | "unitSettings" | "upgradeSettings" | "techSettings" | "stringEditor" | "soundEditor" | "switches" | "locationList" | "unitProperties" | "locationProperties" | "spriteProperties" | "triggerEditor" | "textTriggerEditor" | "missionBriefing" | "cuwpEditor" | "replaceTerrain" | "autoStarts" | "testMap" | "symmetry" | "gridSettings" | "preferences" | "shortcuts" | "validateMap" | "statistics" | "importTriggers" | "exportTriggers" | "importStrings" | "exportStrings" | "find" | "about" | "confirmClose" | "plugins" | "confirmPlugin" | "pluginDialog" | "gameData" | "update";
Every built-in dialog, by the id openDialogAtom takes; DialogHost maps each to its component.
MapImageOptionsinterface
interface MapImageOptions
pixelsPerTile: number | Output pixels per map tile. 32 matches the game's art 1:1; 1 is a minimap. |
|---|---|
units: boolean | |
sprites: boolean | |
locations: boolean | |
locationNames: boolean | |
startLocations: boolean | |
fog: boolean | |
fogPlayer: number | Whose fog is drawn (0-based player), when |
grid: number | Grid spacing in map pixels (32 = one tile); 0 for no grid. |
rect?: Rect | null | The part of the map to draw, in tiles (exclusive |
UnitChangeinterface
interface UnitChange
Unit edits as invertible change lists, in the same spirit as terrain's TileChange.
before/after are whole records: null before is an insertion at index, null
after a removal, both set a replacement. Removals are listed highest index first so
that applying them in order keeps the remaining indices valid; undo walks the list
backwards and so re-inserts lowest first.
index: number | |
|---|---|
before: UnitRecord | null | |
after: UnitRecord | null |
PlayerSlotViewinterface
interface PlayerSlotView
slot: number | 0-based; the chrome shows it as |
|---|---|
type: number | |
typeName: string | |
race: number | |
raceName: string | |
color: number | null | COLR index; null for the four unplayable slots. |
colorHex: string | null | The colour the chrome shows for the slot (CRGB-aware). |
rgb: [ number, number, number ] | null | The CRGB custom triple when one is in effect. |
force: number | null | 0-based force; null for the unplayable slots. |
forceName: string | null |
ForceViewinterface
interface ForceView
force: number | 0-based. |
|---|---|
name: string | |
flags: number | |
allied: boolean | |
alliedVictory: boolean | |
sharedVision: boolean | |
randomStart: boolean | |
players: number[] | 0-based playable slots in the force. |
UnitTypeViewinterface
interface UnitTypeView
id: number | |
|---|---|
name: string | The game's name (or the custom one when the map sets it). |
customName: string | The custom name the map sets, |
useDefault: boolean | |
hitPoints: number | Whole hit points. |
shields: number | |
armor: number | |
buildTime: number | Game frames. |
mineralCost: number | |
gasCost: number | |
weapons: WeaponView[] | The type's ground and air weapons (a turreted vehicle's are its turret's), with the effective damage. |
defaults: { hitPoints: number; shields: number; armor: number; buildTime: number; mineralCost: number; gasCost: number; weapons: WeaponView[]; } | null | units.dat / weapons.dat, null without the game data. |
availability: { defaultAvailable: boolean; players: (boolean | "default")[]; } | PUNI: whether the type can be built by default, and per player ( |
UpgradeLevelsViewinterface
interface UpgradeLevelsView
start: number | |
|---|---|
max: number | |
usesDefault: boolean |
UpgradeViewinterface
interface UpgradeView
id: number | |
|---|---|
name: string | |
useDefault: boolean | |
mineralCost: number | |
mineralFactor: number | |
gasCost: number | |
gasFactor: number | |
timeCost: number | Game frames. |
timeFactor: number | |
defaults: { mineralCost: number; mineralFactor: number; gasCost: number; gasFactor: number; timeCost: number; timeFactor: number; maxLevel: number; } | null | upgrades.dat, null without the game data. |
levels: { defaultStart: number; defaultMax: number; players: UpgradeLevelsView[]; } | UPGR / PUPx: the default start and cap, and each of the 12 players' (effective, with |
TechStateViewinterface
interface TechStateView
available: boolean | |
|---|---|
researched: boolean | |
usesDefault: boolean |
TechViewinterface
interface TechView
id: number | |
|---|---|
name: string | |
useDefault: boolean | |
mineralCost: number | |
gasCost: number | |
researchTime: number | Game frames. |
energyCost: number | |
defaults: { mineralCost: number; gasCost: number; researchTime: number; energyCost: number; } | null | |
state: { defaultAvailable: boolean; defaultResearched: boolean; players: TechStateView[]; } | PTEC / PTEx: the default column and each of the 12 players' effective state. |
SoundRowinterface
interface SoundRow
slot: number | |
|---|---|
stringIndex: number | |
path: string | The path as the string table has it. |
present: boolean | Whether the archive carries a member at that path. |
size: number | Bytes in the archive, 0 when absent. |
member: string | null | The archive member's name as stored (case may differ from the path). |
usedBy: string[] |
CuwpSlotViewinterface
interface CuwpSlotView
The slot as a patch-shaped view: null where the unit's default applies.
index: number | |
|---|---|
used: boolean | |
references: number | How many Create Unit with Properties actions name the slot. |
hitPointsPercent: number | null | |
shieldsPercent: number | null | |
energyPercent: number | null | |
resources: number | null | |
hangar: number | null | |
cloaked: boolean | null | |
burrowed: boolean | null | |
inTransit: boolean | null | |
hallucinated: boolean | null | |
invincible: boolean | null | |
summary: string |
PLUGIN_API_VERSIONconst
const PLUGIN_API_VERSION = 1
The version a host provides; a manifest that asks for a newer one is refused. It stays at 1 while the API is only used by the plugins in the scm-js organisation and grows with them — the first incompatible change after outside plugins exist bumps it.
PluginManifestinterface
interface PluginManifest
plugin.json, next to the entry file. Only name is required.
name: string | |
|---|---|
id?: string | Stable identifier (storage prefix, log prefix); derived from the name when absent. |
version?: string | |
description?: string | |
author?: string | |
homepage?: string | |
entry?: string | Entry file relative to the manifest; |
build?: string | A built, self-contained JavaScript bundle of the plugin, relative to the manifest
(
|
icon?: string | The plugin's face in Manage Plugins and on its own dialogs: an emoji ( |
api?: number | The |
Deactivatetype
type Deactivate = void | (() => void) | Disposable;
What activate may hand back: nothing, a cleanup function, or a Disposable.
PluginActivatetype
type PluginActivate = (api: PluginApi) => Deactivate | Promise<Deactivate>;
PluginModuleinterface
interface PluginModule
The shape of the entry module: export default function activate(api) {…}, or
export default { activate }, or export function activate(api) {…}.
activate: PluginActivate |
|---|
PluginInfointerface
interface PluginInfo
id: string | Manifest id (or slug of the name). |
|---|---|
name: string | |
source: string | The spec the plugin was installed from ( |
version?: string | |
icon?: PluginIcon | The manifest's |
pluginIdOffunction
function pluginIdOf(manifest: {
id?: string;
name: string;
}): string;
A slug for storage keys and log prefixes.