The .iprop format

One self-contained binary: metadata, constants and bytecode, with no external resources.

Specification 0.7 · product 0.7.1

This page summarises the format. The canonical contract is the specification: iprop-v0.7.md. It contains the complete frozen contract. Earlier versions remain in Git history.

Versions

The format is unversioned: the four header bytes after the magic are reserved and must be zero in a file, in a compressed envelope and in its expanded payload, so files written before product 0.7 are rejected and need recompiling. The contract is the 0.7 specification. Numerical, drawing, RNG and collection algorithms retain their specified behavior. Variants, archetypes and their implicit arguments are removed from metadata, bytecode signatures and host APIs. C clients rebuild for API 0.4 / ABI 0.5. The 0.7 specification is frozen with product 0.7.0.

The file layout

header (20 bytes)              magic "IPRP", reserved, flags, section count
section table (12 bytes × N)   id, offset, size
sections                       meta · const · code · optional debug, parts and resource pools
  • All multi-byte values are little-endian; canonical sections are 4-byte aligned.
  • Header flag bit 0 marks the debug section; the validator rejects a flag/section mismatch.
  • Header flag bit 1 marks a packed file. After the 20-byte header come the expanded size (u32) and one zlib stream holding the complete original file. Encoded and expanded files are bounded to 64 MiB; the checksum, exact length, trailing data, dictionaries and nesting are checked before execution.

ipc strips debug data and packs only when that is smaller. Use --debug to keep source maps, --no-compress for an expanded file and --no-opt for the reference lowering; none of them changes the image or output bits.

The sections

sectioncontents
metathe canvas size, the origin, the fuel budget, the input uniforms (type, name, default) and the output slots (kind, list flag, name)
types / collectionscomplete type descriptors and immutable list data; helper values share arena handles
constdeduplicated pools of strings, i32, f32 and colours, referenced by index
codethe function table (names, signatures, locals, offsets), the instruction streams (4 bytes per instruction: opcode, aux, u16 operand) and the part table
debuginformative: local names and the source line of every instruction; stripping it never changes execution
partsone entry per part instance with its name (the import alias path, such as hilt.grip) and its parent, forming the tree that maps outputs into caller coordinates
samplers / distributions / steppersimmutable captured descriptions and point pools; sampler picks draw explicitly, steppers produce deterministic batches
resource exportsinternal mask/layer slots and function ownership, separate from host geometry outputs

Function 0 is the entry point draw with exactly one parameter per declared input, in declaration order starting at slot 0.

The virtual machine

  • A stack machine with locals and calls, and structured control flow only: block, loop, if/else, br, br_if.
  • Branch conditions are integers; floating comparisons produce integer 0/1 conditions.
  • Every instruction spends fuel from the budget declared in meta; running out aborts with a defined error, so every file terminates.
  • Mutable state includes render targets, declared outputs, stacks/locals and RNG streams. Immutable collections and surfaces share a bounded arena. Every canvas write is bounds-checked.

Determinism

  • Generation is a pure function of its inputs: the same file, seed, size and uniforms give the same image and outputs, bit for bit, on every platform and backend.
  • The seeded primitives are specification-pinned instructions, not library calls: the splitmix32 hash, the Weyl-sequence stream, value and fault noise, and the binary64 kernels behind the distributions.
  • Colour helpers pin their fused-multiply-add behaviour, so compiled code matches the reference builds exactly.
  • A committed golden corpus of (program, seed) images guards the pipeline: changing a golden pixel is a breaking change.