Welcome!

Authoring in Markdown

This page is part of the advanced authoring path — a special case the Lupo team sets up on request. Most people don't need it.

TL;DR; Each section referenced from toc.yml is one Marp Markdown file, rendered one slide at a time. Standard Markdown covers formatting, lists, links and tables; a handful of extensions — background images, timed narration, and video embedding — are specific to Lupo and are the part actually worth learning here.

Before you start

See toc.yml reference for how a section file is wired into the project.

The header every file needs

A section file is a Marp deck, and Lupo checks that before it does anything else. The file must open with a front-matter block that sets marp: true; a file without it fails with "Marp header not found", and any other value for marp fails with "Invalid Marp header". theme is the only other free key; anything else in the header has to be one of the Marp directives listed in Styling and themes, and an unknown one is reported as a warning.

---
marp: true
---

# First slide

---

# Second slide

Slides are separated by a line containing only ---.

Basic formatting

Standard Markdown: **bold**, *italic* (or __bold__ / _italic_), `inline code`, and # Heading through ###### Heading. Escape any character with a backslash, e.g. \*not italic\*.

# This is a Title
## This is a subtitle
You can write **bold**, *italic*, [links](https://lupo.ai), and `code`.

Blockquotes use >, and nest with > >. A blank line inside a quote needs a bare > to stay part of the same block:

> First line
>
> > Nested line
>
> Last line

HTML comments (<!-- ... -->) render as nothing — they're where narration text lives, covered below.

Lists

Unordered lists use *, +, or -. Ordered lists don't need to be numbered sequentially in the source — 1. 1. 1. still renders as 1. 2. 3., and starting at 5. starts the rendered list at 5. Nest by indenting two spaces or one tab.

* First item
    * First sub-item
        * First sub-sub-item

1. First
2. Second

Inline: [link text](url). Reference-style, useful when the same link is reused or you want to keep URLs out of the prose:

[Lupo][lupo]
[lupo]: https://lupo.ai/ "Go to Lupo"

There's no special syntax for linking between sections of the same project — that structure is defined by toc.yml, not by links inside the Markdown itself.

Images

Basic syntax: ![alt text](image-path) — no space between ] and (.

Two extensions beyond standard Markdown:

Resizing — set a width and/or height on the image:

![width:500px height:300px](../images/photo.png)

Full-slide background images — the bg keyword turns an image into the slide's background instead of an inline image. Multiple background images on one slide lay out side by side automatically; vertical stacks them instead. left or right (optionally with a percentage) splits the slide, reserving the rest for your regular content:

![bg](image-path)
![bg vertical](image-path)
![bg left:25%](image-path)

Code

Inline code uses backticks. Fenced code blocks take a language tag for syntax highlighting:

```csharp
public int Area(int a, int b);
```

Tables

Standard GFM pipe syntax, with alignment set by colons in the separator row:

| Left | Center | Right |
| :--- | :----: | ----: |
| Text | Text   | Text  |

Equations

LaTeX syntax — inline with single $...$, block/display with double $$...$$:

Inline: $F_{0}=0$

Block:
$$ I_{xx}=\int\int_R y^2 f(x,y) \, dy\,dx $$

Embedding video

Markdown has no native video syntax, so video is embedded as raw HTML5 <video>, with a few Lupo-specific attributes controlling how it times against narration:

  • video-duration — the slide's length matches the video's own duration.
  • audio-duration — the slide's length matches the narration audio's duration instead.
  • repeat — the video loops until the narration audio finishes.
  • muted / no-muted — drop or keep the video's own soundtrack.
<video src="../universe.mp4" controls audio-duration muted>
  Your device does not support video playback.
</video>

Narration and timing

Narration text for a slide goes inside an HTML comment. By default, lines are read in order. Prefixing a line with a time marker starts that narration at a specific moment instead of wherever it would otherwise fall — useful for syncing narration to an embedded video or an animation. One narration per line, no line breaks inside a single narration line:

  • ((5)) — start at 5 seconds
  • ((5.5)) — start at 5.5 seconds
  • ((1:30)) — start at 1 minute 30 seconds
  • ((1:02:03)) — start at 1 hour 2 minutes 3 seconds
<!--
((5)) Welcome to this course.
((12)) In this section, we'll cover the fundamentals.
-->

Timed and untimed lines can mix — an untimed line just follows immediately after whichever timed line came before it. An empty comment is treated as a slide with no narration.

The narrator's voice, speed, pitch and speaking style are not set in the Markdown at all — they come from toc.yml (style at course level, emotion at chapter or section level), so every slide in a section is read the same way. There is no per-line style tag.

A comment whose first word starts with _ and is followed by a colon is not narration but a per-slide directive — <!-- _backgroundColor: #2288C9 --> restyles just that slide. See Styling and themes.

Raw HTML

Inline HTML is supported directly in the Markdown — tables, custom markup, and anything else HTML can express.

Where to go next