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

@braincrew-lab/langchain-canvas

v0.7.26

Published

A live canvas for LangChain agents — stream documents, charts, and rich artifacts into a React panel.

Readme

@braincrew-lab/langchain-canvas

A canvas for your LangChain chat app. Your agent streams an artifact — a web page, a spreadsheet, a slide deck, a chart, a document — and it shows up next to the conversation, live and editable. Users can tweak it by hand and export it to a real file.

Think ChatGPT Canvas or Claude Artifacts, but a package you drop into your own React app and point at your own agent.

한국어 README

const { sendMessage, messages, canvas } = useCanvasStream({ endpoint: "/api/chat" });
// user: "make a pricing table for 3 plans"
// → a real spreadsheet appears in <Canvas />, formulas and all

Install

npm i @braincrew-lab/langchain-canvas

docx, docx-preview and fast-formula-parser come along with the package. If one is missing, that single feature says what to add and the rest keeps working: an export tells the user, and a Word upload falls back to the file card it showed before.

A spreadsheet is opened and written from the Python side, through xlsx_import and TableXlsxExporter in langchain-canvas[xlsx]. Reading a workbook down to its fonts, fills, number formats, merges, widths and images is more than a browser should carry, and the two readers are held to the same result by a golden fixture. The grid itself is unchanged: a table artifact still opens, edits and exports to CSV in the browser.

A deck exports to PowerPoint from the Python side, through SlidesPptxExporter in langchain-canvas[office]. It builds on the deck's template skin, so the original's masters, layouts and embedded fonts survive — which the browser never had. The export menu offers PDF for a deck; wire the Python exporter behind an endpoint of your own for .pptx.

Mount it

Two things: the hook that receives your agent's stream, and the panel that renders it. They share a store, so nothing is wired between them.

import { Canvas, useCanvasStream } from "@braincrew-lab/langchain-canvas";
import "@braincrew-lab/langchain-canvas/styles.css";

function App() {
  const { sendMessage, messages } = useCanvasStream({ endpoint: "/api/chat" });
  return <Canvas />; // render sendMessage/messages in your own chat UI
}
  • useCanvasStream({ endpoint }){ sendMessage, messages, canvas, isStreaming, editSelection }.
  • <Canvas /> ships with "use client", so it drops into a Next.js App Router file as-is.
  • /api/chat streams SSE using the wire protocol (canvas.create / append / patch / replace). The companion Python package emits these from a LangChain/LangGraph agent; any backend sending the same JSON frames works.

That's the whole setup. The rest of this README is how to use each feature — all of it is direct manipulation the user does on the rendered artifact, with no extra code from you.


Features & how to use them

🌐 Web pages (html) — a visual page builder

HTML is the base substrate, rendered in a sandboxed iframe. Selecting and editing works on any HTML the agent produces.

  • Click to select — hover highlights an element, click selects it.
  • Drag to move — drag a selected element to reposition it (uses a CSS transform, so it's non-destructive and keeps the page's flow/responsiveness).
  • Alignment snap guides — while moving, edges/centers snap to nearby elements and the container center, with red guide lines (like Figma).
  • Resize handle — drag the corner to resize. Images resize in %, so they scale with the layout — smaller on mobile, larger on desktop.
  • Marquee select — drag a box to select everything fully inside it; the selection is predictable (outermost items, drilling into a wrapper of several children).
  • Group / ungroup — select 2+ elements and Group; they get a shared id (no wrapper, so layout never breaks) and move together. Click a member to select the group, then Ungroup.
  • Edit text inline — double-click any text; a floating toolbar gives bold / italic / underline / link.
  • Style inspector — color, background, font size/weight, line-height, letter-spacing, padding, radius, width, plus background gradients and background images (upload or URL).
  • Replace images — select an image → Upload a file (embedded as a data URI) or paste a URL.
  • Add blocks — insert a heading, text, button, image, or divider from the toolbar.
  • Section templates — drop in a ready-made Hero / Features / Call-to-action section (self-styled and responsive).
  • Structural actions — duplicate, delete, reorder (move up/down) the selected element.
  • Responsive preview — toggle Desktop / Tablet / Mobile width; media queries respond as they would on a real device.
  • Code view — switch to Code to edit the raw HTML by hand; switch back to Design and the change is live. A viewport meta is injected automatically so the page is responsive on export.
  • Selection → agent — pass onEditElement and a "apply an instruction to this selection" bar appears, so the user can ask the agent to change exactly what they picked.

📊 Spreadsheets (table) — a real spreadsheet

Runs on a spreadsheet engine (Fortune-sheet), not a static table.

  • Live formulas — type =SUM(C2:C4), =AVERAGE(...), =A2*B2; they calculate, with cell references, ranges, and function autocomplete.
  • Formulas from data — a formula the agent sends as a value (e.g. "=AVERAGE(B2:B4)") is pre-computed on load so it shows its result immediately.
  • Full toolbar — fonts, number/currency/percent formats, bold/italic, borders, cell merging, alignment, multiple sheets — like a desktop spreadsheet.
  • Smooth scrolling in both directions over a large grid.
  • Export to .csv here, or to .xlsx with fonts, merges and formats through the Python side.

🖼️ Slides (slides) — a free-canvas deck

A PowerPoint-style editor where every element is movable.

  • Free positioning — drag and resize text/image elements; snap to guides.
  • Inline editing — double-click to edit text; format toolbar for bold/size/color/align.
  • Structure — add/duplicate/delete/reorder slides, thumbnails rail, speaker notes.
  • Themes & backgrounds, present mode (full-screen, arrow-key navigation).
  • Export to .pptx, or copy to Figma (paste straight in as editable frames), or PDF (all slides).

📝 Documents (document) — Markdown / Word

  • Click-to-edit the page as Markdown, rendered with GFM.
  • Export to .docx, .md, .pdf, or .html.

📈 Charts (chart)

  • Line / bar / area / pie, switchable in one click.
  • Edit data inline — a small grid to change values, add/remove rows.
  • Recolor each series (or each pie slice), rename series, set the y-axis label, toggle stacking.
  • Export to .pdf (the chart is SVG, so it prints crisply) or the raw JSON.

📁 Files — round-trip

  • Import by drag-and-drop or a file picker: CSV · Markdown · HTML · JSON. They open as editable artifacts. A spreadsheet is opened on the Python side (xlsx_import).
  • Export every artifact to its native format, plus a universal standalone .html and PDF (browser print).

🧰 Across every artifact

  • Undo / redo⌘Z / ⌘⇧Z (or the toolbar buttons) revert user edits (agent streaming isn't polluted into the stack).
  • Version history — each canvas.replace snapshots a version you can step back through.
  • Error isolation — a renderer that throws shows an inline fallback instead of crashing the host app.
  • Multiple canvases — wrap trees in <CanvasProvider> to run independent instances in one app.

Wrapping it in your app

  • Peer dependency: React 18 or 19 — you bring your own. ESM only.
  • Styles: import "@braincrew-lab/langchain-canvas/styles.css" once.
  • Isolated instances: <CanvasProvider> gives each subtree its own store.
  • Bring your own renderer: pass registry to add or override how a type renders.
import { Canvas, mergeRegistries, builtinRenderers } from "@braincrew-lab/langchain-canvas";

const registry = mergeRegistries(builtinRenderers, {
  metric: ({ artifact }) => <div className="big-number">{artifact.data.value}</div>,
});

<Canvas registry={registry} />

No backend? Replay a fixture or mock the chat

import { useCanvasReplay, scenarios } from "@braincrew-lab/langchain-canvas";

const { play } = useCanvasReplay();
useEffect(() => { play(scenarios.find((s) => s.id === "table")!.events); }, [play]);
useCanvasStream({ mock: (msg) => (/chart/i.test(msg) ? chartEvents : null) }); // null → hit the endpoint

How it works

agent  ──SSE──▶  canvas events  ──▶  reconciler  ──▶  store  ──▶  renderer
                (create/append/patch/replace)   (pure function)          │
                                                                         ▼
                        user edits (type / drag / select)  ──▶  same reconciler

The reconciler is a single pure function — every change (a streamed token, a user edit, a new version) goes through it, so state stays predictable and auditable. Renderers only read the reconciled artifact.

Security

Agent output and imported files are treated as untrusted:

  • HTML renders in an iframe with sandbox="allow-scripts" and no allow-same-origin — a null origin with no reach into your app's DOM, cookies, or storage (the Claude Artifacts model).
  • PDF export renders in a script-disabled sandboxed iframe, so exporting a malicious page can't run anything in your origin.
  • Imported Markdown renders without raw-HTML passthrough.

Dependency advisories

pnpm audit and npm audit report nothing against this package. Two of its dependencies still resolve old transitive packages that carry advisories, and neither publishes a release that lifts them, so pin them in your app — a lockfile override only applies to the project that declares it, never to a library you install.

npm / yarn:

"overrides": {
  "uuid": "14.0.1",
  "brace-expansion": "^2.1.4",
  "@ungap/structured-clone": "1.3.0"
}

pnpm:

"pnpm": { "overrides": {
  "uuid@<14.0.1": "14.0.1",
  "brace-expansion@<1.1.17": "^1.1.17",
  "brace-expansion@>=2.0.0 <2.1.4": "^2.1.4",
  "@ungap/structured-clone": "1.3.0"
} }

uuid is ESM-only from v12 on, and @fortune-sheet/core still reaches it through a CommonJS entry. Node resolves that with require(esm), which landed in 20.19, so pinning uuid past v11 raises this package's floor to that release — hence the engines field. Bundlers take the ESM entry and are unaffected; it is plain node that needs the newer runtime. On Node 20.18 the grid fails to load at all, so the floor is not advisory.

With those in place npm audit and pnpm audit both report nothing on a fresh install of this package. The same overrides run in this repository's own lockfile, against its full test suite.

Advisory feeds disagree, and a private one may flag a version the public feed calls clean — pin to whatever your own review has cleared. The versions above are the ones this repository tests against.

@ungap/structured-clone cannot be removed — react-markdown reaches it through mdast-util-to-hast, whose current release still depends on it. It is ISC and carries no advisory, so any 1.x is fine; the entry above pins the exact version in case your review clears versions one at a time. Markdown, GFM tables and links all render against the pinned one.

License

MIT