pxart help LOOKING
Looking
LOOKING
render FILE... [-o preview.png] [--scale 8] [--no-grid] [--variant V] [--png [DIR]] [--plain]
[--slots N|K=I] [--dry-run]
Preview sheet with a pixel grid and x/y rulers every 4px (default --scale 8; sheet,
anim and onion too). --png also writes each single-frame .px at 1x, FILE.png beside it
or in DIR, and says so. --plain writes -o as the one frame alone, its exact size
(--scale 1 by default), no grid, rulers, labels or --bg: for diff (--no-grid still
pads and labels).
sheet FILE|DIR... -o sheet.png [--scale 8] [--cols 8] [--grid] [--variant V] [--bg COLOR]
[--fit] [--align bottom|pivot] [--rows cols|group] [--slots N|K=I] [--exclude GLOB]
[--dry-run]
Compare any mix of .px/.png frames, labeled with id, WxH and color count. A directory
stands for every .px under it, recursively, sorted by path (PNGs in it are left out, a
sheet rendered there too). --exclude GLOB (repeatable) leaves files out: one whose
name or path under the directory matches ('_*.px', 'wip/*.px'), or every file under a
directory that does ('wip'). A glob that leaves out every file is E_FILE. A palette
file (no frames) among the inputs, a directory's or a glob's, is skipped with a note
('note: sheet skips palette.px: a palette file, no frames'); given alone it is
E_NO_FRAMES. Every cell is the largest frame's size (a frame over 8x the median
frame's area gets a note); --fit makes each cell its own frame's width (or its
label's, if wider) and each row as tall as its tallest frame, --cols cells to a row,
frames bottom-aligned in their row. A PNG whose four corners are exactly the --bg
color (a scene rendered with the same --bg) doesn't count that color: it's the
backdrop. Frames with the same id from different files are labeled with their file's
stem in front (hero:idle/0, beast:idle/0); render and anim label them the same way.
--align pivot lines up each animation group's frames by pivot, as anim and onion do:
the group's frames are drawn on one canvas, every pivot on the same pixel. The
default, --align bottom, bottom-aligns each frame in its cell.
--rows group starts a row for each animation group (one file's walk/down, then its
walk/up, ...; a file's top-level frames share one; a PNG has its own) and wraps within
a group only when it has more than --cols frames: 'sheet party.px --fit --rows group
--align pivot -o party.png' is one walk per row. The default, --rows cols, fills each
row with --cols frames.
anim FILE... [-o walk.gif|DIR] [--scale 8] [--fps N] [--variant V] [--dry-run]
walk.gif (one file: each frame at --scale, its 1x and 2x copies beside it in the same
picture), plus walk.strip.png: row 1 = frames, row 2 = what changed from the previous
frame after removing the whole-sprite shift ("shift dx,dy then N px (P%) (no shift: M px)";
P: N as a percent of the frame's opaque pixels, or of both frames' if more; a bob alone
shows "then 0px (0%)"). The numbers print too, a line per frame (a FILE of several
groups: a block each, top-level and @still frames skipped; -o a DIR);
without -o, anim prints only those lines and writes nothing. Read the strip: the Read
tool shows only a GIF's first frame. Durations come from the file (@anim/@frame ms)
unless --fps. A group with repeat=1 plays once: frame 0 gets no wrap-around diff.
--variant V counts V's render: a halo transparent in the base counts, at any alpha.
An idle: when the bottom stays exactly put (rows Y down identical, 0 px changed) and
only the part above moves (a breath), shifting would light up the legs, so the strip
shows the unshifted diff: "no shift then M px (P%) (rows Y+ still; shift dx,dy: N px)".
Both counts are always shown. That is for an idle, whose legs keep their shape in every
frame of the animation: a walk whose leg moved even 1px keeps the shift, and in a walk
a frame whose legs happen to stay put is the body's bob: "shift +0,+1 then 23px (6%) (no
shift: 201px)". A frame recolored whole (a glow) doesn't count as the legs moving; a
shadow that changes shape does. So that the rise and the fall of a breath read alike,
once one frame shows rows still and rows Y down are identical in every frame of the
animation, every frame whose shift would light them up shows the unshifted diff too; a
walk over a static shadow keeps every shift.
Tiles and overlays: frames that fill the canvas and are a ground tile (every pixel
opaque) or a sparse overlay (at most 1/4 opaque: snow) also try every wrap-around scroll
(shift --wrap), shown when it leaves strictly fewer pixels changed than the best plain
shift: "shift dx,dy (wrap) then N px (P%) (no shift: M px)". A character sprite never wraps.
onion A B -o x.png [--scale 8] [--rows Y0-Y1 | --feet N] [--tint-a [COLOR] | --fade-a]
[--variant V] [--dry-run]
B at 80% opacity drawn over A as a flat silhouette in a translucent red (#ff4060a0),
with render's grid and rulers: where A shows past B is plain.
Prints where each frame's opaque pixels sit on the shared canvas and how B's edges moved
from A's, then the whole-sprite shift that best explains B, as anim finds it:
"B vs A: left +0, right +0, top -1, bottom +0; best shift +0,-1 then 4px changed (no
shift: 20px)": the head rose 1px, the feet stayed. Two different sprites (other sizes, or
more than half the larger one's opaque pixels still changed at the whole sprites' best
shift; --rows and --feet don't change that; two frames of one animation in one file
are always one sprite, however much changed) print
"...; different sprites: edges only": their edges still compare where the feet stand,
but a best shift between two characters means nothing. y grows down, so +1 is lower.
The edges are the sides of each frame's opaque bounding box: 'top -1' is B's top row 1px
above A's.
--rows Y0-Y1 (canvas rows as the readout prints them, both included; one row: --rows Y)
or --feet N (the bottom N rows) limit the edges and the best shift to that band, so a
weapon swing above doesn't hide what the feet did: 'B vs A (bottom 4 canvas rows 20-23;
A opaque in 20-23, B in 21-23): left +0, ...'. The shift still moves all of A (pixels
come into the band from above) and counts only the band's pixels; when the bottom edges
agree, one up or down only lines up what moved above them, and the readout says no
shift. The PNG darkens the rows outside the band.
--tint-a COLOR draws the silhouette in another color. --fade-a draws A itself at 35%
opacity instead.
scene -o s.png [--scale 4] [--size WxH] [--bg #472d3c] [--map M --tile 16x16] [--variant V]
[--tint #rrggbbaa] [--dry-run] ITEM@x,y ...
Default --scale 4 (render's: 8).
Size: --size, else the map's, else 96x64 (six 16x16 tiles by four). Pixels past the
edge are cropped, with a note per item (and one for the map) saying how many; at the
default size a note also names the --size that holds every item.
ITEM is FILE[:frame][%variant][+h|+v|+hv]: +h mirrors it left-right, +v top-bottom
(hero.px:walk/0+h@3,4; '+' needs no quoting, where '!' would be history expansion). Map legend entries (which also take +b, see
Placement) and compose layers take +h/+v too. --map draws a text tilemap first:
legend lines '<char> <FILE[:frame][%variant]>', a blank line, then rows of legend
chars ('.' = empty). In a legend line the rest of the line is the path, relative to
the map file: spaces are fine ('b ../png/trees and bushes/bush.png'), "quotes"
optional. A legend entry that can't load is an error at its legend line.
Items are then drawn on top. '#' lines are comments only before the first row;
after that every non-blank line is a row, so '#' works as a map char (a wall row
'####'). Before the rows, a line that is exactly
'# FILE.px[:frame][%variant]' or '# FILE.png' (one token after '#', no spaces) is the
legend line for '#', not a comment, and so is a quoted path ('# "my tiles/wall.png"');
check and scene print a note for it. Any other line starting with '#' is a comment
('# see wall.px' too).
Layers (a tile and a sprite in one cell): a line '---' after the rows starts another
grid of rows over the same legend. Layers draw in order, later over earlier, and '.'
is empty in each; the map is as big as its widest row and tallest layer.
Placement: a map item draws with its top-left at its cell's top-left (column * tile
w, row * tile h), so a 32x32 stall on 16x16 tiles hangs right and down over the next
cells.
A legend entry ending in +b (with flips: +hb, +vb, +hvb) draws bottom-aligned to its
cell and centered across it, odd pixel left: x = cell x + (tile w - w) // 2,
y = cell y + tile h - h. A tall lamp then stands on its cell and rises into the row
above (cut off at the top edge on row 0). +b is for legend entries only.
A worked map, market.map, on 16x16 tiles (tiles.px:cobble, :water/0 and :crate are
16x16, stall.px is 32x32, lamp.px is 16x32):
# ground layer, then props
c tiles.px:cobble
w tiles.px:water/0
x tiles.px:crate+h
S stall.px+b
L lamp.px+b
l lamp.px+hb
cccccc
cccccc
wwwwww
---
......
.S.L.l
x.....
'pxart scene --map market.map -o market.png' is 96x48: cobbles and water, then the
props over them (compose --map builds the same room as a .px). The stall's cell is
16,16, so it draws at 16 + (16-32)//2, 16 + 16 - 32 = 8,0; the lamps at 48,0 and 80,0
(mirrored); the crate, mirrored, at its cell's top-left, 0,32.
--variant V renders every map tile and .px item with V (a whole dark room), except
those with their own %variant, which wins; a .px without V is an E_SELECT error.
%base is the base palette, so 'lamp.px%base@40,20' (or a legend entry 'L lamp.px%base')
stays unrecolored in a --variant night scene (a lit window, a glowing lamp). '%base'
works wherever %variant does, and a variant can't be named base.
Items and legend entries can be PNGs (hero.png@3,4). x,y may be negative (drawn
partly off the left/top edge), in scene and in compose.
--tint '#10183080' lays that color, at its alpha, over the whole finished scene (bg,
map, every item, those with their own %variant too) at 1x, before --scale: a night
scene in one step. To keep a light bright, mask its circle out of the untinted render
and lay that over the tinted one.
tint IN.png '#rrggbbaa' [-o OUT.png]
scene --tint on a PNG (a rendered scene): lays the color, at its alpha, over every
pixel; each pixel keeps its alpha, so transparent pixels stay transparent. Without -o,
IN is rewritten.
world W.world|ROOM.tmj -o world.png [--scale 2] [--dry-run]
Centering: frames of different sizes are bottom-aligned and centered, the odd pixel
left (x = (canvas - frame) // 2). render and sheet put a grey checkerboard
behind frames; --bg (render, sheet, scene) takes a flat #rrggbb, #rrggbbaa or 'transparent'
(as does every color typed on the command line: --tint, tint, palette --add
k=transparent; the '#' may be left off, and in a script a '#' color needs quotes, or the
shell reads a comment).
--dry-run (render, sheet, anim, onion, scene) prints the readout and each output's size and
layout, writes nothing and says '(dry run; nothing written)'. -o may then be left off. An
image over 4096 px on a side or 16M px gets a WARNING, dry run or not.This page is built from
site/src/data/reference.json in the repository.Edit on GitHub