layoutc stores a tournament paintball field layout as a PNG where every occupied pixel is one bunker. Not a rendering of the layout—the layout. The image is the file format, and it happens to look like the field.
The PNG itself, at actual size, encoded from layoutc’s World Cup 2021 data at 381 mm per pixel. The figure above enlarges its pixels without smoothing, then plots the positions recovered using that same pitch. The numbers land somewhere you can eyeball: a standard Small field is 45.72 × 36.576 m, so at that pitch the whole layout is this 120 × 96 PNG, a thumbnail, yet the color channels restore every bunker to roughly 1.5 mm.
The channel scheme, from rgba() in the entity model:
def rgba(self, pitch:Pitch, /) -> tuple[int, int, int, int]:
"""Return the RGBA color."""
r = int(round(self.x % pitch / pitch * Depth.HIRES))
g = int(round(self.y % pitch / pitch * Depth.HIRES))
b = int(round(self.z % Unit.TURN / Unit.TURN * 2**8))
a = int(GVK(self.g + self.v + self.k))
return r, g, b, aFour channels, four jobs:
- Pixel position is the coarse coordinate. At the high-res pitch of 381 mm per pixel, where the pixel sits in the image identifies the bunker’s 381-mm grid cell.
- R and G carry the sub-pixel remainder, scaled into 254ths of a pixel (
Depth.HIRES = 254, with a 127-depth low-res sibling). 381 / 254 = 1.5, so position survives the round trip to about 1.5 mm. - B is rotation in 256ths of a turn. Angles are arcminutes internally—Millimeters and arcminutes covers why—so
z % TURN / TURNis the fraction of a full turn and the byte quantizes it. - A is a packed identity bitfield: Group in the top two bits (terrain, feature, overlay), Version in bit five, Kind in the low five. Alpha zero means unoccupied, so transparency is literally emptiness—erase a pixel, delete a bunker.
Each layer holds one entity per pixel. Two distinct entities landing in the same cell do not both survive: the later array write replaces the earlier one. Sub-pixel precision preserves position, not multiple occupancy.
Decode reverses the channels with one parameter still supplied outside the image: the matching pixel pitch. The aspect ratio identifies the field-size class, alpha finds the bunkers, and, given that pitch, the channels reverse into position, rotation, and identity. Pitch is not stored in the PNG; dimensions alone can be ambiguous once several layouts are tiled into an atlas.
That symmetry is also the one place the scheme needs a trick. Coordinates fold into quadrant-plus-absolute-value before encoding, and the single bit folding endangers—which side of the axis—travels in a sign nudge documented in One bit in the rounding gap.
The in-memory atlas uses that symmetry too. After folding and quantization, (x, y, z, g, v, k) is one dictionary key and the quadrants occupying that folded point are a set beneath it. Iteration expands the set back into separate entities. Symmetric bunkers therefore share the coordinate and identity tuple without losing which sides they occupy. An exact duplicate collapses, which is intentional set behavior; this is not a lossless multiset of insertions.
What the PNG buys over an opaque binary format is inspectability. Open it in anything that draws images and you’re looking at the field; open it in anything that reads pixels and you have the encoded data. Given the matching pitch, the codec reconstructs the layout. On PyPI as layoutc, and active.