Live code on a slide
In this guide you add editors to a deck: one that shows code, one that runs it with the output on the slide, one that imports a package from npm, a Python one, a diff, and one whose edits are saved to a file in your project. It takes about ten minutes.
You need a deck (see Install) running with npm run devpnpm devyarn devbun run dev. Every block
below is a fenced code block in deck.mdx; the word in braces after the language turns it into an
editor. The editor is Monaco, the editor VS Code is
built on. It ships with the engine and loads only when a slide with an editor is shown, so a deck
without one never downloads it.
1. Put an editor on a slide
Section titled “1. Put an editor on a slide”Add a slide with a {monaco} fence:
---
## An editor
```ts {monaco}{height:'auto'}const tide = { height: 6.1, at: "06:12" };```Click into it and type: completions, hovers and errors work as they do in VS Code. While the editor has focus, your keys go to it; press Esc to hand them back to the deck.
The second braces hold options: height (any CSS length, or 'auto' to grow with the code),
lines (line numbers), readonly, and editorOptions (Monaco’s own settings).
2. Run the code
Section titled “2. Run the code”Change {monaco} to {monaco-run}:
```ts {monaco-run}const heights = [5.2, 6.1, 6.4, 5.9];const highest = Math.max(...heights);console.log(`High water: ${highest} m`);```The output appears under the editor. The block runs when its slide arrives, and again when you
pause typing for two-thirds of a second; Ctrl/⌘ Enter or the Run
button runs it on demand. {autorun:false} waits for the button. Reset puts the code back as
written in the deck, and Copy copies it.
JavaScript and TypeScript run in a Web Worker, away from the deck. The console is captured, an
error keeps its line number, await works at the top level, and a run that takes longer than five
seconds is stopped, so an endless loop can’t freeze the slide. {timeout:10000} gives it longer.
3. Reveal the output on a click
Section titled “3. Reveal the output on a click”To ask the room what the code prints before showing it, hold the output back until the next click:
```ts {monaco-run}{showOutputAt:'+1', outputPosition:'right'}console.log([1, 2, 3].map((n) => n * 2));```showOutputAt is a click step like <Click at>: '+1' is the next click, a number is an absolute
step. outputPosition puts the output to the 'right' of the editor or at the 'bottom' (the
default), and outputHeight caps its height ('200px').
4. Import a package from npm
Section titled “4. Import a package from npm”A bare import loads from esm.sh when the block runs:
```ts {monaco-run}import { chunk } from "lodash-es";
console.log(chunk(["a", "b", "c", "d", "e"], 2));```The editor also fetches the package’s type declarations, so chunk has its real signature on
hover. To pin the version the block imports, and to load the types before anyone types an import,
name the package in the headmatter:
---title: My talkmonacoPackages: lodash-es: "4.17.21"---monacoTypes says where types come from: auto (the default) bundles the declarations from the
deck’s own node_modules into kadal-deck build, and fetches the rest from jsDelivr; local uses
only the installed ones, cdn only the CDN, and none turns types off. monacoRunImports points
bare imports at another CDN, or false makes them an error. Both need the network at run time
unless the package is installed in the deck.
5. Run Python
Section titled “5. Run Python”A python fence runs in Pyodide, CPython compiled to WebAssembly:
```python {monaco-run}import statistics
heights = [5.2, 6.1, 6.4, 5.9]round(statistics.mean(heights), 2)```The value of the last expression is shown, as in a Python prompt, and print output streams in.
The first Python run on a page downloads the interpreter (Pyodide 0.28.3, from jsDelivr), so it
takes a few seconds; every later run reuses it, and all the Python blocks of a deck share one
interpreter. Packages you import (numpy, pandas) load on their own. A Python run may take 20
seconds once the interpreter is up.
6. Show a change as a diff
Section titled “6. Show a change as a diff”{monaco-diff} takes the original, a line of ~~~, and the changed code:
```ts {monaco-diff}const tide = 6.1;const safe = tide < 7;~~~const tide = 6.4;const safe = tide < 6.5;```It shows the two side by side; {sideBySide:false} shows one column with the changes inline.
7. Edit a file in your project from the slide
Section titled “7. Edit a file in your project from the slide”{monaco-write} saves what you type back to the source while kadal-deck dev runs. Point it at a
real file with a <<< import. Create snippets/tide.ts beside deck.mdx:
// #region askexport function isSafe(height: number): boolean { return height < 7;}// #endregionThen, on a slide:
<<< @/snippets/tide.ts#ask {monaco-write}@ is the deck’s folder and #ask is the region between // #region ask and // #endregion.
Edit the function on the slide: under the editor, the status reads “Saved to snippets/tide.ts” a
moment after you stop typing, and the file on disk has your change. A save is refused if the file
changed underneath you. Without a <<<, a {monaco-write} fence saves into deck.mdx itself.
In a built deck and on deck.kadal.cc the editor is read-only: only the dev server can write.
8. Run another language
Section titled “8. Run another language”Any language can run with a runner of your own: a function from the code to its output. Put
runners in setup/code-runners.ts beside deck.mdx. This one pretty-prints JSON:
import { defineCodeRunners } from "@kadal/deck";
export default defineCodeRunners({ json(code) { try { return { text: JSON.stringify(JSON.parse(code), null, 2) }; } catch (e) { return { error: (e as Error).message }; } },});```json {monaco-run}{"tide": 6.4, "safe": false}```A runner can return text, HTML (sanitised before it is shown), an element, or { error }, and
ctx.write() streams output as it arrives. The second argument, ctx, also carries ctx.signal,
aborted when the block runs again or the slide goes away, and ctx.timeout. A runner that calls a
server (a SQL database, a compiler) uses fetch with signal: ctx.signal.
registerCodeRunner("json", fn) from @kadal/deck does the same from your own code.
9. Before you present
Section titled “9. Before you present”- Print, export and previews show each editor as highlighted code. A
{monaco-run}block still runs there, so the PDF page carries its output; a block that imports from the network needs it while exporting. - The phone remote and the audience’s phones see the highlighted code, not an editor.
- On a hosted deck editors and runs work as on your machine;
{monaco-write}is read-only. - Offline, JavaScript and TypeScript blocks without imports always run. Python, esm.sh imports and CDN types need the network, or a cache from an earlier run on that machine.
npx kadal-deck checkpnpm exec kadal-deck checkyarn kadal-deck checkbunx kadal-deck checkreports a diff without its~~~, a run block in a language with no runner, unknown options, and missing snippet files or regions.
- Code: step highlights, marks, code groups, TwoSlash and magic move.
- Configuration:
monacoTypes,monacoPackages,monacoTypesIgnoreandmonacoRunImports. - Export to PDF, PNG and PPTX.