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

mdsnap

v1.0.0

Published

A CLI tool to convert Markdown to images. Support batch conversion, multiple themes, and custom CSS.

Readme

mdsnap

A CLI tool to convert Markdown to images. Supports batch conversion, multiple themes, and custom CSS. The CLI binary is named mdsnap.

CI MIT License

Features

  • 🚀 CLI Tool - Simple command-line interface
  • 📦 Batch Conversion - Convert entire directories of markdown files (subfolder structure preserved)
  • 🎨 7 Themes - gradient-card / minimal / dark / notebook / magazine / blueprint / custom CSS
  • 📝 Full Markdown Support - GFM, code highlighting, tables, blockquotes
  • 💡 Callouts - GitHub / Obsidian style admonitions like > [!warning]
  • 🔗 Wikilinks - Obsidian-style [[double-bracket]] references
  • 🖼️ Multiple Formats - PNG, JPEG, WebP output

Installation

npm install -g mdsnap

Or use directly with npx:

npx mdsnap input.md -o output.png

The npm package is mdsnap. Once installed, the CLI binary is available as mdsnap.

Browser Requirement

mdsnap uses a headless browser (via Puppeteer) to render markdown.

When you npm install the package, Puppeteer normally downloads its bundled Chrome for Testing — that's the simplest path and requires no extra setup. At runtime the CLI looks for a browser in this order:

  1. PUPPETEER_EXECUTABLE_PATH environment variable
  2. Auto-detected system Chrome / Edge / Chromium
  3. Puppeteer's bundled Chrome for Testing

If you skipped the bundled download (e.g. set PUPPETEER_SKIP_DOWNLOAD=true in CI) and don't have a system browser, install one with:

npx puppeteer browsers install chrome

Or point at an existing browser:

export PUPPETEER_EXECUTABLE_PATH="/path/to/chrome"

Usage

Single File

# Basic usage
mdsnap input.md -o output.png

# With theme
mdsnap input.md -o output.png --theme dark

# Custom width
mdsnap input.md -o output.png --width 1200

# With header and footer
mdsnap input.md -o output.png --header "My Blog" --footer "© 2024"

Batch Conversion

# Convert all markdown files in a directory
mdsnap ./docs -o ./images

# With theme and custom settings
mdsnap ./posts -o ./output --theme gradient-card --width 800

Input/output directory layout

Batch mode walks **/*.md under the input directory and mirrors the relative path in the output directory. So a layout like

docs/
  index.md
  lesson01/
    intro.md
    practice.md
  lesson02/
    intro.md

run with mdsnap ./docs -o ./images --format webp produces

images/
  index.webp
  lesson01/
    intro.webp
    practice.webp
  lesson02/
    intro.webp

Files with the same basename in different folders never collide. Output directories are created on demand.

Theme gallery for one sample

When you want to render one markdown file through every built-in theme to compare, the convention used in this repo is:

samples/                  ← your input markdown(s)
  lesson01.md
samples-out/              ← rendered output, grouped by sample name
  lesson01/
    gradient-card.png
    minimal.png
    dark.png
    notebook.png
    magazine.png
    blueprint.png
    prose.png
    sepia.png
    docs.png
    report.png

This is what npm run gallery produces. It reuses one browser instance across all themes, so 10 themes finish in roughly the time of 1-2 single CLI invocations:

# Render every theme of one markdown into samples-out/<sample-name>/
npm run gallery -- samples/lesson01.md

# Pick a format
npm run gallery -- samples/lesson01.md --format webp

# Or only specific themes
npm run gallery -- samples/lesson01.md --theme prose --theme sepia

The samples/ and samples-out/ directories are git-ignored — they are a personal workspace, not part of the published package.

Custom CSS

# Use custom CSS file
mdsnap input.md -o output.png --css ./my-style.css

Smaller files (WebP / JPEG)

PNG output is the default and lossless. For long documents the file can grow to a few MB. Switch to WebP or JPEG with --format to shrink it dramatically:

# WebP — usually the smallest, still high quality
mdsnap input.md -o output.webp --format webp

# JPEG with quality knob (1-100, default 90)
mdsnap input.md -o output.jpg --format jpeg --quality 85

In a real test on an 8.7 KB Chinese lesson markdown rendered at 800px wide:

| Format | Size | Notes | | --- | --- | --- | | PNG | ~1.1 MB | lossless, default | | JPEG q85 | ~700 KB | good for screenshots without code | | WebP | ~540 KB | best size/quality, modern browsers |

Extended Markdown

mdsnap ships with two non-standard syntaxes turned on by default:

Wikilinks

See [[网页]] for details.
Read [[课程脉络|the course map]] later.

Both render as styled inline links with a data-target attribute, so downstream tooling can rewrite them into real URLs if needed.

Callouts (GitHub / Obsidian flavor)

> [!note]
> Helpful detail.

> [!warning] 常见误区
> Custom titles work too.

Recognised types: note, tip, important, warning, caution, info, question, todo, success, failure, danger, bug, example, quote, abstract, summary. Each gets its own accent color in every theme.

CLI Options

| Option | Description | Default | |--------|-------------|---------| | -o, --output <path> | Output file or directory | ./output.png | | -t, --theme <name> | Theme name | gradient-card | | -w, --width <number> | Output width in pixels | 800 | | -p, --padding <number> | Padding in pixels | 40 | | --header <text> | Header text | - | | --footer <text> | Footer text | - | | -c, --css <path> | Custom CSS file path | - | | -f, --format <format> | Output format (png, jpeg, webp) | png | | -q, --quality <number> | Image quality for jpeg/webp | 90 |

Themes

gradient-card

Colorful gradient background with a white rounded card. Perfect for social media sharing.

minimal

Clean white document style. Suitable for documentation and printing.

dark

Dark mode theme. Great for code-heavy content.

notebook

Cream paper, blue ink accents, and a signature red left margin rule that runs the full length of the page. Picks up the lined-paper aesthetic with a faint horizontal rule pattern, auto § 01 section numbering on h2, and a serif drop-cap on the opening paragraph. Use for: lesson notes, study guides, long-form writing.

magazine

Editorial layout with high-contrast display serif, a single bold editorial-red accent, oversized h1, drop cap, pull-quote treatment for blockquotes, and a ❦ ornament in place of horizontal rules. Use for: essays, reviews, opinion pieces.

blueprint

Deep blueprint blue with a faint white grid, "white paper" inserts for tables and code, condensed engineering type with § 02 · counters on h2, and a REV. 1.0 stamp in the corner. Use for: technical guides, runbooks, engineering posts.

prose

Long-form reading. Warm paper #FAFAF7, Charter-family serif body, content column capped at ~70ch with line-height 1.85. Callouts are quiet tinted blocks with no thick coloured bars; wikilinks become dotted underlines. Use for: essays, think pieces, slow reading.

sepia

Kindle-style protected reading. Aged paper #F4ECD8 with deep brown ink #3A2F25, Georgia-family serif at ~64ch, no zebra rows, no painted heading rules. The only flourish is a half-line drop cap on the first paragraph. Use for: pure long text, ebook-feel posts.

docs

Technical reference. Inter sans-serif, every h2 gets a 4px coloured anchor bar to the left for fast scanning, code blocks open with a dark "CODE" / language chrome strip, tables are first-class with a tinted header row. Use for: tutorials, API notes, changelogs.

report

Analytical brief. Off-white #FBFBF8, Inter body with automatic 1. / 1.1 section numbering on h2 / h3 (CSS counters), a monospaced uppercase metadata strip at the top via the --header slot, and double-rule consulting-style tables. Use for: research notes, internal briefs, structured long documents.

custom

Use your own CSS file for complete customization.

API Usage

You can also use mdsnap as a library:

import { renderToImage, renderToBuffer, convert } from 'mdsnap'

// Render to file
const result = await renderToImage({
  markdown: '# Hello World\n\nThis is a test.',
  output: './output.png',
  theme: 'gradient-card',
  width: 800,
})

console.log(result) // { path: './output.png', width: 800, height: 600 }

// Render to buffer
const { buffer, width, height } = await renderToBuffer({
  markdown: '# Hello World',
  theme: 'dark',
})

// Or run a full batch conversion programmatically
const summary = await convert(
  { input: './docs', output: './images', theme: 'dark' },
  { render: renderToImage }
)
console.log(`${summary.succeeded}/${summary.results.length} files converted`)

License

MIT License - feel free to use in your projects.