body A ID (always <= bodyIdB for consistent ordering)
body B ID (always >= bodyIdA for consistent ordering)
body A index
body B index
contact index (index in contacts.contacts when active, -1 when freed)
frameStamp of the last step that processed this contact (for stale contact cleanup); init 0
Double-buffered cached manifold (read / write side per step). Use getReadManifold / getWriteManifold to access via the Contacts.readIdx flip — never index directly.
next contact index in the owning pair's chain (or INVALID_CONTACT_KEY)
owning pair record index; -1 when freed
previous contact index in the owning pair's chain (or INVALID_CONTACT_KEY)
sub-shape A ID
sub-shape B ID
contact between two shapes.
every live contact is nested under exactly one persistent pair record: it lives in that record's chain (headed by pairs.firstContact[pairRecord]) via the prevInPair/nextInPair links. the chain is doubly-linked (unlike jolt's singly-linked manifold chain) so a contact can be unlinked in O(1) when destroyed in place.