English | 简体中文
# SnapDOM SnapDOM is a high-performance DOM engine that captures a rendered element in the browser and exports it as PNG, SVG or canvas. Plugins turn the same capture into self-contained HTML, PDF, editable vectors, GIF, video or context for agents. Everything runs in the page, with no core dependencies. [Documentation and demos](https://snapdom.dev/) · [Technical features](FEATURES.md) · [Official plugins](packages/plugins/README.md) · [简体中文](README_CN.md) ## Why SnapDOM - **Speed.** [Run the live benchmark](https://snapdom.dev/compare/live/) in your browser: first and repeat captures against html2canvas and the other libraries, sorted by measured time. Unchanged elements reuse their last capture. - **Fidelity.** The output matches what the browser painted. Every release runs a pixel suite of real demo pages before it ships. - **Flexibility.** Capture once, export many formats. Official plugins add outputs, and the same [plugin hooks](PLUGIN_SPEC.md) let you write your own. - **Maintenance.** About one release a week over the past year, MIT licensed, with a public [changelog](CHANGELOG.md). ## Quick start ```sh npm i @zumer/snapdom ``` ```js import { snapdom } from '@zumer/snapdom'; const card = document.querySelector('#card'); const image = await snapdom.toPng(card); document.body.appendChild(image); ``` Capture once when you need several outputs: ```js const result = await snapdom(card); const image = await result.toPng(); const canvas = await result.toCanvas(); const blob = await result.toBlob({ format: 'png' }); await result.download({ format: 'jpg', filename: 'card' }); ``` The result keeps that capture even if the source element later changes. Call `snapdom(card)` again to capture its new state. ## What you can build | Use | Output | Provided by | | --- | --- | --- | | Share a card, chart, invoice or dashboard | SVG, PNG, JPG, WebP, canvas or Blob | Core | | Reuse a capture in a texture, overlay or transition | Canvas plus capture geometry | Core | | Save a page fragment for later display | HTML with captured styles and fonts | [`html-export`](packages/plugins/README.md#html-export) plugin | | Give an agent or a log a view of page content | Text/JSON context, or an image with an element map | [`context-export`](packages/plugins/README.md#context-export) / [`agent-map`](packages/plugins/README.md#agent-map) plugins | | Download a document or record changing content | Searchable, paginated PDF, animated GIF or browser-encoded video | [`pdf`](packages/plugins/pdf/README.md) / [`gif-export`](packages/plugins/README.md#gif-export) / [`video-export`](packages/plugins/README.md#video-export) plugins | | Export editable artwork or paste into Figma | Native SVG shapes and text, or a Figma clipboard payload | [`vector`](packages/plugins/vector/README.md) plugin | Image, HTML and context exports use the captured state. GIF and video plugins record the live element over time. ## Installation Install the core and, when you need them, the official plugins: ```sh npm i @zumer/snapdom@latest @zumer/snapdom-plugins@latest ``` Plugins 4.x require SnapDOM 3.3.0 or newer within 3.x. They include the PDF and Vector exporters, MIT licensed like the core. Their sources live in `packages/plugins/`. Or load it in a browser: ```html ``` As an ES module from a CDN: ```js import { snapdom } from 'https://esm.sh/@zumer/snapdom@latest'; import { htmlExport } from 'https://esm.sh/@zumer/snapdom-plugins@latest/html-export'; ``` `https://unpkg.com/@zumer/snapdom@latest/dist/snapdom.mjs` serves the same module. These examples load the latest published core and plugins. ### Build outputs | File | Use | | --- | --- | | `dist/snapdom.mjs` | ES module for imports and bundlers | | `dist/snapdom.js` | Script tag exposing `window.snapdom` | | `types/snapdom.d.ts` | TypeScript declarations | There is no CommonJS build. `@zumer/snapdom/plugins` and the package root share the same runtime and plugin registry. ## Usage ### Choose an output | Result method | Returns | | --- | --- | | `toPng()`, `toJpg()`, `toWebp()` | An `HTMLImageElement` | | `toSvg()` | An SVG-backed `HTMLImageElement` | | `toCanvas()` | An `HTMLCanvasElement` | | `toBlob()` | An SVG `Blob` unless a format was explicitly set on the capture or export | | `toRaw()` / `url` | The capture's SVG data URL | | `download()` | Downloads the chosen format | | `to(name, options?)` | Runs a core or plugin exporter by name | One-step shortcuts such as `snapdom.toPng(element, options)` capture and export in one call. Results also have `toJpeg()` as an alias for `toJpg()`. `toImg()` remains available; prefer `toSvg()` for an SVG image. ### Set size and exclude content ```js const result = await snapdom(card, { width: 800, dpr: 1, backgroundColor: '#ffffff', exclude: '.capture-ignore', excludeMode: 'remove' }); ``` `width` and `height` define output size. If only one is set, the aspect ratio is preserved. `scale` applies when neither is set, and `dpr` multiplies the pixel dimensions. `download()` always uses DPR 1, so the file matches the element's CSS size; pass `scale: devicePixelRatio` for a file as sharp as the screen. | Common option | Default | Purpose | | --- | --- | --- | | `scale` / `dpr` | `1` / device pixel ratio | Output resolution | | `width` / `height` | Unset | Output dimensions | | `embedFonts` | `'auto'` | Embed the web fonts the capture uses | | `backgroundColor` | Transparent; white for JPG/WebP | Output background | | `exclude` | None | Selectors or predicates; `true` means exclude | | `excludeMode` | `'hide'` | Keep an invisible spacer, or use `'remove'` | | `filter` | None | Predicate; `true` keeps a node and `false` filters it out | | `filterMode` | `'hide'` | Independent layout mode for nodes rejected by `filter` | | `clip` | Unset | Capture the viewport or a page-coordinate rectangle | | `captureSelection` | `false` | Include the user's text selection | | `canvas` | Unset | Reuse an existing canvas | | `invalidate` | `false` | Refresh after changes such as programmatic CSSOM edits | | `fast` | `true` | `false` keeps the page responsive during long captures | | `debug` | `false` | Log fallbacks and errors to the console; without it SnapDOM stays quiet and `result.warnings` reports them | [All options](https://snapdom.dev/docs/options/) include shadows, transforms, fonts, CORS, fallbacks and layout reconciliation. ### Export a long page With the default SVG engine, PNG and JPEG file exports automatically handle captures beyond the browser's canvas limits. Capture once, then download one full-resolution file or get its Blob: ```js const capture = await snapdom(article); await capture.download({ format: 'png', scale: 2 }); // Or upload/store the file yourself: const blob = await capture.toBlob({ format: 'png', scale: 2, dpr: 1 }); // JPEG works the same way, up to 65,535px per side: await capture.download({ format: 'jpg', scale: 2, quality: 0.9 }); ``` SnapDOM renders the frozen capture in windows and encodes them into one PNG or JPEG. It preserves the requested dimensions, including shadows and padding, without allocating a canvas for the whole image. `download()` always uses DPR 1; `toBlob()` uses the capture's DPR unless you override it. Ordinary-sized exports use the native encoder. PNG requires `CompressionStream`; older browsers keep the existing downscale and warning, as does a JPEG past 65,535px per side, the format's limit. WebP cannot go past 16,383px per side. Very large files still take time and memory to encode, and the application opening them has its own image limits. ### Export a long page in pieces `toCanvas()`, `toPng()`, `toJpg()` and WebP exports still use a single canvas and scale down past SnapDOM's size guards (16,384px per side in Safari, 32,767px in Chrome/Firefox, plus an area limit). When you need separate canvases, use `crop`: ```js const capture = await snapdom(article); const { contentX, contentY, w0, h0 } = capture.meta; const pieceHeight = 4000; // CSS px for (let y = 0; y < h0; y += pieceHeight) { const canvas = await capture.toCanvas({ scale: 2, dpr: 1, crop: { x: contentX, y: contentY + y, width: w0, height: Math.min(pieceHeight, h0 - y) } }); // save or upload this piece, then move on } ``` `crop` is a rectangle, not a switch. It is in the coordinates of `capture.meta`, and each call returns one canvas. The capture runs once; only the rasterization repeats. Keep `pieceHeight × scale × dpr` under the limit, and set `dpr` yourself, since it defaults to the device pixel ratio. [How tiling works](https://snapdom.dev/blog/huge-page-mosaic/). ### Export HTML or structured context ```js import { htmlExport, contextExport } from '@zumer/snapdom-plugins'; const result = await snapdom(card, { plugins: [htmlExport(), contextExport({ format: 'json' })] }); const html = await result.toHtml(); const context = await result.toContext(); ``` The same plugin system supports overlays, redaction and custom exporters. Local plugins override global plugins by name. See the [official plugin reference](packages/plugins/README.md) and [plugin specification](PLUGIN_SPEC.md). ### Export PDF and editable vectors PDF returns a `Blob` with searchable, selectable text, links, pagination and optional form fields. Vector returns an SVG string without `