Install any skill in seconds. Free to start, no credit card required.
Get Started Free →snapDOM is a fast, accurate DOM-to-image capture tool that converts HTML elements into scalable SVG images. Use for capturing HTML elements, converting DOM to images (SVG, PNG, JPG, WebP), preserving styles, fonts, and pseudo-elements.
.claude/skills/aiskillstore-snapdom/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | -33% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 98% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 51% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -10% | 0% |
Fast, dependency-free DOM-to-image capture library for converting HTML elements into scalable SVG or raster image formats.
Use SnapDOM when you need to:
bashnpm install @zumer/snapdom # or yarn add @zumer/snapdom
html<script type="module"> import { snapdom } from "https://unpkg.com/@zumer/snapdom/dist/snapdom.mjs"; </script>
html<script src="https://unpkg.com/@zumer/snapdom/dist/snapdom.umd.js"></script>
javascript// Create reusable capture object const result = await snapdom(document.querySelector('#target')); // Export to different formats const png = await result.toPng(); const jpg = await result.toJpg(); const svg = await result.toSvg(); const canvas = await result.toCanvas(); const blob = await result.toBlob(); // Use the result document.body.appendChild(png);
javascript// Direct export without intermediate object const png = await snapdom.toPng(document.querySelector('#target')); const svg = await snapdom.toSvg(element);
javascript// Automatically download as file await snapdom.download(element, 'screenshot.png'); await snapdom.download(element, 'image.svg');
javascriptconst result = await snapdom(element, { scale: 2, // 2x resolution width: 800, // Custom width height: 600, // Custom height embedFonts: true, // Include @font-face exclude: '.no-capture', // Hide elements useProxy: true, // Enable CORS proxy straighten: true, // Remove transforms noShadows: false // Keep shadows }); const png = await result.toPng({ quality: 0.95 });
| Option | Type | Purpose | |--------|------|---------| | scale | Number | Scale output (e.g., 2 for 2x resolution) | | width | Number | Custom output width in pixels | | height | Number | Custom output height in pixels | | embedFonts | Boolean | Include non-icon @font-face rules | | useProxy | String\|Boolean | Enable CORS proxy (URL or true for default) | | exclude | String | CSS selector for elements to hide | | straighten | Boolean | Remove translate/rotate transforms | | noShadows | Boolean | Strip shadow effects |
javascript// Capture at different scales const mobile = await snapdom.toPng(element, { scale: 1 }); const tablet = await snapdom.toPng(element, { scale: 1.5 }); const desktop = await snapdom.toPng(element, { scale: 2 });
javascript// Hide specific elements from capture const png = await snapdom.toPng(element, { exclude: '.controls, .watermark, [data-no-capture]' });
javascript// Capture with specific size const result = await snapdom(element, { width: 1200, height: 630 // Standard social media size });
javascript// Fallback for CORS-blocked resources const png = await snapdom.toPng(element, { useProxy: 'https://cors.example.com/?' // Custom proxy });
javascript// Extend with custom exporters snapdom.plugins([pluginFactory, { colorOverlay: true }]); // Hook into lifecycle defineExports(context) { return { pdf: async (ctx, opts) => { /* generate PDF */ } }; } // Lifecycle hooks available: // beforeSnap → beforeClone → afterClone → // beforeRender → beforeExport → afterExport
SnapDOM significantly outperforms html2canvas:
| Scenario | SnapDOM | html2canvas | Improvement | |----------|---------|-------------|-------------| | Small (200×100) | 1.6ms | 68ms | 42x faster | | Medium (800×600) | 12ms | 280ms | 23x faster | | Large (4000×2000) | 171ms | 1,800ms | 10x faster |
bashgit clone https://github.com/zumerlab/snapdom.git cd snapdom npm install
bashnpm run compile
bashnpm test
Add helper scripts here for automation, e.g.:
batch-screenshot.js - Capture multiple elementspdf-export.js - Convert snapshots to PDFcompare-outputs.js - Compare SVG vs PNG qualityAdd templates and examples:
scale instead of width/height for better performanceembedFonts: true to ensure custom fonts appear correctlyuseProxy: true if images fail to loadquality: 0.95 for best qualitystraighten: false if transforms are causing issuesembedFonts: trueuseProxy: truescale valuenoShadows: true to skip shadow rendering| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | pass→pass | 9,736 | 5,987 | -39% | 1 | 1 | 0% | 1,775 | 3,097 | +74% | 0 | 0 | — |
case-06 | pass→pass | 12,119 | 6,835 | -44% | 1 | 1 | 0% | 2,252 | 3,190 | +42% | 0 | 0 | — |
case-07 | fail→pass | 24,414 | 6,749 | -72% | 1 | 1 | 0% | 4,769 | 3,190 | -33% | 0 | 0 | — |
case-08 | fail→pass | 7,188 | 2,381 | -67% | 1 | 1 | 0% | 1,137 | 2,248 | +98% | 0 | 0 | — |
case-09 | fail→pass | 11,079 | 5,431 | -51% | 1 | 1 | 0% | 2,073 | 2,940 | +42% | 0 | 0 | — |
case-01 | fail→pass | 11,559 | 8,331 | -28% | 1 | 1 | 0% | 2,321 | 3,509 | +51% | 0 | 0 | — |
case-02 | fail→pass | 19,239 | 6,969 | -64% | 1 | 1 | 0% | 3,741 | 3,357 | -10% | 0 | 0 | — |
case-03 | fail→pass | 8,544 | 7,051 | -17% | 1 | 1 | 0% | 1,591 | 3,108 | +95% | 0 | 0 | — |
case-04 | pass→pass | 16,025 | 14,276 | -11% | 1 | 1 | 0% | 3,046 | 4,616 | +52% | 0 | 0 | — |
case-10 | fail→pass | 9,111 | 5,158 | -43% | 1 | 1 | 0% | 1,502 | 2,666 | +77% | 0 | 0 | — |
case-11 | fail→pass | 12,704 | 2,570 | -80% | 1 | 1 | 0% | 2,081 | 2,432 | +17% | 0 | 0 | — |
case-12 | pass→pass | 8,490 | 3,869 | -54% | 1 | 1 | 0% | 1,587 | 2,657 | +67% | 0 | 0 | — |
case-13 | pass→pass | 9,298 | 7,501 | -19% | 1 | 1 | 0% | 1,732 | 3,386 | +95% | 0 | 0 | — |
case-14 | pass→pass | 7,239 | 2,902 | -60% | 1 | 1 | 0% | 1,224 | 2,470 | +102% | 0 | 0 | — |
case-15 | pass→pass | 13,855 | 4,990 | -64% | 1 | 1 | 0% | 2,684 | 2,930 | +9% | 0 | 0 | — |
case-16 | pass→pass | 9,626 | 4,150 | -57% | 1 | 1 | 0% | 1,793 | 2,733 | +52% | 0 | 0 | — |
case-17 | fail→pass | 14,986 | 9,527 | -36% | 1 | 1 | 0% | 2,683 | 3,671 | +37% | 0 | 0 | — |
case-18 | fail→pass | 6,213 | 3,656 | -41% | 1 | 1 | 0% | 1,267 | 2,674 | +111% | 0 | 0 | — |
case-19 | pass→pass | 12,091 | 4,928 | -59% | 1 | 1 | 0% | 1,927 | 2,851 | +48% | 0 | 0 | — |
case-20 | pass→pass | 8,340 | 5,925 | -29% | 1 | 1 | 0% | 1,584 | 3,152 | +99% | 0 | 0 | — |
case-21 | fail→pass | 4,629 | 2,752 | -41% | 1 | 1 | 0% | 779 | 2,227 | +186% | 0 | 0 | — |
case-22 | fail→pass | 4,631 | 2,056 | -56% | 1 | 1 | 0% | 683 | 2,176 | +219% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +55 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.