The .map format
A .map file is a text tilemap: a legend saying what each character stands for, then
rows of those characters, one per cell, in one or more layers. Like a .px file, it is
plain text that git can diff, and nothing in it is procedural: it names sprites and says where
each one goes. pxart turns it into a picture, a .px frame or a Tiled world.
# A quay: cobbles, planks and water, then a lamp and a barrel on top.
c tiles.px:cobble/a
C tiles.px:cobble/b
p tiles.px:planks
w tiles.px:water/0
L lamp.px+b
b barrel.px%base
cCcCcC
CcCcCc
pppppp
wwwwww
---
......
.L..b.The legend
Each legend line is a character, whitespace, then an item:
<char> FILE[:frame][%variant][+h|+v|+hv|+b|+hb|+vb|+hvb]-
FILE is a
.pxfile, or a.png, with its path relative to the map file. The rest of the line is the path, so a pack folder with spaces in its name works as it is (b ../png/trees and bushes/bush.png). Quotes are optional. -
:framepicks a frame or group of a.pxfile, as a selector does anywhere else (tiles.px:water/0). A misspelled one is an error at its legend line, with suggestions:bad.map:6: E_SELECT: legend 'p': 'tiles.px:plank': no frame or group 'plank'; groups: cobble, water; frames: cobble/a, cobble/b, cobble/c, planks, water/0, water/1; did you mean 'planks'? -
%variantdraws that item in a variant whatever the scene's variant is, and%basekeeps its base colors (a lamp that stays lit in a night room). -
+h,+vand+hvmirror the item left-right, top-bottom or both. -
+bstands the item on its cell (see Placement); with a mirror it's one suffix,+hb.
A legend entry that can't load is an error at its line, so pxart check room.map finds a broken path
before anything is drawn.
Variant tiles
A legend line can list two or more tiles instead of one. That's a variant list, and each cell with its character draws one of them:
g ../tiles/field.px:grass_a ../tiles/field.px:grass_b ../tiles/field.px:grass_cThe pick isn't random. It's a hash of the room's name (the map's file name without .map) and
the cell's column and row, so a map draws the same way every time, and scene, compose --map
and export --tiled all pick the same tile for each cell. Two maps with the same rows but
different names pick differently, so renaming a room changes its picks.
- Every item is equally likely. List a tile twice to make it twice as common, or list the others more often to make one rare.
- Every item names a tile: a
.pxfile (with a:framewhen it has several) or a.png, each with its own%variantand flips if it wants them (flowers.px+h). A single path with spaces in it stays one path.
The flowers are listed twice among eight, so they grow in about one cell of four. List
flowers a third time, give one of them +h, or turn some g cells into w. To see the picks
themselves, swap the variants for tiles that look nothing alike; this is tutorial 10's
picks/meadow.map:
Tutorial 10 walks through variant lists step by step.
Animated tiles
A map cell draws one frame, so a legend entry that names a whole animation is an error that asks you to pick one:
E_SELECT: legend 'w': 'tiles.px:water': legend 'w' 'tiles.px:water' is 2 frames; pick one with FILE:frame-idName the first frame (w tiles.px:water/0). scene and compose --map draw that frame, a
still picture. In Tiled the tile moves: export tiles.px --tiled tiles.tsj gives each
animation's first tile Tiled's own frame animation, with each frame's ms. A room compiled with
export ROOM.map --tiled then draws its water cells with that tile. Every copy of a tile
animates in step, because the animation belongs to the tile, not the cell.
The editors on this site play animated tiles the way Tiled will: the group's frames in file order,
each for its ms, every cell in step. That's a preview ahead of pxart itself, whose scene draws
the first frame. The site's tests pin each frame to pxart's render of that frame. Tiled plays a
group forward whatever its @anim direction, and so do the editors.
Rows and layers
After the legend, a blank line, then the rows: one character per cell, with . for an empty cell.
A line --- starts another layer of rows over the same legend. Layers draw in order, later ones
over earlier ones, and . is empty in each, so a ground layer and a props layer share cells. The map
is as wide as its widest row and as tall as its tallest layer.
# lines are comments only before the first row. After that, every non-blank line is a row, so #
can be a map character (a wall row ####). Before the rows, a line that is exactly # FILE.px (one
token after the #, or a quoted path) is the legend line for #, not a comment; check and scene
print a note when they read one that way.
Placement
A cell is one tile, 16x16 unless --tile WxH says otherwise. An item draws with its top-left
corner at its cell's top-left (column × tile width, row × tile height), so a 32x32 stall on 16x16
tiles hangs right and down over the next cells.
With +b, an item stands on its cell instead: bottom-aligned, and centered across it with the odd
pixel to the left. Its x is the cell's x plus (tile width − its width) ÷ 2, rounded down, and its y
is the cell's y plus the tile's height, minus its own. A 16x32 lamp then stands on its cell and rises
into the row above (cut off at the top edge on row 0).
Variants
--variant dusk draws every item in its dusk colors, except items with their own %variant. A .px
item without that variant is an error, because the room would come out half at dusk:
scene: --map (bad.map): bad.map:9: E_SELECT: legend 'b': 'barrel.px': unknown variant 'dusk' (have: none)Give the item %base to keep its base colors in such a scene, as the quay does for its barrel, or
give the sprite a dusk of its own (palette barrel.px --variant dusk --derive-from base ...).
What a map becomes
pxart check quay.mapok quay.map: map 6x4 tiles, 6 legend char(s), 2 layers- A picture:
pxart scene --map quay.map -o quay.pngdraws it (4x by default;--scale 1for 1:1), and--variant duskdraws it at dusk. Items placed atx,ycan be drawn on top (pxart scene --map quay.map -o q.png hero.px:walk/0@40,20). - A
.pxframe:pxart compose --map quay.map -o room.pxbuilds the room as one frame, with a palette merged from its tiles' palettes and their variants merged by name. It renders pixel for pixel asscene --mapdoes, in every variant, and its header records the command that made it. - A Tiled world: a
world.src.jsonthat lists.maprooms compiles to Tiled's.worldand.tmjfiles withexport --tiled(pxart help worlds), andpxart worlddraws the compiled world as one picture.
Tutorial 06 builds a level in four layers, from a 256-pixel sky to the props.