The problem
Code on a slide is usually a screenshot of someone’s editor. It’s the wrong font and the wrong colors for the deck, it blurs when it’s printed or projected, and nobody can search it, copy it or read it aloud. Changing one line means taking the screenshot again.
Pasting the code as plain text fixes that but loses the color that makes code readable at a glance: which word is a keyword, where a string ends, what’s a comment. And a slide full of code has a second problem — the audience doesn’t know which two lines you’re talking about.
The idea
- You write a fence with a language.
```ts,```python,```sql,```sh— any of the roughly 190 languages highlight.js knows, and their usual short names. - It wears the theme. Each kind of word — keyword, string, comment, number, type — takes one of the theme’s syntax colors, checked for contrast on the code panel. Switch themes and the code recolors with everything else.
- One line configures a block. An
`@code{…}`span on the line above a fence adds a title bar, line numbers, focus on some lines (the rest recede), a tint on others, or a diff. It renders nothing itself. - Nothing runs in the deck. The colors are worked out when the slide is rendered, so the PDF, the PowerPoint, the webpage and the Studio all show the same highlighted text — and a deck only loads the languages its fences name.
- Copy where it can be copied. With
copy, readers of the webpage, the Studio or the Playground get two buttons: copy the code, or copy it with its colors. They never appear in a PDF, a picture or Present.
How to use it
Code is on in every deck. Write a fence and name the language:
```ts
export async function load(id: string): Promise<User> {
return cache.get(id) ?? api.get(`/users/${id}`);
}
```
To configure one block, put a record on the line above it:
`@code{title=src/load.ts, numbers, focus=2}`
```ts
export async function load(id: string): Promise<User> {
return cache.get(id) ?? api.get(`/users/${id}`);
}
```
| You want | Write |
|---|---|
| A file name above the code | title=src/load.ts |
| Line numbers (never copied with the code) | numbers, and start=120 to begin elsewhere |
| Two lines at full strength, the rest faded | focus=3-4 |
| A tint on a line, nothing faded | mark=4 |
| Added and removed lines | diff, with +, - or a space starting each line |
| Long lines wrapped instead of cut off | wrap |
| Copy buttons in the browser | copy |
| The same setting on every block | code: numbers, wrap in the deck’s front matter |
To keep code tidy, lattice fmt deck.md formats every block with the usual formatter for its language — Prettier for web languages, ruff for Python, sql-formatter for SQL. In the Studio, @code{format} formats a block when you leave the editor.
Where else it fits
Lattice uses highlight.js, the same widely used open-source highlighter many documentation sites and blogs run. So the habits carry over: a fenced block copied from a README, a pull request or a wiki page lands on a slide unchanged and comes out highlighted. Code slides suit engineering reviews and design walkthroughs, API launches, onboarding decks, incident write-ups (the query that caused it, the diff that fixed it), and teaching.
How Lattice uses it
The code slide gives one block the room, and the compare-code slide sets two versions side by side; both require this plugin. On any other slide, a fence is still highlighted. A fence another plugin owns — ```mermaid, ```math, ```functionplot — goes to that plugin instead, so a diagram is drawn, not colored as text.
What it doesn’t do
- A fence without a language stays plain. It sits on the code panel, uncolored.
lint:decknames a language tag nothing knows. - It doesn’t run or check your code. It colors words by their kind; a typo highlights as happily as working code.
- A slide holds about fourteen lines. A code slide doesn’t scroll or shrink the type, so longer blocks are cut off, and
lint:deckwarns first. Trim to the lines that make the point. - Copy buttons stay in the browser. A PDF, a PowerPoint, an image or a video never shows them.
- Formatting is an editing step. Rendering never reformats your code;
lattice fmtor the Studio does, where you can see the change.