CtrlK
BlogDocsLog inGet started
Tessl Logo

gamussa/presenterm

Create terminal-based presentation slides using presenterm's markdown format with themes, diagrams, code highlighting, and more

92

2.15x
Quality

90%

Does it follow best practices?

Impact

97%

2.15x

Average score across 5 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files
name:
presenterm
description:
Create terminal-based presentation slides using presenterm's markdown format. presenterm renders markdown files as slides in the terminal with themes, code highlighting, images, column layouts, speaker notes, and more. Use this skill whenever the user wants to create a presenterm presentation, terminal slides, markdown slides for presenterm, or mentions "presenterm" in any context. Also trigger when the user asks for "terminal presentation", "markdown presentation", "slide deck in markdown", or wants to convert content into presenterm format. Even if the user just says "create a presentation" and they have used presenterm before or the context suggests terminal-based slides, use this skill.

presenterm Slide Creator

Create presentations in presenterm's markdown format — a tool that renders markdown files as rich slides directly in the terminal.

Output: A single .md file that the user runs with presenterm slides.md.

For detailed references, see:

  • Mermaid diagrams — flowcharts, sequences, ER, state, class diagrams
  • D2 diagrams — architecture, styling, SQL tables, containers
  • Themes and styling — theme overrides, footers, color palettes, colored text
  • Design patterns — narrative arc, gradual consistency, antipatterns

Slide Structure

Frontmatter

---
title: "My Presentation Title"
sub_title: Optional subtitle
author: Author Name
theme:
  name: dark
---

Generates an introduction slide automatically. All fields optional. For multiple authors use authors: array.

Slide Separator

<!-- end_slide -->

Not ---. Use <!-- end_slide --> consistently.

Slide Titles (Setext Headers)

My Slide Title
===

Setext headers render centered with special styling. ATX headers (# H1) render as normal headings within a slide — NOT as slide titles.


Comment Commands

CommandPurpose
<!-- end_slide -->End current slide, start next
<!-- pause -->Content below appears on next keypress
<!-- jump_to_middle -->Vertically center subsequent content
<!-- new_line --> / <!-- new_lines: N -->Insert blank lines
<!-- column_layout: [3, 2] -->Define column layout with proportional widths
<!-- column: 0 -->Switch to column (zero-indexed)
<!-- reset_layout -->End column layout
<!-- incremental_lists: true -->Each bullet on separate keypress
<!-- alignment: center -->Align text: left, center, right
<!-- speaker_note: Your note -->Speaker note (visible in presenter mode) — no colons or em dashes inside the note text
<!-- font_size: 2 -->Font size 1-7 (kitty terminal only)
<!-- no_footer -->Hide footer on this slide
<!-- include: other.md -->Include content from another file

User comments (ignored): <!-- // note --> or <!-- comment: note -->


Speaker Notes

Speaker note text is parsed as a YAML scalar, so any : (colon) or (em dash) inside the note breaks the entire deck with mapping values are not allowed here. This is the most common way to ship a broken presenterm file. Use - (hyphen) for both.

WRONG — fails to parse, kills the whole deck:

<!-- speaker_note: Walk through producer config: bootstrap.servers, key.serializer -->
<!-- speaker_note: Pause here — let the audience absorb the diagram -->
<!-- speaker_note: Demo URL: localhost:9092 -->

RIGHT:

<!-- speaker_note: Walk through producer config - bootstrap.servers, key.serializer -->
<!-- speaker_note: Pause here - let the audience absorb the diagram -->
<!-- speaker_note: Demo URL is localhost on port 9092 -->

Before writing any speaker note, mentally scan it for : and . If either appears (including inside URLs, ratios, time codes, parentheticals, or quoted phrases), rewrite with hyphens or rephrase to remove them entirely.

Mark optional content with the literal token CUTTABLE at the start of the note so you can skip slides under time pressure:

<!-- speaker_note: CUTTABLE - the migration timeline slide if running over -->

Column Layouts

<!-- column_layout: [2, 1] -->
<!-- column: 0 -->
Left content (2/3 width)
<!-- column: 1 -->
Right content (1/3 width)
<!-- reset_layout -->

Sizing: [2, 1] = total 3 units. Use [1, 1] for halves, [1, 3, 1] to center.


Code Blocks

Standard fenced code blocks with language identifiers. Key features:

Selective highlighting: ```rust {1,3,5-7} highlights specific lines.

Dynamic highlighting: ```rust {1,3|5-7|all} — each group on successive keypress.

Attributes: +exec (executable), +line_numbers, +no_background, +render (diagrams/LaTeX), +exec_replace, +acquire_terminal.

Hidden lines: Prefix with # to hide from display but include in execution.

External snippets:

```file +exec +line_numbers
path: snippet.rs
language: rust
start_line: 5
end_line: 10
```

Images and Diagrams

Static images: ![alt text](path/to/image.png) Image sizing: ![image:width:50%](photo.png) or ![image:width:300](photo.png)

IMPORTANT: Image filenames with spaces will fail to render. Always use hyphens: my-image.png not my image.png.

Full-Image Title Slide

presenterm has no background image feature. To use an image as a full title slide:

  1. Remove title, sub_title, and author from frontmatter (prevents auto-generated title slide)
  2. Add the image as the first slide with <!-- no_footer -->:
---
theme:
  name: catppuccin-mocha
  override:
    footer:
      style: template
      left: "@gamussa"
      right: "{current_slide} / {total_slides}"
      height: 2
---

<!-- no_footer -->

![image:width:100%](images/my-title-slide.png)

<!-- end_slide -->

First Content Slide
===
...

The image renders at full width. Terminal padding means it won't be truly edge-to-edge, but it's the closest presenterm supports.

Diagrams: Use +render attribute on fenced code blocks.

  • Mermaid (mermaid +render) — flowcharts, sequences, ER, state, class, Gantt, pie, mindmap, xychart-beta (bars/lines). See references/mermaid.md.
  • D2 (d2 +render) — architecture, styled diagrams, SQL tables, containers. See references/d2.md.
  • LaTeX/Typst (latex +render / typst +render) — inline formulas.

Use D2 for polished architecture diagrams. Use Mermaid for variety (Gantt, mindmaps, pie charts).

Diagram vs column layout — pick the right shape

Columns are for side-by-side prose (description vs description, code vs explanation). They are not a way to display quantitative data.

If you have numeric or comparative data — latency benchmarks, throughput numbers, percentages, before/after counts, prices, scores — use a diagram, not columns:

Data shapeReach for
Comparing magnitudes (e.g. p99 latency across 3 databases)mermaid +render with xychart-beta (bars) or pie
Showing share of totalmermaid +render with pie
Showing change over timemermaid +render with xychart-beta (line)
Comparing systems by attributes (prose tradeoffs)column layout
Architecture / data flowd2 +render

A 3-bar chart beats a 3-column wall of numbers every time. The column layout is for words placed next to other words, not for numbers placed next to other numbers.

For architecture and data-flow diagrams, default to D2. The Mermaid options above (xychart-beta, pie, etc.) are for charts and quantitative shapes — they are not the right tool for system topology, request flow, or component relationships. If you're drawing boxes connected by arrows to represent services, databases, or queues, use d2 +render, not Mermaid.

Diagram sizing: Keep 5-10 nodes max. Use LR for wide, TD for tall. Match dark themes.


Themes

Set in frontmatter: theme: { name: catppuccin-mocha }. Safe defaults: catppuccin-mocha, dark. Use terminal-dark to inherit terminal colors.

Available: catppuccin-{latte,frappe,macchiato,mocha}, dark, light, gruvbox-dark, terminal-{dark,light}, tokyonight-{storm,moon,day,night}.

For overrides, footers, palettes, and colored text see references/themes.md.


Pauses and Incremental Content

Manual: <!-- pause --> between content blocks. Lists: <!-- incremental_lists: true --> before bullet list.


Running and Exporting

presenterm slides.md             # Development mode (hot reload)
presenterm -p slides.md          # Presentation mode
presenterm -x slides.md          # Enable code execution
presenterm -e slides.md          # Export to PDF
presenterm -E slides.md          # Export to HTML
presenterm -P slides.md          # Publish speaker notes

PDF Export with Font Sizing

The export.dimensions config controls font size in PDFs — fewer columns/rows = bigger fonts.

GridFont SizeUse Case
60x18Very largeOverflows on text-heavy slides — avoid
80x24Large, readableRecommended — clean PDFs with readable fonts
100x28Default, smallpresenterm default — too small for sharing

Create a dedicated export config (e.g., .presenterm-export.yaml):

export:
  dimensions:
    columns: 80
    rows: 24

snippet:
  render:
    threads: 4

mermaid:
  scale: 2

d2:
  scale: 2

Export with:

presenterm -c .presenterm-export.yaml -e slides.md -o slides.pdf

Makefile Integration

Add a reusable make pdf target with an overridable SLIDE variable:

SLIDE  ?= slides.md
EXPORT_CONFIG := .presenterm-export.yaml

pdf:
> presenterm -c $(EXPORT_CONFIG) -e $(SLIDE) -o $(SLIDE:.md=.pdf)

Usage:

make pdf                              # Default slide
make pdf SLIDE=drafts/my-talk.md      # Any slide

PDF to PowerPoint/Keynote Conversion

presenterm has no native PPTX export. Convert via PDF as image-based slides:

# Requires: pip install python-pptx pdf2image (and poppler installed)
python3 << 'PYEOF'
from pdf2image import convert_from_path
from pptx import Presentation
from pptx.util import Inches
import tempfile, os

images = convert_from_path("slides.pdf", dpi=200)
prs = Presentation()
prs.slide_width = Inches(13.33)
prs.slide_height = Inches(7.5)

for img in images:
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    tmp = tempfile.mktemp(suffix=".png")
    img.save(tmp)
    slide.shapes.add_picture(tmp, Inches(0), Inches(0),
                             prs.slide_width, prs.slide_height)
    os.unlink(tmp)

prs.save("slides.pptx")
PYEOF

The result is image-based slides (not editable text). Keynote opens PPTX natively.

Config File Location (Platform-Specific)

presenterm reads config.yaml from a platform-specific directory — not ~/.config on macOS:

OSConfig directory
macOS~/Library/Application Support/presenterm/
Linux~/.config/presenterm/ (or $XDG_CONFIG_HOME/presenterm/)

If mermaid +render or d2 +render blocks show as plain code, the renderers are likely installed but the config is missing or in the wrong location. Create config.yaml in the correct directory:

snippet:
  render:
    threads: 4

mermaid:
  scale: 2

d2:
  scale: 2

Requires mmdc (Mermaid CLI) and d2 installed and on $PATH. Install with:

npm install -g @mermaid-js/mermaid-cli   # mmdc
brew install d2                           # d2

Options in Frontmatter

options:
  end_slide_shorthand: true    # Allow --- as slide separator
  implicit_slide_ends: true    # Auto-end slides on headings
  command_prefix: "cmd:"       # Require prefix for commands

Complete Example

---
title: "**Streaming** Data with _Kafka_"
sub_title: A quick introduction
author: Viktor Gamov
theme:
  name: catppuccin-mocha
  override:
    footer:
      style: template
      right: "{current_slide} / {total_slides}"
      height: 2
---

Why Streaming?
===

Every business is becoming a real-time business.

<!-- pause -->

Batch processing means **hours of delay**.
Event streaming means **milliseconds**.

<!-- end_slide -->

What is Kafka?
===

<!-- incremental_lists: true -->

* **Producers** send events to topics
* **Consumers** read events from topics
* **Brokers** store and replicate the data

<!-- end_slide -->

<!-- jump_to_middle -->

Demo Time
===

<!-- end_slide -->

Producer Code
===

```java {1-3|5-8|10-13|all}
import org.apache.kafka.clients.producer.*;

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");

Producer<String, String> producer =
    new KafkaProducer<>(props);

producer.send(new ProducerRecord<>(
    "my-topic", "key", "value"
));

producer.close();
<!-- end_slide -->

Summary

<!-- alignment: center -->

Thank you! Questions?

---

## Writing Guidelines

1. **Start with frontmatter** — Always include title, author, and theme.
2. **Use `<!-- end_slide -->`** consistently — Don't mix separators.
3. **Setext headers for titles** — `Title\n===` not `# Title`.
4. **Narrative Arc** — Setup, confrontation, resolution. See [design patterns](references/design-patterns.md).
5. **Progressive reveal** — Use pauses, incremental lists, dynamic highlighting.
6. **Column layouts** for side-by-side content.
7. **`<!-- jump_to_middle -->`** for section breaks.
8. **Speaker notes** — Script demos and mark cuttable sections with `CUTTABLE`. **Scan every note for `:` and `—` before saving** — both break YAML parsing and kill the whole deck. See the Speaker Notes section above.
9. **One idea per slide** — Avoid bullet walls.
10. **Dynamic code highlighting** — `{1-3|5-8|all}` to walk through code.
11. **Diagrams over text — and diagrams over columns for numbers.** Quantitative data (benchmarks, percentages, magnitudes) goes in a `pie` or `xychart-beta`, never a column wall. Mermaid for flowcharts, D2 for architecture.
12. **Match theme colors** in diagrams.
13. **Save as `.md`** — User runs with `presenterm filename.md`.
Workspace
gamussa
Visibility
Public
Created
Last updated
Publish Source
CLI
Badge
gamussa/presenterm badge