npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vivariumjs/runtime

v0.8.0

Published

Sandboxed runtime for AI-generated UI — capability bridge, stable element identity, and inspection. Browser-side member of the Vivarium family.

Readme

Vivarium

Sandboxed runtime for AI-generated UI — render generated code safely, with stable element identity and inspection built in.

Status: published on npm — @vivariumjs/runtime, 0.x (pre-1.0: minor versions may change the surface — see the changelog). This document is the project's anchor: it fixes purpose, scope, and the small set of principles that implementation must honor. The sandbox core, capability bridge, stable identity layer, execution profiles, and the edit context contract are implemented and covered by unit + real-browser e2e tests.

To embed it in your app, start with the getting-started guide (npm install @vivariumjs/runtime). The shortest path, for a browser page with a #canvas element:

import { mountSandbox, CapabilityRegistry } from "@vivariumjs/runtime";

const registry = new CapabilityRegistry();
registry.grant({ name: "greeting.get", description: "a line of text" }, () => "Hello");

const sandbox = mountSandbox(document.getElementById("canvas") as HTMLElement, { registry });
await sandbox.whenReady();
await sandbox.render(`
  export default async function mount(root, api) {
    root.textContent = await api.invoke("greeting.get");
  }
`);

Supported Node: the package declares engines.node >= 20, and CI runs a fresh consumer install on that floor every build — the floor is executed, not just claimed. It is a supported floor, not a recommendation: Node 20 reached end-of-life on 2026-04-30, so an actively supported release line is the better choice for new work.


Why

AI can now write UI code on demand. What it cannot do is be trusted — and neither can the code it writes. Today there are two ways to run AI-generated UI, and both are wrong:

  1. Invent a declarative DSL and interpret it. Safe, but it caps expressiveness at whatever the DSL anticipated. Every real-world app eventually needs the escape hatch the DSL doesn't have.
  2. Run the generated code as-is. Fully expressive, but the generated code inherits the privileges of its host — data access, network, DOM — with no boundary between "what the AI wrote" and "what the platform allows."

Vivarium takes the third path: generated code runs with full expressiveness inside a hard isolation boundary, against a capability surface the host explicitly grants. The code is real code. The boundary is real too.

A second, equally important problem: once generated UI is on screen, humans point at it. "Make this textbox bigger." For an agent to act on that, every rendered element must be addressable — stably identified, mappable back to its source, and serializable as context for the next edit. Inspection is not a devtool bolted on later; it is half the reason this runtime exists.

What Vivarium is

  • An execution sandbox. Generated UI code runs in an isolated realm. It cannot reach the host page, host storage, or the network except through the bridge the host installs.
  • A capability bridge. The only channel between sandbox and host. The host decides what the generated code may do and hear: which data APIs it can call, which events it can emit, which host events it can subscribe to. Nothing is ambient.
  • Execution profiles. Which libraries generated code may import, and how its source is transformed before it runs, is data the host supplies — an embedded import map plus a source transform. What generated code can compose is therefore enumerable, not whatever a CDN happens to serve.
  • An identity and inspection layer. Every rendered element is addressable, under two names with two honest lifetimes. Its ID is an address: an ID the generated code authored (data-viv-id) is durable across re-renders and re-generations, while a synthesized one names a position in the current render. Its reference names that one element for as long as it lives and is never re-pointed — when the element is gone, the runtime refuses the reference instead of describing whatever took its place. Users can select elements; selections serialize into an edit context — a machine-readable description of "what the user is pointing at, in which screen, backed by which source" — consumable by any editing agent.
  • A no-build path from generation to pixels. Generated code renders without an offline compile/bundle/deploy cycle. Changes appear in seconds, not pipelines.

What Vivarium is not

  • Not a page-builder GUI. There is no drag-and-drop editor here. Vivarium renders and inspects; authoring is someone else's job (a human, or an agent such as vivarium-agent).
  • Not an agent. Vivarium never calls a model. It produces edit contexts and consumes code; what happens between the two is out of scope.
  • Not a data layer. Vivarium does not know what a schema is. Data arrives through the capability bridge from whatever backend the host wires in.
  • Not a design system. Profiles define capability, not appearance. Theming and visual identity belong to the host.

Fixed principles

These are the anchors. An implementation that violates one of these is not Vivarium.

  1. The sandbox boundary is absolute. No configuration flag may grant generated code direct host access. If the bridge doesn't expose it, it doesn't exist.
  2. Capabilities are explicit and enumerable. The host grants; the sandbox requests; nothing is ambient. An agent (or auditor) can list everything a piece of generated UI is able to do.
  3. Every element is addressable. Stable identity is mandatory, not optional. Code without identity annotations is still runnable, but the runtime synthesizes and maintains IDs regardless.
  4. The edit context is a public contract. Its shape is versioned and documented, because external tools (agents, editors, tests) depend on it.
  5. Generation-to-render is measured in seconds. Any design that reintroduces an offline build step between "the agent wrote code" and "the user sees it" is a regression.

Decided in v0

  • Isolation: a sandboxed iframe (opaque origin, allow-scripts only) with a default-src 'none' document CSP — network egress is closed; the bridge is the only channel. A host may let generated UI display images or media from data:/blob: URLs it builds inside the sandbox (inlineSources); no option opens a network source.
  • That boundary is one of origin and network, not of time. Whether generated code that never yields stalls the host page is the engine's call: Chromium runs the sandboxed frame apart from the page, Firefox on the page's own thread. The opt-in watchdog reports and tears down code that stops answering wherever the engine keeps the page running — see the guide.
  • Bridge: JSON-RPC 2.0 over postMessage; capabilities surface as enumerable cap:<name> methods granted by the host, and host events travel the other way as evt:<name> notifications — granted by name, subscribed to by name.
  • Generated code: ES modules, default-exporting mount(root, api). Execution profiles are pluggable data (embedded module import map + host-side source transform); the reference profile is React + TSX via Sucrase. It is built from this repository (test/react-tsx-profile.js, tools/build-profile-assets.ts) and is not part of the npm package; without a profile, generated code is a plain ES module working on the DOM.
  • Identity: deterministic structural ids (viv:tag[n]/…), authored data-viv-id preserved with descendants anchored under it; per-element references (ref:<n>, never reused) for holding a selection.
  • Edit context: versioned public contract — see docs/edit-context.md.

Host integration note

Keep the sandbox container inside the viewport. Chromium throttles requestAnimationFrame in offscreen iframes, so an artifact whose mount awaits an animation frame will hang (and the render request will time out) if the host page lets the sandbox scroll out of view.

Deliberately undecided

  • Whether and how third-party component whitelisting works
  • A curated primitive surface (inputs, lists, layout, data views) above the profiles — versioned and enumerable, so agents can be taught exactly what exists. Not built: today generated code composes the DOM or a profile's library.
  • State handover across re-renders (the unmount path exists; re-render does not yet offer the outgoing module a save opportunity)

Relationship to MCP Apps

MCP Apps, the Model Context Protocol's UI extension, and Vivarium share an isolation and transport shape: generated UI runs in a sandboxed iframe and talks to its host over JSON-RPC on postMessage, starting with an initialize handshake. They answer different questions. MCP Apps delivers a server's UI into a conversation host. Vivarium makes every element of a generated screen addressable, turns what the user points at into an edit context, and lets the change travel as a reviewable changeset.

Vivarium does not implement MCP Apps, and no MCP host is needed to use it. Connecting the two is adapter work on the consuming side. One difference decides what such an adapter can carry: an MCP App view may declare the network origins it needs (_meta.ui.csp), while Vivarium's sandbox opens no network source under any option. A view that depends on the network cannot run unchanged inside it; its data has to arrive through granted capabilities instead.

Relationship to the Vivarium family

A running instance of the family — propose, preview, approve, apply, roll back — is browsable as a gallery of archived runs: vivarium-gallery (live). Each exhibit keeps the final artifacts, the turn ledger and the rollback record of an actual run. A run archived with its changeset documents and approval records can be re-checked offline against them, without a server or a model; the index marks the runs that cannot.

Vivarium is the family's namesake and its only browser-side member. It depends on nothing except, where changesets are exchanged, the vivarium-changeset contract. It is consumed by hosts directly, and its edit context is the input format of vivarium-agent.

Standalone use is a first-class scenario: "embed safely-sandboxed, AI-generated UI in an existing product" requires this repo and nothing else.

License

MIT. The runtime is and will remain free, fully functional, and offline-capable — no accounts, no feature gates.