Components that are
Quick to make/maintain/run, Isolated from net/disk/deps, Portable to web/server/native.

QIP components are fast to create with coding agents and fast for users to run.

Users get small .wasm modules that load quickly. You get code small enough to review.

Render across browser, server, mobile, native, CLI, and CI. Same input, same output everywhere.


Today we grant every line of code the world #

Most software is built with layers of frameworks, packages, platforms, and operating-system features. It means even a tiny calculation assumes availability of installed packages, environment variables, filesystem layout, network services, locale, clocks, and the exact setup of the machine around it.

Containers can precisely package that environment. This is useful for full applications, but for a text/image transformation, validator, calculation, or small interactive tool, it is often more machinery than the work requires. Our defaults expand the security boundary that every line of code gets and now AI coding raises the stakes.

QIP uses a narrower boundary: explicit input, output, memory, and zero host access. That makes small components easier to create, test, and review — including code written by coding agents.

             host: files · network · clock · env · syscalls
          ━━━━━━━━━━━━━━━━━━━━━━━━━━╳━━━━━━━━━━━━━━━━━━━━━━━━━
                              (no imports)

 input       ┌────────────────────────────────────────────┐     output
 bytes &     │ component.wasm                             │     bytes
 uniforms    │ ╭────────────────────────────────────────╮ │     
             │ │ memory                                 │ │
             │ │  ┌──────────────┐   ┌───────────────┐  │ │
─────────────┼─┼─▶│ input buffer │──▶│ output buffer │──┼─┼───────────▶
             │ │  └──────────────┘   └───────────────┘  │ │
             │ ╰────────────────────────────────────────╯ │
             └────────────────────────────────────────────┘
                  small enough to read in one sitting

Components that render any content #

Use QIP components for text, images, documents, archives, interactive UI, or any MIME type.

Browse the text, image, audio, TUI, and GUI component collections.

Just like the web is request -> response, QIP components are input -> output. Yet QIP components are not tied to HTML or JavaScript: they take any content as input and render any content as output. You just say what MIME type it is.

Your components can render Markdown into HTML, URLs into QR codes, SVG into bitmap images, SQLite databases into CSV, or WARC archives into deployable websites. Missing something? Prompt a small component and add it to your collection.

echo "# A Markdown renderer that works _identically_ on any platform" \
| npx qipdo qip.dev text/markdown/gfm-commonmark.0.31.2.wasm
# <h1>A Markdown renderer that works <em>identically</em> on any platform</h1>

Portable pipelines of purity #

You can pipe one component into another step-by-step like a recipe.

Make a recipe you like? It will work identically on mobile, in a browser, in your CI pipeline, or on Windows. You can be confident if it works here, it works there.

For example, one component can render Markdown to HTML, then it passes that to the next component to highlight TSX code blocks:

printf '%s\n' \
  '# Markdown with code snippet' \
  '' \
  '```tsx' \
  'const pi: number = 3.14;' \
  '```' \
| npx qipdo qip.dev \
  text/markdown/gfm-commonmark.0.31.2.wasm \
  text/html/html-code-syntax-highlight-tsx.wasm

# <h1>Markdown with code snippet</h1>
# <pre><code class="language-tsx hljs"><span class="hljs-keyword">const</span> <span class="hljs-attr">pi</span>: <span class="hljs-built_in">number</span> = <span class="hljs-number">3.14</span>;
# </code></pre>

Browser rendering #

You can render the same QIP components in the browser:

HTML output

Use the <qip-edit> custom element to render a series of QIP components with user <input>.

<form aria-label="Markdown to HTML">
    <qip-edit>
        <source src="/text/markdown/gfm-commonmark.0.31.2.wasm" type="application/wasm" />
        <source src="/text/html/html-code-syntax-highlight-tsx.wasm" type="application/wasm" />
        <textarea name="input" rows="5"># Markdown with highlighted code
```tsx
const pi: number = 3.14;
```</textarea>
        <output name="output"><iframe title="Rendered HTML preview" sandbox></iframe></output>
    </qip-edit>
</form>

NoGPU <canvas> components #

QIP GUI Components receive keyboard and pointer events and render pixels.

They are pure WebAssembly, with no WebGL or WebGPU required. The same pixels come out in every browser, in CI and on a server, so snapshot tests are exact and server rendering runs on cheap CPUs.

Use <qip-play> to render them in the browser, or use our SDK to render them in Swift.


A component can also keep state between frames. This port of the Mac OS X Flurry screensaver keeps 3,600 smoke particles and its last frame in memory. Every 20 ms it fades the previous frame and draws the new smoke on top, as the original OpenGL version does.

See /flurry for how it works, and a stateless WGSL version that runs on both WebGPU and WebAssembly.


Components can return SVG too. Hover over the QIP logo and its twelve bars spring apart into a little character or a term like .SVG or .ZIG, then fly back when the pointer leaves. Click or tap to keep it.

See /play-qip-logo-creature for the keyboard controls and how it's built.



See /play for more interactive examples, or /charts for chart-focused components.

The website router without bitrot #

Markdown… Recipes… We can compose this into a static website generator. Each file gets rendered by a recipe of QIP components based on its MIME type. These become the HTTP response bodies.

Every component is replaceable. Don’t like the Markdown renderer? Swap it out.

And every page route becomes combined into a .warc Web Archive. This allows you to do site-wide transforms. Need a plugin to generate OG images? Vibe-code one.

First, create a folder of Markdown and images files and use qip router to render a website:

site/
  index.md
  about.md
  docs/index.md
  docs/install.md
  _recipes/text/markdown/10-commonmark.0.31.2.wasm
# Run a dev server on port 4114
qip router dev -C ./site -p 4114

# Make a HEAD request to the /about page
qip router head -C ./site /about

# Make a GET request to the /about page
# This works even with no dev server running, letting your coding agent test things
qip router get -C ./site /about

# Copy a component to syntax highlight bash code
cp html-code-syntax-highlight-bash.wasm ./site/_recipes/text/markdown/20-html-code-syntax-highlight-bash.wasm

# Generate an archive of the entire site with view source enabled to share your components
qip router warc -C ./site --view-source

The same components that you use to render the static site can run in the browser via JavaScript. There’s no such thing as a “server component” or “client component”: they are the same component.

Because components are self-contained, maintenance becomes a breeze. Don't worry about needing to update your dependencies every few months so your site still builds. Your site is content plus some .wasm files and a little bit of glue to connect the two. Bitrot be gone!

Tools without the trackers #

Ever need to generate a favicon or decode base64 and find yourself on a site with more ad banners than inputs? Here are some open source utilities that you can download the .wasm to and run locally.

Want another? Request me to make one.

FAQ #

What motivated a new component ABI?

I found existing uses of WebAssembly verbose or tied to specific hosts. For example, WASI is very large and still as of late 2026, isn’t stable, which makes it difficult to build upon. It also imports a lot of context from its environment which breaks a key goal of QIP, which is determinism. Another goal is platform-agnosticism, and I saw solutions like Emscripten were coupled to a JavaScript host which meant that JavaScript would have to be run on the server or on native, whereas I wanted to be able to choose the host runtime technology. Through this process of designing and evolving the ABI was to keep it small, this lets a range of language implement it, it makes the boilerplate required small, and its small surface area is hopefully easy to support long term.

How is QIP different from WASI?

WASI is useful when a WebAssembly program needs operating-system-like capabilities. QIP is purposefully much narrower. A QIP component gets bytes from the host, transforms them, and returns bytes. It cannot access the filesystem, network, environment, clock, or secrets.

That smaller contract allow components to run easily in browsers, mobile apps, servers, CI, and native hosts. It also makes the attack-surface much narrower.

How is QIP different from React?

React has become the default choice for making web apps and many native apps. Adopting React usually means adopting JavaScript full-stack. QIP wants to be platform and language agnostic: you can write QIP components in anything that compiles to .wasm and you can run .wasm modules pretty much in any modern platform. Because QIP Components are just WebAssembly they work in React (TODO: React QIP documentation page).

How is QIP different from Flutter?

Flutter follows the write-once, run-anywhere philosophy. QIP is also write-once, run-anywhere but is designed to be embedded inside existing apps. You don’t have to port your entire app to QIP and WebAssembly.

This means you can make the most of native tooling and frameworks with proper UI controls and tight integration with the target platform. And then you sprinkle in QIP components where they make sense for their cross-platform or security benefit.

Flutter helps you write one app for many platforms. QIP helps you write one component for many apps.

Learn more #