This document provides a comprehensive guide to the MPD (Mermaid Presentation DSL) grammar, including the formal EBNF specification, quick reference, and examples.
MPD (Mermaid Presentation DSL) is a declarative language for defining interactive presentations over Mermaid diagrams. The grammar is formally specified in EBNF notation.
Every MPD program starts with a version header:
mpd 1.0
deck {
// Presentation content
}
A deck is the root container for presentation content:
mpd 1.0
deck {
scene default {
step overview {
camera reset();
overlay bubble(target: dataId("A"), text: "Welcome!");
}
}
}
A scene groups related steps and can optionally reference a specific diagram:
scene intro {
step overview {
camera reset();
}
step detail {
camera fit(target: dataId("B"));
}
}
scene outro diagram "main-diagram" {
step summary {
camera fitAll();
}
}
A step defines a presentation state with actions:
step overview {
camera reset();
style highlight(target: dataId("A"));
overlay bubble(target: dataId("A"), text: "Start here");
}
A binding defines event-to-action mappings:
binding {
on click target node("A") {
do nav.goto(id: "detail");
}
on key "ArrowRight" {
do nav.next();
}
}
let count = 42; // Integer
let rate = 0.95; // Number
let message = "Hello"; // String
let enabled = true; // Boolean
let empty = null; // Null
let duration = 500ms; // Duration
let percent = 50%; // Percent
let color = #3b82f6; // Color hex
let config = {
theme: "dark",
fontSize: 14,
enabled: true
};
let items = [1, 2, 3, "four"];
Target expressions select diagram elements:
node("A") // Node by ID
edge("A", "B") // Edge between nodes
subgraph("cluster1") // Subgraph by ID
css(".highlight") // CSS selector
id("element-id") // Element by ID
text("Label") // Element by text content
dataId("nodeA") // Element by data-id attribute
// Target combinations
union(node("A"), node("B")) // Union of targets
intersect(target1, target2) // Intersection
except(all, node("A")) // All except A
group(node("A"), node("B")) // Grouped selection
camera fit(target: dataId("A"), padding: 60, duration: 500, easing: "cubicOut");
camera reset();
camera zoom(factor: 1.2, center: { x: 100, y: 100 });
camera pan(deltaX: 50, deltaY: 0);
camera fitAll(padding: 40);
style highlight(target: dataId("A"));
style clear();
style classAdd(target: node("B"), className: "active");
style classRemove(target: node("B"), className: "inactive");
overlay bubble(target: dataId("A"), text: "Important note!");
overlay hide(id: "bubble-1");
nav.next();
nav.prev();
nav.goto(id: "overview");
nav.goto(index: 2);
nav.reset();
Focus statements combine camera positioning with optional styling:
focus node("A") pad 60 align center lock xy id "main-focus";
Focus options:
pad <number> - Padding around targetalign <direction> - Alignment (center, start, end, top, bottom, left, right)lock <mode> - Lock camera movement (none, x, y, xy)id <identifier> - Store focus bbox in $focus.<id>runtime {
camera {
engine: "basic";
options: {
minZoom: 0.5,
maxZoom: 3.0
};
bounds: viewport;
}
}
runtime {
overlay {
engine: "basic";
options: {
placement: "top",
offset: 10
};
}
}
runtime {
navigation {
wheelZoom: true;
dragPan: true;
tapToAdvance: true;
progressUI: true;
startAt: "overview";
keys: {
next: "ArrowRight",
prev: "ArrowLeft"
};
}
}
runtime {
controls {
mode: "floating";
position: "bottom-right";
showPlayPause: true;
showPrevNext: true;
showZoomControls: true;
showStepIndicator: true;
autoHide: false;
offset: { x: 20, y: 20 };
}
}
Controls configuration options:
mode: Control display mode - "floating" (overlay), "fixed" (in layout), or "none" (disabled)position: Position for floating controls - "bottom-right", "bottom-left", "top-right", "top-left", or "bottom-center"showPlayPause: Show play/pause toggle button for auto-advance (default: true)showPrevNext: Show previous/next step buttons (default: true)showZoomControls: Show zoom in/out and fit all buttons (default: true)showStepIndicator: Show step counter display (default: true)autoHide: Automatically hide controls after inactivity (default: false)offset: Offset from position edge as { x: number, y: number } (default: { x: 20, y: 20 })Controls can also be configured programmatically via JavaScript:
import { presentMermaid, createFloatingControls } from 'finsteps';
const controller = await presentMermaid({
mountEl,
mermaidText,
mpdText,
options: {
controls: createFloatingControls({
controller, // Will be set automatically
camera, // Optional, for zoom controls
position: 'bottom-right',
showPlayPause: true,
showPrevNext: true,
showZoomControls: true
})
}
});
Diagrams can be declared inline or referenced by ID:
diagram "main" {
mermaid <<<MERMAID
flowchart LR
A[Start] --> B[End]
MERMAID;
config {
theme: "dark",
flowchart: {
curve: "basis"
}
};
}
Configure how targets resolve to diagram elements:
selectors {
strategy: mermaid-node-id;
fallback: [css, text];
node: {
prefix: "node-",
dataId: true
};
edge: {
prefix: "edge-",
byLabel: true
};
}
Define custom CSS classes and spotlight effects:
styles {
classes: {
highlight: "finsteps-highlight",
dim: "finsteps-dim"
};
spotlight: {
activeClass: "finsteps-active",
inactiveClass: "finsteps-inactive"
};
theme: dark;
}
mpd 1.0
deck {
runtime {
camera {
engine: "basic";
bounds: viewport;
}
navigation {
wheelZoom: true;
dragPan: true;
startAt: "overview";
}
}
scene default {
step overview {
camera reset();
overlay bubble(target: dataId("A"), text: "Full diagram view");
}
step detail {
camera fit(target: dataId("B"), padding: 60, duration: 500);
style highlight(target: dataId("B"));
overlay bubble(target: dataId("B"), text: "Detailed view");
}
}
binding {
on key "ArrowRight" {
do nav.next();
}
on key "ArrowLeft" {
do nav.prev();
}
on click target node("B") {
do nav.goto(id: "detail");
}
}
}
The complete EBNF grammar is available in ebnf/mpd.ebnf. This formal specification defines:
MPD can be validated using:
parseMPD() function to parse and get diagnostics