Cheat Sheet
Cheat Sheet
Every operator and option in the .tac language, in one place. For the reasoning
behind each decision see syntax-decisions.md;
for a runnable example see Samples/tachyonn.tac.
Document structure
| Syntax | Meaning |
|---|---|
=== β¦ === | Frontmatter block (deck metadata + style keys) |
# Title | Section divider slide |
## Title | Content slide (a new slide starts here) |
## (no text) | Inherits the previous content title |
### Title | Highlight box (callout) inside the slide β not a new slide |
:: id | Block/slide id, at the end of a header line |
// comment | Line comment (also valid in frontmatter) |
--- | Column separator inside multi-column / grid layouts |
Navigation: β/β (and Space/Enter) advance, β/β (and
Backspace) go back β all four arrows move linearly through the deck,
consuming pending clicks first. Shift+β/β jumps to the next section and
Shift+β/β to the previous one (sections = # dividers). O opens the
2D overview map (sections as columns, their ## slides stacked below); T
opens the table of contents β every section as a link, jump straight to it.
Inline formatting
| Syntax | Result |
|---|---|
**bold** | bold |
*italic* | italic |
***bold italic*** | bold italic |
~~strike~~ | |
`code` | inline code (literal; variable backtick fences) |
H_[2]O | subscript |
E = mc^[2] | superscript |
+[x^2] | inline math (LaTeX, see Math) |
[text]{.class style="β¦"} | Pandoc span (classes + inline style) |
Links
| Syntax | Meaning |
|---|---|
&[https://site, label] | External link with label |
&[https://site] | External link, URL as label |
:[idSlide] | Internal link by id |
:[idSlide, "label"] | Internal link with a custom label |
Images
![<modifiers> src, caption] or ![src]{name=value, β¦}. Bare filenames are
looked up in ./img/ first, then next to the .tac. A http(s):// URL is
downloaded and cached at compile time into img/.cache/ (and embedded), so
the deck stays offline at render. Use tachyonn export β¦ --refresh-cache (or the
CLI --refresh-cache flag) to re-download; offline, a placeholder is shown.
| Shortcut | Named | Meaning |
|---|---|---|
<c> | align=center | Center |
<l> | align=left | Left |
<r> | align=right | Right |
<vc> | valign=center | Vertically centered β the default |
<vt> | valign=top | Vertically top |
<vb> | valign=bottom | Vertically bottom |
<f> | fit=full | Full content width |
<h> | fit=half | Half width |
<t> | fit=thumb | Thumbnail |
<w=N> | width=N | Width (bare number = px; 50%/12vh kept) |
<h=N> | height=N | Height |
<p=N> | padding=N | Space around the image (all four sides) |
<pt=N> <pr=N> <pb=N> <pl=N> | paddingTop= paddingRight= paddingBottom= paddingLeft= | Space on one side |
<px=N> <py=N> | paddingX= paddingY= | Space on one axis |
Combine in one <> with commas: ![<r, h=80> logo.png].
Housekeeping: tachyonn unused-images deck.tac (or a directory) lists every
file in img/ that no deck in that directory references β with sizes and a
ready-to-run rm line. It scans all .tac/tac.config/.tt/.csv there,
because img/ is shared across sibling decks. --include-cache also checksimg/.cache/.
Pasting an image: tachyonn paste-image deck.tac --row N takes whatever is
on the clipboard β a bitmap (screenshot, "copy image" from a browser) or a file
copied in Finder β writes it into img/ as <deck>-01.png, and inserts the![β¦] line after row N. Options: --name, --caption, --modifiers "<c> w=60%",--no-insert. Bound to cmd-shift-v in the Zed keymap template
(zed-editor/keymap.json).
Vertical alignment only changes anything where the box that hosts the image
is taller than the image itself β in practice, a grid card, which stretches to
the row height. An image alone in a card is centered by default, so you
rarely need to write <vc>; use <vt>/<vb> to pin it to the top or bottom.
Sharing the card with text keeps the normal flow. There is no need to fake it
with pt=/py= anymore.
Lists
| Marker | Type |
|---|---|
- * + | Unordered |
1. 2) | Ordered decimal (. or ) delimiter) |
a. A. | Ordered alphabetic (lower/upper) |
i. IV. | Ordered roman (lower/upper) |
Nest with 2- or 4-space indentation; types can be mixed freely.
Quotes
> A line of quotation.
> β Optional author (last line, em-dash + space)Tables
Markdown pipe syntax, with an optional options line |<β¦> before the header.
| Option (on |<β¦>) | Effect |
|---|---|
| s | Striped rows |
| b | Bordered cells |
| c | Center the whole table |
| lcr⦠| Global per-column alignment (2+ chars of l/c/r) |
Per-column alignment also via a header-cell prefix <l>/<c>/<r>, or the
separator :--- / :---: / ---:.
Merged cells (colspan/rowspan): a cell containing only < merges into the
cell to its left (extends colspan); a cell containing only ^ merges
into the cell above (extends rowspan). Both chain across consecutive
cells/rows.
| Item | Q1 | Q2 |
| ------ | -- | -- |
| Totals | < | (colspan 2, "Totals" spans both columns)From a CSV file:
| Syntax | Effect |
|---|---|
|[<f=data.csv>] | Build a table from data.csv (first row = header) |
|[<f=data.csv, sep=;>] | Custom field separator |
|[<f=data.csv>, s, b, c] | CSV table + the options above |
Code blocks
Fenced with triple backticks and a language id. Options go in {β¦} after the
language.
| Option | Effect |
|---|---|
highlight=N | Highlight line(s): 2, 2,4, or 2-5 |
highlight=a|b|c | Incremental: each | group is emphasized on the next click (the last group stays). Adds clicks to the slide. |
lineNumbers / ln | Show the gutter; lineNumbers=10 starts at 10 |
title="β¦" | Title bar above the code |
wrap | Wrap long lines inside the box instead of scrolling horizontally |
io | Enable attached input/output sub-boxes (see below) |
reveal | With io: reveal code, then input, then output β one click each |
Input / output boxes (io): inside the fence, a line --- input or--- output starts a named sub-box rendered below the code; text after the
marker renames the box (e.g. --- input stdin). Only the code region is
syntax-highlighted. Add reveal to step through them per click.
```python {io, reveal}
n = int(input())
print(n * n)
--- input
5
--- output
25
```A ```mermaid block is rendered as a diagram (client-side, offline) instead
of highlighted code.
Math (LaTeX / KaTeX)
| Syntax | Result |
|---|---|
+[E = mc^2] | Inline math |
+[<b> \int_0^1 f\,dx] | Display (block) math, like $$β¦$$ |
Content is literal TeX; brackets balance, so +[\sqrt[3]{x}] works. Rendered by
KaTeX, bundled offline.
Global macros β define \newcommands once in the frontmatter with texMacro:
(one per line, repeatable) and they apply to every formula in the deck:
texMacro: \newcommand{\R}{\mathbb{R}}
texMacro: \newcommand{\vv}[1]{\mathbf{#1}}
texMacro: \half \frac{1}{2}Accepts the full \newcommand{\name}[n]{body} form (the [n] is optional β KaTeX
infers argument count from #1β¦#n), \def, or the short \name expansion.
The same texMacro: line also works inside a .tt theme file, so a theme
(e.g. a "physics" notation pack) can ship its own macros β the deck's owntexMacro: lines win over the theme's on a name clash. A macro whose body
references #2 without #1 (an argument-numbering gap) prints a friendly
warning at compile time.
Highlight boxes (callouts)
### opens a box inside the slide; the text after it is the title bar.
| Modifier | Variant |
|---|---|
(none) / <s> / <standard> | Standard |
<a> / <alert> | Alert |
<e> / <example> | Example |
<name> | Custom (style via --tac-callout-<name>) |
Clicks & animation
The single operators >[β¦] / <[β¦] drive per-click reveals.
| Syntax | Effect |
|---|---|
>[n]{β¦} | Content enters on click n |
<[n]{β¦} | Visible at first, leaves on click n |
>[a-b]{β¦} | Enters at a, gone by b |
>[]{β¦} | Auto: each child reveals in sequence, continuing the slide's click count (after a >[1] and a >[2], the first automatic child enters on click 3) |
The braces take any .tac, including a whole ### box (title bar and all):
>[4]{
###<alert> The uncomfortable truth
Nobody hires you just because you know a language's syntax.
}A hidden reveal keeps its space β the slide is laid out once, for its final
state, so nothing moves or resizes between clicks (a code block above three
revealed paragraphs is drawn at its final size right away). Set reveal: push
(deck, tac.config or per-slide) for the old behaviour, where a hidden
block-level reveal collapses and the content below slides up.
reveal: | Effect |
|---|---|
reserve (default) | Hidden blocks keep their space; layout is identical at every click |
push | Hidden blocks collapse; revealing them pushes the content below down |
Magic Move: give the destination slide transition: magic and shared
elements fly (FLIP) from their old spot to the new one. Mark them with a[text]{.magic-NAME} span (same NAME on both slides) or a data-magic
attribute; the slide title morphs automatically. The flight lasts 0.5s by
default β set magicDuration: (e.g. 1.5s, 800ms) on the destination slide
or deck to change it.
Slide transitions
Set transition: once in the deck frontmatter (or in a tac.config, so every
deck in the folder inherits it); a slide's own transition: still wins when you
move forward into it.
===
title: My deck
transition: slide-in // slide (default) | slide-in | slide-out-in | fade | zoom | none
transitionDuration: 0.6s // optional, default 0.5s
transitionShift: 12% // optional, default 10% β travel of the soft families
===| Value | Motion |
|---|---|
slide | The classic one: both slides travel a full screen together β you see the old one leave and the new one arrive |
slide-in | Only the new slide moves: it drifts in over the old one, fading from transparent to opaque. The old one stays still underneath |
slide-out-in | Sequential (like Vue's mode="out-in"): the old slide drifts out and fades, then the new one drifts in |
fade | Cross-fade, no movement |
zoom | Scale in / out |
none | Hard cut |
Direction is automatic: horizontal between # sections, vertical between the## slides of a section, and mirrored when you navigate backwards.
Macros, loops & include
The double operators <<[β¦] / >>[β¦] carry structure (no collision with the
single reveal operators). Everything expands at parse time β zero runtime cost.
| Syntax | Effect |
|---|---|
<<[<name> β¦bodyβ¦] | Define a macro/snippet (in tac.config, the frontmatter, or the body) |
>>[<name>] | Insert the macro |
>>[<name> k=v, β¦] | Insert with params (available inside as /var[k]) |
>>[<each> VAR in: a, b, c] β¦ [[/each]] | Loop: repeat the body per value, substituting /var[VAR] |
>>[path.tac] | Include another file (its frontmatter is dropped) |
Includes are resolved before macros, so a file can be a library of slides
shared by several decks: define the slides once as macros, include the library,
insert them wherever you want them.
// shared/comuns.tac β a library: defining a macro emits nothing by itself
<<[<contato>
## Where to find me ::contato
- E-mail: **you@example.org**
- Office: 42, block B
]
<<[<avisos>
## Notices β /var[week] ::avisos
- Homework due Friday
- Exam on /var[date]
]// aula01.tac β any deck that wants them
>>[shared/comuns.tac]
## A slide of this deck's own
β¦
>>[<avisos> week="1", date=12/08]
>>[<contato>]Change the library, every deck follows. If a slide needs no variation at all,
skip the macro: put it alone in a file and >>[shared/final.tac] where it goes.
Or skip the include entirely: a macro defined in a tac.config is available
to every deck below it in the tree, exactly like a property. Put the definition
in the course's root tac.config and each lecture only writes >>[<contato>] β
no include line at all. The usual cascade applies: the nearest tac.config
wins over the ones above it, and a definition in the deck itself wins over both.
Two things to know: paths are always relative to the top-level .tac, even
inside a nested include; and a macro body has to keep its [/] balanced (it is
what marks where the body ends).
Directives
/name[arg1, arg2, key=value], inline or on its own line.
| Directive | Effect |
|---|---|
/layout[name] | Set the slide layout |
/notes[β¦] | Speaker notes (presenter only) |
/fn[β¦] | Footnote |
/var[key] | Interpolate a frontmatter value |
/cite[id] | Citation |
/component[Name, propsβ¦] | Embed a registered Vue component (see below) |
/icon[] | A Nerd Font glyph β paste the character itself from nerdfonts.com |
Components (/component[β¦])
Registered in tachyonn-render/app/slides/custom-components.ts. Props arekey=value, comma-separated; numbers and true/false are converted to their
real types.
| Component | Props | Use |
|---|---|---|
QrCode | url (required), size (px, 260), label, ecl (L/M/Q/H, M), margin (modules, 2), color (#000000), background (#ffffff), showUrl (false) | QR code for a link |
Counter | initial (0), step (1) | Click counter (demo) |
/component[QrCode, url=https://exemplo.org/aula?turma=2026, label=Slides da aula, size=320]The QR is drawn as vector SVG, so it stays sharp and weightless in the PDF
export. It is generated offline, on the client β nothing is fetched. A url too
long to encode shows a message on the slide instead of breaking the deck; raisesize and lower ecl if a dense code is hard to scan from the back of the room.
Icons (/icon[β¦])
Go to nerdfonts.com/cheat-sheet, copy
the glyph itself, and paste it between the brackets:
## /icon[] Deploy
Built with /icon[] and shipped to /icon[].The Symbols Nerd Font ships inside Tachyonn (MIT), so this works offline, on
any machine, in the PDF and in the network viewer β you do not need a patched
font installed, and the deck's own typography is untouched: only the glyph
changes font.
Works anywhere text goes: slide and section titles, the cover, callout titles,
list items, table cells and footer slots. The icon inherits the color of
wherever it sits (orange in a title, white on a callout bar); iconSize andiconColor override that.
Layouts (/layout[β¦])
| Name | Use |
|---|---|
title | Presentation cover |
cover | A full cover slide anywhere in the deck (alias of title; set variant:/image: per-slide) |
section | Section divider (from #) |
standard | Default (from ##) |
two-column / three-column | Columns (split by ---) |
image-and-text | Image beside text |
big-number | Numeric highlight |
quote | Large quotation |
grid | Grid of cards (split by ---) |
code-window | Full-slide editor-style code |
media | Dominant image/video |
Frontmatter & style keys
Set in the deck === β¦ ===, in a per-directory tac.config, or per-slide in a=== β¦ === right after the ## (per-slide wins).
| Key (synonyms) | Effect |
|---|---|
title subtitle author date | Deck metadata. title/subtitle/author are what the automatic cover shows |
description | Deck metadata only β a one-line summary for the footer token {description}. It is not cover content; use coverBody: for that |
accent / accentColor | --tac-accent |
color / textColor | Base text color |
headingColor / titleColor | Headings color |
mutedColor borderColor | Muted text / borders |
font / fontSans, fontMono / fontCode | Fonts |
background / bg | Color, gradient, ![img], or video ![bg.mp4] (autoplays, muted, behind the slide) |
overlay / scrim | Legibility veil over the background: dark / light / a number (0.6) / any CSS color |
valign | top / center / bottom / between / around |
reveal / revealMode / clickMode | How hidden >[n]{β¦} blocks behave: reserve (default β keep their space, nothing moves between clicks) / push (collapse and push content down) |
quoteWidth | Width of the box on a /layout[quote] slide, as a fraction of the slide (default 70%) |
theme: NAME | Apply a theme: built-in preset (default, dark, physics) or a .tt file path. physics also ships a TeX macro pack (\ket, \pdv, \R, \normβ¦) |
class / classes | Extra utility classes on the root |
textSize slidePadding | Per-slide sizing knobs |
transition | Deck-wide default (or per-slide): slide (default) / slide-in / slide-out-in / fade / zoom / none; magic per-slide. Direction (left/right vs. up/down, forward vs. back) is derived from the deck's 2D geometry |
transitionDuration | Base duration of the slide transition (e.g. 0.7s; default 0.5s) β deck level |
transitionShift / transitionDistance | Travel distance of slide-in / slide-out-in (e.g. 18%; default 10%) β deck level |
magicDuration | Magic Move flight duration (e.g. 1.5s, 800ms; default 0.5s) |
coverVariant | centered / image-bg / image-title / split / stacked / minimal |
coverImage | Cover image or video (a video file plays muted, looping) |
coverBody / coverContent | Body of the automatic cover: each occurrence is one line of .tac (repeat the key; an empty one starts a new paragraph). Full syntax β lists, ![img], **bold**, +[math]. \n inside a single key also breaks the line |
coverSplitWidth / coverSplit / splitWidth | How much of the slide the media takes on split (width) / stacked (height). Default 50% |
coverBodySize coverBodyGap | Text size / top gap of the free body of a /layout[cover] slide |
variant (per-slide) | On a cover/title slide: its cover variant; on a # section: that section's variant (overrides sectionVariant) |
(body of a /layout[cover] slide) | Rendered in the text column, under title/subtitle/author β paragraphs, lists, an image. The auto-generated deck cover has no body |
image (per-slide) | Cover image for a cover/title slide (image-bg routes it to the background) |
sectionVariant | centered / toc / toc-side / number / backdrop / color-block / bigtype |
kicker (per-section, aliases overline / eyebrow) | Small overline above a # divider's title |
sectionBlockColor sectionBlockTextColor sectionBlockSize | color-block: the fill, the text over it, the title size |
sectionBigTypeSize | bigtype: the title size (default 7rem) |
kickerSize kickerColor kickerFont | Styling of the overline |
tocHeading | section / deck / none |
toc: false (per-section) | Keep this # section out of the index shown on the section dividers |
progress / progressColor | Progress bar position / color |
texMacro | Global TeX macro (\newcommand{\R}{\mathbb{R}}); repeatable, works in a .tt theme too |
time / duration (per-slide) | Presenter timer target for this slide: seconds (90) or M:SS/H:MM:SS (3:00) |
css | Inline CSS rule (repeat to add more) |
cssFile / cssFiles | Load .css file(s) next to the .tac |
imageMaxWidth imageQuality | Image optimization: resize past N px (default 1920) and re-encode opaque PNGs as JPEG at quality N (82). off embeds originals. This is what keeps exported PDFs small |
footer.left footer.center footer.right | Footer slots (text or ![img]); also settable per-slide to override just that slot |
footerFont footerSize footerColor | Footer typeface (falls back to the deck font), size (default 13px) and color |
iconSize iconColor | Size (1em) and color of /icon[β¦] glyphs; by default the icon inherits the color where it sits |
Footer text tokens: {page} {total} {title} {subtitle} {author}{date} {description}.
Export
From the app: File β Export PDFβ¦ (Cmd/Ctrl+E) opens the print view and the
native dialog (Save as PDF β no Chrome needed). From the CLI:tachyonn export deck.tac (headless). Both share these options:
| CLI flag | Query param | Effect |
|---|---|---|
--steps all|final | steps=final | One page per click (all) vs per slide (final) |
--handout CxR | handout=2x2 | Handout: CΓR slides per sheet |
--notes | notes=1 | Include speaker notes under each slide |
--slides 2-5,8 | slides=2-5,8 | Export only a subset (1-based) |
-o out.pdf | β | Output path (CLI; default <input>.pdf) |
--image png|svg | β | One image per slide instead of a PDF (PNG raster or vector SVG) |
--out-dir DIR | β | Folder for the images (default <input>-export/) |
--image svg wraps each slide in an SVG <foreignObject> (vector, selectable
text); the viewer must support foreignObject (browsers do).