# @marp-team/marp-cli Marp CLI is a command-line interface tool for converting Marp/Marpit Markdown files into presentation formats including HTML, PDF, PowerPoint (PPTX), and images (PNG/JPEG). Built on top of the Marpit framework and Marp Core, it provides a complete solution for creating beautiful slide presentations from Markdown with support for themes, custom engines, slide transitions, and presenter notes. The CLI offers multiple operation modes including one-shot conversion, watch mode for live preview during development, and server mode for on-demand conversion via HTTP requests. It supports parallel processing for batch conversions, custom theming through CSS, and integration with browsers (Chrome, Edge, Firefox) for rendering PDF and image outputs. The tool can be installed via npm, Homebrew, Scoop, or used as a standalone binary, and is also available as an official Docker container image. ## CLI Commands ### Basic Conversion to HTML Converts a Markdown file to an HTML presentation. The default output template is `bespoke`, which includes navigation, fullscreen support, and keyboard shortcuts. ```bash # Convert to HTML (default output) marp slide-deck.md # Specify output path marp slide-deck.md -o output.html # Convert multiple files marp slides/*.md # Keep directory structure with input-dir marp -I ./slides -o ./output ``` ### Convert to PDF Converts Markdown to PDF format using a browser engine (Chrome, Edge, or Firefox). Requires a compatible browser to be installed. ```bash # Basic PDF conversion marp --pdf slide-deck.md # With output filename marp slide-deck.md -o presentation.pdf # Add presenter notes as PDF annotations marp --pdf --pdf-notes slide-deck.md # Add bookmarks/outlines from headings and pages marp --pdf --pdf-outlines slide-deck.md # Customize PDF outlines (headings only) marp --pdf --pdf-outlines --pdf-outlines.pages=false slide-deck.md ``` ### Convert to PowerPoint (PPTX) Creates a PowerPoint document from Markdown slides, preserving presenter notes and slide layouts. ```bash # Basic PPTX conversion marp --pptx slide-deck.md # With output filename marp slide-deck.md -o presentation.pptx # Experimental: Generate editable PPTX (requires LibreOffice) marp --pptx --pptx-editable slide-deck.md ``` ### Convert to Images Converts slides to PNG or JPEG image files. Can generate a single title slide image or multiple images for all slides. ```bash # Convert first slide (title) to PNG marp --image png slide-deck.md # Convert all slides to multiple PNG files marp --images png slide-deck.md # Convert to JPEG with custom quality marp --images jpeg --jpeg-quality 90 slide-deck.md # Set scale factor for high-resolution images marp slide-deck.md -o title@2x.png --image-scale 2 ``` ### Watch Mode Monitors Markdown files for changes and automatically rebuilds the output. Includes live reload when viewing in a browser. ```bash # Watch mode with auto-rebuild marp -w slide-deck.md # Watch with preview window marp -w -p slide-deck.md # Watch entire directory marp -w -I ./slides -o ./output ``` ### Server Mode Starts an HTTP server that converts Markdown files on-demand. Useful for development and previewing multiple presentations. ```bash # Start server mode (default port: 8080) marp -s ./slides # Access converted files via browser: # http://localhost:8080/slide-deck.md -> HTML # http://localhost:8080/slide-deck.md?pdf -> PDF # http://localhost:8080/slide-deck.md?pptx -> PPTX # http://localhost:8080/slide-deck.md?png -> PNG image # http://localhost:8080/slide-deck.md?jpeg -> JPEG image # Custom port via environment variable PORT=3000 marp -s ./slides # Server with preview window marp -s -p ./slides ``` ### Parallel Conversion Processes multiple files concurrently for faster batch conversions. ```bash # Default parallelism (5 workers) marp --pdf slides/*.md # Custom parallelism marp --pdf -P 10 slides/*.md # Disable parallel processing marp --pdf --no-parallel slides/*.md ``` ### Browser Options Configure which browser to use and how it connects for PDF/image conversion. ```bash # Use specific browser marp --browser firefox slide-deck.md -o slide.pdf # Prefer Firefox, fallback to Chrome marp --browser firefox,chrome slide-deck.md -o slide.pdf # Set custom browser path marp --browser-path /usr/bin/chromium slide-deck.md -o slide.pdf # Set browser timeout (seconds) marp --browser-timeout 60 slide-deck.md -o slide.pdf # Use WebDriver BiDi protocol marp --browser-protocol webdriver-bidi slide-deck.md -o slide.pdf ``` ### Theme Options Override or apply custom themes to presentations. ```bash # Use built-in theme marp --theme gaia slide-deck.md # Use custom theme CSS file marp --theme ./my-theme.css slide-deck.md # Load multiple theme files marp --theme-set ./themes/*.css slide-deck.md # Load themes from directory marp --theme-set ./themes slide-deck.md ``` ### Metadata Options Set presentation metadata for HTML, PDF, and PPTX outputs. ```bash # Set title and description marp --title "My Presentation" --description "A slide deck about Marp" slide-deck.md # Set author and keywords marp --author "John Doe" --keywords "marp,presentation,slides" slide-deck.md # Set Open Graph image for HTML marp --og-image "https://example.com/og-image.png" --url "https://example.com/slides" slide-deck.md ``` ### Export Presenter Notes Extracts presenter notes from slides into a text file. ```bash # Export notes to text file marp --notes slide-deck.md # Specify output filename marp slide-deck.md -o notes.txt ``` ### Local File Access Allow accessing local files during conversion (use with caution). ```bash # Enable local file access for PDF/PPTX/image conversion marp --pdf --allow-local-files slide-deck.md ``` ## Node.js API ### marpCli Function The main programmatic interface for using Marp CLI in Node.js applications. Accepts an array of CLI arguments and returns a Promise resolving to an exit status code. ```javascript import { marpCli, CLIError, CLIErrorCode } from '@marp-team/marp-cli' async function convertPresentation() { try { // Basic HTML conversion const exitCode = await marpCli(['slide-deck.md']) if (exitCode > 0) { console.error(`Conversion failed with exit code: ${exitCode}`) } else { console.log('Conversion successful!') } } catch (err) { if (err instanceof CLIError) { console.error(`Marp CLI Error (code ${err.errorCode}): ${err.message}`) // Handle specific error codes switch (err.errorCode) { case CLIErrorCode.NOT_FOUND_BROWSER: console.error('No compatible browser found') break case CLIErrorCode.LISTEN_PORT_IS_ALREADY_USED: console.error('Server port is already in use') break case CLIErrorCode.GENERAL_ERROR: default: console.error('General error occurred') } } else { throw err } } } // Convert to PDF await marpCli(['presentation.md', '--pdf']) // Convert to PPTX with metadata await marpCli([ 'presentation.md', '--pptx', '--title', 'My Presentation', '--author', 'John Doe' ]) // Convert multiple files with parallelism await marpCli(['slides/*.md', '--pdf', '-P', '8']) // Use custom theme await marpCli(['presentation.md', '--theme', './custom-theme.css']) ``` ### waitForObservation Function Handles watch mode and server mode when using the API. Returns a Promise that resolves with a helper object containing a `stop()` method to terminate observation. ```javascript import { marpCli, waitForObservation } from '@marp-team/marp-cli' async function runServerMode() { // Start server mode (this Promise won't resolve until stopped) const serverPromise = marpCli(['--server', './slides/']) .then((exitCode) => console.log(`Server stopped with code ${exitCode}`)) .catch(console.error) // Wait for server to be ready const { stop } = await waitForObservation() console.log('Server is now running on http://localhost:8080') // Server is running... do something (e.g., run tests, wait for signal) await new Promise(resolve => setTimeout(resolve, 60000)) // Run for 60 seconds // Stop the server and resolve the marpCli Promise stop() await serverPromise } async function runWatchMode() { // Start watch mode marpCli(['--watch', 'presentation.md']) .then((exitCode) => console.log(`Watch mode ended with code ${exitCode}`)) .catch(console.error) // Wait for watcher to be ready const { stop } = await waitForObservation() console.log('Watching for file changes...') // Handle graceful shutdown on SIGINT process.on('SIGINT', () => { console.log('\nStopping watch mode...') stop() }) } ``` ### defineConfig Helper Provides TypeScript-friendly configuration with autocompletion support for configuration files. ```javascript // marp.config.mjs import { defineConfig } from '@marp-team/marp-cli' export default defineConfig({ // Input/Output options inputDir: './slides', output: './dist', // Conversion type pdf: true, // PDF options pdfNotes: true, pdfOutlines: { pages: true, headings: true }, // Metadata title: 'My Presentation', author: 'John Doe', description: 'A slide deck created with Marp', keywords: ['marp', 'presentation'], // Theme options theme: 'gaia', themeSet: ['./themes/custom.css'], // Template options (bespoke) template: 'bespoke', bespoke: { osc: true, // On-screen controller progress: true, // Progress bar transition: true // Enable transitions }, // Browser options browser: 'chrome', browserTimeout: 30, // Engine options html: true, allowLocalFiles: false, // Advanced: Custom engine options options: { markdown: { breaks: false // Disable auto line breaks }, minifyCSS: false } }) ``` ### Custom Engine with Plugins Create a custom engine to extend Marp with markdown-it plugins. ```javascript // engine.mjs import markdownItEmoji from 'markdown-it-emoji' import markdownItFootnote from 'markdown-it-footnote' import markdownItMark from 'markdown-it-mark' export default ({ marp }) => { return marp .use(markdownItEmoji) .use(markdownItFootnote) .use(markdownItMark) } // Usage: // marp --engine ./engine.mjs presentation.md ``` ```javascript // engine-with-options.mjs // Advanced engine returning a configured instance export default async (constructorOptions) => { const { Marp } = await import('@marp-team/marp-core') const markdownItContainer = await import('markdown-it-container') const marp = new Marp({ ...constructorOptions, html: true }) // Add custom container support marp.use(markdownItContainer.default, 'warning', { validate: (params) => params.trim() === 'warning', render: (tokens, idx) => { if (tokens[idx].nesting === 1) { return '