scmJS docs

Paint

scm-js/plugin-paint, a default — Tools ▸ Paint…, Ctrl+Shift+P, or Paint… on the map's right-click menu then opens a panel that floats over the map (api.ui.panel). Pick a tool in it — freehand, line, rectangle, ellipse, polygon, star, spray, text, eraser — and draw on the map; the brush is whatever the active layer's palette has picked (api.palette.active() and api.terrain.active(), refreshed on the "palette" and "layer" events): flat terrain or a tile, a doodad, a unit for a player, a sprite, or fog for some players. Closed shapes can be filled (grid, staggered grid, random), objects are spaced along the outline (auto = their own size) and can be jittered, units and sprites can cycle through players 1–8 or take random ones, and units can skip the spots the Units palette's placement checks refuse (tx.canPlaceUnit). Every stroke is one api.document.edit.

shapes.ts is the pure part and that repository's tests/shapes.test.ts pins it: a tool's drag becomes an outline Path (linePath, rectPath, ellipsePath, starPath, with constrainSquare / constrainAngle for Shift and boxFromCenter for Alt); objects come from samplePath (arc length, so corners are not doubled) plus fillPoints inside a closed shape, then jitterPoints and dedupePoints; tiles and fog cells come from strokeCells (a Bresenham walk dilated by a round brush of the panel's width) plus fillCells (cells whose centre is inside); textCells lays a 5 × 7 dot font (font.ts) out as cells, which become one object per dot or width × width tiles per dot. A deterministic generator seeded on mouse-down makes the preview and the commit scatter the same way. plugin.ts is the panel, the running api.ui.mapTool (the gesture per tool, onCancel returning true to drop a shape and keep painting, draw for the dashed outline, the per-point boxes in player colour, the eraser's crosses and the count), and the transaction: stampTerrain / setTiles / setFog for cells, placeUnit / placeSprite / placeDoodad for points, removeUnits / removeSprites / removeDoodads for the eraser.