The complete reference for the presentation language. It is embedded below, and the same text is available in the app as a separate page.
pwmd syntax
pwmd turns Markdown into a presentation. Regular Markdown remains the content format: headings, lists, links, tables, blockquotes, images, and fenced code blocks all work normally. Presentation features use standalone HTML-comment directives:
<!-- @directive arguments -->
Prefer spaces just inside the comment delimiters: <!-- @directive --> or <!-- @directive arguments -->. This form is more compatible with Markdown renderers that handle compact comments differently; rendering behavior varies. pwmd also accepts compact comments for backward compatibility.
A directive is only interpreted on its own line and never inside a fenced code block. Invalid directives are left as ordinary hidden HTML comments.
FRONTMATTER
An optional flat frontmatter block at the very beginning sets the presentation title and multiplicative text scales for every slide:
title is a nonempty string naming the presentation independently of its filename. It appears in recent-presentation lists; it does not set or change slide headings or @slide titles. Omit it to use the filename or URL as the recent-list label.
Document typography
Supported scale keys are text-scale, h1-scale–h6-scale, table-scale, code-scale, quote-scale, and math-scale. Element base ratios are built into the theme. For example, h1 uses text scale × built-in h1 base × h1-scale. Missing values use the built-in defaults.
Slides and panels
A standalone --- starts a new slide; a standalone *** starts a new panel on the current slide. They are ignored inside fenced code blocks. A slide can contain up to 26 panels.
<!-- @slide Introduction -->
# First panel***
# Second panel
---
<!-- @slide Next slide -->
# New slide
Slide metadata
Put slide directives at the beginning of a slide, before panel content. Slide-metadata parsing stops at the first non-empty, non-directive line.
Title
<!-- @slide Slide title -->
The title is editor metadata, used in the editor’s slide list and editing UI; the player does not currently render it. If omitted, the editor uses the slide’s first # heading and writes an @slide directive when saving.
Layout and visible grids
<!-- @layout AB/AC -->
<!-- @grid AB/AC -->
Letters identify panel areas. Repeating a letter merges its cells into one rectangular area; / starts a new row. Panel order follows each letter’s first occurrence.
AB/AC
+---+---+
| A | B |
+---+---+
| A | C |
+---+---+
@layout hides panel dividers.
@grid displays dashed panel dividers.
. represents an empty cell.
Rows must have equal length and every panel letter must form one contiguous rectangle.
Layouts support at most 26 rows, columns, and panels. Invalid layouts fall back to an automatic grid.
Add collapse to reduce the grid’s outer and panel padding:
<!-- @layout AA/BC collapse -->
Slide theme
<!-- @slide-theme stone blue gray -->
The three values are BASE ACCENT FRAME:
BASE: background, surface, and text palette
ACCENT: highlight color
FRAME: frame and divider color
Colors are built-in Tailwind color-family names such as slate, stone, blue, amber, and zinc. A theme affects the whole slide.
Slide background
A slide background can combine a wallpaper image, a color, and a gradient. Only the first directive of each kind takes effect.
Only a panel’s first @bg, @gradient, and @wallpaper are used. @wallpaper consumes its following image.
Content layout
Persistent directives affect following content within the panel until changed. One-off @width, @align, and @scale target only the next content block.
Alignment, width, and columns
<!-- @set-align left -->
<!-- @set-width 60% -->
Narrow, left-aligned content.
<!-- @width 80% -->
Only this paragraph is 80% wide.
This paragraph returns to 60%.
<!-- @set-align center -->
<!-- @set-width reset -->
Full-width centred content again.
@align left|center|right|justify sets alignment for the next content block only; without an argument it selects the default center for that block.
@set-align left|center|right|justify sets the persistent panel alignment; without an argument it restores center. reset is not an accepted alignment argument.
One-off overrides never change persistent defaults, even when a persistent directive follows a pending override. All three scopes reset at each new panel. For example, <!-- @set-align left -->, then <!-- @align right --> aligns the next block right and subsequent content left. Combine it with <!-- @width 80% --> and <!-- @scale 120% --> to independently style that block.
@width N% sets only the next content block’s width, then the persistent width resumes. @width reset is a one-off 100%.
@set-width N% sets the persistent width for following blocks in this panel. @set-width reset restores 100%.
Width defaults to 100% in each panel and is relative to that panel’s available content width, not the slide. Alignment defaults to center. Pending one-off width and alignment skips whitespace, layout directives, spacers, and hidden presenter notes; it applies to Markdown blocks (including headings, lists, code and tables), callouts, or media. Float/cover/contain retain their own explicit sizing.
@columns N [GAP] sets CSS columns for Markdown text. N is 1–12; GAP is 0–999 cqw units.
<!-- @columns 2 4 -->
Longer text in two columns.
<!-- @col-break -->
This paragraph starts in the next column.
<!-- @columns -->
@col-break starts the following Markdown content in the next CSS column. It only has an effect while @columns is active.
Scale
<!-- @set-scale 90% -->
This and the following content remain at 90%.
<!-- @scale 130% -->
Only this next content block is at 130%.
@set-scale PERCENT changes the persistent scale from that point onward. @scale PERCENT applies only to the next content block, then the persistent scale resumes. Both scale every text type after its document-level typography multipliers; they do not resize images or video. Use @set-scale 100% to restore the default block scale.
Colors
<!-- @color amber -->
This is amber.
<!-- @color reset -->
This uses the default text color.
@color accepts a color name or inline-color index 1, 2, or 3.
<!-- @set-colors cyan rose lime -->
_First color_, __second color__, ___third color___.
<!-- @color 2 -->
This uses the second color.
@set-colors COLOR1 COLOR2 COLOR3 overrides the inline palette for the rest of the panel.
@set-colors reset restores the default palette.
@set-color-1, @set-color-2, and @set-color-3 override one palette entry; use reset to restore it.
Defaults are amber, violet, and emerald.
Spacing
Top content.
<!-- @space -->
Bottom content.
@space fills the remaining panel height.
First block.
<!-- @gap 4 -->
Second block.
@gap N inserts an empty block N cqw high (N: -999–999). A negative value reduces the space before the following block, pulling it upward.
@set-gap N changes the normal gap between panel content blocks. reset, or no argument, restores the default gap.
Progressive reveal
Visible immediately.
<!-- @reveal -->
Visible on the first next step.
<!-- @reveal 3 -->
Visible on step three.
<!-- @reveal end -->
Visible immediately again.
Reveal steps are shared across every panel on the slide. Hidden blocks retain their space and fade in. An unnumbered @reveal receives the next automatic step; blocks with the same explicit number appear together.
Block content
Callouts and notes
<!-- @callout warning -->
# Attention> Highlighted content.> It may span multiple lines.
The heading is optional; at least one quoted (>) line is required. Built-in icons: info, tip, success, warning, danger, error, question, quote, love, like, dislike.
Markdown callouts also work:
>[!warning] Attention
>Highlighted content.
Use <!-- @note --> directly before a blockquote to make it speaker-only; the audience will not see it. The paired mobile remote renders these notes as Markdown.
<!-- @note -->
> **Presenter cue:** Explain the feature demonstrated on this slide.> Mention the next step before advancing.
An ordinary blockquote without @note remains visible audience content.
Images
A standalone Markdown image is normal Markdown content. @img turns the following image into a media block:
The optional ratio is WIDTH:HEIGHT; optional shape is rounded, square, or circle.
YouTube, QR, and draw.io
Each directive consumes the next Markdown link:
<!-- @youtube autoplay on muted on volume 5 -->
[Demo](https://youtu.be/VIDEO_ID?t=1m30s)
<!-- @qr -->
[Open presentation](https://example.com/deck.md)
<!-- @drawio -->
[Architecture](./diagrams/architecture.drawio)
@youtube supports autoplay on|off, muted on|off, and volume 1…10; URL t or start sets its start time. @qr generates a clickable QR code. @drawio renders a diagrams.net file.
@qr and @drawio can consume a data fenced block instead of a link:
<!-- @qr -->
```data
Any QR payload.
```
<!-- @drawio -->
```data
<mxfile>…</mxfile>
```
Gallery
A gallery consumes the following contiguous Markdown list:
The first duration (ms or s) is the default, with a default of 5s and maximum of 60s. Images may have individual durations. rows-N requests 1–12 rows; galleries support up to 100 images.
@cover, @contain, and @float
@cover and @contain are panel-level display directives. Put one of them at the beginning of a panel, alongside panel background directives. They apply to the panel’s first supported content block, not merely to the line immediately following the directive. The directive may appear elsewhere in the source, but normalization moves it to the panel header.
In this example the heading remains normal content and the image is the first supported target, so it fills the panel. @cover crops an image when necessary; @contain fills the panel while preserving the image aspect ratio, which is useful for diagrams and SVGs.
Only the first @cover or @contain in a panel takes effect. Supported targets are standalone Markdown images, tables, fenced code blocks, and @img, @youtube, @qr, @gallery, @callout, or @space blocks. If the panel has no supported target, the directive has no visual effect.
@float places its next block at one side so following content can flow next to it:
<!-- @float right 40% 3 -->
<!-- @img rounded -->

This Markdown can flow beside the image.
Syntax: @float left|right WIDTH [GAP]; WIDTH is a percentage and GAP is in cqw. The target can be an image, table, fenced code block, or @img, @youtube, @qr, @drawio, @gallery, @callout, or @space.
Markdown extensions
Formulas
A $$ pair on its own lines renders a KaTeX display formula:
$$
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
$$
Mermaid
flowchart LR
A[Idea] --> B[Plan] --> C[Launch]
A fenced code block with language mermaid renders as a diagram.
Frontmatter limits
The frontmatter block supports flat key: value lines, not general YAML structures such as nested mappings, lists, or multiline values. Keep it at the very beginning of the document; outside that header, standalone --- lines separate slides. Use slide and panel directives for their local presentation settings.
Sizing guide
Use this section when planning a deck manually or asking an AI to author one. Values using cqw are proportional: 1cqw is 1% of the slide container width, so a value scales with the presentation instead of being a fixed pixel size.
Player baseline
Element
Default size
Planning implication
Panel safe padding
5cqw on every side
Keep ordinary content inside this area. @cover and @contain intentionally remove it.
Body text
1.25cqw, 1.5 line-height
A full-width slide supports short, presentation-sized paragraphs rather than document-length prose.
Default block gap
about 0.8cqw
Consecutive Markdown blocks already have breathing room.
H1
about 4.5cqw
Use for one primary statement, usually no more than one per panel.
H2
about 2.75cqw
Use for section labels or a secondary message.
H3
about 1.8cqw
Use for small subsections or grouped points.
H4–H6
about 1.25–1.5cqw
Use sparingly; body text, lists, or callouts are often clearer.
The first heading in a Markdown block has no top margin. Later headings receive a section gap. A heading immediately after @col-break also starts without a top margin.
Practical ranges
Need
Recommended starting point
Notes
Normal content width
@set-width 100%
Default in every panel; @width 100% is a one-block override.
Readable text measure
@set-width 55%–75%, or one-off @width 60%
Use persistent width for several blocks, one-off width for a statement, quotation, or compact explanation.
Side visual with flowing text
`@float left
right 30%–45% 2`
Deliberate vertical space
@gap 2–6
Use negative values only for small optical corrections, such as @gap -1 or @gap -2.
Default gap between content blocks
@set-gap 1–3
Do not use a large panel-wide gap if only one relationship needs space; prefer @gap.
Two text columns
@columns 2 2–4
Best on a wide, single-panel slide; avoid columns in narrow grid panels.
Image/video ratio
16:9, 4:3, or 1:1
Choose a ratio that matches the source. Use @cover for edge-to-edge media and @contain for an uncropped full-panel diagram or SVG.
Dense material
@set-scale 90% or one-off @scale 80%–90%
Reduce scale before adding too much content, but avoid making presentation text document-sized.
Authoring rules for AI
Treat each panel as one visual idea. A multi-panel slide needs correspondingly shorter content per panel.
Start with one # heading or a short H2-level label; do not stack several large headings unless demonstrating typography.
Prefer 3–6 short list items over a long paragraph. Keep nested lists shallow.
Use @columns for parallel, scannable material—not to fit more prose. @col-break is for intentional column starts.
Use persistent @set-width or one-off @width, @float, @cover, and @contain to establish hierarchy before changing text scale.
Leave room for headings, images, tables, and reveal steps. Hidden reveal content still reserves its layout space.
Check the result at the intended aspect ratio and screen size; cqw preserves proportions, but it cannot make overloaded content readable.
Syntax reference
The complete reference for the presentation language. It is embedded below, and the same text is available in the app as a separate page.
pwmd syntax
pwmd turns Markdown into a presentation. Regular Markdown remains the content format: headings, lists, links, tables, blockquotes, images, and fenced code blocks all work normally. Presentation features use standalone HTML-comment directives:
Prefer spaces just inside the comment delimiters:
<!-- @directive -->or<!-- @directive arguments -->. This form is more compatible with Markdown renderers that handle compact comments differently; rendering behavior varies. pwmd also accepts compact comments for backward compatibility.A directive is only interpreted on its own line and never inside a fenced code block. Invalid directives are left as ordinary hidden HTML comments.
FRONTMATTER
An optional flat frontmatter block at the very beginning sets the presentation title and multiplicative text scales for every slide:
--- title: "Product update" text-scale: 120% h1-scale: 150% h2-scale: 110% table-scale: 80% --- # First slide Presentation content.titleis a nonempty string naming the presentation independently of its filename. It appears in recent-presentation lists; it does not set or change slide headings or@slidetitles. Omit it to use the filename or URL as the recent-list label.Document typography
Supported scale keys are
text-scale,h1-scale–h6-scale,table-scale,code-scale,quote-scale, andmath-scale. Element base ratios are built into the theme. For example, h1 usestext scale × built-in h1 base × h1-scale. Missing values use the built-in defaults.Slides and panels
A standalone
---starts a new slide; a standalone***starts a new panel on the current slide. They are ignored inside fenced code blocks. A slide can contain up to 26 panels.<!-- @slide Introduction --> # First panel *** # Second panel --- <!-- @slide Next slide --> # New slideSlide metadata
Put slide directives at the beginning of a slide, before panel content. Slide-metadata parsing stops at the first non-empty, non-directive line.
Title
The title is editor metadata, used in the editor’s slide list and editing UI; the player does not currently render it. If omitted, the editor uses the slide’s first
#heading and writes an@slidedirective when saving.Layout and visible grids
Letters identify panel areas. Repeating a letter merges its cells into one rectangular area;
/starts a new row. Panel order follows each letter’s first occurrence.@layouthides panel dividers.@griddisplays dashed panel dividers..represents an empty cell.Add
collapseto reduce the grid’s outer and panel padding:Slide theme
The three values are
BASE ACCENT FRAME:BASE: background, surface, and text paletteACCENT: highlight colorFRAME: frame and divider colorColors are built-in Tailwind color-family names such as
slate,stone,blue,amber, andzinc. A theme affects the whole slide.Slide background
A slide background can combine a wallpaper image, a color, and a gradient. Only the first directive of each kind takes effect.
<!-- @slide-wallpaper -->  <!-- @slide-bg slate-900/70 --> <!-- @slide-gradient down transparent -> slate-900/70 60% -> slate-950 --> # Content above the background@slide-wallpaperconsumes the following Markdown image; blank lines are allowed in between.@slide-bgaccepts a Tailwind color with optional-50…-950shade and/0…/100opacity, for exampleblack/50.@slide-gradientusesdown,up,left, orright, with->-separated stops. A stop may have a position, such asblue/60 45%.Sound
Sound is slide-level YouTube audio. The directive must be followed by a Markdown link.
<!-- @sound autoplay on muted on volume 5 --> [Soundtrack](https://www.youtube.com/watch?v=VIDEO_ID)Options are pairs in any order:
autoplay on|off— default:offmuted on|off— default:offvolume 1…10— default:7Browsers generally require
muted onfor autoplay.Panel backgrounds
Use the same three background directives without the
slide-prefix:<!-- @wallpaper -->  <!-- @bg black/55 --> <!-- @gradient up black/80 -> transparent --> # Panel contentOnly a panel’s first
@bg,@gradient, and@wallpaperare used.@wallpaperconsumes its following image.Content layout
Persistent directives affect following content within the panel until changed. One-off
@width,@align, and@scaletarget only the next content block.Alignment, width, and columns
@align left|center|right|justifysets alignment for the next content block only; without an argument it selects the defaultcenterfor that block.@set-align left|center|right|justifysets the persistent panel alignment; without an argument it restorescenter.resetis not an accepted alignment argument.<!-- @set-align left -->, then<!-- @align right -->aligns the next block right and subsequent content left. Combine it with<!-- @width 80% -->and<!-- @scale 120% -->to independently style that block.@width N%sets only the next content block’s width, then the persistent width resumes.@width resetis a one-off100%.@set-width N%sets the persistent width for following blocks in this panel.@set-width resetrestores100%.100%in each panel and is relative to that panel’s available content width, not the slide. Alignment defaults tocenter. Pending one-off width and alignment skips whitespace, layout directives, spacers, and hidden presenter notes; it applies to Markdown blocks (including headings, lists, code and tables), callouts, or media. Float/cover/contain retain their own explicit sizing.@columns N [GAP]sets CSS columns for Markdown text.Nis 1–12;GAPis 0–999cqwunits.@col-breakstarts the following Markdown content in the next CSS column. It only has an effect while@columnsis active.Scale
@set-scale PERCENTchanges the persistent scale from that point onward.@scale PERCENTapplies only to the next content block, then the persistent scale resumes. Both scale every text type after its document-level typography multipliers; they do not resize images or video. Use@set-scale 100%to restore the default block scale.Colors
@coloraccepts a color name or inline-color index1,2, or3.<!-- @set-colors cyan rose lime --> _First color_, __second color__, ___third color___. <!-- @color 2 --> This uses the second color.@set-colors COLOR1 COLOR2 COLOR3overrides the inline palette for the rest of the panel.@set-colors resetrestores the default palette.@set-color-1,@set-color-2, and@set-color-3override one palette entry; useresetto restore it.amber,violet, andemerald.Spacing
@spacefills the remaining panel height.@gap Ninserts an empty blockN cqwhigh (N: -999–999). A negative value reduces the space before the following block, pulling it upward.<!-- @set-gap 3 --> # Heading A paragraph. <!-- @set-gap reset -->@set-gap Nchanges the normal gap between panel content blocks.reset, or no argument, restores the default gap.Progressive reveal
Reveal steps are shared across every panel on the slide. Hidden blocks retain their space and fade in. An unnumbered
@revealreceives the next automatic step; blocks with the same explicit number appear together.Block content
Callouts and notes
<!-- @callout warning --> # Attention > Highlighted content. > It may span multiple lines.The heading is optional; at least one quoted (
>) line is required. Built-in icons:info,tip,success,warning,danger,error,question,quote,love,like,dislike.Markdown callouts also work:
Use
<!-- @note -->directly before a blockquote to make it speaker-only; the audience will not see it. The paired mobile remote renders these notes as Markdown.<!-- @note --> > **Presenter cue:** Explain the feature demonstrated on this slide. > Mention the next step before advancing.An ordinary blockquote without
@noteremains visible audience content.Images
A standalone Markdown image is normal Markdown content.
@imgturns the following image into a media block:<!-- @img 16:9 rounded --> The optional ratio is
WIDTH:HEIGHT; optional shape isrounded,square, orcircle.YouTube, QR, and draw.io
Each directive consumes the next Markdown link:
<!-- @youtube autoplay on muted on volume 5 --> [Demo](https://youtu.be/VIDEO_ID?t=1m30s) <!-- @qr --> [Open presentation](https://example.com/deck.md) <!-- @drawio --> [Architecture](./diagrams/architecture.drawio)@youtubesupportsautoplay on|off,muted on|off, andvolume 1…10; URLtorstartsets its start time.@qrgenerates a clickable QR code.@drawiorenders a diagrams.net file.@qrand@drawiocan consume adatafenced block instead of a link:<!-- @qr --> ```data Any QR payload. ``` <!-- @drawio --> ```data <mxfile>…</mxfile> ```Gallery
A gallery consumes the following contiguous Markdown list:
<!-- @gallery 4s rows-2 --> -  6s -  -  3sThe first duration (
msors) is the default, with a default of5sand maximum of60s. Images may have individual durations.rows-Nrequests 1–12 rows; galleries support up to 100 images.@cover,@contain, and@float@coverand@containare panel-level display directives. Put one of them at the beginning of a panel, alongside panel background directives. They apply to the panel’s first supported content block, not merely to the line immediately following the directive. The directive may appear elsewhere in the source, but normalization moves it to the panel header.<!-- @cover --> # Introductory heading In this example the heading remains normal content and the image is the first supported target, so it fills the panel.
@covercrops an image when necessary;@containfills the panel while preserving the image aspect ratio, which is useful for diagrams and SVGs.<!-- @contain --> Only the first
@coveror@containin a panel takes effect. Supported targets are standalone Markdown images, tables, fenced code blocks, and@img,@youtube,@qr,@gallery,@callout, or@spaceblocks. If the panel has no supported target, the directive has no visual effect.@floatplaces its next block at one side so following content can flow next to it:<!-- @float right 40% 3 --> <!-- @img rounded -->  This Markdown can flow beside the image.Syntax:
@float left|right WIDTH [GAP];WIDTHis a percentage andGAPis incqw. The target can be an image, table, fenced code block, or@img,@youtube,@qr,@drawio,@gallery,@callout, or@space.Markdown extensions
Formulas
A
$$pair on its own lines renders a KaTeX display formula:$$ \sum_{i=1}^{n} i = \frac{n(n+1)}{2} $$Mermaid
A fenced code block with language
mermaidrenders as a diagram.Frontmatter limits
The frontmatter block supports flat
key: valuelines, not general YAML structures such as nested mappings, lists, or multiline values. Keep it at the very beginning of the document; outside that header, standalone---lines separate slides. Use slide and panel directives for their local presentation settings.Sizing guide
Use this section when planning a deck manually or asking an AI to author one. Values using
cqware proportional:1cqwis 1% of the slide container width, so a value scales with the presentation instead of being a fixed pixel size.Player baseline
5cqwon every side@coverand@containintentionally remove it.1.25cqw,1.5line-height0.8cqw4.5cqw2.75cqw1.8cqw1.25–1.5cqwThe first heading in a Markdown block has no top margin. Later headings receive a section gap. A heading immediately after
@col-breakalso starts without a top margin.Practical ranges
@set-width 100%@width 100%is a one-block override.@set-width 55%–75%, or one-off@width 60%–45% 2`@gap 2–6@gap -1or@gap -2.@set-gap 1–3@gap.@columns 2 2–416:9,4:3, or1:1@coverfor edge-to-edge media and@containfor an uncropped full-panel diagram or SVG.@set-scale 90%or one-off@scale 80%–90%Authoring rules for AI
#heading or a short H2-level label; do not stack several large headings unless demonstrating typography.@columnsfor parallel, scannable material—not to fit more prose.@col-breakis for intentional column starts.@set-widthor one-off@width,@float,@cover, and@containto establish hierarchy before changing text scale.cqwpreserves proportions, but it cannot make overloaded content readable.