The placement rule
Measured
A frame's top-left corner is the anchor point, plus the stored placement pair, minus half the frame's width and height. The placement is measured to the centre of the frame, not its corner, and it is added rather than subtracted.
Two things follow. Shipped vertical values are negative, because artwork grows upward from where a figure stands. And re-cropping art changes the placement it needs by half the crop on each axis — which is exactly why the community's crop-and-re-centre workaround always nearly worked, with an error that moved when you edited rather than staying put.
Why the old editor broke sprites
Measured
The tool the community used for years writes no placement data at all. Placement is authored per frame and is not recoverable from the artwork: across 28,447 unit frames the horizontal value is independent of frame width, and height explains only about half of the vertical value.
So art that passes through that tool cannot have its placement reconstructed by any amount of cleverness. It has to be written back deliberately.
Five stored facings, eight directions
Measured
A sprite normally stores about five facings and covers eight directions by mirroring. A direction at or past the stored count folds back onto a stored one and raises a flag, and that flag makes the drawing code negate the horizontal placement — a horizontal flip, using the same value the placement rule above turns on.
Which compass bearing is direction zero is still unknown. Two separate rotations sit between a script-level facing and a stored index, and neither is anchored to a real bearing by anything measured here.
There is no frame timing in the file
Measured
No field of a sprite file is read by the game as a duration, delay, frame rate or tick count. Playback cadence comes from a global counter, not from the artwork.
The first version of this argument was wrong, and the document says so: it claimed a record could only be reached by one kind of arithmetic, which code the same page already cited disproves. The negative only stands because it was re-derived a second way after that.
Some unread bytes are not garbage
Open question
Several fields the game never reads are nevertheless too consistent to be leftover memory: one holds the same value in 4,661 of 4,667 records, another in all 4,667. And 501 records carry a patterned value in bits the game masks away before looking.
Something wrote those deliberately — most likely the original authoring tool. What they meant is open.
Palette entries are stored blue, red, green
We were wrong about this
This project's decoder had the channel order reversed, which swapped red and green while leaving blue correct — a bug that looks like nothing at all on any material where red and green are close. Writing known pure colours into a palette and photographing what the game drew settled it, and also refuted the community specification's description of the same field, which this project had accepted on trust.