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

dopecanvas

v0.1.7

Published

The office editor built for the AI era — a drop-in React component that renders LLM-generated HTML as paginated, editable documents.

Readme

DopeCanvas

The office suite built for the AI era.

DopeCanvas is a drop-in React component that replaces Word, Excel, and PowerPoint with a single, unified document canvas. It renders LLM-generated HTML as a paginated, editable document -- complete with tables, charts, rich formatting, and page breaks -- so your users work in a familiar office-like environment while your AI writes the code behind it.

The LLM sees HTML. The user sees a professional report. Both can edit it.


Why DopeCanvas?

The problem with traditional office tools

Word, Excel, and PowerPoint are powerful individually, but painful together. Building a complex report means juggling three apps, copy-pasting between them, versioning each file separately, and hoping nothing breaks when you update a number in a spreadsheet that feeds into a chart in a slide deck that references a paragraph in a document.

The problem with Notion-style tools

Notion solved the integration problem, but introduced new ones: limited formatting control, a learning curve that amounts to a new way of working, and -- critically -- poor compatibility with LLM workflows. You can't easily have an AI generate a Notion page with precise layout, formulas, and styling.

The DopeCanvas solution

DopeCanvas takes a different approach entirely:

  • HTML is the document format. LLMs already understand HTML natively. No custom schemas, no proprietary formats, no serialization loss. The AI writes HTML/CSS, and DopeCanvas renders it as a paginated, editable document.
  • One canvas, all capabilities. Text, tables, charts, styled layouts -- everything lives in one document, on real pages with real page breaks. No switching between apps.
  • Users edit visually. Click any text to edit it. Use the toolbar for formatting. It feels like Word, but it's powered by the web.
  • Programmatic API. Load content, extract content, sync to databases. DopeCanvas is a framework, not just a viewer.

How It Works

LLM writes HTML/CSS/JS
        |
        v
  DopeCanvas.loadHTML()
        |
        v
  Pagination Engine measures content,
  distributes blocks across pages
        |
        v
  User sees paginated, editable document
  (white pages, margins, shadows, page numbers)
        |
        v
  User clicks to edit (contentEditable)
  Toolbar provides formatting (bold, italic, etc.)
        |
        v
  DopeCanvas.getHTML() returns modified HTML
        |
        v
  Sync to database, send back to LLM, export

The key insight: the LLM works with code, the user works with a document, and they're editing the same thing.


Quick Start

Install

npm install dopecanvas

Basic Usage

import { DopeCanvas } from 'dopecanvas';

function App() {
  // This HTML could come from an LLM, a database, or an API
  const html = `
    <h1 style="color: #1a1a2e; font-family: Georgia, serif;">
      Quarterly Report
    </h1>
    <p style="line-height: 1.6;">
      Revenue reached <strong>$48.2M</strong>, a 23% YoY increase.
    </p>
    <table style="width: 100%; border-collapse: collapse;">
      <tr style="background: #1a1a2e; color: white;">
        <th style="padding: 10px;">Metric</th>
        <th style="padding: 10px;">Q3</th>
        <th style="padding: 10px;">Q4</th>
      </tr>
      <tr>
        <td style="padding: 8px; border-bottom: 1px solid #ddd;">Revenue</td>
        <td style="padding: 8px; border-bottom: 1px solid #ddd;">$42.5M</td>
        <td style="padding: 8px; border-bottom: 1px solid #ddd;">$48.2M</td>
      </tr>
    </table>
  `;

  return (
    <DopeCanvas
      html={html}
      onContentChange={(updated) => {
        console.log('User edited the document:', updated);
      }}
    />
  );
}

That's it. You get a paginated, editable document with a formatting toolbar, page setup controls, and an API to read the content back.

With Page Configuration

<DopeCanvas
  html={html}
  pageConfig={{
    size: 'a4',        // 'letter' | 'a4' | 'legal' | { width, height }
    margins: {
      top: 96,         // pixels (96px = 1 inch at 96 DPI)
      right: 96,
      bottom: 96,
      left: 96,
    },
  }}
  onContentChange={(html) => saveToDatabase(html)}
  onPageConfigChange={(config) => console.log('Page settings changed:', config)}
/>

With the Document API

import { DocumentAPI } from 'dopecanvas';

const api = new DocumentAPI();

// Load content programmatically
api.loadHTML('<h1>Hello World</h1><p>Generated by AI.</p>');

// Listen for user edits
api.onChange((html) => {
  syncToDatabase(html);
});

// Read content
const html = api.getHTML();
const text = api.getPlainText();

// Access specific elements for database sync
const tableContent = api.getElementContent('revenue-table');
api.setElementContent('summary', '<p>Updated by the system.</p>');

What Makes This LLM-Native

HTML in, HTML out

Most document editors use proprietary internal models (ProseMirror schemas, Slate.js value trees, OOXML). These are hostile to LLMs -- the AI has to learn a custom format, and translation is lossy.

DopeCanvas uses HTML as the document format. Period. The LLM writes HTML with inline styles, classes, and any structure it wants. DopeCanvas renders it faithfully and returns it faithfully. No schema stripping, no attribute sanitization, no surprises.

No editor framework baggage

We deliberately chose native contentEditable over TipTap, ProseMirror, or Slate.js. Those frameworks enforce schemas that strip CSS classes, inline styles, data attributes, and JavaScript -- destroying the LLM's output. With DopeCanvas, what the AI writes is exactly what renders.

Structured content for structured prompts

Because the document is real HTML, you can:

  • Ask the LLM to generate a report section and inject it at a specific element ID
  • Extract a table from the document and send it back to the LLM for analysis
  • Have the LLM update specific sections while preserving user edits elsewhere
  • Round-trip between AI generation and human editing without format conversion

Plain JavaScript = formulas, charts, and live analysis

This is the killer feature that falls out of using real HTML: <script> tags just work.

Other editors strip scripts during sanitization. DopeCanvas activates them. That means an LLM can generate a full analytical report with computed totals, interactive Chart.js visualizations, and cross-table data binding — using nothing but plain JavaScript — and it all runs live inside the document.

Computed cells and formulas. No formula engine needed. The LLM writes a <script> that reads data from table cells, computes totals/averages/growth percentages, and writes the results back. When the user edits a number, an input event listener recalculates everything instantly:

<table id="revenue">
  <tr><td>Q1</td><td class="num">$9.8M</td></tr>
  <tr><td>Q2</td><td class="num">$11.2M</td></tr>
  <tr class="total-row">
    <td>Total</td><td class="num fx" id="total">$21.0M</td>
  </tr>
</table>

<script>
(function () {
  var table = document.getElementById('revenue');
  function recalc() {
    var rows = table.querySelectorAll('tr:not(.total-row)');
    var sum = 0;
    rows.forEach(function (tr) {
      var text = tr.querySelector('.num').textContent;
      sum += parseFloat(text.replace(/[^0-9.]/g, ''));
    });
    document.getElementById('total').textContent = '$' + sum.toFixed(1) + 'M';
  }
  recalc();
  table.addEventListener('input', recalc);
})();
</script>

Charts from table data. The LLM generates a <canvas> element and a script that loads Chart.js from a CDN, reads values from the table, and renders a bar chart, line graph, or doughnut. When the user edits a cell, the chart animates to reflect the new data:

<canvas id="chart" width="560" height="300"></canvas>

<script>
(function () {
  function init() {
    // Read data from the table, build chart
    var chart = new Chart(document.getElementById('chart'), {
      type: 'bar',
      data: { labels: ['Q1','Q2','Q3','Q4'], datasets: [/*...*/] }
    });
    // Re-read table and update chart on every edit
    document.getElementById('revenue').addEventListener('input', function () {
      chart.data.datasets[0].data = readTableData();
      chart.update();
    });
  }
  // Load Chart.js dynamically, then init
  var s = document.createElement('script');
  s.src = 'https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js';
  s.onload = init;
  document.head.appendChild(s);
})();
</script>

Why this matters. The LLM doesn't need to learn a plugin API, a chart config schema, or a formula language. It writes the same JavaScript it already knows. Any library that runs in a browser — Chart.js, D3, MathJax, Mermaid — can be loaded and used. The document is a full web page with the UX of a Word doc.

The included sample-report-charts.html demo shows this in action: four Chart.js charts (bar, line, doughnut, horizontal bar) all driven by editable tables with live-updating totals, growth percentages, and KPI cards.

See it in action

Edit a table cell and watch every chart, total, and KPI card update instantly:

Dynamic content demo


Features

Pagination Engine

  • Real page sizes: Letter (8.5 x 11"), A4 (210 x 297mm), Legal (8.5 x 14"), or custom dimensions
  • Configurable margins (top, right, bottom, left)
  • Automatic content measurement and distribution across pages
  • CSS break-before: page / break-after: page for manual page breaks
  • Page numbers

Visual Document Rendering

  • White pages on a scrollable gray background (like Word/Google Docs)
  • Page shadows and margins
  • Content rendered exactly as the HTML specifies -- gradients, flexbox, grid, anything

Inline Editing

  • Click any text to edit in place via contentEditable
  • Table cells are individually editable
  • All original CSS styling is preserved during editing

Formatting Toolbar

  • Text: Bold, Italic, Underline, Strikethrough, Font Size, Headings (H1-H6)
  • Color: Text color, Highlight color
  • Alignment: Left, Center, Right, Justify
  • Lists: Ordered, Unordered, Indent, Outdent
  • Page: Size selector, Margin controls
  • History: Undo / Redo
  • Contextual: toolbar adapts based on whether you're editing text, a table, or other elements

Document API

  • loadHTML(html, css?) -- Load content into the canvas
  • getHTML() -- Get current content (reflects user edits)
  • getPlainText() -- Get text content without markup
  • onChange(callback) -- Subscribe to edit events
  • getPageCount() / setPageConfig() -- Page operations
  • querySelectorAll() / getElementContent() / setElementContent() -- Element-level access

Architecture

dopecanvas/
  src/
    core/
      PageLayoutEngine.ts    -- Measures blocks, distributes across pages
      EditableManager.ts     -- contentEditable, MutationObserver, undo/redo
      DocumentEngine.ts      -- Orchestrator
      types.ts               -- PageConfig, PageSize, etc.
    components/
      DopeCanvas.tsx          -- Main React component (toolbar + paged view)
      PagedView.tsx           -- Renders paginated pages
      Page.tsx                -- Single page frame
      Toolbar/                -- Formatting and page setup controls
    api/
      DocumentAPI.ts          -- External programmatic interface
    hooks/
      useDocumentEngine.ts    -- React hook for the engine
      useSelectionContext.ts  -- Selection state tracking

No dependencies beyond React. No TipTap, no ProseMirror, no Slate, no draft-js. Just React, TypeScript, and the browser's native editing APIs.


Use Cases

  • AI report generation -- LLM generates a financial report, user reviews and edits it visually, system syncs changes back
  • Template-based documents -- Define HTML templates with placeholder IDs, fill them programmatically, let users customize
  • Collaborative AI editing -- User writes in the canvas, sends sections to an LLM for rewriting, merges results back
  • Data-driven documents -- Tables bound to database queries, charts generated from data, all in one paginated view
  • Print-ready output -- Paginated layout with proper page breaks, margins, and formatting for PDF export

Roadmap

  • [x] Live formulas via JS -- LLM-authored <script> tags compute totals, growth %, averages in real time
  • [x] Charts via JS -- Chart.js / D3 / any library loaded from CDN, driven by editable table data
  • [ ] Table formulas (Excel-style) -- Cell references (A1, B2:C5) with HyperFormula engine for spreadsheet power users
  • [ ] Database binding -- Postgres/Convex tables backing document tables
  • [ ] Contextual toolbars -- Different tools for text, tables, charts, images
  • [ ] Collaborative editing -- Multi-user real-time editing via CRDT
  • [x] PDF export -- High-fidelity print from the paginated layout
  • [ ] Drag and drop -- Move blocks between pages
  • [ ] Image handling -- Insert, resize, position images within the document
  • [ ] Presentation mode -- Page-by-page slideshow from the same document
  • [ ] TOC -- Generate table of content

Development

# Clone and install
git clone https://github.com/yourusername/dopecanvas.git
cd dopecanvas
npm install

# Start dev server
npm run dev

# Build
npm run build

# Type check
npx tsc --noEmit

See It In Action

Visit dopeoffice.ai to see DopeCanvas powering a full AI-native office suite. It's the reference implementation showing what's possible when you combine this framework with an LLM backend -- AI-generated reports, live editing, database-synced tables, and more.


License

MIT