┏━━━┓ ━┳━ ┏━━━┓
┗━┳━┛ ━┻━ ┣━━━┛
QIP Components are Quick to run/make/maintain, Isolated from network/disk/dependencies, and Portable across browser/server/native.
QIP Components are fast for you to create with coding agents and fast for users to run. Your users get small .wasm modules that load fast. You get small amounts of code that is easy to review.
We believe small functions should not need a massive application environment to run. Write or vibe Zig/C then compile to WebAssembly, and you get a deterministic puzzle piece that runs the same everywhere in the browser, on the server, on native, or in your terminal.
Render text, images, documents, PDFs, zip files, or even interactive TUIs or GUIs. Components pass content in and content out, with an optional MIME type for each side. You can combine components step-by-step like a recipe.
Make a recipe you like? You can be confident it will work identically on mobile, in a browser, in your CI pipeline, on Windows, or whatever comes next. If it works here, it works there.
Modern software never stops moving. QIP components are self-contained, so you can worry less about supply-chain attacks, outdated libraries, remote-code execution, and environment drift.
QIP is built around a strict contract: same component with the same input results in the same output. It does not read the clock, locale, filesystem, package graph, environment variables, OS, device, config, or network — unless you deliberately pass it in. Every input is explicit. This determinism means if it works today, it’ll continue to work tomorrow.
Components, AI coding, security: you can pick all three.
Install CLI
npm install --global @qip.dev/qipx
qipx requires Node.js 22 or newer.
Try It
Let's start by running rgb-to-hex.wasm. qipx downloads the component from qip.dev and saves it locally at text/rgb-to-hex.wasm:
printf 'rgb(101, 79, 240)' \
| npx @qip.dev/qipx qip.dev run text/rgb-to-hex.wasm
It prints #654ff0.
Now benchmark the same component with the same input:
printf 'rgb(101, 79, 240)' \
| npx @qip.dev/qipx qip.dev bench \
-i - --runs 100 text/rgb-to-hex.wasm
Test behavior complies with a reusable oracle that checks a range of expected output or can even fuzz:
npx @qip.dev/qipx qip.dev comply \
text/rgb-to-hex.wasm \
--suite oracles/rgb-to-hex.comply.wasm
Then open the same component in the interactive qipdb debugger:
npx @qip.dev/qipx qip.dev tui \
-F component=@text/rgb-to-hex.wasm \
-F 'input=rgb(101, 79, 240)' \
tui/qipdb.wasm
Press ↓ to step instruction by instruction seeing state of memory and every variable. Press Space to continue to completion and Ctrl-C to exit.
Press b s to stop before the next SIMD instruction. Press b m w to stop
before the next instruction that writes linear memory.
Multiple components run left to right like a unix pipeline:
printf 'qip + wasm\n' \
| npx @qip.dev/qipx qip.dev run \
bytes/zlib-compress.wasm \
bytes/base64-encode.wasm
On macOS, pipe the clipboard through a component and copy the result back:
pbpaste | npx qipdo qip.dev text/unicode-17-uppercase.wasm | pbcopy
qipdb
qipdb runs a QIP Content component inside a small WebAssembly interpreter and
shows its instructions, operand stack, locals, globals, linear memory, calls,
loops, and live counters.
Start with the small rgb-to-hex component:
npx @qip.dev/qipx qip.dev tui \
-F component=@text/rgb-to-hex.wasm \
-F 'input=rgb(101, 79, 240)' \
tui/qipdb.wasm
Inspect a larger Commonmark Markdown component with tables and indirect calls:
npx @qip.dev/qipx qip.dev tui \
-F component=@text/markdown/commonmark.0.31.2.wasm \
-F 'input=# Hello from qipdb' \
tui/qipdb.wasm
Debug a PNG decodee with SIMD acceleration passing a image file as input:
npx @qip.dev/qipx qip.dev tui \
-F component=@image/png/png-to-bmp-b8g8r8a8-srgb-simd.wasm \
-F [email protected] \
tui/qipdb.wasm
qipdb deliberately supports a bounded
WebAssembly profile rather than every WebAssembly feature, this lets it gain determinism.
Module contract
QIP does not use WASI or WIT, standards that have ballooned in complexity from scope creep. We want to get stuff done in today’s browsers so we pick a much smaller contract between hosts and modules:
input_ptr() / input_bytes_cap(): where the host writes input.
input_content_type_ptr() / input_content_type_size(): optional MIME type of the input
output_bytes_cap(): the declared maximum output size.
output_content_type_ptr() / output_content_type_size(): optional MIME type of the output
render(input_size) -> i64: function that does the work to transform input and return the output pointer and
size, or reject the input.
uniform_set_<key>(value): optional primitive integer/float parameters applied before rendering.
You can read more about the Content component contract in our docs.
CLI Usage
You can pipe the results of other CLI tools to stdin, pass one raw file with
-i, or construct form data with repeatable -F options. Combine -i with typed
-F file parts for multipart/related. You can also
chain multiple QIP components together like unix tools.
Put one or more HTTPS hosts before run, dry run, bench, or comply to
load a missing component by its relative path:
printf '# Hello\n' \
| qipx qip.dev run text/markdown/gfm-commonmark.0.31.2.wasm
qipx uses local components when available. Otherwise, it downloads them over HTTPS and saves them at the same local file path for later runs. There's no special protocol or discovery mechanism: it’s just a GET.
This is the beginning of the README. Read the rest at the original. Read the full README ↗