{"_id":"@ardabot/lensui","_rev":"2-c275d53fc01683cf7fddfd8aac028ab5","name":"@ardabot/lensui","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@ardabot/lensui","version":"0.1.0","author":{"url":"https://www.ardabot.ai/","name":"ArdaBot, Inc."},"license":"MIT","_id":"@ardabot/lensui@0.1.0","maintainers":[{"name":"ardabot","email":"cj.bordeleau@ardabot.ai"}],"homepage":"https://lensui.vercel.app","bugs":{"url":"https://github.com/ardabotai/lensui/issues"},"bin":{"lensui":"dist/bridge.js","lensui-bridge":"dist/bridge.js"},"dist":{"shasum":"cc4e192a6e1d267e6cd1454fd6439db2a1ebf16d","tarball":"https://registry.npmjs.org/@ardabot/lensui/-/lensui-0.1.0.tgz","fileCount":31,"integrity":"sha512-Nj5pqu+/K5wTixeXUx1rwwMZjrphDYjTG0x9/wLAjIfAv4eavlp998cQQnuUBCnKXmi29cSus17lwTInIgzBgg==","signatures":[{"sig":"MEUCIANKO4B0Wt5AwSaraqD7DkcZofa2EYxICcGlWqb1JKwzAiEAipxz3KhpRWw8rAXdXFkjPZXxGRztIjbV+9hCD2Yb+To=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1436488},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./byok":{"types":"./dist/byok.d.ts","default":"./dist/byok.js"},"./core":{"types":"./dist/core.d.ts","default":"./dist/core.js"},"./html":{"types":"./dist/html.d.ts","default":"./dist/html.js"},"./skill":"./skills/lensui/SKILL.md","./stage":"./dist/lensui.stage.global.js","./bridge":{"types":"./dist/bridge.d.ts","default":"./dist/bridge.js"},"./client":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"./mcp-server":{"types":"./dist/mcp-server.d.ts","default":"./dist/mcp-server.js"},"./html/stage-global":{"types":"./dist/stage-global.d.ts","default":"./dist/stage-global.js"}},"gitHead":"9baa3bea9b243eac66ee1b7218657b7eea120b5f","scripts":{"build":"node scripts/build.mjs"},"_npmUser":{"name":"ardabot","email":"cj.bordeleau@ardabot.ai"},"repository":{"url":"git+https://github.com/ardabotai/lensui.git","type":"git"},"_npmVersion":"10.9.7","description":"Token-efficient generative UI runtime for agent-rendered interfaces.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/lensui_0.1.0_1779139843503_0.8251979111812773","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ardabot/lensui","version":"0.2.0","description":"Token-efficient generative UI runtime for agent-rendered interfaces.","type":"module","license":"MIT","author":{"name":"ArdaBot, Inc.","url":"https://www.ardabot.ai/"},"homepage":"https://lensui.vercel.app","repository":{"type":"git","url":"git+https://github.com/ardabotai/lensui.git"},"bugs":{"url":"https://github.com/ardabotai/lensui/issues"},"publishConfig":{"access":"public"},"bin":{"lensui":"dist/bridge.js","lensui-bridge":"dist/bridge.js"},"main":"./dist/index.js","types":"./dist/index.d.ts","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./core":{"types":"./dist/core.d.ts","default":"./dist/core.js"},"./html":{"types":"./dist/html.d.ts","default":"./dist/html.js"},"./html/stage-global":{"types":"./dist/stage-global.d.ts","default":"./dist/stage-global.js"},"./client":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"./mcp-server":{"types":"./dist/mcp-server.d.ts","default":"./dist/mcp-server.js"},"./byok":{"types":"./dist/byok.d.ts","default":"./dist/byok.js"},"./bridge":{"types":"./dist/bridge.d.ts","default":"./dist/bridge.js"},"./stage":"./dist/lensui.stage.global.js","./skill":"./skills/lensui/SKILL.md"},"scripts":{"build":"node scripts/build.mjs"},"_id":"@ardabot/lensui@0.2.0","gitHead":"c8a806414e02bd97df29f421283d64b7e4438d0e","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-Z1JW/SQbWmmvLCa/mwgDBziJhG3Cf8rxCfLs9t5800nhx+CUXzlnDkc0JHvXiES0y55l+gP8Yj/kgQGGHU5reA==","shasum":"9f1fde5c9d61c9f7beb0a597e8c2fba87bcb9eef","tarball":"https://registry.npmjs.org/@ardabot/lensui/-/lensui-0.2.0.tgz","fileCount":31,"unpackedSize":1688977,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDtwUcVR5ry7gsv4lomFYAMMRN7GKeEkLwn5I9+oL2RfgIgSVhfKoGxA1ev0fgA9hkfHgtfb3CO6WCgJbQeeprYBuU="}]},"_npmUser":{"name":"ardabot","email":"cj.bordeleau@ardabot.ai"},"directories":{},"maintainers":[{"name":"ardabot","email":"cj.bordeleau@ardabot.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lensui_0.2.0_1779393921606_0.5310955174253198"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-18T21:30:43.417Z","modified":"2026-05-21T20:05:21.896Z","0.1.0":"2026-05-18T21:30:43.774Z","0.2.0":"2026-05-21T20:05:21.783Z"},"bugs":{"url":"https://github.com/ardabotai/lensui/issues"},"author":{"name":"ArdaBot, Inc.","url":"https://www.ardabot.ai/"},"license":"MIT","homepage":"https://lensui.vercel.app","repository":{"type":"git","url":"git+https://github.com/ardabotai/lensui.git"},"description":"Token-efficient generative UI runtime for agent-rendered interfaces.","maintainers":[{"name":"ardabot","email":"cj.bordeleau@ardabot.ai"}],"readme":"# LensUI\n\nLensUI is a token-efficient generative UI runtime for agents. It renders compact lightcode and command streams into live browser UI, while staying agnostic to voice, auth, billing, memory, model providers, and host capabilities.\n\n[Docs](https://lensui.vercel.app) · [GitHub](https://github.com/ardabotai/lensui) · [npm](https://www.npmjs.com/package/@ardabot/lensui)\n\nThe framework is designed for agents that should show visual answers without sending HTML, JSX, Tailwind classes, CSS, D3 calls, Three.js scenes, or arbitrary JavaScript on every turn. The agent sends semantic UI lightcode; the renderer owns the DOM, layout fitting, component lifecycle, media handling, and live source updates.\n\nThe built-in renderer favors compact semantic components over repeated markup. High-leverage surfaces such as timelines, comparisons, source strips, steps, memory readbacks, media mosaics, tables, news lists, and media rails accept `items=` rows using `^` for cells and `;` for rows, so models can compose rich UI with a handful of lines.\n\n## npm Package\n\n`@ardabot/lensui` is the single public npm package for LensUI. It includes the lightcode parser, browser DOM renderer, command stream client, optional MCP/BYOK helpers, local loopback bridge, global browser bundle, and canonical agent skill.\n\nSubpath exports:\n\n- `@ardabot/lensui/core` - parser, command stream parser, component registry, workspace state, metadata extraction, and shared types.\n- `@ardabot/lensui/html` - browser DOM renderer, built-in components, source updates, lifecycle hooks, and `window.lensStage`.\n- `@ardabot/lensui/client` - optional WebSocket client for receiving command streams from a host.\n- `@ardabot/lensui/mcp-server` - optional session-bound MCP bridge for applying lightcode to connected clients.\n- `@ardabot/lensui/byok` - optional local/dev BYOK inference adapter. This is not part of core rendering.\n- `@ardabot/lensui/bridge` - local loopback bridge that lets coding agents send lightcode into a live browser LensUI container, plus filesystem registry helpers for local hosts.\n- `@ardabot/lensui/skill` - packaged agent instructions for generating and repairing LensUI lightcode.\n\nLensUI core and HTML packages contain no provider SDKs, auth, billing, memory, voice, WebKit, or host tool code.\n\n## Quick Start\n\nInstall the browser runtime into a host app:\n\n```sh\nnpm install @ardabot/lensui\n```\n\n`pnpm add @ardabot/lensui`, `yarn add @ardabot/lensui`, and `bun add @ardabot/lensui` work too.\n\nMount a runtime and render compact lightcode:\n\n```ts\nimport { createPersistentStageRuntime } from \"@ardabot/lensui/html\";\n\nconst root = document.querySelector<HTMLElement>(\"#lens-stage-mount\");\nconst stage = createPersistentStageRuntime(root!);\n\nstage.setSource(\"markets\", { bitcoin: { usd: 76448 }, ethereum: { usd: 2098 } });\n\nstage.render(`0DS|markets|https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd|ttl=30|mode=poll\n0F|st=mono|mode=dark\n0V|Market Pulse|Live source\n1G|auto|min=180|max=3\n2M|BTC|$markets.bitcoin.usd|usd\n2M|ETH|$markets.ethereum.usd|usd\n2M|Tokens|-64%|vs React\n1H|line|4,7,6,10,9,13,16|trend|h=190`);\n```\n\nRendered by the browser runtime:\n\n![LensUI rendered Market Pulse example](./assets/readme-render.png)\n\nFor script-tag usage, copy or serve `node_modules/@ardabot/lensui/dist/lensui.stage.global.js`, add `<div id=\"lens-stage-mount\"></div>`, and call `window.lensStage.render(...)`. Fixed app surfaces can use the default `stage` sizing; iframe/card embeds can opt into content-driven sizing with `<div id=\"lens-stage-mount\" data-lens-sizing=\"auto\"></div>`.\n\nFor agents, run `npx -y --package @ardabot/lensui@latest lensui skill` or use [`skills/lensui/SKILL.md`](./skills/lensui/SKILL.md) as the canonical instruction source for lightcode, LightStyle, compact rows, patching, and component repair.\n\n`createPersistentStageRuntime` loads and saves the component/style registry in `localStorage` by default. That lets agents save a component once, then refer to it by name in later renders instead of resending full HTML, CSS, or JavaScript. Browser hosts can pass a custom key with `createPersistentStageRuntime(root, { persistence: { key: \"my-app:lensui\" } })`. Native or Node adapters can persist the same `LensUISavedRegistry` shape to local files; `@ardabot/lensui/bridge` exports `loadRegistryFromFile` and `saveRegistryToFile` for local filesystem hosts.\n\n## Live Agent Demo\n\nThe docs demo can generate a scoped `lensID` and secret token for one LensUI container. Run the local bridge, then paste the generated prompt into Claude Code or another local coding agent:\n\n```sh\nnpx -y --package @ardabot/lensui@latest lensui bridge --port 5743\n```\n\nThe browser connects out to `http://127.0.0.1:5743`, and the agent posts compact lightcode back to that same local bridge:\n\n```sh\ncurl -X POST http://127.0.0.1:5743/lens/<lensID>/render \\\n  -H \"authorization: Bearer <token>\" \\\n  -H \"content-type: application/json\" \\\n  --data '{\"lightcode\":\"0F|st=mono\\n0V|Hello from your agent\"}'\n```\n\nUse `npx -y --package @ardabot/lensui@latest lensui skill` to print the LensUI agent skill from the npm package. The bridge binds to loopback by default, requires the per-container token, and routes only to browser containers that have already opened the matching event stream.\n\nThe bridge has two write endpoints:\n\n- `POST /lens/:lensID/render` with `{ \"lightcode\": \"...\" }` for ordinary semantic renders.\n- `POST /lens/:lensID/apply` with `{ \"commandStream\": \"...\" }` for patches, saved components, saved styles, source updates, and page actions.\n\nCommand streams start with `!`. Block commands continue until a lone `.`:\n\n```text\n!\n@!|CanvasPanel|html|agent-generated\n<div><canvas></canvas><script>/* custom component code */</script></div>\n.\nR\n0F|st=studio\n0V|Custom UI|Saved component\n1CanvasPanel\n.\n```\n\n`/render` and `/apply` returning `200` means the bridge delivered the message to a connected browser. If the browser target is not open or the token is stale, the bridge returns `No connected LensUI container for that lensID/token.`\n\nFrom this repository:\n\n```sh\npnpm install\npnpm build\npnpm build:site\npnpm bench\npnpm test\npnpm coverage\npnpm e2e\n```\n\nWhen LensUI is vendored inside another app, run the same commands from the parent with `pnpm --dir LensUI ...`.\n\n## Maintainer Release\n\nThe public runtime ships as one npm package named `@ardabot/lensui`:\n\n```sh\npnpm build\npnpm pack:check\npnpm publish:npm\n```\n\nFor npm accounts that require a one-time password:\n\n```sh\npnpm publish:npm -- --otp 123456\n```\n\nUse `pnpm publish:npm -- --dry-run` to inspect the tarball without publishing.\n\nThe package is MIT licensed and host-neutral. The docs app and examples stay in the GitHub repo; runtime consumers normally install `@ardabot/lensui`.\n\n## Browser Runtime\n\nBuild output:\n\n```text\nnode_modules/@ardabot/lensui/dist/lensui.stage.global.js\n```\n\nMount it in any browser app:\n\n```html\n<div id=\"lens-stage-mount\"></div>\n<script src=\"./dist/lensui.stage.global.js\"></script>\n<script>\n  window.lensStage.render(`0F|0\n0V|LensUI|Agent rendered UI\n1G|auto|min=180|max=3\n2M|Latency|182|ms|tone=success\n2H|line|4,7,6,10|trend`);\n</script>\n```\n\nRuntime sizing is host-declared on the mount element:\n\n```html\n<!-- Fixed app/TV/canvas surface. Content fits the box when possible and scrolls on overflow. -->\n<div id=\"lens-stage-mount\" data-lens-sizing=\"stage\"></div>\n\n<!-- Embedded/docs/card surface. Content keeps natural height and the host can resize around it. -->\n<div id=\"lens-stage-mount\" data-lens-sizing=\"auto\"></div>\n```\n\nAfter each render, source update, or resize, the HTML runtime dispatches a bubbling `lensui:size` event from the mount. Hosts can use `detail.contentHeight` and `detail.contentWidth` to resize iframes or native containers. Agents and MCP bindings can also ask the runtime for the latest snapshot with `read(\"layout\")` before sending a dense render:\n\n```ts\nroot.addEventListener(\"lensui:size\", (event) => {\n  const { sizing, flow, contentHeight } = (event as CustomEvent).detail;\n  if (sizing === \"auto\") iframe.style.height = `${contentHeight}px`;\n  console.debug(\"LensUI layout\", flow);\n});\n\nconst layout = window.lensStage.read(\"layout\");\n```\n\nThe global runtime API:\n\n```ts\ninterface LensStageRuntime {\n  render(lightcode: string, components?: LensComponentDefinition[], styles?: LightStylePackDefinition[], defaultStyle?: string): LensApplyResult;\n  apply(commandStream: string): LensApplyResult;\n  patch(offset: number, deleteCount: number, lightcode: string): LensApplyResult;\n  registerComponent(definition: LensComponentDefinition): LensApplyResult;\n  patchComponent(name: string, offset: number, deleteCount: number, source: string): LensApplyResult;\n  deleteComponent(name: string): LensApplyResult;\n  registerStyle(definition: LightStylePackDefinition): LensApplyResult;\n  patchStyle(name: string, offset: number, deleteCount: number, source: string): LensApplyResult;\n  deleteStyle(name: string): LensApplyResult;\n  setDefaultStyle(name?: string): LensApplyResult;\n  setSource(id: string, payload: unknown): boolean;\n  read(kind: \"lightcode\" | \"components\" | \"styles\" | \"registry\" | \"metadata\" | \"status\" | \"layout\"): unknown;\n  loadRegistry(registry: LensUISavedRegistry): LensApplyResult;\n  enablePersistence(options?: LensRegistryPersistenceOptions): LensStageRuntime;\n  persistRegistry(options?: LensRegistryPersistenceOptions): void;\n  clearPersistedRegistry(options?: LensRegistryPersistenceOptions): void;\n}\n```\n\n## Lightcode And Commands\n\nLightcode is optimized for runtime token efficiency, not human readability.\n\n```text\n0DS|news|https://example.com/feed.json|ttl=600|mode=poll\n0F|st=mono|f=mono|d=compact\n0Y|panel|bg=card|bd=fg/28|p=4|r=2\n0V|Brief|Live source\n1M|Headline|$news.headline|source|s=panel\n1NL|Latest||$news.items\n```\n\nEvery render lightcode line starts with a base36 depth token. `0` is top level, `1` is the child level, `2` is the grandchild level, and so on. The depth token replaces indentation so the protocol keeps hierarchy without spending tokens on whitespace.\n\nLensUI containers are designed to be screen-size and aspect-ratio agnostic. Agents should express layout intent with semantic containers such as `G|auto|min=180|max=3`; the browser runtime then collapses columns by the actual container width, prefers scrollable portrait flow on narrow screens, and only scales as a last resort. This keeps host experiences polished without making LensUI output depend on 16:9.\n\nLightStyle lives in the same lightcode document. `0F` controls frame-level visual direction and can reference saved packs with `st=name`; `0Y` defines compact style recipes; nodes apply recipes with `s=name`. Built-in packs include `neutral`, `mono`, `studio`, `paper`, `gallery`, and `terminal`; each pack provides light and dark palettes and defaults to `mode=system`. Force a scheme only when needed with `0F|mode=light` or `0F|mode=dark`; palette-specific overrides use keys such as `light-bg=0,0,98` and `dark-bg=0,0,3`. LightStyle is semantic token data, not CSS. It styles UI chrome, typography, panels, charts, and renderer-owned accents only; source media, art, video, animation, canvas/WebGL art, and embedded web content keep original colors.\n\nCommand streams patch UI, components, and style packs without resending the whole stage:\n\n```text\n!\n@!|KPI|a|g\n0@|KPI|M|tone=success\n.\nY!|mono-compact|g\n0F|f=mono|d=compact|r=2|fx=grid\n0Y|panel|bg=card|bd=fg/28|p=4|r=2\n.\nR\n0F|st=mono-compact\n0V|Market\n1KPI|Cost|12|usd|s=panel\n.\n^|3|1\n1KPI|Cost|14|usd\n.\n```\n\nLive data transport is host-owned. A host can poll HTTP, subscribe over WebSocket/SSE, receive native app events, or proxy gateway updates, then push snapshots into the existing surface with `stage.setSource(\"id\", payload)` or a command-stream source update:\n\n```text\n!\nS|markets|application/json\n{\"btc\":\"$104.8K\",\"trend\":[4,7,6,10]}\n.\n```\n\nSource updates re-resolve `$source.path` bindings in metrics, charts, lists, status rows, and other renderer-owned nodes without asking the agent to regenerate lightcode.\n\n## Security Model\n\nLensUI validates lightcode before committing render state. Failed renders leave the previous UI intact.\n\nThe uncomfortable part is real: LensUI can run agent-authored HTML, CSS, and JavaScript components. That is intentionally on by default because raw components are the path to maximum expressiveness. Treat those components like untrusted plugin code unless your host has reviewed or promoted them.\n\nThe renderer does not store provider tokens, does not perform billing, and does not own host permissions. Browser security boundaries, CSP, sandboxed iframes, isolated origins, approval hooks, component allowlists, and host-owned capability brokers are the right places to decide what a given app will accept. Keep secrets, billing, auth, and privileged effects out of frontend components; route sensitive actions through host APIs that can validate and confirm them.\n\nSaved components are classified by trust level:\n\n- `built-in`\n- `user-saved`\n- `agent-generated`\n- `remote-imported`\n\nJavaScript belongs in saved components, not ordinary render lightcode. Hosts can allow `html` or `react` components for rich custom behavior, but normal agent turns should instantiate those components by short name so token cost, cleanup, and patching stay manageable.\n\nHosts that need a stricter posture can pass `componentPolicy` to `createStageRuntime` or `createPersistentStageRuntime` to disable HTML components, scripts, inline event handlers, or style tags.\n\nProvider inference should normally live in a host or gateway. The optional BYOK adapter is for local/dev/self-hosted use where the user intentionally supplies their own provider endpoint and token.\n\n## Examples\n\n- `examples/stage-template.html` - minimal stage fixture used by E2E tests.\n- `examples/embedded-demo.html` - mount LensUI inside a normal app region, register a component, apply command streams, and update a live source.\n- `apps/docs` - compact Next.js documentation app with Home, Specimens, and Demo routes. The proof surfaces use the real LensUI runtime where practical.\n- `docs/benchmarks.json` - checked-in token-efficiency fixtures comparing equivalent React, HTML, and LensUI lightcode payloads.\n- `skills/lensui/SKILL.md` - reusable agent skill for hosts that want models to generate LensUI lightcode.\n\n## Development\n\n```sh\npnpm install --frozen-lockfile\npnpm build\npnpm build:site\npnpm dev:site\npnpm typecheck\npnpm bench\npnpm test\npnpm coverage\npnpm e2e\n```\n\n`pnpm bench` estimates token savings for checked-in fixtures and fails when\naverage savings drop below the documented CI floor. The benchmark is transparent\nand intentionally simple so protocol bloat is visible in review.\n\nCoverage uses Vitest's V8 provider and writes text, JSON summary, and lcov\nreports to `coverage/`. The current package-wide floor is 45% statements, 40%\nbranches, 50% functions, and 46% lines across `packages/*/src/**/*.ts`.\n\nHost applications can copy `dist/lensui.stage.global.js` into their own app resources during packaging. LensUI itself remains host-agnostic.\n\n## License\n\nLensUI is MIT licensed.\n\nCopyright (c) 2026 ArdaBot, Inc.\n","readmeFilename":"README.md"}