QIP Component Contract

There are four types of QIP components:

Content contract #

Hosts may call render(...) more than once on the same component instance. Each call is a new render request using the bytes currently written at input_ptr() and the component's current uniform state.

Component authors should make repeated renders deliberate:

This allows browser hosts to keep one module instance alive and render many inputs through it. It also allows wrappers to set uniforms immediately before each render without reinstantiating the component.

Content-Type Metadata (Optional)

Content components may optionally export content-type metadata for friendlier composition and host Content-Type selection.

Rules:

Content-Type Composition

These are the composition rules for QIP component pipelines:

Memory Recommendations

Interactive contract #

Pixel format

Input events

Tile contract #

Use Tile for qip image filter pipelines.

Required:

Optional:

Tile memory:

tile_bytes = tile_span * tile_span * 4 channels * 4 bytes(float32)

Where:

If any stage reports halo > 0, host uses the full-image float32 pipeline for all stages in the contiguous tile block.

See also: IMAGE.md.

Form contract #

Export style notes:

Contract Detection #

Detecting which contract a wasm module conforms to is a deterministic process of checking exports.

  1. qip run with exactly one component tries Interactive first-frame handling first.
  2. If that does not match, normal pipeline building starts.
  3. During pipeline building, any component exporting tile_rgba32float_64x64 is classified as Tile.
  4. Non-tile components are classified as Content.
  5. qip form uses the Form contract path.

Example:

Optional Uniforms (uniform_set_<key>) #

Components may export uniform setter functions and callers can pass values via query args.

Uniform export contract:

Host behavior:

CLI syntax:

Examples:

# i32 uniform
qip run modules/utf8/text-to-bmp.wasm '?cols=120'

# f32 uniforms
qip image -i in.jpg -o out.png modules/rgba/color-halftone.wasm '?max_radius=2.0&angle_c=0.26'

# packed 32-bit RGBA passed as hexadecimal (0xRRGGBBAA)
qip run modules/image/svg+xml/svg-recolor-current-color.wasm '?color_rgba=0xff5511ff'

Zig example:

var color_rgba: u32 = 0x000000FF;

// For wasm i32 uniforms, qip maps 0x-prefixed values as raw 32-bit bits.
export fn uniform_set_color_rgba(v: u32) u32 {
    color_rgba = v;
    return color_rgba;
}

Form Set Contract #

Use Form for prompt-driven workflows in qip form.

Claim: form logic should stay explicit and host-cooperative.

Reason:

For required exports and flow details, see docs/form_abi.md.

Intersections #

Content and Interactive:

Content and Tile:

Future Direction: Numeric Arrays And Tensors #

QIP used to allow exporting output_i32_cap, but we removed it from the current alpha.

The potential approach is array-shaped data: byte histograms, RGB histograms, line-offset tables, batched CRC results, image masks, label matrices, and quantized spectra. Those outputs are naturally numeric collections, not strings of bytes that happen to contain numbers.

When we revisit this, we should separate three concerns:

Mojo is useful prior art here because it treats scalar numerics as one-lane SIMD values while keeping tensor shape separate from memory layout. That points to a better QIP design than a one-off i32[]: start with SIMD-aware element types, then make shape and layout explicit enough for hosts and compilers to optimize without guessing.