Skip to content

Commit ad8b8ef

Browse files
committed
Update README
1 parent 24311eb commit ad8b8ef

1 file changed

Lines changed: 189 additions & 2 deletions

File tree

README.md

Lines changed: 189 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,190 @@
1-
List of modules built by the Palaeoverse team.
1+
# Palaeoverse Modules
22

3-
One folder per module.
3+
List of teaching modules built by the Palaeoverse team.
4+
5+
One folder per module: `<module>/index.qmd`, plus whatever images and data it
6+
needs. Every module is rendered twice from that single source: 1) as a page on the
7+
[Palaeoverse website](https://palaeoverse.org/training/modules) and 2) as a
8+
reveal.js slide deck (`index-slides.html`) for teaching the same material live.
9+
10+
The two files at the root of this repo exist to make one source serve both
11+
outputs:
12+
13+
| File | Role |
14+
| --- | --- |
15+
| `web_and_slides.lua` | Pandoc/Quarto filter, applied at render time. Decides what appears on the website, what appears on the slides, and how the slides are broken up. |
16+
| `web_and_slides.r` | One-shot authoring helper. Converts a finished long-form document into the tagged form the filter expects. |
17+
18+
# Authoring a module
19+
20+
## Front matter
21+
22+
Start from an existing module (`ggplot/index.qmd` is a good template). These
23+
fields matter:
24+
25+
```yaml
26+
---
27+
title: "Plotting in R with ggplot2"
28+
description: "Visualizing your data with the grammar of graphics"
29+
author: "Will Gearty"
30+
date: "2026-06-12"
31+
categories: [r, tidyverse, dataviz] # various tags
32+
difficulty: Beginner # Beginner/Intermediate/Advanced
33+
image: images/2d_density.png # thumbnail for module
34+
format:
35+
html: default
36+
revealjs:
37+
smaller: true
38+
output-file: index-slides.html # the deck, alongside the page
39+
execute:
40+
output-location: fragment # slide output reveals on click
41+
echo: true
42+
freeze: auto # must be auto, not true
43+
filters:
44+
- at: pre-ast
45+
path: web_and_slides_autogenerated.lua
46+
---
47+
```
48+
49+
`difficulty`, `categories` and `freeze: auto` are enforced by CI (see
50+
[Technical summary](#technical-summary)). The `filters` entry is what activates
51+
everything below; `web_and_slides.r` adds it for you, or you can copy it.
52+
53+
## Writing for two outputs
54+
55+
Three fenced-div (`:::`) classes control where content lands:
56+
57+
| Class | Website Tutorial | Slides |
58+
| --- | --- | --- |
59+
| `.narration` | normal prose | speaker notes |
60+
| `.slides-only` | dropped | shown on the slide |
61+
| `.html-only` | shown | dropped |
62+
63+
Anything not wrapped in one of these appears in both outputs. So the usual shape
64+
of a module is: headings and code chunks shared by both outputs, the connecting
65+
prose in `.narration` (a paragraph on the page, a note you talk from on the
66+
slide), and the occasional `.slides-only` bullet summary or `.html-only` aside.
67+
68+
````markdown
69+
## Making a scatter plot
70+
71+
::: {.narration}
72+
On the website this is a paragraph of explanation. On the slides it is what you
73+
say out loud while the plot is up.
74+
75+
Consecutive paragraphs can share one block.
76+
:::
77+
78+
::: {.slides-only}
79+
- x is body mass
80+
- y is flipper length
81+
:::
82+
83+
```{r}
84+
ggplot(penguins) +
85+
aes(x = body_mass, y = flipper_len) +
86+
geom_point()
87+
```
88+
````
89+
90+
## Automated slide rendering via `web_and_slides.lua`
91+
92+
The following changes are applied to the reveal.js slides via our custom Lua filter:
93+
94+
- **Headings become slides:** `##` starts a slide as usual; `###` and deeper are
95+
promoted so each also gets its own slide, instead of piling onto the parent.
96+
A `#` heading becomes a centered divider slide, so don't put content under one.
97+
- **One plot per slide:** The slide closes after each figure. Prose that follows
98+
a figure moves to the next slide (introducing it), unless nothing but prose
99+
remains before the next heading — then it stays put rather than making a blank
100+
slide. Split slides repeat the current heading, so they keep a title.
101+
- **Callouts get their own slide:** A callout is un-boxed onto a slide of its
102+
own, titled by its own heading. Give a callout a `## Heading` as its first line
103+
(rather than `title="..."`) if you want that title on the slide; an untitled
104+
callout keeps the section title.
105+
- **Multi-chunk slides build up:** A slide holding two or more code chunks is
106+
expanded into an auto-animate sequence: one step per chunk, earlier chunks
107+
staying on screen, and the notes for each chunk advancing with it.
108+
109+
Preview both outputs with:
110+
111+
```sh
112+
quarto render ggplot/index.qmd # -> index.html and index-slides.html
113+
```
114+
115+
## `web_and_slides.r` Helper
116+
117+
The `web_and_slides.r` helper file takes a long-form document and mechanically prepares it:
118+
119+
```sh
120+
Rscript web_and_slides.r <input.qmd> [output.qmd]
121+
[--filter=<path/to/filter.lua>] [--no-inject] [--no-settings]
122+
```
123+
124+
It does the following:
125+
126+
1. Wraps each set of consecutive prose paragraphs in a single
127+
`::: {.narration}` block. Headings, code chunks, lists, blockquotes,
128+
tables, standalone images, and existing fenced divs (including callouts and
129+
everything inside them) are left untouched.
130+
2. Registers the filter in the front matter at the `pre-ast` stage, replacing any
131+
earlier registration. `--no-inject` skips this; `--filter=` names a different
132+
file.
133+
3. Sets slide-friendly YAML (skip with `--no-settings`):
134+
- adds `execute.echo: true` (renders source code on slides)
135+
- adds `execute.output-location: fragment` (renders code results as separate chunk)
136+
- adds `format.revealjs.smaller: true` (text shrinks to fit on slides)
137+
- removes `format.revealjs.scrollable` (disables scrolling through slides)
138+
4. Reports headings that will render awkwardly (e.g., `#` become centered title slides).
139+
You should fix these by hand.
140+
141+
The front matter is checked for valid YAML before anything is written. Needs the
142+
`readr`, `stringr`, `yaml`, and `fs` packages.
143+
144+
With no `output.qmd` specified it rewrites the input in place.
145+
146+
# Two ways to build a module
147+
148+
## 1. Long-form first, then convert
149+
150+
_Best when the module is primarily a written tutorial, or already exists as prose._
151+
152+
Write the module as an ordinary prose-and-code document, ignoring slides
153+
entirely. When it reads well, run `web_and_slides.r` over it once, then clean up
154+
the result by hand: act on any headings it flagged and add `:::{.slides-only}` /
155+
`:::{.html-only}` blocks where the two outputs should diverge.
156+
157+
```sh
158+
# write the preliminary tutorial in mymodule/index.qmd.orig
159+
Rscript web_and_slides.r mymodule/index.qmd.orig mymodule/index.qmd
160+
quarto render mymodule/index.qmd
161+
```
162+
163+
The script is intended to be run as a **single pass once the long-form version is
164+
finished**. However, in principle it can be run on the same file multiple times.
165+
Prose already inside a `.narration` block is left alone, so a second run over its
166+
own output changes nothing. If you start hand-editing the converted file, keep
167+
editing that file. If you would rather keep iterating on the long-form text,
168+
keep it alongside as `index.qmd.orig` and regenerate `index.qmd` (but any hand
169+
cleanup you did to `index.qmd` will need redoing).
170+
171+
## 2. Tag as you go
172+
173+
_Best when you are thinking about the slides and the prose tutorial at the same
174+
time, and when you want fine control over which output gets what._
175+
176+
Skip `web_and_slides.r` completely. Write `index.qmd` with the intent to render
177+
both output types from the beginning. Copy the `filters` entry and the
178+
slide-friendly `execute` / `revealjs` settings from another module's front matter.
179+
Then, as you write use an `.html-only` block if you only want the text to
180+
appear in the prose tutorial, a `.slides-only` block if a section should only
181+
appear on the slides (e.g., bullet points), or a `.narration` block have
182+
content appear in the prose tutorial and be shown as speaker notes for the slides.
183+
184+
# Additional references:
185+
186+
- Quarto tutorial ([with Positron](https://quarto.org/docs/get-started/hello/positron.html) | [with RStudio](https://quarto.org/docs/get-started/computations/rstudio.html))
187+
- [Markdown basics in Quarto](https://quarto.org/docs/authoring/markdown-basics.html)
188+
- [HTML basics in Quarto](https://quarto.org/docs/output-formats/html-basics.html)
189+
- [Revealjs in Quarto](https://quarto.org/docs/presentations/revealjs/)
190+
- [Quarto Listings](https://quarto.org/docs/websites/website-listings.html)

0 commit comments

Comments
 (0)