# 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.

- Source: https://oharu121.com/blog/marp-vs-revealjs-markdown-presentation-tools-comparison/
- Published: 2026-09-03T00:02:06+09:00
- Tags: Markdown, Node.js, Developer Tooling

---
## 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:

```bash
# 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

```html
<!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)

```markdown
---
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)

```html
<!-- 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.

*Figure — SourceDensity: 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 format | Marp | Reveal.js |
|---------|------|-----------|
| HTML | Built in | Built in |
| PDF | Built in (needs Chrome) | Separate tool required (decktape and similar) |
| PPTX | Built in | Not supported |
| PNG/JPG images | Built 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:

```bash
# 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

| Aspect | Marp | Reveal.js |
|------|------|-----------|
| Authoring speed | Fast | Moderate |
| Source readability | Excellent (Markdown) | Low (HTML) |
| Animation | None | Plentiful |
| Code highlight control | Basic | Line-by-line stepping |
| Export | HTML/PDF/PPTX/images | HTML (the rest needs other tools) |
| Fit with Git | Excellent | Possible, but diffs are hard to read |
| Visual freedom | Moderate | Unlimited |

**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.
