Skip to content

File Formats

xAstroBoy edited this page Jul 5, 2026 · 2 revisions

File Formats

All of these were reverse-engineered from libshell.so (V79 and V205.2 databases). This page is the quick reference; the code in src/loaders/ and src/cook/ is the authority.

V79 side — OPA container (OPAA)

A V79 official home is an APK whose assets/scene.zip holds content/ descriptors + cache/android/ cooked .opa blobs. Common blob types:

File Contents
<fbx>.opa Model geometry: node hierarchy, per-material submeshes, positions/UVs/indices.
<name>.skin.opa Skinned mesh: SkinnedPos (pos f32×3 + weights f16×4 + bone idx u8×4), StdData (normals/tangents/vertex color u8×4 @8/uv f16×4 @12 — uv0 + uv1 lightmap), indices, joint-name list, per-bone inverse-bind. v0x409 adds 2 u32 submesh fields.
<name>.skel.opa Skeleton: jointIds (u64), joint names, parent indices, per-joint local bind TRS (T3, quat wxyz, S3).
<name>.anim.opa Clip: joint-name list, Transform track = per-frame per-joint parent-local 4×4.
<fbx>.sanim.opa Node/material animation: per-node Translation(3)/Rotation(4 quat)/Scale(3) and UVTransform(6 = 2×3) tracks.
<name>.mat.sanim.opa Per-material UV/tint sub-animation (UVTransform, MaterialTint RGBA). Parse all files; Additive materials blend ADD.

Track record layout (shared): a name marker (0xFFFF len string) then a 12-byte header (flag, nKeys, nVals) then nVals floats. Derive frames = nVals / comps (comps = 3/4/6) — never from nKeys (flag=1 tracks pad key-time data). Strings are length-prefixed with no char filter (joint names can contain : from Maya/FBX namespaces).

Materials (*.mat.txt YAML in scene.zip): Transparent / Additive / AlphaTest / DoubleSided / Unlit / Depth flags, texture slots (diffuse/lightmap/normal/mr/emissive/ao by AssetRef id), and uniforms — including the authored alphatestthreshold (per-material cutout threshold: trees 0.5, plants 0.25, balloons 0.75 — the cook honors it exactly).

Textures: KTX11 ASTC, block footprint from the header table (4x4..12x12). The cook passes the source mip chain through byte-exact when the texture is unmodified.

V205 side — HSL APK

The cook emits a modern HSL environment. Key file-ids (FlatBuffer-wrapped):

File-id Contents
RENDMESH Cooked geometry (vertex streams by semantic — sem4 = vertexColor0, sem7/8 = skin weights/indices; submeshes; skin block ROOT.f0=u16(2) for skinned).
MATL Material. Shader ref = FlatBuffer field 7 via vtable (not a fixed offset). field0 = u16 mode + u16 param-blob byte SIZE followed by the matParams values (NOT a flag bitfield — the masked blob leads with the alphaCutoff f32). field2 = blend mode (2 = alpha, 3 = additive).
HSTF Scene: entities + components (Transform — localRotation is euler radians, Mesh, Skybox, Collider, Animator, Audio, …).
HZAN Animation: HZAN:SKEL skeleton + ACL-compressed HZAN:ANIM (magic 0xA34912B6) clip.
RENDTXTR (TXTR) Texture: ASTC (or R16G16B16A16 for VAT), width/height, mip count, byte blob. field0 = 2 = sRGB — every official Meta texture carries it; without it the device samples LINEAR and every color washes out.
RENDSHAD Shader container: f7 = stage table (SPIR-V module blobs), f12 = pass table. Skinned bases carry forwardSkinned, forward, forwardSkinned_debug, forward_debug — skinned meshes DRAW forwardSkinned (edit the right pass!), and passes share modules (repoint every reference on a swap). Transparent pass = f4 omitted.
SEBD PhysX collision blob (navmesh ColliderMesh / colliders); Meta 16-aligns the manifest + markers.

matParams binding

Cooked material constants bind to the shader UBO by MurmurHash3("matParams." + name) — match by name, not slot order.

VAT texture

f2 = 5R16G16B16A16_SFLOAT, width = vertexCount, height = frameCount, texel = per-vertex offset (x,y,z,1) for that frame, full half-float mip chain required.

Coordinate / transform notes

  • V79 skinned SkinnedPos verts are model-local; world placement is in the skeleton bind.
  • HSTF localRotation is euler radians (no w); clipFromWorld = P·V (model is a push-constant).
  • Depth is reversed-Z on D32_SFLOAT.
  • V79 UV convention: v = 1 − v relative to glTF; uv1 (TEXCOORD1 u16×2) is the lightmap unwrap.

Related: Architecture · Animation System · Developer Guide.

Clone this wiki locally