Marp vs Reveal.js built from identical content — Markdown slides vs an HTML framework

Building the same deck in Marp and Reveal.js: source readability at 243 vs 287 lines, the animation gap, export formats, and which one fits which job.

The Markdown mark, a black rounded rectangle enclosing an M and a downward arrow, on a white card
On this page

Introduction

Beyond PowerPoint and Google Slides, there are slide tools you can manage as code. Two representative ones are Marp, which generates slides from Markdown, and Reveal.js, an HTML/JS presentation framework.

To work out which fits my use case, I built the same content in both tools and compared them.

Prerequisites and environment

  • macOS (Apple Silicon)
  • Node.js 22.x
  • pnpm 11.x
  • Marp CLI 4.4.0
  • Reveal.js 5.1.0 (via CDN)

What Marp is

Marp stands for “Markdown Presentation Ecosystem”, a tool that generates presentation slides from Markdown files.

Main characteristics:

  • Text written in Markdown becomes the slide directly
  • --- (a horizontal rule) separates slides
  • The CLI converts to HTML, PDF, PPTX, and PNG
  • The VS Code extension supports live preview
  • Themes and styles are set in frontmatter

What Reveal.js is

Reveal.js is a presentation framework based on HTML, CSS, and JavaScript. It is also the technology behind slides.com.

Main characteristics:

  • Fragment animation (revealing elements one at a time)
  • Vertical slides (a drill-down structure)
  • Smooth transitions via data-auto-animate
  • Code line highlighting via data-line-numbers
  • A plugin ecosystem (maths, notes, search, and more)

Setup

Marp

Installing the VS Code extension marp-team.marp-vscode gives you live slide preview inside the editor. The CLI installs as follows:

Terminal window
# Install the CLI
pnpm add -D @marp-team/marp-cli
# Build the slides
pnpm dlx @marp-team/marp-cli slides.md -o slides.html
# PDF output
pnpm dlx @marp-team/marp-cli slides.md -o slides.pdf
# PPTX output
pnpm dlx @marp-team/marp-cli slides.md -o slides.pptx
# Image output (for LinkedIn/Instagram carousels)
pnpm dlx @marp-team/marp-cli slides.md --images png

The output format is detected automatically from the extension. PDF output requires Chrome or Chromium; HTML and PPTX work as-is.

Reveal.js

<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/theme/black.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>Slide 1</section>
<section>Slide 2</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
hash: true,
plugins: [RevealHighlight]
});
</script>
</body>
</html>

Via CDN there is nothing to install and a single HTML file is self-contained. To install locally, use pnpm add reveal.js.

Building the same content in both

For test content I turned an article I wrote earlier, about AI coding CLI tools and SSD writes, into a presentation. It contains code blocks, tables, data comparisons, and a narrative flow, which makes it a good subject for exposing what each tool is and is not good at.

The demo I built is published in this repository:

https://github.com/oharu121/marp-reveal-js-demo

Marp source (excerpt)

---
marp: true
theme: default
paginate: true
backgroundColor: #1a1a2e
color: #eee
style: |
th { background: #e94560; color: white; }
.columns { display: flex; gap: 2em; }
.columns > div { flex: 1; }
---
<!-- _class: lead -->
# AI Coding CLIs Are Killing Your SSD?
---
## The Incident
> OpenAI's Codex CLI was found writing **640TB/year** to SSDs
- Trace-level logging to `~/.codex/logs_2.sqlite`
- **37TB** written in just 21 days
---
## Why This Matters
<div class="columns">
<div>
### Consumer SSD Lifespan
| SSD | TBW Rating |
|-----|-----------|
| Samsung 990 PRO 1TB | ~600 TBW |
</div>
<div>
### Codex Impact
- **640 TB/year** write rate
- Exceeds warranty in **< 1 year**
</div>
</div>

Points to note:

  • The style: block in frontmatter customises the CSS
  • <!-- _class: lead --> applies the title-slide layout
  • <div class="columns"> produces a two-column layout (HTML embedded in Markdown)
  • Tables, quotes, and code blocks are all plain standard Markdown

Reveal.js source (excerpt)

<!-- Fragment animation: elements appear one at a time -->
<section data-auto-animate>
<h2>Cross-Tool Comparison</h2>
<table>
<thead><tr><th>Tool</th><th>SSD Issue</th></tr></thead>
<tbody>
<tr class="fragment"><td>Codex CLI</td><td><span class="status-bad">Critical</span></td></tr>
<tr class="fragment"><td>Claude Code</td><td><span class="status-warn">Past issues</span></td></tr>
<tr class="fragment"><td>Gemini CLI</td><td><span class="status-ok">None</span></td></tr>
</tbody>
</table>
</section>
<!-- Vertical slides: drill down with the down arrow key -->
<section>
<section>
<h2>Claude Code: Past Bugs</h2>
<p><small>Press ↓ for each bug</small></p>
</section>
<section>
<h3>Bug 1: Debug Log Infinite Loop</h3>
<p class="fragment">Logger records ops taking >75ms</p>
<p class="fragment">→ Debug file grows large</p>
<p class="fragment">→ <span class="status-bad">42GB in 7 days</span></p>
</section>
</section>
<!-- Code line highlighting: clicking moves the focus -->
<section>
<pre><code class="language-bash" data-line-numbers="1-2|4-5|7-12">
$ du -sh ~/.claude/debug
2.8M ~/.claude/debug # Normal
$ du -sh ~/.claude/file-history
12M ~/.claude/file-history # Normal
$ du -sh ~/.claude/*/ | sort -hr | head -5
866M plugins/
434M projects/
266M security/
12M file-history/
2.8M debug/
</code></pre>
</section>

Points to note:

  • class="fragment" animates elements appearing one at a time
  • Nesting <section> produces vertical slides (drill-down)
  • data-line-numbers="1-2|4-5|7-12" highlights code lines step by step
  • data-auto-animate gives smooth transitions between slides
  • data-background-gradient changes the background per slide

Comparison results

Source readability

Marp’s source is Markdown you can just read. Previewed on GitHub or opened in VS Code, the content is clear.

# Marp source: 243 lines of Markdown
$ wc -l slides.md
243
# Reveal.js source: 287 lines of HTML
$ wc -l index.html
287

By line count there is not much in it. By what those lines hold, it inverts. Counting every line whose entire content is one or more HTML tags and nothing else, Reveal.js spends 115 of its 287 lines, 40%, on markup alone, against Marp’s 19 of 243. Subtract the markup and the blanks and Marp carries more content in fewer total lines: 162 lines against 152.

What each source file spends its lines onTwo stacked bars drawn to one scale. Marp's slides.md is 243 lines: 162 content, 19 markup only at 8 percent, and 62 blank. Reveal.js's index.html is 287 lines: 152 content, 115 markup only at 40 percent, and 20 blank. Although Reveal.js has 44 more lines in total, it carries 10 fewer lines of content.contentmarkup onlyblankMarp — slides.md243 lines16219 (8%)Reveal.js — index.html287 lines152115 (40%)Fewer total lines, and more of them carry content.
Measured from the demo repository. A markup-only line is one whose whole trimmed content is tags, such as </section> or <div class="columns">.

That is what makes Marp’s source double as documentation while Reveal.js’s needs an HTML parser.

Animation and transitions

This is the biggest difference.

Marp has no in-slide animation. --- switches slides and that is it.

Paging through the Marp deck. Each press replaces one whole slide with the next, and nothing moves within a slide — the comparison table arrives complete.

In Reveal.js:

  • Fragments: reveal table rows one at a time, uncover a conclusion in stages
  • Vertical slides: keep the main flow while drilling down into detail
  • Code line highlighting: data-line-numbers="1-2|4-5" moves the focus on each click
  • auto-animate: elements move smoothly between slides
The same content in Reveal.js. The rows of that comparison table arrive one per click, so the audience reads each tool’s verdict before the next appears.

For technical videos (Fireship-style code explanations) and conference talks, this difference is decisive.

Export

Output formatMarpReveal.js
HTMLBuilt inBuilt in
PDFBuilt in (needs Chrome)Separate tool required (decktape and similar)
PPTXBuilt inNot supported
PNG/JPG imagesBuilt in (--images)Not supported

Marp’s PPTX output is handy when you need to hand a file to stakeholders who use PowerPoint. --images png can be posted straight to a social carousel.

Fit with CI/CD

Marp gives you a natural md → html/pdf/pptx CLI pipeline:

Terminal window
# Build the slides automatically in GitHub Actions
pnpm dlx @marp-team/marp-cli slides.md -o dist/slides.html

Reveal.js is static HTML, so it needs no build step at all, but automating PDF export requires a headless browser.

Themes and styling

Marp lets you scope CSS from the style: block in frontmatter. There are constraints, but basic customisation of colours, fonts, table styles, and backgrounds is perfectly possible.

Reveal.js gives you full CSS and JS, so there is no ceiling. CSS variables (--r-heading-color and others) make theme adjustment easy, and complex layouts are entirely free.

Choosing by use case

Where Marp fits

  • Weekly meetings and sprint reviews: write quickly in Markdown, manage in Git, track diffs
  • Turning internal documentation into slides: add --- to an existing Markdown document and it is a deck
  • LinkedIn and Instagram carousel posts: --images png exports each slide as an image
  • Automated builds in CI/CD: slots naturally into a CLI pipeline
  • Collaborative editing in a team: Markdown reviews well and merge conflicts resolve easily

Where Reveal.js fits

  • Conference talks: fragment animation and vertical slides control where the audience looks
  • Recording technical videos: stepping through code line highlights suits Fireship-style explanation
  • Interactive demos: JS plugins can embed dynamic content
  • When elaborate visual production is required: background gradients, custom animation

Summary

AspectMarpReveal.js
Authoring speedFastModerate
Source readabilityExcellent (Markdown)Low (HTML)
AnimationNonePlentiful
Code highlight controlBasicLine-by-line stepping
ExportHTML/PDF/PPTX/imagesHTML (the rest needs other tools)
Fit with GitExcellentPossible, but diffs are hard to read
Visual freedomModerateUnlimited

The conclusion is that these are not competing tools; they have different purposes.

  • Marp = everyday slides: presentation as an extension of documentation. Write it, version it, convert to PPTX or PNG when needed
  • Reveal.js = the talk that matters: build the audience’s experience out of animation and interaction

Personally, I found Marp covers 80% of day-to-day work comfortably. Its biggest advantage is that it ships inside the codebase as a Markdown file, so a presentation becomes an artefact you version alongside the code. Reveal.js is worth switching to for conference talks and technical videos, where production values feed directly into the result.

Share this article