# pxstud.io Lua scripting API — Tilemaps

> Part of the pxstud.io Lua scripting reference, whose overview (https://pxstud.io/docs/scripting.md) explains its conventions. The option groups and types it refers to are in https://pxstud.io/docs/scripting/option-groups.md and https://pxstud.io/docs/scripting/types.md. Everything in one file: https://pxstud.io/llms-full.txt. The whole site's index: https://pxstud.io/llms.txt.

### Tilemaps
Tilemap layers place tiles from their own tileset on a grid. Tiles are numbered from 1 (0 is the empty tile).

#### `app.addTilemapLayer(name?, tileWidth, tileHeight, parentId?, tilesetLayerId?)` — changes, undoable
Creates a new tilemap layer with an empty tileset of tileWidth x tileHeight tiles on top of every other layer (or of the group parentId's layers) and makes it active. Use app.addTilemapTile to add tiles to it. With tilesetLayerId the layer shares that layer's tileset: editing, adding or removing tiles affects both.

- `name` (string, optional) — Layer name; defaults to 'Tilemap N'.
- `tileWidth` (number)
- `tileHeight` (number)
- `parentId` (string, optional) — A group to add it to (on top of its layers); omitted = the top level.
- `tilesetLayerId` (string, optional) — Share the tileset of this existing tilemap layer instead of making a new one (tileWidth and tileHeight are then ignored).

Returns (string): The new tilemap layer's id.

#### `app.addTilemapTile(layerId, pixels?)` — changes, undoable
Appends a tile to a tilemap layer's tileset and returns its tile index (1-based; 0 is the implicit empty tile). Throws if layerId isn't a tilemap layer.

- `layerId` (string)
- `pixels` (table, optional) — Flat pixel buffer (RGBA = 4 numbers per pixel, indexed = 1) sized to the tile; omit for a transparent tile.

Returns (number): The new tile's 1-based index.

#### `app.clearTilemapTile(layerId, tileIndex)` — changes, undoable, refused on a locked layer
Makes a tile fully transparent. Every placement of it goes blank.

- `layerId` (string)
- `tileIndex` (number) — 1-based tile index.

Returns nothing.

#### `app.convertToNormalLayer(layerId)` — changes, undoable, refused on a locked layer
Converts a tilemap layer into an image layer, rasterizing its tile placements into a cel on every frame (Layer > Convert to Normal Layer). The layer keeps its id. One undo step.

- `layerId` (string) — A tilemap layer.

Returns nothing.

#### `app.convertToTilemap(layerId, tileWidth, tileHeight, opts?)` — changes, undoable, refused on a locked layer
Converts an image layer into a tilemap layer with a new tileset of tileWidth x tileHeight tiles cut from its cels on every frame (Layer > Convert to Tilemap). The layer keeps its id; its cels become tile placements. One undo step.

- `layerId` (string) — An image layer (not the Background).
- `tileWidth` (number)
- `tileHeight` (number)
- `opts` (table, optional)
  - `dedupe` (boolean; default true) — Share identical tiles.
  - `matchFlips` (boolean; default false) — Also share tiles that match flipped or rotated 90 degrees (and turn the tileset's match options on).

Returns nothing.

#### `app.duplicateTilemapTile(layerId, tileIndex)` — changes, undoable
Appends a copy of a tile to the end of a tilemap layer's tileset (its index is the old tile count + 1).

- `layerId` (string)
- `tileIndex` (number) — 1-based index of the tile to copy.

Returns (number): The copy's 1-based tile index.

#### `app.fillTiles(layerId, frameId, col, row, opts?)` — changes, undoable, refused on a locked layer
Tile bucket: fills the cells holding the same tile as cell (col, row) with one tile (an empty cell is tile 0) — exactly the GUI bucket in Place tiles mode. The fill stays inside the canvas's tile grid.

- `layerId` (string) — A tilemap layer.
- `frameId` (string)
- `col` (number) — The clicked tile-grid column (not a sprite pixel).
- `row` (number) — The clicked tile-grid row.
- `opts` (table, optional) Also takes the **Placement options** (see "Option groups"), and:
  - `contiguous` (boolean; default context.bucketFillMode (true for the context's contiguous mode, false for global)) — Only the connected cells (true), or every cell holding the clicked cell's tile (false).
  - `tileIndex` (integer ≥ 1; default context.tileIndex) — The 1-based tile to fill with.
  - `flipH` (boolean; default context.tileFlipH) — Flip placed tiles horizontally.
  - `flipV` (boolean; default context.tileFlipV) — Flip placed tiles vertically.
  - `rotate90` (boolean; default context.tileRotate90) — Rotate placed tiles 90° clockwise (square tiles only).

Returns nothing.

#### `app.getTilemap(layerId, frameId)` — reads
A tilemap layer's tile placements on one frame as { x, y (tile-grid cell), tileIndex, flipH, flipV, rotate90 } — the shape app.setTilemapInstances takes. Linked frames report their shared placements.

- `layerId` (string) — A tilemap layer.
- `frameId` (string)

Returns (table): Array of placement tables.

#### `app.getTilePixels(layerId, tileIndex)` — reads
A tile's image as a flat RGBA list (tileWidth*tileHeight*4, row-major; palette colors resolved on indexed sprites).

- `layerId` (string) — A tilemap layer.
- `tileIndex` (number) — 1-based tile.

Returns (table): Flat RGBA list.

#### `app.getTileset(layerId)` — reads
A tilemap layer's tileset as { tileWidth, tileHeight, tileCount, matchFlipH, matchFlipV, matchRotate, baseIndex, name?, id? } (the match flags are the Auto-paint options, see app.setTilesetMatch; baseIndex is the number the first tile is displayed with, see app.setTilesetProperties; id is present when layers share the tileset, and equal ids mean the same tileset). Tiles are numbered 1..tileCount (0 = the empty tile).

- `layerId` (string) — A tilemap layer.

Returns (table): Tileset table.

#### `app.importTilesFromImage(layerId, width, height, pixels, opts?)` — changes, undoable, refused on a locked layer
Slices an image into the layer's tileset in tileWidth x tileHeight cells (edge cells are padded with transparency), appending the tiles it doesn't already have. With frameId it also places the result on that frame. One undo step.

- `layerId` (string) — A tilemap layer.
- `width` (number) — Image width in pixels.
- `height` (number) — Image height in pixels.
- `pixels` (table) — Flat RGBA numbers (4 per pixel, width*height pixels).
- `opts` (table, optional)
  - `dedupe` (boolean; default true) — Reuse identical tiles instead of adding duplicates.
  - `matchFlips` (boolean; default false) — With dedupe: also reuse a tile that matches flipped horizontally/vertically or rotated 90 degrees (square tiles), placing it with the matching flags.
  - `skipEmpty` (boolean; default true) — Cells with no visible pixel make no tile.
  - `frameId` (string) — Also place the sliced cells on this frame of the layer, replacing the cells the image covers.
  - `col` (integer; default 0) — Tile column of the image's left edge when placing.
  - `row` (integer; default 0) — Tile row of the image's top edge when placing.

Returns (number): How many tiles were added.

#### `app.moveTilemapTile(layerId, from, to)` — changes, undoable
Moves a tile to a new position in the tileset, remapping every placement so nothing changes visually.

- `layerId` (string)
- `from` (number) — 1-based current tile index.
- `to` (number) — 1-based tile index after the move.

Returns nothing.

#### `app.paintTilemapPixels(layerId, frameId, x, y, width, height, pixels, mode)` — changes, undoable, refused on a locked layer
Paints canvas-space pixels onto a tilemap layer, writing through each tile placement's flip/rotation. One undo step.

- `layerId` (string)
- `frameId` (string)
- `x` (number) — Canvas-space left edge of the written region.
- `y` (number) — Canvas-space top edge of the written region.
- `width` (number)
- `height` (number)
- `pixels` (table) — Flat RGBA numbers (4 per pixel, width*height pixels); alpha 0 erases.
- `mode` (TilePaintMode: "edit" | "auto") — "edit" changes the tiles the cells already use (all placements update); "auto" works per painted cell like Aseprite Auto: reuses an identical tile (or a flipped/rotated one, per app.setTilesetMatch), else a copy-on-write / new tile, then removes tiles the edit left unused.

Returns nothing.

#### `app.removeTilemapTile(layerId, tileIndex)` — changes, undoable, refused on a locked layer
Deletes a tile from a tilemap layer's tileset. Placements of it are cleared; placements of higher-numbered tiles shift down by one so they keep showing the same image (exactly the tileset panel's Delete).

- `layerId` (string) — A tilemap layer.
- `tileIndex` (number) — 1-based tile to delete.

Returns nothing.

#### `app.setTilemapInstances(layerId, frameId, instances)` — changes, undoable, refused on a locked layer
Replaces a tilemap layer's tile placements for one frame. x/y are tile-grid coordinates. Throws if layerId isn't a tilemap layer.

- `layerId` (string)
- `frameId` (string)
- `instances` (table) — Array of {x, y, tileIndex, flipH, flipV, rotate90} tables replacing this frame's placements; empty clears them.

Returns nothing.

#### `app.setTilemapTilePixels(layerId, tileIndex, pixels)` — changes, undoable, refused on a locked layer
Replaces a tilemap layer tile's pixels. Every placement of that tile (all frames, any flip/rotation) updates instantly. Throws on bad layerId/index/pixels length.

- `layerId` (string)
- `tileIndex` (number)
- `pixels` (table) — Flat pixel buffer (RGBA = 4 numbers per pixel, indexed = 1) sized to the tile.

Returns nothing.

#### `app.setTilesetMatch(layerId, flipH, flipV, rotate)` — changes, undoable
Sets the tileset's "match flips" options: in "auto" tilemap painting, new pixels equal to an existing tile flipped/rotated reuse that tile with the placement flags set, instead of creating a tile.

- `layerId` (string) — A tilemap layer.
- `flipH` (boolean) — Match tiles flipped horizontally.
- `flipV` (boolean) — Match tiles flipped vertically.
- `rotate` (boolean) — Match tiles rotated 90 degrees (square tiles only).

Returns nothing.

#### `app.setTilesetProperties(layerId, name?, baseIndex?)` — changes, undoable
Sets a tileset's name and Base Index. The base index only changes how tiles are numbered in the Tileset panel and in Aseprite; tile indices in scripts stay 1-based. Applies to every layer sharing the tileset.

- `layerId` (string) — A tilemap layer.
- `name` (string, optional) — The tileset's name; "" clears it; nil leaves it.
- `baseIndex` (number, optional) — Aseprite's Base Index: the number the first tile is displayed with (default 1), -32768 to 32767; nil leaves it.

Returns nothing.

#### `app.stampTiles(layerId, frameId, cells, opts?)` — changes, undoable, refused on a locked layer
Stamps a tile into (or, with erase, clears) the given tile-grid cells of a tilemap layer — exactly the GUI tile stamp. Untouched cells keep their placements. With symmetry, the mirrored cells get the mirrored tile (flips mirror with them); with respectSelection, cells outside the selection are skipped.

- `layerId` (string) — A tilemap layer.
- `frameId` (string)
- `cells` (table) — List of TILE-GRID cells { x = col, y = row } (or { col, row }) — not sprite pixels.
- `opts` (table, optional) Also takes the **Placement options** (see "Option groups"), and:
  - `tileIndex` (integer ≥ 0; default context.tileIndex) — The 1-based tile to place.
  - `flipH` (boolean; default context.tileFlipH) — Flip placed tiles horizontally.
  - `flipV` (boolean; default context.tileFlipV) — Flip placed tiles vertically.
  - `rotate90` (boolean; default context.tileRotate90) — Rotate placed tiles 90° clockwise (square tiles only).
  - `erase` (boolean; default false) — Remove the cells' placements instead of placing a tile.

Returns nothing.
