presenterm/print.html
2025-05-03 20:25:36 +00:00

3226 lines
201 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="navy sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>presenterm documentation</title>
<meta name="robots" content="noindex">
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('navy')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">presenterm documentation</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/mfontanini/presenterm" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="presenterm"><a class="header" href="#presenterm">presenterm</a></h1>
<p><a href="https://github.com/mfontanini/presenterm/">presenterm</a> lets you create presentations in markdown format and run them from your terminal, with support for
image and animated gif support, highly customizable themes, code highlighting, exporting presentations into PDF format,
and plenty of other features.</p>
<h2 id="demo"><a class="header" href="#demo">Demo</a></h2>
<p>This is how the <a href="https://github.com/mfontanini/presenterm/blob/master/examples/demo.md">demo presentation</a> looks like:</p>
<p><img src="./assets/demo.gif" alt="demo" /></p>
<p><strong>A few other example presentations can be found <a href="https://github.com/mfontanini/presenterm/tree/master/examples">here</a></strong>.</p>
<!-- Links -->
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="installing-presenterm"><a class="header" href="#installing-presenterm">Installing <em>presenterm</em></a></h1>
<p><em>presenterm</em> works on Linux, macOS, and Windows and can be installed in different ways:</p>
<h2 id="pre-built-binaries-recommended"><a class="header" href="#pre-built-binaries-recommended">Pre-built binaries (recommended)</a></h2>
<p>The recommended way to install <em>presenterm</em> is to download the latest pre-built version for
your system from the <a href="https://github.com/mfontanini/presenterm/releases">releases</a> page.</p>
<h2 id="install-via-cargo"><a class="header" href="#install-via-cargo">Install via cargo</a></h2>
<p>Alternatively, download <a href="https://www.rust-lang.org/">rust</a> and run:</p>
<pre><code class="language-bash">cargo install --locked presenterm
</code></pre>
<h2 id="latest-unreleased-version"><a class="header" href="#latest-unreleased-version">Latest unreleased version</a></h2>
<p>To install from the latest source code run:</p>
<pre><code class="language-bash">cargo install --git https://github.com/mfontanini/presenterm
</code></pre>
<h2 id="macos"><a class="header" href="#macos">macOS</a></h2>
<p>Install the latest version in macOS via <a href="https://formulae.brew.sh/formula/presenterm">brew</a> by running:</p>
<pre><code class="language-bash">brew install presenterm
</code></pre>
<h2 id="nix"><a class="header" href="#nix">Nix</a></h2>
<p>To install <em>presenterm</em> using the Nix package manager run:</p>
<pre><code class="language-bash">nix-env -iA nixos.presenterm # for nixos
nix-env -iA nixpkgs.presenterm # for non-nixos
</code></pre>
<p>Or, you can install it by adding the following to your configuration.nix if you are on NixOS</p>
<pre><code class="language-nix">environment.systemPackages = [
pkgs.presenterm
];
</code></pre>
<p>Alternatively if you're a Nix user using flakes you can run:</p>
<pre><code class="language-shell">nix run nixpkgs#presenterm # to run from nixpkgs
nix run github:mfontanini/presenterm # to run from github repo
</code></pre>
<p>For more information see
<a href="https://search.nixos.org/packages?channel=unstable&amp;show=presenterm&amp;from=0&amp;size=50&amp;sort=relevance&amp;type=packages&amp;query=presenterm">nixpkgs</a>.</p>
<h2 id="arch-linux"><a class="header" href="#arch-linux">Arch Linux</a></h2>
<p><em>presenterm</em> is available in the <a href="https://archlinux.org/packages/extra/x86_64/presenterm/">official repositories</a>. You can use <a href="https://wiki.archlinux.org/title/pacman">pacman</a> to install as follows:</p>
<pre><code class="language-bash">pacman -S presenterm
</code></pre>
<h4 id="binary-release"><a class="header" href="#binary-release">Binary release</a></h4>
<p>Alternatively, you can use any AUR helper to install the upstream binaries:</p>
<pre><code class="language-bash">paru/yay -S presenterm-bin
</code></pre>
<h4 id="building-from-git"><a class="header" href="#building-from-git">Building from git</a></h4>
<pre><code class="language-bash">paru/yay -S presenterm-git
</code></pre>
<h2 id="windows"><a class="header" href="#windows">Windows</a></h2>
<p>Install the latest version in Scoop via <a href="https://scoop.sh/#/apps?q=presenterm&amp;id=a462290f824b50f180afbaa6d8c7c1e6e0952e3a">Scoop</a> by running:</p>
<pre><code class="language-powershell">scoop install presenterm
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
<p>This guide teaches you how to use <em>presenterm</em>. At this point you should have already installed <em>presenterm</em>, otherwise
visit the <a href="features/../install.html">installation</a> guide to get started.</p>
<h2 id="quick-start"><a class="header" href="#quick-start">Quick start</a></h2>
<p>Download the demo presentation and run it using:</p>
<pre><code class="language-bash">git clone https://github.com/mfontanini/presenterm.git
cd presenterm
presenterm examples/demo.md
</code></pre>
<h1 id="presentations"><a class="header" href="#presentations">Presentations</a></h1>
<p>A presentation in <em>presenterm</em> is a single markdown file. Every slide in the presentation file is delimited by a line
that contains a single HTML comment:</p>
<pre><code class="language-html">&lt;!-- end_slide --&gt;
</code></pre>
<p>Presentations can contain most commonly used markdown elements such as ordered and unordered lists, headings, formatted
text (<strong>bold</strong>, <em>italics</em>, <del>strikethrough</del>, <code>inline code</code>, etc), code blocks, block quotes, tables, etc.</p>
<h2 id="introduction-slide"><a class="header" href="#introduction-slide">Introduction slide</a></h2>
<p>By setting a front matter at the beginning of your presentation you can configure the title, sub title, author and other
metadata about your presentation. Doing so will cause <em>presenterm</em> to create an introduction slide:</p>
<pre><code class="language-yaml">---
title: "My _first_ **presentation**"
sub_title: (in presenterm!)
author: Myself
---
</code></pre>
<p>All of these attributes are optional and should be avoided if an introduction slide is not needed. Note that the <code>title</code>
key can contain arbitrary markdown so you can use bold, italics, <code>&lt;span&gt;</code> tags, etc.</p>
<h3 id="multiple-authors"><a class="header" href="#multiple-authors">Multiple authors</a></h3>
<p>If you're creating a presentation in which there's multiple authors, you can use the <code>authors</code> key instead of <code>author</code>
and list them all this way:</p>
<pre><code class="language-yaml">---
title: Our first presentation
authors:
- Me
- You
---
</code></pre>
<h2 id="slide-titles"><a class="header" href="#slide-titles">Slide titles</a></h2>
<p>Any <a href="https://spec.commonmark.org/0.30/#setext-headings">setext header</a> will be considered to be a slide title and will
be rendered in a more slide-title-looking way. By default this means it will be centered, some vertical padding will be
added and the text color will be different.</p>
<pre><code class="language-markdown">Hello
===
</code></pre>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>See the <a href="features/themes/introduction.html">themes</a> section on how to customize the looks of slide titles and any other element
in a presentation.</p>
</div>
<h2 id="ending-slides"><a class="header" href="#ending-slides">Ending slides</a></h2>
<p>While other applications use a thematic break (<code>---</code>) to mark the end of a slide, <em>presenterm</em> uses a special
<code>end_slide</code> HTML comment:</p>
<pre><code class="language-html">&lt;!-- end_slide --&gt;
</code></pre>
<p>This makes the end of a slide more explicit and easy to spot while you're editing your presentation. See the
<a href="features/../configuration/options.html#implicit_slide_ends">configuration</a> if you want to customize this behavior.</p>
<p>If you really would prefer to use thematic breaks (<code>---</code>) to delimit slides, you can do that by enabling the
<a href="features/../configuration/options.html#end_slide_shorthand"><code>end_slide_shorthand</code></a> options.</p>
<h2 id="colored-text"><a class="header" href="#colored-text">Colored text</a></h2>
<p><code>span</code> HTML tags can be used to provide foreground and/or background colors to text. There's currently two ways to
specify colors:</p>
<ul>
<li>Via the <code>style</code> attribute, in which only the CSS attributes <code>color</code> and <code>background-color</code> can be used to set the
foreground and background colors respectively. Colors used in both CSS attributes can refer to
<a href="features/themes/definition.html#color-palette">theme palette colors</a> by using the <code>palette:&lt;name&gt;</code> or <code>p:&lt;name</code> syntaxes.</li>
<li>Via the <code>class</code> attribute, which must point to a class defined in the <a href="features/themes/definition.html#color-palette">theme
palette</a>. Classes allow configuring foreground/background color combinations to be
used across your presentation.</li>
</ul>
<p>For example, the following will use <code>ff0000</code> as the foreground color and whatever the active theme's palette defines as
<code>foo</code>:</p>
<pre><code class="language-markdown">&lt;span style="color: #ff0000; background-color: palette:foo"&gt;colored text!&lt;/span&gt;
</code></pre>
<p>Alternatively, can you can define a class that contains a foreground/background color combination in your theme's
palette and use it:</p>
<pre><code class="language-markdown">&lt;span class="my_class"&gt;colored text!&lt;/span&gt;
</code></pre>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>Keep in mind <strong>only <code>span</code> tags are supported</strong>.</p>
</div>
<h2 id="font-sizes"><a class="header" href="#font-sizes">Font sizes</a></h2>
<p>The <a href="https://sw.kovidgoyal.net/kitty/"><em>kitty</em></a> terminal added in version 0.40.0 support for a new protocol that allows
TUIs to specify the font size to be used when printing text. <em>presenterm</em> is one of the first applications supports this
protocol in various places:</p>
<ul>
<li>Themes can specify it in the presentation title in the introduction slide, in slide titles, and in headers by using
the <code>font_size</code> property. All built in themes currently set font size to 2 (1 is the default) for these elements.</li>
<li>Explicitly by using the <code>font_size</code> comment command:</li>
</ul>
<pre><code class="language-markdown"># Normal text
&lt;!-- font_size: 2 --&gt;
# Larger text
</code></pre>
<p>Terminal support for this feature is verified when <em>presenterm</em> starts and any attempt to change the font size, be it
via the theme or via the comment command, will be ignored if it's not supported.</p>
<h1 id="key-bindings"><a class="header" href="#key-bindings">Key bindings</a></h1>
<p>Navigation within a presentation should be intuitive: jumping to the next/previous slide can be done by using the arrow
keys, <em>hjkl</em>, and page up/down keys.</p>
<p>Besides this:</p>
<ul>
<li>Jumping to the first slide: <code>gg</code>.</li>
<li>Jumping to the last slide: <code>G</code>.</li>
<li>Jumping to a specific slide: <code>&lt;slide-number&gt;G</code>.</li>
<li>Exit the presentation: <code>&lt;ctrl&gt;c</code>.</li>
</ul>
<p>You can check all the configured keybindings by pressing <code>?</code> while running <em>presenterm</em>.</p>
<h2 id="configuring-key-bindings"><a class="header" href="#configuring-key-bindings">Configuring key bindings</a></h2>
<p>If you don't like the default key bindings, you can override them in the <a href="features/../configuration/settings.html#key-bindings">configuration
file</a>.</p>
<h1 id="modals"><a class="header" href="#modals">Modals</a></h1>
<p><em>presenterm</em> currently has 2 modals that can provide some information while running the application. Modals can be
toggled using some key combination and can be hidden using the escape key by default, but these can be configured via
the <a href="features/../configuration/settings.html#key-bindings">configuration file key bindings</a>.</p>
<h2 id="slide-index-modal"><a class="header" href="#slide-index-modal">Slide index modal</a></h2>
<p>This modal can be toggled by default using <code>control+p</code> and lets you see an index that contains a row for every slide in
the presentation, including its title and slide index. This allows you to find a slide you're trying to jump to
quicklier rather than scanning through each of them.</p>
<p><a href="https://asciinema.org/a/1VgRxVIEyLrMmq6OZ3oKx4PGi"><img src="https://asciinema.org/a/1VgRxVIEyLrMmq6OZ3oKx4PGi.svg" alt="asciicast" /></a></p>
<h2 id="key-bindings-modal"><a class="header" href="#key-bindings-modal">Key bindings modal</a></h2>
<p>The key bindings modal displays the key bindings for each of the supported actions and can be opened by pressing <code>?</code>.</p>
<h1 id="hot-reload"><a class="header" href="#hot-reload">Hot reload</a></h1>
<p>Unless you run in presentation mode by passing in the <code>--present</code> parameter, <em>presenterm</em> will automatically reload your
presentation file every time you save it. <em>presenterm</em> will also automatically detect which specific slide was modified
and jump to it so you don't have to be jumping back and forth between the source markdown and the presentation to see
how the changes look like.</p>
<p><a href="https://asciinema.org/a/bu9ITs8KhaQK5OdDWnPwUYKu3"><img src="https://asciinema.org/a/bu9ITs8KhaQK5OdDWnPwUYKu3.svg" alt="asciicast" /></a></p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="images"><a class="header" href="#images">Images</a></h1>
<p>Images are supported and will render in your terminal as long as it supports either the <a href="https://iterm2.com/documentation-images.html">iterm2 image
protocol</a>, the <a href="https://sw.kovidgoyal.net/kitty/graphics-protocol/">kitty graphics
protocol</a>, or <a href="https://saitoha.github.io/libsixel/">sixel</a>. Some of
the terminals where at least one of these is supported are:</p>
<ul>
<li><a href="https://sw.kovidgoyal.net/kitty/">kitty</a></li>
<li><a href="https://iterm2.com/">iterm2</a></li>
<li><a href="https://wezfurlong.org/wezterm/index.html">WezTerm</a></li>
<li><a href="https://codeberg.org/dnkl/foot">foot</a></li>
</ul>
<p>Sixel support is experimental so it needs to be explicitly enabled via the <code>sixel</code> configuration flag:</p>
<pre><code class="language-bash">cargo build --release --features sixel
</code></pre>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>This feature flag is only needed if your terminal emulator <em>only</em> supports sixel. Many terminals support the kitty or
iterm2 protocols so using this flag is often not required to get images to render successfully.</p>
</div>
<hr />
<p>Things you should know when using image tags in your presentation's markdown are:</p>
<ul>
<li>Image paths are relative to your presentation path. That is a tag like <code>![](food/potato.png)</code> will be looked up at
<code>$PRESENTATION_DIRECTORY/food/potato.png</code>.</li>
<li>Images will be rendered by default in their original size. That is, if your terminal is 300x200px and your image is
200x100px, it will take up 66% of your horizontal space and 50% of your vertical space.</li>
<li>The exception to the point above is if the image does not fit in your terminal, it will be resized accordingly while
preserving the aspect ratio.</li>
<li>If your terminal does not support any of the graphics protocol above, images will be rendered using ascii blocks. It
ain't great but it's something!</li>
</ul>
<h2 id="tmux"><a class="header" href="#tmux">tmux</a></h2>
<p>If you're using tmux, you will need to enable the <a href="https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it">allow-passthrough
option</a> for images to
work correctly.</p>
<h2 id="image-size"><a class="header" href="#image-size">Image size</a></h2>
<p>The size of each image can be set by using the <code>image:width</code> or <code>image:w</code> attributes in the image tag. For example, the
following will cause the image to take up 50% of the terminal width:</p>
<pre><code class="language-markdown">![image:width:50%](image.png)
</code></pre>
<p>The image will always be scaled to preserve its aspect ratio and it will not be allowed to overflow vertically nor
horizontally.</p>
<h2 id="protocol-detection"><a class="header" href="#protocol-detection">Protocol detection</a></h2>
<p>By default the image protocol to be used will be automatically detected. In cases where this detection fails, you can
set it manually via the <code>--image-protocol</code> parameter or by setting it in the <a href="features/../configuration/settings.html#preferred-image-protocol">config
file</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="comment-commands"><a class="header" href="#comment-commands">Comment commands</a></h1>
<p><em>presenterm</em> uses "comment commands" in the form of HTML comments to let the user specify certain behaviors that can't
be specified by vanilla markdown.</p>
<h2 id="pauses"><a class="header" href="#pauses">Pauses</a></h2>
<p>Pauses allow the sections of the content in your slide to only show up when you advance in your presentation. That is,
only after you press, say, the right arrow will a section of the slide show up. This can be done by the <code>pause</code> comment
command:</p>
<pre><code class="language-html">&lt;!-- pause --&gt;
</code></pre>
<h2 id="font-size"><a class="header" href="#font-size">Font size</a></h2>
<p>The font size can be changed by using the <code>font_size</code> command:</p>
<pre><code class="language-html">&lt;!-- font_size: 2 --&gt;
</code></pre>
<p>This causes the remainder of the slide to use the font size specified. The font size can range from 1 to 7, 1 being the
default.</p>
<blockquote>
<p>![note]
This is currently only supported in the <a href="https://sw.kovidgoyal.net/kitty/"><em>kitty</em></a> terminal and only as of version
0.40.0. See the notes on font sizes on the <a href="features/introduction.html#font-sizes">introduction page</a> for more information on
this.</p>
</blockquote>
<h2 id="jumping-to-the-vertical-center"><a class="header" href="#jumping-to-the-vertical-center">Jumping to the vertical center</a></h2>
<p>The command <code>jump_to_middle</code> lets you jump to the middle of the page vertically. This is useful in combination
with slide titles to create separator slides:</p>
<pre><code class="language-markdown">blablabla
&lt;!-- end_slide --&gt;
&lt;!-- jump_to_middle --&gt;
Farming potatoes
===
&lt;!-- end_slide --&gt;
</code></pre>
<p>This will create a slide with the text "Farming potatoes" in the center, rendered using the slide title style.</p>
<h2 id="explicit-new-lines"><a class="header" href="#explicit-new-lines">Explicit new lines</a></h2>
<p>The <code>newline</code>/<code>new_line</code> and <code>newlines</code>/<code>new_lines</code> commands allow you to explicitly create new lines. Because markdown
ignores multiple line breaks in a row, this is useful to create some spacing where necessary:</p>
<pre><code class="language-markdown">hi
&lt;!-- new_lines: 10 --&gt;
mom
&lt;!-- new_line --&gt;
bye
</code></pre>
<h2 id="incremental-lists"><a class="header" href="#incremental-lists">Incremental lists</a></h2>
<p>Using <code>&lt;!-- pause --&gt;</code> in between each bullet point a list is a bit tedious so instead you can use the
<code>incremental_lists</code> command to tell <em>presenterm</em> that <strong>until the end of the current slide</strong> you want each individual
bullet point to appear only after you move to the next slide:</p>
<pre><code class="language-markdown">&lt;!-- incremental_lists: true --&gt;
* this
* appears
* one after
* the other
&lt;!-- incremental_lists: false --&gt;
* this appears
* all at once
</code></pre>
<h2 id="no-footer"><a class="header" href="#no-footer">No footer</a></h2>
<p>If you don't want the footer to show up in some particular slide for some reason, you can use the <code>no_footer</code> command:</p>
<pre><code class="language-html">&lt;!-- no_footer --&gt;
</code></pre>
<h2 id="skip-slide"><a class="header" href="#skip-slide">Skip slide</a></h2>
<p>If you don't want a specific slide to be included in the presentation use the <code>skip_slide</code> command:</p>
<pre><code class="language-html">&lt;!-- skip_slide --&gt;
</code></pre>
<h2 id="text-alignment"><a class="header" href="#text-alignment">Text alignment</a></h2>
<p>The text alignment for the remainder of the slide can be configured via the <code>alignment</code> command, which can use values:
<code>left</code>, <code>center</code>, and <code>right</code>:</p>
<pre><code class="language-markdown">&lt;!-- alignment: left --&gt;
left alignment, the default
&lt;!-- alignment: center --&gt;
centered
&lt;!-- alignment: right --&gt;
right aligned
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="layouts"><a class="header" href="#layouts">Layouts</a></h1>
<p><em>presenterm</em> currently supports a column layout that lets you split parts of your slides into column. This allows you to
put text on one side, and code/images on the other, or really organize markdown into columns in any way you want.</p>
<p>This is done by using commands, just like <code>pause</code> and <code>end_slide</code>, in the form of HTML comments. This section describes
how to use those.</p>
<h2 id="wait-why-not-html"><a class="header" href="#wait-why-not-html">Wait, why not HTML?</a></h2>
<p>While markdown <em>can</em> contain HTML tags (beyond comments!) and we <em>could</em> represent this using divs with alignment, I
don't really want to:</p>
<ol>
<li>Deal with HTML and all the implications this would have. e.g. nesting many divs together and all the chaos that would
bring to the rendering code.</li>
<li>Require people to write HTML when we have such a narrow use-case for it here: we only want column layouts.</li>
</ol>
<p>Because of this, <em>presenterm</em> doesn't let you use HTML and instead has a custom way of specifying column layouts.</p>
<h2 id="column-layout"><a class="header" href="#column-layout">Column layout</a></h2>
<p>The way to specify column layouts is by first creating a layout, and then telling <em>presenterm</em> you want to enter each of
the column in it as you write your presentation.</p>
<h3 id="defining-layouts"><a class="header" href="#defining-layouts">Defining layouts</a></h3>
<p>Defining a layout is done via the <code>column_layout</code> command, in the form of an HTML comment:</p>
<pre><code class="language-html">&lt;!-- column_layout: [3, 2] --&gt;
</code></pre>
<p>This defines a layout with 2 columns where:</p>
<ul>
<li>The total number of "size units" is <code>3 + 2 = 5</code>. You can think of this as the terminal screen being split into 5
pieces vertically.</li>
<li>The first column takes 3 out of those 5 pieces/units, or in other words 60% of the terminal screen.</li>
<li>The second column takes 2 out of those 5 pieces/units, or in other words 40% of the terminal screen.</li>
</ul>
<p>You can use any number of columns and with as many units you want on each of them. This lets you decide how to structure
the presentation in a fairly straightforward way.</p>
<h3 id="using-columns"><a class="header" href="#using-columns">Using columns</a></h3>
<p>Once a layout is defined, you just need to specify that you want to enter a column before writing any text to it by
using the <code>column</code> command:</p>
<pre><code class="language-html">&lt;!-- column: 0 --&gt;
</code></pre>
<p>Now all the markdown you write will be placed on the first column until you either:</p>
<ul>
<li>Reset the layout by using the <code>reset_layout</code> command.</li>
<li>The slide ends.</li>
<li>You jump into another column by using the <code>column</code> command again.</li>
</ul>
<h2 id="example"><a class="header" href="#example">Example</a></h2>
<p>The following example puts all of this together by defining 2 columns, one with some code and bullet points, another one
with an image, and some extra text at the bottom that's not tied to any columns.</p>
<pre><code class="language-markdown">Layout example
==============
&lt;!-- column_layout: [2, 1] --&gt;
&lt;!-- column: 0 --&gt;
This is some code I like:
```rust
fn potato() -&gt; u32 {
42
}
```
Things I like about it:
1. Potato
2. Rust
3. The image on the right
&lt;!-- column: 1 --&gt;
![](examples/doge.png)
_Picture by Alexis Bailey / CC BY-NC 4.0_
&lt;!-- reset_layout --&gt;
Because we just reset the layout, this text is now below both of the columns.
</code></pre>
<p>This would render the following way:</p>
<p><img src="features/../assets/layouts.png" alt="" /></p>
<h2 id="other-uses"><a class="header" href="#other-uses">Other uses</a></h2>
<p>Besides organizing your slides into columns, you can use column layouts to center a piece of your slide. For example, if
you want a certain portion of your slide to be centered, you could define a column layout like <code>[1, 3, 1]</code> and then only
write content into the middle column. This would make your content take up the center 60% of the screen.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="code-highlighting"><a class="header" href="#code-highlighting">Code highlighting</a></h1>
<p>Code highlighting is supported for the following languages:</p>
<div class="table-wrapper"><table><thead><tr><th>Language</th><th>Execution support</th></tr></thead><tbody>
<tr><td>ada</td><td></td></tr>
<tr><td>asp</td><td></td></tr>
<tr><td>awk</td><td></td></tr>
<tr><td>bash</td><td></td></tr>
<tr><td>batchfile</td><td></td></tr>
<tr><td>C</td><td></td></tr>
<tr><td>cmake</td><td></td></tr>
<tr><td>crontab</td><td></td></tr>
<tr><td>C#</td><td></td></tr>
<tr><td>clojure</td><td></td></tr>
<tr><td>C++</td><td></td></tr>
<tr><td>CSS</td><td></td></tr>
<tr><td>D</td><td></td></tr>
<tr><td>diff</td><td></td></tr>
<tr><td>docker</td><td></td></tr>
<tr><td>dotenv</td><td></td></tr>
<tr><td>elixir</td><td></td></tr>
<tr><td>elm</td><td></td></tr>
<tr><td>erlang</td><td></td></tr>
<tr><td>fish</td><td></td></tr>
<tr><td>go</td><td></td></tr>
<tr><td>haskell</td><td></td></tr>
<tr><td>HTML</td><td></td></tr>
<tr><td>java</td><td></td></tr>
<tr><td>javascript</td><td></td></tr>
<tr><td>json</td><td></td></tr>
<tr><td>julia</td><td></td></tr>
<tr><td>kotlin</td><td></td></tr>
<tr><td>latex</td><td></td></tr>
<tr><td>lua</td><td></td></tr>
<tr><td>makefile</td><td></td></tr>
<tr><td>markdown</td><td></td></tr>
<tr><td>nix</td><td></td></tr>
<tr><td>ocaml</td><td></td></tr>
<tr><td>perl</td><td></td></tr>
<tr><td>php</td><td></td></tr>
<tr><td>protobuf</td><td></td></tr>
<tr><td>puppet</td><td></td></tr>
<tr><td>python</td><td></td></tr>
<tr><td>R</td><td></td></tr>
<tr><td>ruby</td><td></td></tr>
<tr><td>rust</td><td></td></tr>
<tr><td>scala</td><td></td></tr>
<tr><td>shell</td><td></td></tr>
<tr><td>sql</td><td></td></tr>
<tr><td>swift</td><td></td></tr>
<tr><td>svelte</td><td></td></tr>
<tr><td>tcl</td><td></td></tr>
<tr><td>toml</td><td></td></tr>
<tr><td>terraform</td><td></td></tr>
<tr><td>typescript</td><td></td></tr>
<tr><td>xml</td><td></td></tr>
<tr><td>yaml</td><td></td></tr>
<tr><td>vue</td><td></td></tr>
<tr><td>zig</td><td></td></tr>
<tr><td>zsh</td><td></td></tr>
</tbody></table>
</div>
<p>Other languages that are supported are:</p>
<ul>
<li>nushell, for which highlighting isn't supported but execution is.</li>
<li>rust-script, which is highlighted as rust but is executed via the <a href="https://rust-script.org/">rust-script</a> tool,
which lets you specify dependencies in your snippet.</li>
</ul>
<p>If there's a language that is not in this list and you would like it to be supported, please <a href="https://github.com/mfontanini/presenterm/issues/new">create an
issue</a>. If you'd also like code execution support, provide details
on how to compile (if necessary) and run snippets for that language. You can also configure how to run code snippet for
a language locally in your <a href="features/code/../../configuration/settings.html#custom-snippet-executors">config file</a>.</p>
<h2 id="enabling-line-numbers"><a class="header" href="#enabling-line-numbers">Enabling line numbers</a></h2>
<p>If you would like line numbers to be shown on the left of a code block use the <code>+line_numbers</code> switch after specifying
the language in a code block:</p>
<pre><code class="language-markdown">```rust +line_numbers
fn hello_world() {
println!("Hello world");
}
```
</code></pre>
<h2 id="selective-highlighting"><a class="header" href="#selective-highlighting">Selective highlighting</a></h2>
<p>By default, the entire code block will be syntax-highlighted. If instead you only wanted a subset of it to be
highlighted, you can use braces and a list of either individual lines, or line ranges that you'd want to highlight.</p>
<pre><code class="language-markdown">```rust {1,3,5-7}
fn potato() -&gt; u32 { // 1: highlighted
// 2: not highlighted
println!("Hello world"); // 3: highlighted
let mut q = 42; // 4: not highlighted
q = q * 1337; // 5: highlighted
q // 6: highlighted
} // 7: highlighted
```
</code></pre>
<h2 id="dynamic-highlighting"><a class="header" href="#dynamic-highlighting">Dynamic highlighting</a></h2>
<p>Similar to the syntax used for selective highlighting, dynamic highlighting will change which lines of the code in a
code block are highlighted every time you move to the next/previous slide.</p>
<p>This is achieved by using the separator <code>|</code> to indicate what sections of the code will be highlighted at a given time.
You can also use <code>all</code> to highlight all lines for a particular frame.</p>
<pre><code class="language-markdown">```rust {1,3|5-7}
fn potato() -&gt; u32 {
println!("Hello world");
let mut q = 42;
q = q * 1337;
q
}
```
</code></pre>
<p>In this example, lines 1 and 3 will be highlighted initially. Then once you press a key to move to the next slide, lines
1 and 3 will no longer be highlighted and instead lines 5 through 7 will. This allows you to create more dynamic
presentations where you can display sections of the code to explain something specific about each of them.</p>
<p>See this real example of how this looks like.</p>
<p><a href="https://asciinema.org/a/iCf4f6how1Ux3H8GNzksFUczI"><img src="https://asciinema.org/a/iCf4f6how1Ux3H8GNzksFUczI.svg" alt="asciicast" /></a></p>
<h2 id="including-external-code-snippets"><a class="header" href="#including-external-code-snippets">Including external code snippets</a></h2>
<p>The <code>file</code> snippet type can be used to specify an external code snippet that will be included and highlighted as usual.</p>
<pre><code class="language-markdown">```file +exec +line_numbers
path: snippet.rs
language: rust
```
</code></pre>
<p>If you'd like to include only a subset of the file, you can use the optional fields <code>start_line</code> and <code>end_line</code>:</p>
<pre><code class="language-markdown">```file +exec +line_numbers
path: snippet.rs
language: rust
# Only shot lines 5-10
start_line: 5
end_line: 10
```
</code></pre>
<h2 id="showing-a-snippet-without-a-background"><a class="header" href="#showing-a-snippet-without-a-background">Showing a snippet without a background</a></h2>
<p>Using the <code>+no_background</code> flag will cause the snippet to have no background. This is useful when combining it with the
<code>+exec_replace</code> flag described further down.</p>
<h2 id="adding-highlighting-syntaxes-for-new-languages"><a class="header" href="#adding-highlighting-syntaxes-for-new-languages">Adding highlighting syntaxes for new languages</a></h2>
<p><em>presenterm</em> uses the syntaxes supported by <a href="https://github.com/sharkdp/bat">bat</a> to highlight code snippets, so any
languages supported by <em>bat</em> natively can be added to <em>presenterm</em> easily. Please create a ticket or use
<a href="https://github.com/mfontanini/presenterm/pull/385">this</a> as a reference to submit a pull request to make a syntax
officially supported by <em>presenterm</em> as well.</p>
<p>If a language isn't natively supported by <em>bat</em> but you'd like to use it, you can follow
<a href="https://github.com/sharkdp/bat#adding-new-syntaxes--language-definitions">this guide in the bat docs</a> and
invoke <em>bat</em> directly in a presentation:</p>
<pre><code class="language-markdown">```bash +exec_replace
bat --color always script.py
```
</code></pre>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>Check the <a href="features/code/execution.html#executing-and-replacing">code execution docs</a> for more details on how to allow the tool to run
<code>exec_replace</code> blocks.</p>
</div>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="snippet-execution"><a class="header" href="#snippet-execution">Snippet execution</a></h1>
<h2 id="executing-code-blocks"><a class="header" href="#executing-code-blocks">Executing code blocks</a></h2>
<p>Annotating a code block with a <code>+exec</code> attribute will make it executable. Pressing <code>control+e</code> when viewing a slide that
contains an executable block, the code in the snippet will be executed and the output of the execution will be displayed
on a box below it. The code execution is stateful so if you switch to another slide and then go back, you will still see
the output.</p>
<pre><code class="language-markdown">```bash +exec
echo hello world
```
</code></pre>
<p>Code execution <strong>must be explicitly enabled</strong> by using either:</p>
<ul>
<li>The <code>-x</code> command line parameter when running <em>presenterm</em>.</li>
<li>Setting the <code>snippet.exec.enable</code> property to <code>true</code> in your <a href="features/code/../../configuration/settings.html#snippet-execution"><em>presenterm</em> config
file</a>.</li>
</ul>
<p>Refer to <a href="features/code/highlighting.html#code-highlighting">the table in the highlighting page</a> for the list of languages for which
code execution is supported.</p>
<hr />
<p><a href="https://asciinema.org/a/BbAY817esxagCgPtnKUwgYnHr"><img src="https://asciinema.org/a/BbAY817esxagCgPtnKUwgYnHr.svg" alt="asciicast" /></a></p>
<div class="mdbook-alerts mdbook-alerts-warning">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
warning
</p>
<p>Run code in presentations at your own risk! Especially if you're running someone else's presentation. Don't blindly
enable snippet execution!</p>
</div>
<h2 id="executing-and-replacing"><a class="header" href="#executing-and-replacing">Executing and replacing</a></h2>
<p>Similar to <code>+exec</code>, <code>+exec_replace</code> causes a snippet to be executable but:</p>
<ul>
<li>Execution happens automatically without user intervention.</li>
<li>The snippet will be automatically replaced with its execution output.</li>
</ul>
<p>This can be useful to run programs that generate some form of ASCII art that you'd like to generate dynamically.</p>
<p><a href="https://asciinema.org/a/hklQARZKb5sP5mavL4cGgbYXD"><img src="https://asciinema.org/a/hklQARZKb5sP5mavL4cGgbYXD.svg" alt="asciicast" /></a></p>
<p>Because of the risk involved in <code>+exec_replace</code>, where code gets automatically executed when running a presentation,
this requires users to explicitly opt in to it. This can be done by either passing in the <code>-X</code> command line parameter
or setting the <code>snippet.exec_replace.enable</code> flag in your configuration file to <code>true</code>.</p>
<h2 id="code-to-image-conversions"><a class="header" href="#code-to-image-conversions">Code to image conversions</a></h2>
<p>The <code>+image</code> attribute behaves like <code>+exec_replace</code> but also assumes the output of the executed snippet will be an
image, and it will render it as such. For this to work, the code <strong>must only emit an image in jpg/png formats</strong> and
nothing else.</p>
<p>For example, this would render the demo presentation's image:</p>
<pre><code class="language-markdown">```bash +image
cat examples/doge.png
```
</code></pre>
<p>This attribute carries the same risks as <code>+exec_replace</code> and therefore needs to be enabled via the same flags.</p>
<h2 id="executing-snippets-that-need-a-tty"><a class="header" href="#executing-snippets-that-need-a-tty">Executing snippets that need a TTY</a></h2>
<p>If you're trying to execute a program like <code>top</code> that needs to run on a TTY as it renders text, clears the screen, etc,
you can use the <code>+acquire_terminal</code> modifier on a code already marked as executable with <code>+exec</code>. Executing snippets
tagged with these two attributes will cause <em>presenterm</em> to suspend execution, the snippet will be invoked giving it the
raw terminal to do whatever it needs, and upon its completion <em>presenterm</em> will resume its execution.</p>
<p><a href="https://asciinema.org/a/AHfuJorCNRR8ZEnfwQSDR5vPT"><img src="https://asciinema.org/a/AHfuJorCNRR8ZEnfwQSDR5vPT.svg" alt="asciicast" /></a></p>
<h2 id="styled-execution-output"><a class="header" href="#styled-execution-output">Styled execution output</a></h2>
<p>Snippets that generate output which contains escape codes that change the colors or styling of the text will be parsed
and displayed respecting those styles. Do note that you may need to force certain tools to use colored output as they
will likely not use it by default.</p>
<p>For example, to get colored output when invoking <code>ls</code> you can use:</p>
<pre><code class="language-markdown">```bash +exec
ls /tmp --color=always
```
</code></pre>
<p>The parameter or way to enable this will depend on the tool being invoked.</p>
<h2 id="hiding-code-lines"><a class="header" href="#hiding-code-lines">Hiding code lines</a></h2>
<p>When you mark a code snippet as executable via the <code>+exec</code> flag, you may not be interested in showing <em>all the lines</em> to
your audience, as some of them may not be necessary to convey your point. For example, you may want to hide imports,
non-essential functions, initialization of certain variables, etc. For this purpose, <em>presenterm</em> supports a prefix
under certain programming languages that let you indicate a line should be executed when running the code but should not
be displayed in the presentation.</p>
<p>For example, in the following code snippet only the print statement will be displayed but the entire snippet will be
ran:</p>
<pre><code class="language-markdown">```rust
# fn main() {
println!("Hello world!");
# }
```
</code></pre>
<p>Rather than blindly relying on a prefix that may have a meaning in a language, prefixes are chosen on a per language
basis. The languages that are supported and their prefix is:</p>
<ul>
<li>rust: <code># </code>.</li>
<li>python/bash/fish/shell/zsh/kotlin/java/javascript/typescript/c/c++/go: <code>/// </code>.</li>
</ul>
<p>This means that any line in a rust code snippet that starts with <code># </code> will be hidden, whereas all lines in, say, a
golang code snippet that starts with a <code>/// </code> will be hidden.</p>
<h2 id="pre-rendering"><a class="header" href="#pre-rendering">Pre-rendering</a></h2>
<p>Some languages support pre-rendering. This means the code block is transformed into something else when the presentation
is loaded. The languages that currently support this are <em>mermaid</em>, <em>LaTeX</em>, and <em>typst</em> where the contents of the code
block is transformed into an image, allowing you to define formulas as text in your presentation. This can be done by
using the <code>+render</code> attribute on a code block.</p>
<p>See the <a href="features/code/latex.html">LaTeX and typst</a> and <a href="features/code/mermaid.html">mermaid</a> docs for more information.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h2 id="mermaid"><a class="header" href="#mermaid">Mermaid</a></h2>
<p><a href="https://mermaid.js.org/">mermaid</a> snippets can be converted into images automatically in any code snippet tagged with
the <code>mermaid</code> language and a <code>+render</code> tag:</p>
<pre><code class="language-markdown">```mermaid +render
sequenceDiagram
Mark --&gt; Bob: Hello!
Bob --&gt; Mark: Oh, hi mark!
```
</code></pre>
<p><strong>This requires having <a href="https://github.com/mermaid-js/mermaid-cli">mermaid-cli</a> installed</strong>.</p>
<p>Note that because the mermaid CLI will spin up a browser under the hood, this may not work in all environments and can
also be a bit slow (e.g. ~2 seconds to generate every image). Mermaid graphs are rendered asynchronously by a number of
threads that can be configured in the <a href="features/code/../../configuration/settings.html#snippet-rendering-threads">configuration file</a>.
This configuration value currently defaults to 2.</p>
<p>The size of the rendered image can be configured by changing:</p>
<ul>
<li>The <code>mermaid.scale</code> <a href="features/code/../../configuration/settings.html#mermaid-scaling">configuration parameter</a>.</li>
<li>Using the <code>+width:&lt;number&gt;%</code> attribute in the code snippet.</li>
</ul>
<p>For example, this diagram will take up 50% of the width of the window and will preserve its aspect ratio:</p>
<pre><code class="language-markdown">```mermaid +render +width:50%
sequenceDiagram
Mark --&gt; Bob: Hello!
Bob --&gt; Mark: Oh, hi mark!
```
</code></pre>
<p>It is recommended to change the <code>mermaid.scale</code> parameter until images look big enough and then adjust on an image by
image case if necessary using the <code>+width</code> attribute. Otherwise, using a small scale and then scaling via <code>+width</code> may
cause the image to become blurry.</p>
<h2 id="theme"><a class="header" href="#theme">Theme</a></h2>
<p>The theme of the rendered mermaid diagrams can be changed through the following
<a href="features/code/../themes/introduction.html#mermaid">theme</a> parameters:</p>
<ul>
<li><code>mermaid.background</code> the background color passed to the CLI (e.g., <code>transparent</code>, <code>red</code>, <code>#F0F0F0</code>).</li>
<li><code>mermaid.theme</code> the <a href="https://mermaid.js.org/config/theming.html#available-themes">mermaid theme</a> to use.</li>
</ul>
<h2 id="always-render-diagrams"><a class="header" href="#always-render-diagrams">Always render diagrams</a></h2>
<p>If you don't want to use <code>+render</code> every time, you can configure which languages get this automatically via the <a href="features/code/../../configuration/settings.html#auto_render_languages">config
file</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="latex-and-typst"><a class="header" href="#latex-and-typst">LaTeX and typst</a></h1>
<p><code>latex</code> and <code>typst</code> code blocks can be marked with the <code>+render</code> attribute (see <a href="features/code/highlighting.html">highlighting</a>) to have
them rendered into images when the presentation is loaded. This allows you to define formulas in text rather than having
to define them somewhere else, transform them into an image, and them embed it.</p>
<p>For example, the following presentation:</p>
<pre><code># Formulas
```latex +render
\[ \sum_{n=1}^{\infty} 2^{-n} = 1 \]
```
</code></pre>
<p>Would be rendered like this:</p>
<p><img src="features/code/../../assets/formula.png" alt="" /></p>
<h2 id="dependencies"><a class="header" href="#dependencies">Dependencies</a></h2>
<h3 id="typst"><a class="header" href="#typst">typst</a></h3>
<p>The engine used to render both of these languages is <a href="https://github.com/typst/typst">typst</a>. <em>typst</em> is easy to
install, lightweight, and boilerplate free as compared to <em>LaTeX</em>.</p>
<h3 id="pandoc"><a class="header" href="#pandoc">pandoc</a></h3>
<p>For <em>LaTeX</em> code rendering both <em>typst</em> and <a href="https://github.com/jgm/pandoc">pandoc</a> are required. How this works is the
<em>LaTeX</em> code you write gets transformed into <em>typst</em> code via <em>pandoc</em> and then rendered by using <em>typst</em>. This lets us:</p>
<ul>
<li>Have the same look/feel on generated formulas for both languages.</li>
<li>Avoid having to write lots of boilerplate <em>LaTeX</em> to make rendering for that language work.</li>
<li>Have the same logic to render formulas for both languages, except with a small preparation step for <em>LaTeX</em>.</li>
</ul>
<h2 id="controlling-ppi"><a class="header" href="#controlling-ppi">Controlling PPI</a></h2>
<p><em>presenterm</em> lets you define how many Pixels Per Inch (PPI) you want in the generated images. This is important because
as opposed to images that you manually include in your presentation, where you control the exact dimensions, the images
generated on the fly will have a fixed size. Configuring the PPI used during the conversion can let you adjust this: the
higher the PPI, the larger the generated images will be.</p>
<p>Because as opposed to most configurations this is a very environment-specific config, the PPI parameter is not part of
the theme definition but is instead has to be set in <em>presenterm</em>'s <a href="features/code/../../configuration/introduction.html">config file</a>:</p>
<pre><code class="language-yaml">typst:
ppi: 400
</code></pre>
<p>The default is 300 so adjust it and see what works for you.</p>
<h2 id="image-paths"><a class="header" href="#image-paths">Image paths</a></h2>
<p>If you're including an image inside a <em>typst</em> snippet, you must:</p>
<ul>
<li>Use absolute paths, e.g. <code>#image("/image1.png")</code>.</li>
<li>Place the image in the same or a sub path of the path where the presentation is. That is, if your presentation file is
at <code>/tmp/foo/presentation.md</code>, you can place images in <code>/tmp/foo</code>, and <code>/tmp/foo/bar</code> but not under <code>/tmp/bar</code>. This is
because of the absolute path rule above: the path will be considered to be relative to the presentation file's
directory.</li>
</ul>
<h2 id="controlling-the-image-size"><a class="header" href="#controlling-the-image-size">Controlling the image size</a></h2>
<p>You can also set the generated image's size on a per code snippet basis by using the <code>+width</code> modifier which specifies
the width of the image as a percentage of the terminal size.</p>
<pre><code class="language-markdown">```typst +render +width:50%
$f(x) = x + 1$
```
</code></pre>
<h2 id="customizations"><a class="header" href="#customizations">Customizations</a></h2>
<p>The colors and margin of the generated images can be defined in your theme:</p>
<pre><code class="language-yaml">typst:
colors:
background: ff0000
foreground: 00ff00
# In points
horizontal_margin: 2
vertical_margin: 2
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="themes"><a class="header" href="#themes">Themes</a></h1>
<p><em>presenterm</em> tries to be as configurable as possible, allowing users to create presentations that look exactly how they
want them to look like. The tool ships with a set of <a href="https://github.com/mfontanini/presenterm/tree/master/themes">built-in
themes</a> but users can be created by users in their local
setup and imported in their presentations.</p>
<h2 id="setting-themes"><a class="header" href="#setting-themes">Setting themes</a></h2>
<p>There's various ways of setting the theme you want in your presentation:</p>
<h3 id="cli"><a class="header" href="#cli">CLI</a></h3>
<p>Passing in the <code>--theme</code> parameter when running <em>presenterm</em> to select one of the built-in themes.</p>
<h3 id="within-the-presentation"><a class="header" href="#within-the-presentation">Within the presentation</a></h3>
<p>The presentation's markdown file can contain a front matter that specifies the theme to use. This comes in 3 flavors:</p>
<h4 id="by-name"><a class="header" href="#by-name">By name</a></h4>
<p>Using a built-in theme name makes your presentation use that one regardless of what the default or what the <code>--theme</code>
option specifies:</p>
<pre><code class="language-yaml">---
theme:
name: dark
---
</code></pre>
<h4 id="by-path"><a class="header" href="#by-path">By path</a></h4>
<p>You can define a theme file in yaml format somewhere in your filesystem and reference it within the presentation:</p>
<pre><code class="language-yaml">---
theme:
path: /home/me/Documents/epic-theme.yaml
---
</code></pre>
<h4 id="overrides"><a class="header" href="#overrides">Overrides</a></h4>
<p>You can partially/completely override the theme in use from within the presentation:</p>
<pre><code class="language-yaml">---
theme:
override:
default:
colors:
foreground: "beeeff"
---
</code></pre>
<p>This lets you:</p>
<ol>
<li>Create a unique style for your presentation without having to go through the process of taking an existing theme,
copying somewhere, and changing it when you only expect to use it for that one presentation.</li>
<li>Iterate quickly on styles given overrides are reloaded whenever you save your presentation file.</li>
</ol>
<h1 id="built-in-themes"><a class="header" href="#built-in-themes">Built-in themes</a></h1>
<p>A few built-in themes are bundled with the application binary, meaning you don't need to have any external files
available to use them. These are packed as part of the <a href="https://github.com/mfontanini/presenterm/blob/master/build.rs">build
process</a> as a binary blob and are decoded on demand only
when used.</p>
<p>Currently, the following themes are supported:</p>
<ul>
<li>A set of themes based on the <a href="https://github.com/catppuccin/catppuccin">catppuccin</a> color palette:
<ul>
<li><code>catppuccin-latte</code></li>
<li><code>catppuccin-frappe</code></li>
<li><code>catppuccin-macchiato</code></li>
<li><code>catppuccin-mocha</code></li>
</ul>
</li>
<li><code>dark</code>: A dark theme.</li>
<li><code>gruvbox</code>: A theme inspired by the colors used in <a href="https://github.com/morhetz/gruvbox">gruvbox</a>.</li>
<li><code>light</code>: A light theme.</li>
<li><code>terminal-dark</code>: A theme that uses your terminals color and looks best if your terminal uses a dark color scheme. This
means if your terminal background is e.g. transparent, or uses an image, the presentation will inherit that.</li>
<li><code>terminal-light</code>: The same as <code>terminal-dark</code> but works best if your terminal uses a light color scheme.</li>
<li><code>tokyonight-storm</code>: A theme inspired by the colors used in <a href="https://github.com/folke/tokyonight.nvim">toyonight</a>.</li>
</ul>
<h2 id="trying-out-built-in-themes"><a class="header" href="#trying-out-built-in-themes">Trying out built-in themes</a></h2>
<p>All built-in themes can be tested by using the <code>--list-themes</code> parameter:</p>
<pre><code class="language-bash">presenterm --list-themes
</code></pre>
<p>This will run a presentation where the same content is rendered using a different theme in each slide:</p>
<p><a href="https://asciinema.org/a/zeV1QloyrLkfBp6rNltvX7Lle"><img src="https://asciinema.org/a/zeV1QloyrLkfBp6rNltvX7Lle.svg" alt="asciicast" /></a></p>
<h1 id="loading-custom-themes"><a class="header" href="#loading-custom-themes">Loading custom themes</a></h1>
<p>On startup, <em>presenterm</em> will look into the <code>themes</code> directory under the <a href="features/themes/../../configuration/introduction.html">configuration
directory</a> (e.g. <code>~/.config/presenterm/themes</code> in Linux) and will load any <code>.yaml</code>
file as a theme and make it available as if it was a built-in theme. This means you can use it as an argument to the
<code>--theme</code> parameter, use it in the <code>theme.name</code> property in a presentation's front matter, etc.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="theme-definition"><a class="header" href="#theme-definition">Theme definition</a></h1>
<p>This section goes through the structure of the theme files. Have a look at some of the <a href="https://github.com/mfontanini/presenterm/tree/master/themes">existing
themes</a> to have an idea of how to structure themes.</p>
<h2 id="root-elements"><a class="header" href="#root-elements">Root elements</a></h2>
<p>The root attributes on the theme yaml files specify either:</p>
<ul>
<li>A specific type of element in the input markdown or rendered presentation. That is, the slide title, headings, footer,
etc.</li>
<li>A default to be applied as a fallback if no specific style is specified for a particular element.</li>
</ul>
<h2 id="alignment"><a class="header" href="#alignment">Alignment</a></h2>
<p><em>presenterm</em> uses the notion of alignment, just like you would have in a GUI editor, to align text to the left, center,
or right. You probably want most elements to be aligned left, <em>some</em> to be aligned on the center, and probably none to
the right (but hey, you're free to do so!).</p>
<p>The following elements support alignment:</p>
<ul>
<li>Code blocks.</li>
<li>Slide titles.</li>
<li>The title, subtitle, and author elements in the intro slide.</li>
<li>Tables.</li>
</ul>
<h3 id="leftright-alignment"><a class="header" href="#leftright-alignment">Left/right alignment</a></h3>
<p>Left and right alignments take a margin property which specifies the number of columns to keep between the text and the
left/right terminal screen borders.</p>
<p>The margin can be specified in two ways:</p>
<h4 id="fixed"><a class="header" href="#fixed">Fixed</a></h4>
<p>A specific number of characters regardless of the terminal size.</p>
<pre><code class="language-yaml">alignment: left
margin:
fixed: 5
</code></pre>
<h4 id="percent"><a class="header" href="#percent">Percent</a></h4>
<p>A percentage over the total number of columns in the terminal.</p>
<pre><code class="language-yaml">alignment: left
margin:
percent: 8
</code></pre>
<p>Percent alignment tends to look a bit nicer as it won't change the presentation's look as much when the terminal size
changes.</p>
<h3 id="center-alignment"><a class="header" href="#center-alignment">Center alignment</a></h3>
<p>Center alignment has 2 properties:</p>
<ul>
<li><code>minimum_size</code> which specifies the minimum size you want that element to have. This is normally useful for code blocks
as they have a predefined background which you likely want to extend slightly beyond the end of the code on the right.</li>
<li><code>minimum_margin</code> which specifies the minimum margin you want, using the same structure as <code>margin</code> for left/right
alignment. This doesn't play very well with <code>minimum_size</code> but in isolation it specifies the minimum number of columns
you want to the left and right of your text.</li>
</ul>
<h2 id="colors"><a class="header" href="#colors">Colors</a></h2>
<p>Every element can have its own background/foreground color using hex notation:</p>
<pre><code class="language-yaml">default:
colors:
foreground: "ff0000"
background: "00ff00"
</code></pre>
<h2 id="default-style"><a class="header" href="#default-style">Default style</a></h2>
<p>The default style specifies:</p>
<ul>
<li>The margin to be applied to all slides.</li>
<li>The colors to be used for all text.</li>
</ul>
<pre><code class="language-yaml">default:
margin:
percent: 8
colors:
foreground: "e6e6e6"
background: "040312"
</code></pre>
<h2 id="intro-slide"><a class="header" href="#intro-slide">Intro slide</a></h2>
<p>The introductory slide will be rendered if you specify a title, subtitle, or author in the presentation's front matter.
This lets you have a less markdown-looking introductory slide that stands out so that it doesn't end up looking too
monotonous:</p>
<pre><code class="language-yaml">---
title: Presenting from my terminal
sub_title: Like it's 1990
author: John Doe
---
</code></pre>
<p>The theme can specify:</p>
<ul>
<li>For the title and subtitle, the alignment and colors.</li>
<li>For the author, the alignment, colors, and positioning (<code>page_bottom</code> and <code>below_title</code>). The first one will push it
to the bottom of the screen while the second one will put it right below the title (or subtitle if there is one)</li>
</ul>
<p>For example:</p>
<pre><code class="language-yaml">intro_slide:
title:
alignment: left
margin:
percent: 8
author:
colors:
foreground: black
positioning: below_title
</code></pre>
<h2 id="footer"><a class="header" href="#footer">Footer</a></h2>
<p>The footer currently comes in 3 flavors:</p>
<h3 id="template-footers"><a class="header" href="#template-footers">Template footers</a></h3>
<p>A template footer lets you put text on the left, center and/or right of the screen. The template strings
can reference <code>{current_slide}</code> and <code>{total_slides}</code> which will be replaced with the current and total number of slides.</p>
<p>Besides those special variables, any of the attributes defined in the front matter can also be used:</p>
<ul>
<li><code>title</code>.</li>
<li><code>sub_title</code>.</li>
<li><code>event</code>.</li>
<li><code>location</code>.</li>
<li><code>date</code>.</li>
<li><code>author</code>.</li>
</ul>
<p>Strings used in template footers can contain arbitrary markdown, including <code>span</code> tags that let you use colored text. A
<code>height</code> attribute allows specifying how tall, in terminal rows, the footer is. The text in the footer will always be
placed at the center of the footer area. The default footer height is 2.</p>
<pre><code class="language-yaml">footer:
style: template
left: "My **name** is {author}"
center: "_@myhandle_"
right: "{current_slide} / {total_slides}"
height: 3
</code></pre>
<p>Do note that:</p>
<ul>
<li>Only existing attributes in the front matter can be referenced. That is, if you use <code>{date}</code> but the <code>date</code> isn't set,
an error will be shown.</li>
<li>Similarly, referencing unsupported variables (e.g. <code>{potato}</code>) will cause an error to be displayed. If you'd like the
<code>{}</code> characters to be used in contexts where you don't want to reference a variable, you will need to escape them by
using another brace. e.g. <code>{{potato}} farms</code> will be displayed as <code>{potato} farms</code>.</li>
</ul>
<h4 id="footer-images"><a class="header" href="#footer-images">Footer images</a></h4>
<p>Besides text, images can also be used in the left/center/right positions. This can be done by specifying an <code>image</code> key
under each of those attributes:</p>
<pre><code class="language-yaml">footer:
style: template
left:
image: potato.png
center:
image: banana.png
right:
image: apple.png
# The height of the footer to adjust image sizes
height: 5
</code></pre>
<p>Images will be looked up:</p>
<ul>
<li>First, relative to the presentation file just like any other image.</li>
<li>If the image is not found, it will be looked up relative to the themes directory. e.g. <code>~/.config/presenterm/themes</code>.
This allows you to define a custom theme in your themes directory that points to a local image within that same
location.</li>
</ul>
<p>Images will preserve their aspect ratio and expand vertically to take up as many terminal rows as <code>footer.height</code>
specifies. This parameter should be adjusted accordingly if taller-than-wider images are used in a footer.</p>
<p>See the <a href="https://github.com/mfontanini/presenterm/blob/master/examples/footer.md">footer example</a> as a showcase of how a
footer can contain images and colored text.</p>
<p><img src="features/themes/../../assets/example-footer.png" alt="" /></p>
<h3 id="progress-bar-footers"><a class="header" href="#progress-bar-footers">Progress bar footers</a></h3>
<p>A progress bar that will advance as you move in your presentation. This will by default use a block-looking character to
draw the progress bar but you can customize it:</p>
<pre><code class="language-yaml">footer:
style: progress_bar
# Optional!
character: 🚀
</code></pre>
<h3 id="none"><a class="header" href="#none">None</a></h3>
<p>No footer at all!</p>
<pre><code class="language-yaml">footer:
style: empty
</code></pre>
<h2 id="slide-title"><a class="header" href="#slide-title">Slide title</a></h2>
<p>Slide titles, as specified by using a setext header, has the following properties:</p>
<ul>
<li><code>padding_top</code> which specifies the number of rows you want as padding before the text.</li>
<li><code>padding_bottom</code> which specifies the number of rows you want as padding after the text.</li>
<li><code>separator</code> which specifies whether you want a horizontal ruler after the text (and the <code>padding_bottom</code>):</li>
</ul>
<pre><code class="language-yaml">slide_title:
padding_bottom: 1
padding_top: 1
separator: true
</code></pre>
<h2 id="headings"><a class="header" href="#headings">Headings</a></h2>
<p>Every header type (h1 through h6) can have its own style composed of:</p>
<ul>
<li>The prefix you want to use.</li>
<li>The colors, just like any other element:</li>
</ul>
<pre><code class="language-yaml">headings:
h1:
prefix: "██"
colors:
foreground: "rgb_(48,133,195)"
h2:
prefix: "▓▓▓"
colors:
foreground: "rgb_(168,223,142)"
</code></pre>
<h2 id="code-blocks"><a class="header" href="#code-blocks">Code blocks</a></h2>
<p>The syntax highlighting for code blocks is done via the <a href="https://github.com/trishume/syntect">syntect</a> crate. The list
of all the supported built-in <em>syntect</em> themes is the following:</p>
<ul>
<li>base16-ocean.dark</li>
<li>base16-eighties.dark</li>
<li>base16-mocha.dark</li>
<li>base16-ocean.light</li>
<li>InspiredGitHub</li>
<li>Solarized (dark)</li>
<li>Solarized (light)</li>
</ul>
<p>Besides those and thanks to the work done on the awesome <a href="https://github.com/sharkdp/bat">bat tool</a>, <em>presenterm</em> has
access to not only the built-in <em>syntect</em>'s built-in themes but also the ones in <em>bat</em>. Run <code>bat --list-themes</code> to see a
list of all of them.</p>
<p>Code blocks can also have an optional vertical and horizontal padding so your code is not too close to its bounding
rectangle:</p>
<pre><code class="language-yaml">code:
theme_name: base16-eighties.dark
padding:
horizontal: 2
vertical: 1
</code></pre>
<h4 id="custom-highlighting-themes"><a class="header" href="#custom-highlighting-themes">Custom highlighting themes</a></h4>
<p>Besides the built-in highlighting themes, you can drop any <code>.tmTheme</code> theme in the <code>themes/highlighting</code> directory under
your <a href="features/themes/../../configuration/introduction.html">configuration directory</a> (e.g. <code>~/.config/presenterm/themes/highlighting</code> in
Linux) and they will be loaded automatically when <em>presenterm</em> starts.</p>
<h2 id="block-quotes"><a class="header" href="#block-quotes">Block quotes</a></h2>
<p>For block quotes you can specify a string to use as a prefix in every line of quoted text:</p>
<pre><code class="language-yaml">block_quote:
prefix: "▍ "
</code></pre>
<h2 id="mermaid-1"><a class="header" href="#mermaid-1">Mermaid</a></h2>
<p>The <a href="https://mermaid.js.org/">mermaid</a> graphs can be customized using the following parameters:</p>
<ul>
<li><code>mermaid.background</code> the background color passed to the CLI (e.g., <code>transparent</code>, <code>red</code>, <code>#F0F0F0</code>).</li>
<li><code>mermaid.theme</code> the <a href="https://mermaid.js.org/config/theming.html#available-themes">mermaid theme</a> to use.</li>
</ul>
<pre><code class="language-yaml">mermaid:
background: transparent
theme: dark
</code></pre>
<h2 id="alerts"><a class="header" href="#alerts">Alerts</a></h2>
<p>GitHub style markdown alerts can be styled by setting the <code>alert</code> key:</p>
<pre><code class="language-yaml">alert:
# the base colors used in all text in an alert
base_colors:
foreground: red
background: black
# the prefix used in every line in the alert
prefix: "▍ "
# the style for each alert type
styles:
note:
color: blue
title: Note
icon: I
tip:
color: green
title: Tip
icon: T
important:
color: cyan
title: Important
icon: I
warning:
color: orange
title: Warning
icon: W
caution:
color: red
title: Caution
icon: C
</code></pre>
<h2 id="extending-themes"><a class="header" href="#extending-themes">Extending themes</a></h2>
<p>Custom themes can extend other custom or built in themes. This means it will inherit all the properties of the theme
being extended by default.</p>
<p>For example:</p>
<pre><code class="language-yaml">extends: dark
default:
colors:
background: "000000"
</code></pre>
<p>This theme extends the built in <em>dark</em> theme and overrides the background color. This is useful if you find yourself
<em>almost</em> liking a built in theme but there's only some properties you don't like.</p>
<h2 id="color-palette"><a class="header" href="#color-palette">Color palette</a></h2>
<p>Every theme can define a color palette, which includes a list of pre-defined colors and a list of background/foreground
pairs called "classes". Colors and classes can be used when styling text via <code>&lt;span&gt;</code> HTML tags, whereas colors can also
be used inside themes to avoid duplicating the same colors all over the theme definition.</p>
<p>A palette can de defined as follows:</p>
<pre><code class="language-yaml">palette:
colors:
red: "f78ca2"
purple: "986ee2"
classes:
foo:
foreground: "ff0000"
background: "00ff00"
</code></pre>
<p>Any palette color can be referenced using either <code>palette:&lt;name&gt;</code> or <code>p:&lt;name&gt;</code>. This means now any part of the theme
can use <code>p:red</code> and <code>p:purple</code> where a color is required.</p>
<p>Similarly, these colors can be used in <code>span</code> tags like:</p>
<pre><code class="language-html">&lt;span style="color: palette:red"&gt;this is red&lt;/span&gt;
&lt;span class="foo"&gt;this is foo-colored&lt;/span&gt;
</code></pre>
<p>These colors can used anywhere in your presentation as well as in other places such as in
<a href="features/themes/definition.html#template-footers">template footers</a> and <a href="features/themes/../introduction.html#introduction-slide">introduction slides</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="exporting-presentations-in-pdf-format"><a class="header" href="#exporting-presentations-in-pdf-format">Exporting presentations in PDF format</a></h1>
<p>Presentations can be converted into PDF by using <a href="https://pypi.org/project/weasyprint/">weasyprint</a>. Follow their
<a href="https://doc.courtbouillon.org/weasyprint/stable/first_steps.html">installation instructions</a> since it may require you
to install extra dependencies for the tool to work.</p>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>If you were using <em>presenterm-export</em> before it was deprecated, that tool already required <em>weasyprint</em> so it is
already installed in whatever virtual env you were using and there's nothing to be done.</p>
</div>
<p>After you've installed <em>weasyprint</em>, run <em>presenterm</em> with the <code>--export-pdf</code> parameter to generate the output PDF:</p>
<pre><code class="language-bash">presenterm --export-pdf examples/demo.md
</code></pre>
<p>The output PDF will be placed in <code>examples/demo.pdf</code>. Alternatively you can use the <code>--output</code> flag to specify where you
want the output file to be written to.</p>
<div class="mdbook-alerts mdbook-alerts-note">
<p class="mdbook-alerts-title">
<span class="mdbook-alerts-icon"></span>
note
</p>
<p>If you're using a separate virtual env to install <em>weasyprint</em> just make sure you activate it before running
<em>presenterm</em> with the <code>--export-pdf</code> parameter.</p>
</div>
<h2 id="pdf-page-size"><a class="header" href="#pdf-page-size">PDF page size</a></h2>
<p>By default, the size of each page in the generated PDF will depend on the size of your terminal.</p>
<p>If you would like to instead configure the dimensions by hand, set the <code>export.dimensions</code> key in the configuration file
as described in the <a href="features/../configuration/settings.html#pdf-export-size">settings page</a>.</p>
<h2 id="pause-behavior"><a class="header" href="#pause-behavior">Pause behavior</a></h2>
<p>See the <a href="features/../configuration/settings.html#pause-behavior">settings page</a> to learn how to configure the behavior of pauses in
generated PDFs.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="slide-transitions"><a class="header" href="#slide-transitions">Slide transitions</a></h1>
<p>Slide transitions allow animating your presentation every time you move from a slide to the next/previous one. See the
<a href="features/../configuration/settings.html">configuration page</a> to learn how to configure transitions.</p>
<p>The following animations are supported:</p>
<h2 id="fade"><a class="header" href="#fade"><code>fade</code></a></h2>
<p>Fade the current slide into the next one.</p>
<p><a href="https://asciinema.org/a/RvxLw0FHOopjdF4ixWbCkWuSw"><img src="https://asciinema.org/a/RvxLw0FHOopjdF4ixWbCkWuSw.svg" alt="asciicast" /></a></p>
<h2 id="slide_horizontal"><a class="header" href="#slide_horizontal"><code>slide_horizontal</code></a></h2>
<p>Slide horizontally to the next/previous slide.</p>
<p><a href="https://asciinema.org/a/T43ttxPWZ8TsM2auTqNZSWrmZ"><img src="https://asciinema.org/a/T43ttxPWZ8TsM2auTqNZSWrmZ.svg" alt="asciicast" /></a></p>
<h2 id="collapse_horizontal"><a class="header" href="#collapse_horizontal"><code>collapse_horizontal</code></a></h2>
<p>Collapse the current slide into the center of the screen horizontally.</p>
<p><a href="https://asciinema.org/a/VB8i3kGMvbkbiYYPpaZJUl2dW"><img src="https://asciinema.org/a/VB8i3kGMvbkbiYYPpaZJUl2dW.svg" alt="asciicast" /></a></p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h2 id="speaker-notes"><a class="header" href="#speaker-notes">Speaker notes</a></h2>
<p>Starting on version 0.10.0, <em>presenterm</em> allows presentations to define speaker notes. The way this works is:</p>
<ul>
<li>You start an instance of <em>presenterm</em> using the <code>--publish-speaker-notes</code> parameter. This will be the main instance in
which you will present like you usually do.</li>
<li>Another instance should be started using the <code>--listen-speaker-notes</code> parameter. This instance will only display
speaker notes in the presentation and will automatically change slides whenever the main instance does so.</li>
</ul>
<p>For example:</p>
<pre><code class="language-bash"># Start the main instance
presenterm demo.md --publish-speaker-notes
# In another shell: start the speaker notes instance
presenterm demo.md --listen-speaker-notes
</code></pre>
<p><a href="https://asciinema.org/a/ETusvlmHuHrcLKzwa0CMQRX2J"><img src="https://asciinema.org/a/ETusvlmHuHrcLKzwa0CMQRX2J.svg" alt="asciicast" /></a></p>
<p>See the <a href="https://github.com/mfontanini/presenterm/blob/master/examples/speaker-notes.md">speaker notes example</a> for more
information.</p>
<h3 id="defining-speaker-notes"><a class="header" href="#defining-speaker-notes">Defining speaker notes</a></h3>
<p>In order to define speaker notes you can use the <code>speaker_notes</code> comment command:</p>
<pre><code class="language-markdown">Normal text
&lt;!-- speaker_note: this is a speaker note --&gt;
More text
</code></pre>
<p>When running this two instance setup, the main one will show "normal text" and "more text", whereas the second one will
only show "this is a speaker note" on that slide.</p>
<h3 id="multiline-speaker-notes"><a class="header" href="#multiline-speaker-notes">Multiline speaker notes</a></h3>
<p>You can use multiline speaker notes by using the appropriate YAML syntax:</p>
<pre><code class="language-yaml">&lt;!--
speaker_note: |
something
something else
--&gt;
</code></pre>
<h3 id="multiple-instances"><a class="header" href="#multiple-instances">Multiple instances</a></h3>
<p>On Linux and Windows, you can run multiple instances in publish mode and multiple instances in listen mode at the same
time. Each instance will only listen to events for the presentation it was started on.</p>
<p>On Mac this is not supported and only a single listener can be used at a time.</p>
<h3 id="enabling-publishing-by-default"><a class="header" href="#enabling-publishing-by-default">Enabling publishing by default</a></h3>
<p>You can use the <code>speaker_notes.always_publish</code> key in your config file to always publish speaker notes. This means you
will only ever need to use <code>--listen-speaker-notes</code> and you will never need to use <code>--publish-speaker-notes</code>:</p>
<pre><code class="language-yaml">speaker_notes:
always_publish: true
</code></pre>
<h3 id="internals"><a class="header" href="#internals">Internals</a></h3>
<p>This uses UDP sockets on localhost to communicate between instances. The main instance sends events every time a slide
is shown and the listener instances listen to them and displays the speaker notes for that specific slide.</p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="configuration"><a class="header" href="#configuration">Configuration</a></h1>
<p><em>presenterm</em> allows you to customize its behavior via a configuration file. This file is stored, along with all of your
custom themes, in the following directories:</p>
<ul>
<li><code>$XDG_CONFIG_HOME/presenterm/</code> if that environment variable is defined, otherwise:</li>
<li><code>~/.config/presenterm/</code> in Linux.</li>
<li><code>~/Library/Application Support/presenterm/</code> in macOS.</li>
<li><code>~/AppData/Roaming/presenterm/config/</code> in Windows.</li>
</ul>
<p>The configuration file will be looked up automatically in the directories above under the name <code>config.yaml</code>. e.g. on
Linux you should create it under <code>~/.config/presenterm/config.yaml</code>. You can also specify a custom path to this file
when running <em>presenterm</em> via the <code>--config-file</code> parameter.</p>
<p>A <a href="https://github.com/mfontanini/presenterm/blob/master/config.sample.yaml">sample configuration file</a> is provided in
the repository that you can use as a base.</p>
<h1 id="configuration-schema"><a class="header" href="#configuration-schema">Configuration schema</a></h1>
<p>A JSON schema that defines the configuration file's schema is available to be used with YAML language servers such as
<a href="https://github.com/redhat-developer/yaml-language-server">yaml-language-server</a>.</p>
<p>Include the following line at the beginning of your configuration file to have your editor pull in autocompletion
suggestions and docs automatically:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://raw.githubusercontent.com/mfontanini/presenterm/master/config-file-schema.json
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="options"><a class="header" href="#options">Options</a></h1>
<p>Options are special configuration parameters that can be set either in the configuration file under the <code>options</code> key,
or in a presentation's front matter under the same key. This last one allows you to customize a single presentation so
that it acts in a particular way. This can also be useful if you'd like to share the source files for your presentation
with other people.</p>
<p>The supported configuration options are currently the following:</p>
<h2 id="implicit_slide_ends"><a class="header" href="#implicit_slide_ends">implicit_slide_ends</a></h2>
<p>This option removes the need to use <code>&lt;!-- end_slide --&gt;</code> in between slides and instead assumes that if you use a slide
title, then you're implying that the previous slide ended. For example, the following presentation:</p>
<pre><code class="language-markdown">---
options:
implicit_slide_ends: true
---
Tasty vegetables
================
* Potato
Awful vegetables
================
* Lettuce
</code></pre>
<p>Is equivalent to this "vanilla" one that doesn't use implicit slide ends.</p>
<pre><code class="language-markdown">Tasty vegetables
================
* Potato
&lt;!-- end_slide --&gt;
Awful vegetables
================
* Lettuce
</code></pre>
<h2 id="end_slide_shorthand"><a class="header" href="#end_slide_shorthand">end_slide_shorthand</a></h2>
<p>This option allows using thematic breaks (<code>---</code>) as a delimiter between slides. When enabling this option, you can still
use <code>&lt;!-- end_slide --&gt;</code> but any thematic break will also be considered a slide terminator.</p>
<pre><code>---
options:
end_slide_shorthand: true
---
this is a slide
---------------------
this is another slide
</code></pre>
<h2 id="command_prefix"><a class="header" href="#command_prefix">command_prefix</a></h2>
<p>Because <em>presenterm</em> uses HTML comments to represent commands, it is necessary to make some assumptions on <em>what</em> is a
command and what isn't. The current heuristic is:</p>
<ul>
<li>If an HTML comment is laid out on a single line, it is assumed to be a command. This means if you want to use a real
HTML comment like <code>&lt;!-- remember to say "potato" here --&gt;</code>, this will raise an error.</li>
<li>If an HTML comment is multi-line, then it is assumed to be a comment and it can have anything inside it. This means
you can't have a multi-line comment that contains a command like <code>pause</code> inside.</li>
</ul>
<p>Depending on how you use HTML comments personally, this may be limiting to you: you cannot use any single line comments
that are not commands. To get around this, the <code>command_prefix</code> option lets you configure a prefix that must be set in
all commands for them to be configured as such. Any single line comment that doesn't start with this prefix will not be
considered a command.</p>
<p>For example:</p>
<pre><code>---
options:
command_prefix: "cmd:"
---
&lt;!-- remember to say "potato here" --&gt;
Tasty vegetables
================
* Potato
&lt;!-- cmd:pause --&gt;
**That's it!**
</code></pre>
<p>In the example above, the first comment is ignored because it doesn't start with "cmd:" and the second one is processed
because it does.</p>
<h2 id="incremental_lists"><a class="header" href="#incremental_lists">incremental_lists</a></h2>
<p>If you'd like all bullet points in all lists to show up with pauses in between you can enable the <code>incremental_lists</code>
option:</p>
<pre><code>---
options:
incremental_lists: true
---
* pauses
* in
* between
</code></pre>
<p>Keep in mind if you only want specific bullet points to show up with pauses in between, you can use the
<a href="configuration/../features/commands.html#incremental-lists"><code>incremental_lists</code> comment command</a>.</p>
<h2 id="strict_front_matter_parsing"><a class="header" href="#strict_front_matter_parsing">strict_front_matter_parsing</a></h2>
<p>This option tells <em>presenterm</em> you don't care about extra parameters in presentation's front matter. This can be useful
if you're trying to load a presentation made for another tool. The following presentation would only be successfully
loaded if you set <code>strict_front_matter_parsing</code> to <code>false</code> in your configuration file:</p>
<pre><code class="language-markdown">---
potato: 42
---
# Hi
</code></pre>
<h2 id="image_attributes_prefix"><a class="header" href="#image_attributes_prefix">image_attributes_prefix</a></h2>
<p>The <a href="configuration/../features/images.html#image-size">image size</a> prefix (by default <code>image:</code>) can be configured to be anything you
would want in case you don't like the default one. For example, if you'd like to set the image size by simply doing
<code>![width:50%](path.png)</code> you would need to set:</p>
<pre><code class="language-yaml">---
options:
image_attributes_prefix: ""
---
![width:50%](path.png)
</code></pre>
<h2 id="auto_render_languages"><a class="header" href="#auto_render_languages">auto_render_languages</a></h2>
<p>This option allows indicating a list of languages for which the <code>+render</code> attribute can be omitted in their code
snippets and will be implicitly considered to be set. This can be used for languages like <code>mermaid</code> so that graphs are
always automatically rendered without the need to specify <code>+render</code> everywhere.</p>
<pre><code class="language-yaml">---
options:
auto_render_languages:
- mermaid
---
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="settings"><a class="header" href="#settings">Settings</a></h1>
<p>As opposed to options, the rest of these settings <strong>can only be configured via the configuration file</strong>.</p>
<h2 id="default-theme"><a class="header" href="#default-theme">Default theme</a></h2>
<p>The default theme can be configured only via the config file. When this is set, every presentation that doesn't set a
theme explicitly will use this one:</p>
<pre><code class="language-yaml">defaults:
theme: light
</code></pre>
<h2 id="terminal-font-size"><a class="header" href="#terminal-font-size">Terminal font size</a></h2>
<p>This is a parameter that lets you explicitly set the terminal font size in use. This should not be used unless you are
in Windows, given there's no (easy) way to get the terminal window size so we use this to figure out how large the
window is and resize images properly. Some terminals on other platforms may also have this issue, but that should not be
as common.</p>
<p>If you are on Windows or you notice images show up larger/smaller than they should, you can adjust this setting in your
config file:</p>
<pre><code class="language-yaml">defaults:
terminal_font_size: 16
</code></pre>
<h2 id="preferred-image-protocol"><a class="header" href="#preferred-image-protocol">Preferred image protocol</a></h2>
<p>By default <em>presenterm</em> will try to detect which image protocol to use based on the terminal you are using. In case
detection for some reason fails in your setup or you'd like to force a different protocol to be used, you can explicitly
set this via the <code>--image-protocol</code> parameter or the configuration key <code>defaults.image_protocol</code>:</p>
<pre><code class="language-yaml">defaults:
image_protocol: kitty-local
</code></pre>
<p>Possible values are:</p>
<ul>
<li><code>auto</code>: try to detect it automatically (default).</li>
<li><code>kitty-local</code>: use the kitty protocol in "local" mode, meaning both <em>presenterm</em> and the terminal run in the same host
and can share the filesystem to communicate.</li>
<li><code>kitty-remote</code>: use the kitty protocol in "remote" mode, meaning <em>presenterm</em> and the terminal run in different hosts
and therefore can only communicate via terminal escape codes.</li>
<li><code>iterm2</code>: use the iterm2 protocol.</li>
<li><code>sixel</code>: use the sixel protocol. Note that this requires compiling <em>presenterm</em> using the <code>--features sixel</code> flag.</li>
</ul>
<h2 id="maximum-presentation-width"><a class="header" href="#maximum-presentation-width">Maximum presentation width</a></h2>
<p>The <code>max_columns</code> property can be set to specify the maximum number of columns that the presentation will stretch to. If
your terminal is larger than that, the presentation will stick to that size and will be centered, preventing it from
looking too stretched.</p>
<pre><code class="language-yaml">defaults:
max_columns: 100
</code></pre>
<p>If you would like your presentation to be left or right aligned instead of centered when the terminal is too wide, you
can use the <code>max_columns_alignment</code> key:</p>
<pre><code class="language-yaml">defaults:
max_columns: 100
# Valid values: left, center, right
max_columns_alignment: left
</code></pre>
<h2 id="maximum-presentation-height"><a class="header" href="#maximum-presentation-height">Maximum presentation height</a></h2>
<p>The <code>max_rows</code> and <code>max_rows_alignment</code> properties are analogous to <code>max_columns*</code> to allow capping the maximum number
of rows:</p>
<pre><code class="language-yaml">defaults:
max_rows: 100
# Valid values: top, center, bottom
max_rows_alignment: left
</code></pre>
<h2 id="incremental-lists-behavior"><a class="header" href="#incremental-lists-behavior">Incremental lists behavior</a></h2>
<p>By default, <a href="configuration/../features/commands.html">incremental lists</a> will pause before and after a list. If you would like to change
this behavior, use the <code>defaults.incremental_lists</code> key:</p>
<pre><code class="language-yaml">defaults:
incremental_lists:
# The defaults, change to false if desired.
pause_before: true
pause_after: true
</code></pre>
<h1 id="slide-transitions-1"><a class="header" href="#slide-transitions-1">Slide transitions</a></h1>
<p>Slide transitions allow animating your presentation every time you move from a slide to the next/previous one. The
configuration for slide transitions is the following:</p>
<pre><code class="language-yaml">transition:
# how long the transition should last.
duration_millis: 750
# how many frames should be rendered during the transition
frames: 45
# the animation to use
animation:
style: &lt;style_name&gt;
</code></pre>
<p>See the <a href="configuration/../features/slide-transitions.html">slide transitions page</a> for more information on which animation styles are
supported.</p>
<h1 id="key-bindings-1"><a class="header" href="#key-bindings-1">Key bindings</a></h1>
<p>Key bindings that <em>presenterm</em> uses can be manually configured in the config file via the <code>bindings</code> key. The following
is the default configuration:</p>
<pre><code class="language-yaml">bindings:
# the keys that cause the presentation to move forwards.
next: ["l", "j", "&lt;right&gt;", "&lt;page_down&gt;", "&lt;down&gt;", " "]
# the keys that cause the presentation to move backwards.
previous: ["h", "k", "&lt;left&gt;", "&lt;page_up&gt;", "&lt;up&gt;"]
# the keys that cause the presentation to move "fast" to the next slide. this will ignore:
#
# * Pauses.
# * Dynamic code highlights.
# * Slide transitions, if enabled.
next_fast: ["n"]
# same as `next_fast` but jumps fast to the previous slide.
previous_fast: ["p"]
# the key binding to jump to the first slide.
first_slide: ["gg"]
# the key binding to jump to the last slide.
last_slide: ["G"]
# the key binding to jump to a specific slide.
go_to_slide: ["&lt;number&gt;G"]
# the key binding to execute a piece of shell code.
execute_code: ["&lt;c-e&gt;"]
# the key binding to reload the presentation.
reload: ["&lt;c-r&gt;"]
# the key binding to toggle the slide index modal.
toggle_slide_index: ["&lt;c-p&gt;"]
# the key binding to toggle the key bindings modal.
toggle_bindings: ["?"]
# the key binding to close the currently open modal.
close_modal: ["&lt;esc&gt;"]
# the key binding to close the application.
exit: ["&lt;c-c&gt;", "q"]
# the key binding to suspend the application.
suspend: ["&lt;c-z&gt;"]
</code></pre>
<p>You can choose to override any of them. Keep in mind these are overrides so if for example you change <code>next</code>, the
default won't apply anymore and only what you've defined will be used.</p>
<h1 id="snippet-configurations"><a class="header" href="#snippet-configurations">Snippet configurations</a></h1>
<p>The configurations that affect code snippets in presentations.</p>
<h2 id="snippet-execution-1"><a class="header" href="#snippet-execution-1">Snippet execution</a></h2>
<p><a href="configuration/../features/code/execution.html#executing-code-blocks">Snippet execution</a> is disabled by default for security reasons.
Besides passing in the <code>-x</code> command line parameter every time you run <em>presenterm</em>, you can also configure this globally
for all presentations by setting:</p>
<pre><code class="language-yaml">snippet:
exec:
enable: true
</code></pre>
<p><strong>Use this at your own risk</strong>, especially if you're running someone else's presentations!</p>
<h2 id="snippet-execution--replace"><a class="header" href="#snippet-execution--replace">Snippet execution + replace</a></h2>
<p><a href="configuration/../features/code/execution.html#executing-and-replacing">Snippet execution + replace</a> is disabled by default for security
reasons. Similar to <code>+exec</code>, this can be enabled by passing in the <code>-X</code> command line parameter or configuring it
globally by setting:</p>
<pre><code class="language-yaml">snippet:
exec_replace:
enable: true
</code></pre>
<p><strong>Use this at your own risk</strong>. This will cause <em>presenterm</em> to execute code without user intervention so don't blindly
enable this and open a presentation unless you trust its origin!</p>
<h2 id="custom-snippet-executors"><a class="header" href="#custom-snippet-executors">Custom snippet executors</a></h2>
<p>If <em>presenterm</em> doesn't support executing code snippets for your language of choice, please <a href="https://github.com/mfontanini/presenterm/issues/new">create an
issue</a>! Alternatively, you can configure this locally yourself by
setting:</p>
<pre><code class="language-yaml">snippet:
exec:
custom:
# The keys should be the language identifier you'd use in a code block.
c++:
# The name of the file that will be created with your snippet's contents.
filename: "snippet.cpp"
# A list of environment variables that should be set before building/running your code.
environment:
MY_FAVORITE_ENVIRONMENT_VAR: foo
# A prefix that indicates a line that starts with it should not be visible but should be executed if the
# snippet is marked with `+exec`.
hidden_line_prefix: "/// "
# A list of commands that will be ran one by one in the same directory as the snippet is in.
commands:
# Compile if first
- ["g++", "-std=c++20", "snippet.cpp", "-o", "snippet"]
# Now run it
- ["./snippet"]
</code></pre>
<p>The output of all commands will be included in the code snippet execution output so if a command (like the <code>g++</code>
invocation) was to emit any output, make sure to use whatever flags are needed to mute its output.</p>
<p>Also note that you can override built-in executors in case you want to run them differently (e.g. use <code>c++23</code> in the
example above).</p>
<p>See more examples in the <a href="https://github.com/mfontanini/presenterm/blob/master/executors.yaml">executors.yaml</a> file
which defines all of the built-in executors.</p>
<h2 id="snippet-rendering-threads"><a class="header" href="#snippet-rendering-threads">Snippet rendering threads</a></h2>
<p>Because some <code>+render</code> code blocks can take some time to be rendered into an image, especially if you're using
<a href="https://mermaid.js.org/">mermaid</a> charts, this is run asychronously. The number of threads used to render these, which
defaults to 2, can be configured by setting:</p>
<pre><code class="language-yaml">snippet:
render:
threads: 2
</code></pre>
<h2 id="mermaid-scaling"><a class="header" href="#mermaid-scaling">Mermaid scaling</a></h2>
<p><a href="https://mermaid.js.org/">mermaid</a> graphs will use a default scaling of <code>2</code> when invoking the mermaid CLI. If you'd like
to change this use:</p>
<pre><code class="language-yaml">mermaid:
scale: 2
</code></pre>
<h2 id="enabling-speaker-note-publishing"><a class="header" href="#enabling-speaker-note-publishing">Enabling speaker note publishing</a></h2>
<p>If you don't want to run <em>presenterm</em> with <code>--publish-speaker-notes</code> every time you want to publish speaker notes, you
can set the <code>speaker_notes.always_publish</code> attribute to <code>true</code>.</p>
<pre><code class="language-yaml">speaker_notes:
always_publish: true
</code></pre>
<h1 id="presentation-exports"><a class="header" href="#presentation-exports">Presentation exports</a></h1>
<p>The configurations that affect PDF exports.</p>
<h2 id="pdf-export-size"><a class="header" href="#pdf-export-size">PDF export size</a></h2>
<p>The size of exported PDFs can be configured via the <code>export.dimensions</code> key:</p>
<pre><code class="language-yaml">export:
dimensions:
columns: 80
rows: 30
</code></pre>
<p>See <a href="configuration/../features/pdf-export.html">the PDF export page</a> for more information.</p>
<h2 id="pause-behavior-1"><a class="header" href="#pause-behavior-1">Pause behavior</a></h2>
<p>By default pauses will be ignored in generated PDF files. If instead you'd like every pause to generate a new page in
the export, set the <code>export.pauses</code> attribute:</p>
<pre><code class="language-yaml">export:
pauses: new_slide
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h1 id="parsing-and-rendering"><a class="header" href="#parsing-and-rendering">Parsing and rendering</a></h1>
<p>This document goes through the internals of how we take a markdown file and finish rendering it into the terminal
screen.</p>
<h2 id="parsing"><a class="header" href="#parsing">Parsing</a></h2>
<p>Markdown file parsing is done via the <a href="https://github.com/kivikakk/comrak">comrak</a> crate. This crate parses the markdown
file and gives you back an AST that contains the contents and structure of the input file.</p>
<p>ASTs are a logical way of representing the markdown file but this structure makes it a bit hard to process. Given our
ultimate goal is to render this input, we want it to be represented in a way that facilitates that. Because of this we
first do a pass on this AST and construct a list of <code>MarkdownElement</code>s. This enum represents each of the markdown
elements in a flattened, non-recursive, way:</p>
<ul>
<li>Inline text is flattened so that instead of having a recursive structure you have chunks of text, each with their own
style. So for example the text "<strong>hello <em>my name is <del>bob</del></em></strong>" which would look like a 3 level tree (I think?) in the
AST, gets transformed to something like <code>[Bold(hello), ItalicsBold(my name is), ItalicsBoldStrikethrough(bob)]</code> (names
are completely not what they are in the code, this is just to illustrate flattening). This makes it much easier to
render text because we don't need to walk the tree and keep the state between levels.</li>
<li>Lists are flattened into a single <code>MarkdownElement::List</code> element that contains a list of items that contain their
text, prefix ("*" for bullet lists), and nesting depth. This also simplifies processing as list elements can also
contain formatted text so we would otherwise have the same problem as above.</li>
</ul>
<p>This first step then produces a list of elements that can easily be processed.</p>
<h2 id="building-the-presentation"><a class="header" href="#building-the-presentation">Building the presentation</a></h2>
<p>The format above is <em>nicer</em> than an AST but it's still not great to be used as the input to the code that renders the
presentation for various reasons:</p>
<ul>
<li>The presentation needs to be styled, which means we need to apply a theme on top of it to transform it. Putting this
responsibility in the render code creates too much coupling: now the render needs to understand markdown <em>and</em> how
themes work.</li>
<li>The render code tends to be a bit annoying: we need to jump around in the screen, print text, change colors, etc. If
we add the responsibility of transforming the markdown into visible text to the render code itself, we end up having a
mess of UI code mixed with the markdown element processing.</li>
<li>Some elements can't be printed as-is. For example, a list item has text and a prefix, so we don't want the render code
to be in charge of understanding and executing those transformations.</li>
</ul>
<p>Because of this, we introduce a step in between parsing and rendering where we build a presentation. A presentation is
made up of a list of slides and each slide is made up of render operations. Render operations are the primitives that
the render code understands to print text on the screen. These can be the following, among others:</p>
<ul>
<li>Render text.</li>
<li>Clear the screen.</li>
<li>Set the default colors to be used.</li>
<li>Render a line break.</li>
<li>Jump to the middle of the screen.</li>
</ul>
<p>This allows us to have a simple model where the logic that takes markdown elements and a theme and chooses <em>how</em> it will
be rendered is in one place, and the logic that takes those instructions and executes them is elsewhere. So for example,
this step will take a bullet point and concatenate is suffix ("*" for bullet points for example), turn that into a
single string and generate a "render text" operation.</p>
<p>This has the nice added bonus that the rendering code doesn't have to be fiddling around with string concatenation or
other operations that could take up CPU cycles: it just takes these render operations and executes them. Not that
performance matters here but it's nice to get better performance for free.</p>
<h2 id="render-a-slide"><a class="header" href="#render-a-slide">Render a slide</a></h2>
<p>The rendering code is straightforward and simply takes the current slide, iterates all of its rendering operations, and
executes those one by one. This is done via the <a href="https://github.com/crossterm-rs/crossterm">crossterm</a> crate.</p>
<p>The only really complicated part is fitting text into the screen. Because we apply our own margins, we perform word
splitting and wrapping around manually, so there's some logic that takes the text to be printed and the width of the
terminal and splits it accordingly.</p>
<p>Note that this piece of code is the only one aware of the current screen size. This lets us forget in previous steps
about how large the screen is and simply delegate that responsibility to this piece.</p>
<h2 id="entire-flow"><a class="header" href="#entire-flow">Entire flow</a></h2>
<p><img src="internals/../assets/parse-flow.png" alt="" /></p>
<div style="break-before: page; page-break-before: always;"></div><style>
.mdbook-alerts {
padding: 8px 16px;
margin-bottom: 16px;
border-left: 0.25em solid var(--mdbook-alerts-color);
}
.mdbook-alerts > *:first-child {
margin-top: 0;
}
.mdbook-alerts > *:last-child {
margin-bottom: 0;
}
.mdbook-alerts-title {
display: flex;
font-weight: 600;
align-items: center;
line-height: 1;
color: var(--mdbook-alerts-color);
text-transform: capitalize;
}
.mdbook-alerts-icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.2em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--mdbook-alerts-icon);
mask-image: var(--mdbook-alerts-icon);
}
.mdbook-alerts-note {
--mdbook-alerts-color: rgb(9, 105, 218);
/* https://icon-sets.iconify.design/material-symbols/info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16v-4q0-.425-.288-.712T12 11q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m0-8q.425 0 .713-.288T13 8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8q0 .425.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20m0-8"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-tip {
--mdbook-alerts-color: rgb(26, 127, 55);
/* https://icon-sets.iconify.design/material-symbols/lightbulb-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 22q-.825 0-1.412-.587T10 20h4q0 .825-.587 1.413T12 22m-3-3q-.425 0-.712-.288T8 18q0-.425.288-.712T9 17h6q.425 0 .713.288T16 18q0 .425-.288.713T15 19zm-.75-3q-1.725-1.025-2.738-2.75T4.5 9.5q0-3.125 2.188-5.312T12 2q3.125 0 5.313 2.188T19.5 9.5q0 2.025-1.012 3.75T15.75 16zm.6-2h6.3q1.125-.8 1.738-1.975T17.5 9.5q0-2.3-1.6-3.9T12 4Q9.7 4 8.1 5.6T6.5 9.5q0 1.35.613 2.525T8.85 14M12 14"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-important {
--mdbook-alerts-color: rgb(130, 80, 223);
/* https://icon-sets.iconify.design/material-symbols/chat-info-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 7q.425 0 .713-.288T13 6q0-.425-.288-.712T12 5q-.425 0-.712.288T11 6q0 .425.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9q-.425 0-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm-.85-2H20V4H4v13.125zM4 16V4z"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-warning {
--mdbook-alerts-color: rgb(154, 103, 0);
/* https://icon-sets.iconify.design/material-symbols/warning-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M2.725 21q-.275 0-.5-.137t-.35-.363q-.125-.225-.137-.488t.137-.512l9.25-16q.15-.25.388-.375T12 3q.25 0 .488.125t.387.375l9.25 16q.15.25.138.513t-.138.487q-.125.225-.35.363t-.5.137zm1.725-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17q0-.425-.288-.712T12 16q-.425 0-.712.288T11 17q0 .425.288.713T12 18m0-3q.425 0 .713-.288T13 14v-3q0-.425-.288-.712T12 10q-.425 0-.712.288T11 11v3q0 .425.288.713T12 15m0-2.5"%2F%3E%3C%2Fsvg%3E');
}
.mdbook-alerts-caution {
--mdbook-alerts-color: rgb(207, 34, 46);
/* https://icon-sets.iconify.design/material-symbols/brightness-alert-outline-rounded/ */
--mdbook-alerts-icon: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 17q.425 0 .713-.288T13 16q0-.425-.288-.712T12 15q-.425 0-.712.288T11 16q0 .425.288.713T12 17m0-4q.425 0 .713-.288T13 12V8q0-.425-.288-.712T12 7q-.425 0-.712.288T11 8v4q0 .425.288.713T12 13m-3.35 7H6q-.825 0-1.412-.587T4 18v-2.65L2.075 13.4q-.275-.3-.425-.662T1.5 12q0-.375.15-.737t.425-.663L4 8.65V6q0-.825.588-1.412T6 4h2.65l1.95-1.925q.3-.275.663-.425T12 1.5q.375 0 .738.15t.662.425L15.35 4H18q.825 0 1.413.588T20 6v2.65l1.925 1.95q.275.3.425.663t.15.737q0 .375-.15.738t-.425.662L20 15.35V18q0 .825-.587 1.413T18 20h-2.65l-1.95 1.925q-.3.275-.662.425T12 22.5q-.375 0-.737-.15t-.663-.425zm.85-2l2.5 2.5l2.5-2.5H18v-3.5l2.5-2.5L18 9.5V6h-3.5L12 3.5L9.5 6H6v3.5L3.5 12L6 14.5V18zm2.5-6"%2F%3E%3C%2Fsvg%3E');
}
</style>
<h2 id="acknowledgements"><a class="header" href="#acknowledgements">Acknowledgements</a></h2>
<p>This tool is heavily inspired by:</p>
<ul>
<li><a href="https://github.com/maaslalani/slides/">slides</a></li>
<li><a href="https://github.com/d0c-s4vage/lookatme">lookatme</a></li>
<li><a href="https://sli.dev/">sli.dev</a></li>
</ul>
<p>Support for code highlighting on many languages is thanks to <a href="https://github.com/sharkdp/bat">bat</a>, which contains a
custom set of syntaxes that extend <a href="https://github.com/trishume/syntect">syntect</a>'s default set of supported languages.
Run <code>presenterm --acknowledgements</code> to get a full list of all the licenses for the binary files being pulled in.</p>
<h2 id="contributors"><a class="header" href="#contributors">Contributors</a></h2>
<p>Thanks to everyone who's contributed to <em>presenterm</em> in one way or another! This is a list of the users who have
contributed code to make <em>presenterm</em> better in some way:</p>
<a href="https://github.com/mfontanini/presenterm/graphs/contributors">
<img src="https://contrib.rocks/image?repo=mfontanini/presenterm" />
</a>
<!-- Links -->
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script>
window.addEventListener('load', function() {
window.setTimeout(window.print, 100);
});
</script>
</div>
</body>
</html>