Convert HTML/CSS/JS snippets into marketing-ready PNG, JPG, WebP, AVIF, PDF, SVG, ICO, or animated GIF/APNG assets — entirely in the browser, no backend required.
- Paste or upload a self-contained HTML snippet and preview it live in a sandboxed iframe.
- Size presets (Instagram Post/Story, LinkedIn Post, A4 Poster) or custom width/height.
- 1x/2x/3x export resolution, solid or transparent background, an image quality slider (JPG/WebP/AVIF), and animation fps/duration controls (GIF/APNG, up to 60s).
- Export to PNG, JPG, WebP, AVIF, PDF, SVG (HTML embedded in a
<foreignObject>), ICO (multi-resolution favicon), or animated GIF/APNG — plus a one-click "Copy PNG" to clipboard. - One-click "Download Skill MD" — a markdown guide explaining how to write HTML that converts well.
- Ships as a static site: deploy to GitHub Pages or Cloudflare Pages with no server component, aside from one fire-and-forget usage-counter request per export (see below).
npm install
npm run devOpen the printed local URL, paste some HTML in the left panel, click Render, then Export.
npm run build # type-check + production build into dist/
npm run preview # serve the production build locally
npm run lint # oxlintThe preview renders inside a sandboxed <iframe sandbox="allow-scripts allow-same-origin"> using srcdoc. Export captures that iframe's DOM with
modern-screenshot, which
rasterizes by serializing the node into an SVG <foreignObject> and letting
the browser's own engine paint it. This is what makes the export match the
live preview pixel-for-pixel: modern CSS such as background-clip: text
(gradient-clipped text), backdrop-filter, filter, and mix-blend-mode
render correctly, instead of being silently dropped the way a CSS-
reimplementing rasterizer (e.g. html2canvas) drops them. Same-origin and
CORS-enabled images/fonts are auto-embedded as data URLs so they survive the
foreignObject sandbox. PNG/JPG/WebP/AVIF are a single capture via
canvas.toBlob; PDF wraps a single capture in a pixel-sized page via
jsPDF; ICO resizes that single capture
into a 16/32/48/256px multi-resolution favicon; SVG re-embeds the iframe's
live, serialized DOM inside an SVG <foreignObject> directly (not a vector
trace — renders in browsers, not in vector editors).
GIF and APNG export restart the iframe's document
(document.open/write/close, since location.reload() is a no-op for
srcdoc iframes) so finite animations play from the start, then repeatedly
capture frames over the chosen duration/fps. GIF frames are encoded with
gif.js (its web worker script is
vendored at public/gif.worker.js); APNG frames are encoded with
UPNG.js, trading GIF's 256-color/no
real-alpha limits for true 8-bit alpha at a larger file size. Both share the
same animation-seeking rig: any clone-based rasterizer samples a live CSS
animation at whatever wall-clock moment the clone is read, which — combined
with animation-fill-mode: forwards — would otherwise snap every frame
straight to the animation's end state. To avoid that, each CSS animation is
permanently disabled (animation: none) for the duration of the export and
re-created as an independent Web Animations API Animation using the same
keyframes/timing, fully detached from the CSS animation property. That
detached animation is seeked to the exact frame time via currentTime and its
computed style baked inline before each capture, so every frame is a
deterministic, controlled pose rather than whatever the live animation happened
to be showing.
A running total export count is kept via
Abacus and shown live in the header
badge ("N exports"). On load, the header does a GET to
https://abacus.jasoncameron.dev/get/fasilwdr-postersnap/exports-total to
seed the badge; every successful export then fires a GET to
https://abacus.jasoncameron.dev/hit/fasilwdr-postersnap/exports-total (see
src/lib/analytics.ts) and updates the badge from the response. Neither
request sends any HTML/image content, and failures (offline, rate-limited)
just leave the badge as-is instead of blocking the export.
React + TypeScript + Vite, Tailwind CSS v4, Zustand for state, modern-screenshot, jsPDF, gif.js, and UPNG.js for export.
MIT — see LICENSE.