SCP scene tables
The SCP of a model quartet is the scene file. Its first table lists the mesh placements; the rest describes what a level is made of apart from geometry: a tree of nodes, a table of their world matrices, a joint table, and a blob, a chain of typed sections that hold the spot chunks, splines, lights and other scene objects. Every level PAK holds one or more SCPs, 547 in all. Proven · all 547 SCPs
All numbers are big-endian. Pointers inside an SCP are stored as offsets from its start; 0xFFFFFFFF is a null. The loader turns them into pointers when it loads the file, so a stored 0 is a valid offset, not a null. Observed · static reading of the executable
Header
Section titled “Header”Each table is a count and an offset from the start of the file. The loader relocates the offsets named in the last column of the table below.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 4 | u32 = 0xBABF003C | magic | Proven | |
| 0x4 | 4 | u32 | unknown | Unknown | |
| 0x8 | 2 | u16 = 0x0048 | header_size | Observed | |
| 0xA | 2 | u16 | load_flags | Observed | bit 1 borrowed storage, bit 4 relocated; 0 on disc |
| 0xC | 4 | u32 | unknown | Unknown | |
| 0x10 | 4 | u32 | placement_count | Proven | |
| 0x14 | 4 | u32 | placement_offset | Proven | records of 0x30 bytes |
| 0x18 | 4 | u32 | node_count | Proven | |
| 0x1C | 4 | u32 | node_offset | Proven | records of 0x70 bytes |
| 0x20 | 4 | u32 | joint_count | Proven | 141 in the 505 level SCPs with joints |
| 0x24 | 4 | u32 | joint_offset | Proven | records of 16 bytes |
| 0x28 | 8 | u32[2] | table_28 | Unknown | a table of 0x38-byte records the loader relocates; 0 in every file read |
| 0x30 | 8 | u32[2] | table_30 | Unknown | a table of 0x200-byte records the loader relocates; 0 in every file read |
| 0x38 | 4 | u32 | matrix_count | Proven | equals node_count in all 547 files |
| 0x3C | 4 | u32 | matrix_offset | Proven | records of 8 bytes |
| 0x40 | 4 | u32 | unknown | Unknown | 0 |
| 0x44 | 4 | u32 | blob_offset | Proven | 0xFFFFFFFF or 0 when there is no blob (136 SCPs); the chain starts here |
A node is 112 bytes. The scene is a tree of nodes; each node lists its children and the placements it owns.
Two sets of five (count, pointer) pairs; only the first pair of each set is ever used.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 16 | f32[4] | sphere | Inferred | a bounding sphere (centre xyz, radius) on some nodes, zero on the rest |
| 0x10 | 4 | u32 | id | Proven | sdbm of the node's name; 1 of 106 in CHARLIE resolves (Main) |
| 0x14 | 12 | u32[3] | editor_leftovers | Observed | heap-like addresses of the authoring session; not data |
| 0x20 | 20 | u32[5] | child_counts | Proven | only the first is ever nonzero |
| 0x34 | 20 | u32[5] | child_offsets | Proven | 0xFFFFFFFF when unused; each element is the offset of a node record |
| 0x48 | 20 | u32[5] | placement_counts | Proven | |
| 0x5C | 20 | u32[5] | placement_offsets | Proven | each element is the offset of a placement record |
Of the ten (count, offset) pairs only the first of each set occurs: 165,525 child links and 155,292 placement links over the disc’s 166,089 nodes, and every link lands on the start of a record. Proven · all 547 SCPs
564 nodes are never a child (the 547 file roots and 17 others), and 12,211 of the 167,503 placements are owned by no node. Proven · all 547 SCPs
The leftovers have no use. Node names are not stored, and a node’s id resolves to a name only in rare cases (Main in CHARLIE). Observed
World matrices
Section titled “World matrices”The matrix table has one 8-byte record per node, in node order: a name or model hash and the offset of a 64-byte row-major matrix with the translation in floats 12 to 14 (the row-vector convention of Placements).
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 4 | u32 | hash | Observed | the group's name hash (NavSplines, CHALLENGE, AI, Audio, ...) or, for a node of one mesh, the model hash; else 0 |
| 0x4 | 4 | u32 | matrix_offset | Proven |
For 63 of CHARLIE’s 85 placements the node’s matrix equals the placement’s own. The group and root matrices are diag(−1, 1, 1), the export mirror; a spot chunk’s matrix is not composed with it. Observed
Joints
Section titled “Joints”The joint table has 141 records of 16 bytes in each of the 505 level SCPs, byte for byte the same: the rig of the player’s skater and board (Hips, Spine, Spine1, …, BoardTruck, BoardNose, Hair*). The two actor SCPs (male, female) have 40-joint variants. Proven · all 547 SCPs
It is the table that skinned meshes take their bone names from.
The blob
Section titled “The blob”At blob_offset is a chain of sections, each starting with four words and ending where the next begins.
The data starts data_offset bytes into the section. The chain ends with a 16-byte record {junk, 8, 0, 0}.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 4 | u32 | flags | Proven | the high 16 bits are the type; the low 16 are junk for splines and vary for the other types (an occluder's low half is its shape) |
| 0x4 | 4 | u32 | size | Proven | bytes of the section, header included |
| 0x8 | 4 | u32 | count | Proven | |
| 0xC | 4 | u32 | data_offset | Proven | 0x10, or 0x20 to 0x40 for type 0xE |
The 411 SCPs that have a blob all walk to the end record; the data_offset of 0x20 to 0x40 in type 0xE sections is what makes the chain continuous (reading it as 0x10 stops it early in 35 files). Proven · all 411 chains
The engine keeps a registry of section types: a loader and an unloader per type, registered at start-up, each receiving the section’s pointer. Types 2, 3, 5 and 10 have a loader of their own; types 0, 1, 9, a and c share the spline manager, one class each. Types 4, 6, b, d, e and f have no registry entry. Observed · static reading of the executable
| Type | Content | Sections | Read |
|---|---|---|---|
| 2 | spot chunks | 387 | Proven |
0, 1, 9, a, c |
splines, one class per type | 231 | Proven |
| 3 | spot cameras: 48-byte records of a spot name and two frames | 10 | Proven |
| 4 | lights | 55 | Proven |
| 5 | locators: one record in echo, a waypoint |
1 | Proven |
b |
occluders: 16-byte records of a name, a matrix and a line outline | 9 | Proven |
d |
lighting layers: names of specular cube textures (spec_locator_N) |
23 | Observed |
f |
records of 240 bytes starting with a position (w = 1): probe or ambient volumes | 23 | Inferred |
6 |
small trailer sections of 32 to 432 bytes whose count word is a leftover address and whose bytes are small-integer arrays | 175 | Unknown |
e |
128-byte records of a 64-byte matrix, an id and a parent hash, then zeros; data offset 0x20 to 0x40; no consumer found | 38 | Observed |
10 |
2,096 records of a 64-byte matrix, a radius, an entity index, a box of 24 f32 (corners at ±4) and named sub-records (snow_timebane_fence_dest, distancemarker_01, vfx_skt_cae_a_debristrash_m.ice); the records tile every section |
40 | Observed |
The section counts are over the disc’s SCPs. Observed
The reading of type 10 as breakable props comes from the names and the engine’s loader for the type, whose function was not read in full. Inferred
The disc by level
Section titled “The disc by level”Counted by a strict reader over the SCPs of each level’s PAKs (base and layers); every chain complete. Proven · all 547 SCPs
| Level | PAKs | Nodes | Placements | Spot chunks | Teleport chunks |
|---|---|---|---|---|---|
| Charlie | 41 | 35,820 | 49,820 | 3,217 | 30 |
| Delta | 19 | 12,050 | 13,323 | 1,344 | 22 |
| Echo | 17 | 8,382 | 8,472 | 4,714 | 57 |
| Foxtrot | 17 | 13,252 | 9,394 | 7,375 | 48 |
| India | 17 | 11,403 | 9,749 | 6,458 | 87 |
| Juliet | 17 | 41,184 | 39,467 | 7,695 | 60 |
| Mike | 40 | 11,401 | 8,944 | 7,637 | 15 |
| November | 17 | 13,576 | 9,764 | 7,194 | 63 |
| Oscar | 17 | 7,746 | 7,608 | 4,012 | 75 |
| Papa | 17 | 11,275 | 10,962 | 3,369 | 81 |
| All | 166,089 | 167,503 | 53,015 | 538 |
The tables at header offsets 0x28 and 0x30 are relocated by the loader but empty in every SCP read. What the sections of types 6, e and 10 are for (and what consumes e and f) is not established.