Furth FortuneM9 reference

Mission foundation / System overview

Nautilus

One import boundary for outside assets

Nautilus decodes source formats such as GLB, PNG, JPEG, and FBX into MerTek mesh, texture, rig, animation, and point-data profiles. Render code reads only those profiles.

Inside the system

Architecture plates

Each plate preserves the internal layout, paths, boundaries, and highlighted decisions. Use the short label first, then follow the lines through the system.

Plate 01

The one crossing, and the five things it forbids

foreign bytes · the Nautilus edge · Nautilus profiles · what is forbidden after them

FOREIGN BYTES THE ONE EDGE NAUTILUS PROFILES glTF 2.0 / GLBJSON plus a binary chunk FBX binarynode-record container Wavefront OBJplus its .mtl sidecar Stanford PLYASCII and both binary orders 3DGS .ply / .splatGaussian-splat containers SRTM HGTelevation raster tile PNG / JPEGembedded or named beside native/nautilus/ dependency-free C11, no external deps nautilus_glb.h · nautilus_gltf_import.h nautilus_fbx.h · nautilus_fbx_mesh.h nautilus_fbx_import.h nautilus_obj.h · nautilus_mtl.h nautilus_ply.h · nautilus_splat_import.h nautilus_dem_import.h SHARED EDGE CODECS thalassa_codec_png.h thalassa_codec_jpeg.h The magic bytes pick the decoder. A declared mimeType is a hint only, so a mislabelled image cannot misroute. NTM1 meshnautilus_mesh.h NTR1 rignautilus_rig.h NAN1 clipnautilus_rig.h NTX1 texturenautilus_texture.h NTP2 attributed pointnautilus_point.h THE ONLY THING DOWNSTREAM SEES Reef author and executor the Glint IR and its five lowerings the scene .tri layer FORBIDDEN AFTER THE EDGE · GATE nautilus-import-edge-foreign-codec-ban NO FOREIGN PARSE in the render flow. No glTF walk and no image decode in a scene. NO SECOND IMPORTER One edge verb per format. The old cgltf tool is retired to a README. NO NEW FLAT FORMAT No .mtkmesh, no .tex, no .rig, no .clip. The profiles carry it. NO STAND-IN DECODER No Python, PIL or ffmpeg step. No offline convert. The gate runs real code. NO VENDORED LIBRARY No stb_image, libpng, libjpeg or cgltf. Write it in-tree instead.
Plate 02

The five canonical profiles, and the decode that refuses

five containers · fixed header · declared streams · what each decode refuses

CONTAINER FIXED HEADER DECLARED STREAMS REFUSES NTM1nautilus_mesh.h 81 bytes: flags, four bit depths, vertex and triangle counts, bounds 7 flag bits: normal, uv, color, index, tangent, extra uv sets, sections a flag bit past 6, a zero count, a stream off the end NTR1nautilus_rig.h magic plus a u16 joint count, then per joint a parent index and a TRS the bind pose, plus an OPTIONAL trailing IVB1 block of 16 floats per joint a truncated joint table; a partial rig is freed NAN1nautilus_rig.h a f32 duration and a u16 channel count, then one descriptor each per channel: joint, path t/r/s/weights, interp step/linear/cubic, times, values an unknown path or interp; a key count past the buffer NTX1nautilus_texture.h 16 bytes: channels, colorspace, block format, mip count, width, height 10 formats: BC1 BC4 BC5 BC7 BC6H ETC2, and raw R16 RG16 RGBA16F RGBA8 an unknown format, a mip count over 30, a huge area NTP2nautilus_point.h magic, point count and a declared stream table; position is stream 0 6 semantics: position, color, scale, rotation, opacity, spherical harmonics a declared count the input cannot hold: a decode bomb TWO LAYERS VALIDATE, AND NEITHER ASSUMES THE OTHER RAN 1 · the Trident boundary codec_validate_ntm codec_validate_ntp texture_validate_ntx_header It walks the WHOLE container and refuses unless total equals length. 2 · the header decoder nautilus_mesh_decode nautilus_rig_decode nautilus_point_decode Bad magic, truncation or over-size returns 0, never a partial read. WHY BOTH EXIST The decoder is header-only C with a stated precondition: a complete container. The boundary is what proves that precondition BEFORE the first offset or allocation is computed. 10 crash-contract fuzz leaves drive layer 2.
Plate 03

Six front ends, one result shape

front end · Trident verb · the one part record · the untrusted sidecar

FRONT END TRIDENT VERB THE ONE RESULT SHAPE glTF 2.0 / GLBnautilus_glb + nautilus_gltf_import FBX binarynautilus_fbx{,_mesh,_import}.h Wavefront OBJnautilus_obj + nautilus_mtl Stanford PLYnautilus_ply 3DGS .ply / .splatnautilus_splat_import SRTM HGTnautilus_dem_import t.geom.importGltfmesh rig skin clip morph t.geom.importFbxmesh and rig t.geom.importObjmesh, material, texture t.geom.importPlyand importPlyBuffers no import verbdeclared as a c-only-hold t.import.demreads the tool's .ntm the ONE part record every import verb returns this document DOCUMENT ok · contentHash · partCount meshCount · skinCount · parts[] EACH PART mesh { positions, normals, uv0, indices, vertexCount, triangleCount } material { baseColor, metallic, roughness } rig · skin · clips · morph · texture Absence is a DECLARED false, not a missing key: hasRig, hasSkin, hasTexture, hasMorph, clipCount. The content hash is a sha256 of the bytes actually read, never a length the file declared about itself. A SIDECAR IS A SECOND UNTRUSTED INPUT the .obj names its own files mtllib names the .mtl. map_Kd names the image. Both are filenames taken verbatim from a file this edge is parsing, so both resolve ONLY beside the .obj. An absolute, drive-qualified, or dot-dot path is malformed and refuses. HOW A NEW FORMAT ARRIVES Add a header beside the others that produces the same profiles, then one row in GEOM_FN_TABLE. Do not add a path into the renderer. A front end with no verb is not shipped, and the tree says so: the splat gate is declared c-only-hold and names the missing verb.
Plate 04

The sequence a scene actually drives

path → import → encode → reopen → pose and draw · plus the persistence leg

THE IMPORT 1 · a PATH the scene hands over a string and nothing else 2 · t.geom.importGltf the nautilus_glb micro-JSON loader decodes every triangle primitive 3 · parts[] mesh, material, rig, skin, clips, morph, texture 4 · contentHash sha256 of the source bytes that were actually read 5 · ENCODE TO THE CANONICAL PROFILES t.geom.rigEncodeNrRig becomes NTR1 bytes t.geom.clipEncodeNaClip becomes NAN1 bytes t.texture.encodeRGBA8 becomes NTX1, lossless t.hash.fnv1a64fingerprint each container 6 · REOPEN · THE RENDER RUNS OFF THESE, NOT OFF THE LIVE IMPORT t.geom.rigDecodeNTR1 becomes the rig again t.geom.clipDecodeNAN1 becomes the clip again t.texture.decodeNTX1 pixels equal the originals re-encode and hashmust equal the first hash 7 · MORPH IN MODEL SPACE, THEN LET THE BLOCK SKIN t.anim.player.seeksamples the reopened clip t.anim.morph.applythe authored weight track t.geom.meshInterleavep3n3u2j4w4 plus the palette world_texture_skinnedthe Glint block skins on GPU THE PERSISTENCE LEG t.geom.importPlyBuffers · built and driven The edge decodes straight into packed f64 buffers. db.entity.save writes vec3[] and i32[] FROM those buffers; db.entity.getBuffer reads them back packed. The full Stanford Bunny stores and round-trips in the default arena, which the boxed path could not. the asset_* rows · fed and driven lifelike_lipsync.tri imports a head GLB through t.geom.importGltf, then saves the decoded rig, skin, morph set and NAN1 clip into asset_rig, asset_mesh_skin, asset_morph and asset_anim_clip. The clip row names the rig its joints address, a skeletonRef FK to asset_rig.
Plate 05

The vocabulary stops where the bytes stop

foreign names · the mapping edge · Nautilus names · the two halves of one gate

THE NAME IN THE FILE WHERE IT IS MAPPED THE NAME DOWNSTREAM pbrMetallicRoughness baseColorFactor metallicRoughnessTexture KHR_materials_* KHR_texture_transform Lcl Translation / Rotation / Scaling mtllib · usemtl · map_Kd POSITION · JOINTS_0 · WEIGHTS_0 the mapping happens here native/nautilus/** mfn_importGltf, in trident/trident_kernels.c These two paths are the ONLY places the gate excludes. Anywhere else, the name is a gate failure. material { baseColor, metallic, roughness } mesh { positions, normals, uv0, indices } rig { jointCount, joints[{parent,t,r,s}] } clip { duration, channels[{joint,path}] } texture { width, height, rgba } Keep the MODEL, own the NAME. A transmission factor with an attenuation colour and distance is right because the physics is right, not because a standard spells it that way. ONE LEAF, TWO HALVES, results 2 half 1 · the BYTES 23 refused call and include signatures: cgltf_parse, stbi_load, png_create_read_struct, jpeg_read_header and their siblings. A call needs its trailing parenthesis to match, so prose that names a retired library stays legal. half 2 · the NAMES 5 refused vocabulary tokens, listed above left. The scan reads tracked .c, .h, .cpp, .mm and .tri through git, so an ignored mutated fixture under a .local directory cannot look like shipped source. A real edge case carries nautilus-edge-ok: plus a reason.

Key parts

What the system does

These are the main boundaries, inputs, outputs, and failure rules. The examples show a specific use of each part.

One import boundary

Outside files are decoded and checked in one place. Downstream systems receive a known MerTek asset, not the original vendor format.

Specific example

A vehicle model from a supplier can enter a training scene without adding that supplier format to the renderer.

Standard asset profiles

Meshes, textures, rigs, animation, and point data have owned platform shapes. Each importer maps its source into those shapes.

Specific example

Drone imagery and a ground model can be prepared for the same visualization pipeline.

Vocabulary control

External field names end at import. MerTek uses clear internal terms so one supplier does not define the program data model.

Specific example

Different sensor vendors can map their material or image terms into one reviewed mission vocabulary.

Uses

Example uses

Pilot questions

What the team must decide

Which source formats suppliers deliver

What checks are required before an asset is accepted

Which asset terms need a shared program definition

Request a technical briefing