# Tutorial: composing a schedule

You have a set of topics you've been presenting — slides built up over time from a past offsite, training day, or workshop. The slides are in Markdown. You probably also have reference material: PDFs, old PowerPoints, Word docs, spreadsheets. Here's how to organise it all and present it live, with a countdown timer for each topic, a next-slide preview, and speaker notes in front of you.

## What you're building

Two windows open side by side: a presenter HUD on your laptop and the slide deck on the projector or screen share. The HUD shows you the current topic's countdown timer, your speaker notes, a preview of the next slide, and a pacing indicator telling you whether you're running ahead or behind. The audience sees only the deck.

## Organising your content

Each topic lives in its own folder. Rename each topic's slide file to `index.md` and put it under `content/topics/<slug>/`:

```text
content/
  topics/
    why-habits-matter/
      index.md
    the-habit-loop/
      index.md
    making-change-stick/
      index.md
```

The `<slug>` is the identifier you'll use in your schedule file — lowercase, hyphen-separated, no spaces.

If a topic has images or other assets, put them in the same folder:

```text
content/
  topics/
    why-habits-matter/
      index.md
      diagram.png
      loop.excalidraw
```

### Reference material

Source material that informed your content but isn't part of the slides — PDFs, old decks, notes — lives in `reference/`. Nothing in `reference/` is ever included in a composed deck; it's just a home for the files that fed into your content.

```text
reference/
  original-offsite-deck.pptx
  habits-research.pdf
```

## Writing a schedule

A schedule file lives at `content/schedules/<slug>/index.md`. Here's a complete example for a one-day event with two sessions and a coffee break:

```markdown
---
title: Habits Offsite
description: A one-day workshop on building good habits.
timings: 2 x 90m
---

# Habits Offsite

---

## Morning session

---

{{ why-habits-matter, 30m }}

---

{{ the-habit-loop, 45m }}

---

{{ break coffee, 15m }}

---

## Afternoon session

---

{{ making-change-stick, 60m }}

---
```

**`timings`** tells the presenter how long each session is. Use duration notation (`2 x 90m` means two 90-minute sessions) or wall-clock ranges (`9:00-10:30, 11:00-12:30`) — the latter computes session durations and implied break lengths from the times themselves. For duration notation, add `start_time: 9:00` to give the HUD an accurate clock anchor; without it, break times are estimated from a 9:00 default and the HUD shows a notice.

**`{{ why-habits-matter, 30m }}`** includes that topic's slides at this point in the deck, with a 30-minute budget. The HUD will count down from 30 minutes while you're on those slides.

**`{{ break coffee, 15m }}`** marks a 15-minute coffee break. The HUD shows a break countdown when you reach this point. In time-range mode the duration is optional — the gap between the surrounding sessions provides it.

### Multi-day events

For a two-day event, use `***` to separate the days and `{{ schedule slug }}` to pull in child schedules:

```markdown
---
title: Two-Day Habits Workshop
---

{{ schedule habits-day-1 }}

***

{{ schedule habits-day-2 }}
```

Each child schedule (`content/schedules/habits-day-1/index.md`, etc.) has its own `timings`. The parent inherits them automatically. `***` on its own line marks the day boundary — it's standard Markdown that Marp ignores, so it won't appear as a slide separator. See `docs/reference.md` for the full marker syntax.

## Building the deck

From your project root:

```sh
marp-compose my-offsite
```

This reads `content/schedules/my-offsite/index.md`, composes the deck, and writes the output to `decks/schedules/my-offsite/`:

```text
decks/
  schedules/
    my-offsite/
      index.html    ← the rendered slide deck (includes embedded presenter metadata)
      schedule.md   ← the composed markdown (for inspection)
```

You will also need a `marp.config.js` at the project root. See `docs/reference.md` for a starter configuration.

If an item is missing, the build fails with a clear error. Use `--draft` to skip missing items and insert a placeholder slide instead — useful while the content is still being written.

### Live preview while editing

Add `--preview` (or `-p`) to compose, open the deck in Chrome, and watch for changes. Edits to any topic, schedule, or `.excalidraw` file trigger an automatic recompose and browser reload:

```sh
marp-compose my-offsite --preview
```

If you are using `@goalwards/deck`, use `deck preview` instead:

```sh
deck preview my-offsite
```

Add `--draft` to keep the preview running even if some items are missing — they appear as placeholder slides:

```sh
deck preview my-offsite --draft
```

This works for topics too — pass the topic slug directly.

## Presenting

```sh
npm install -g @goalwards/marp-present
marp-present my-offsite
```

Two browser windows open: the presenter HUD and the deck. Put the HUD on your laptop screen; share or project the deck. The HUD and deck stay in sync via a local WebSocket connection — navigate in either window and the other follows.

For the full HUD walkthrough — timers, pacing, keyboard shortcuts — see `docs/reference.md` in the marp-present repository.

## Animating diagrams with build stages

If a topic has an Excalidraw diagram with multiple frames, you can reveal it step by step using `{{ build }}`.

Suppose `content/topics/the-habit-loop/loop.excalidraw` has three frames — `01-cue`, `02-routine`, `03-reward`. Add the directive to a slide in the topic:

```markdown
---

## The habit loop

{{ build loop }}

*Cue → routine → reward.*

---
```

`marp-compose` expands that one slide into three slides, one per frame. Each gets the appropriate SVG substituted in and a speaker note (`<!-- build 1 of 3 -->`, `<!-- build 2 of 3 -->`, `<!-- build 3 of 3 -->`). Everything else on the slide — the heading, body text, speaker notes — is identical across all three. Your source `index.md` is never modified; the expansion happens at compose time.

To reveal only the last two frames:

```markdown
{{ build loop -2.. }}
```

For the full syntax — all range forms, alt text, error conditions — see the "Build stages" section in `docs/reference.md`.

## What's next

- **Full marker syntax, CLI flags, and excalidraw-stages:** `docs/reference.md` in this repository
- **Presenter HUD reference:** `docs/reference.md` in the marp-present repository
