Welcome to VersoSlides — a Verso genre for building
reveal.js slide presentations from Lean.
This demo exercises all the major features.
VersoSlides supports:
Elaborated Lean code blocks with hovers and info panels
Inline Lean expressions: elaborated and type-checked
Progressive proof reveals with magic comments
Hidden setup code and replaced expressions
Fragment animations (block and inline)
Per-slide metadata (backgrounds, transitions)
Speaker notes (press s on your keyboard)
Read on for examples of each.
Here is an elaborated Lean code block:
def hello : IO Unit := do
IO.println "Hello from VersoSlides!"
#checkhello : IO Unit hello
hello : IO Unit
And some inline hello for good measure. Unit
A light-themed slide with Lean code:
def greet (name : String) : String :=
s!"Hello, {name}!"
#eval"Hello, Lean!" greet "Lean"
"Hello, Lean!"
def replicate (n : Nat) (x : α) : List α :=
match n with
| 0 => []
| n' + 1 => x :: replicate n' x
theorem replicate_length : ∀ {n : Nat} {x : α},
(replicate n x).length = n := byα:Type u_1⊢ ∀ {n : Nat} {x : α}, (replicate n x).length = n
intro nα:Type u_1n:Nat⊢ ∀ {x : α}, (replicate n x).length = n
intro xα:Type u_1n:Natx:α⊢ (replicate n x).length = n
induction nα:Type u_1x:α⊢ (replicate 0 x).length = 0α:Type u_1x:αn✝:Nata✝:(replicate n✝ x).length = n✝⊢ (replicate (n✝ + 1) x).length = n✝ + 1
.α:Type u_1x:α⊢ (replicate 0 x).length = 0 grind [replicate]All goals completed! 🐙
next n' ih =>α:Type u_1x:αn':Natih:(replicate n✝ x).length = n✝⊢ (replicate (n✝ + 1) x).length = n✝ + 1
simp only [replicate]α:Type u_1x:αn':Natih:(replicate n✝ x).length = n✝⊢ (x :: replicate n' x).length = n' + 1
conv =>α:Type u_1x:αn':Natih:(replicate n✝ x).length = n✝| (x :: replicate n' x).length = n' + 1
rhsα:Type u_1x:αn':Natih:(replicate n✝ x).length = n✝| n' + 1
rw [← ih]α:Type u_1x:αn':Natih:(replicate n✝ x).length = n✝| (replicate n' x).length + 1
simpAll goals completed! 🐙
theorem fact_pos : ∀ n, 0 < fact n := by⊢ ∀ (n : Nat), 0 < fact n
intro nn:Nat⊢ 0 < fact n
induction n with
| zero =>⊢ 0 < fact 0 simp [fact]All goals completed! 🐙
| succ n ih =>n:Natih:0 < fact n⊢ 0 < fact (n + 1)
simp [fact]n:Natih:0 < fact n⊢ 0 < fact n
omegaAll goals completed! 🐙
theorem sum_to_formula : ∀ n,
2 * sum_to n = n * (n + 1) := by⊢ ∀ (n : Nat), 2 * sum_to n = n * (n + 1)
intro nn:Nat⊢ 2 * sum_to n = n * (n + 1)
induction n with
| zero =>⊢ 2 * sum_to 0 = 0 * (0 + 1) simp [sum_to]All goals completed! 🐙
| succ n ih =>n:Natih:2 * sum_to n = n * (n + 1)⊢ 2 * sum_to (n + 1) = (n + 1) * (n + 1 + 1)
grind [sum_to]All goals completed! 🐙
def y := hiddenFunction 22
def z := 5
def zz := 22
This slide has hidden setup code.
We have α available here:
#checkList.{0} α : Type List α
List.{0} α : Type
But not β.Unknown identifier `β`
-- There is no info panel here
def simple : Nat := 42
def result : Nat :=
...
fn main() {
let nums = vec![3, 1, 4, 1, 5, 9];
let max = nums.iter().max().unwrap();
println!("Max: {max}");
}
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3};
for (auto x : v) std::cout << x << "\n";
}
module
import Std.Data.HashMap
open Std
def xs : HashMap Nat String := {}
import Lake
open Lake DSL
require «verso-slides» from git
"https://github.com/leanprover/verso-slides.git"@"main"
package «etaps-tutorial» where
version := v!"0.1.0"
lean_lib MiniRadix
module
public def x : Nat := 1
def y : Nat := 2
module
import Lib.A
def z := x
/-- error: Unknown identifier `y` -/
#guard_msgs in
def x' := y
import Lake
open Lake DSL
package p
lean_lib A
def x := "Module A!"
We can refer to x.
This block fades up.
This block also fades up, but with explicit index 2.
Here is an inline red highlight within a sentence.
And another inline blue highlight with an explicit index.
\frac{dV(t)}{dt} = \delta_t\, V(t) + \pi_t - b_t
- \mu_{x+t}\bigl(S_t - V(t)\bigr)
\delta_t is the force of interest at time t
\pi_t is the premium payment rate
b_t is the continuous benefit payment rate
\mu_{x+t} is the force of mortality for a life aged x + t
S_t is the sum payable on death at time t
This content appears on the first implicit vertical sub-slide.
This is vertical sub-slide A.
Navigate down to see the next sub-slide.
This vertical sub-slide has a custom green background.
Big text!
This paragraph has a custom id attribute.
This paragraph has a custom data-id for auto-animate matching.
Small title
Big title
This slide has a purple background and uses the zoom transition.
The :::hstack directive arranges children side by side.
Left column content.
Center column content.
Right column content.
The :::vstack directive arranges children vertically with centered alignment.
Top item.
Middle item.
Bottom item.
The :::stack directive overlays children on top of each other.
Combine with fragments to reveal them one at a time.
First layer (visible initially).
Second layer (appears on click).
The :::frame directive adds a default styled border around content.
This paragraph is framed.
Another framed block, separately bordered.
The :::stretch directive makes an element fill the remaining slide space.
This content stretches to fill available vertical space.
A footer line after the stretched content.
The :::class directive pushes one or more CSS classes onto each child block.
Custom-classed text!
The {class} role wraps inline content in a <span> with CSS classes.
This sentence has green highlighted text that appears as a fragment.
The {id} role wraps inline content with an HTML id attribute.
This word is identifiable by its ID.
The {attr} role applies arbitrary HTML attributes to inline content.
This word has a custom data attribute.
This text is styled with custom CSS injected via a css code block.
The {image} role renders an <img> tag with configurable width and height. The path to the image is relative to the source file.
The {leanCommand} role renders a single elaborated Lean command inline.
Here is an inline command: #checkNat.add_comm (n m : Nat) : n + m = m + n Nat.add_commNat.add_comm (n m : Nat) : n + m = m + n
Square
Circle
Star
Navigate down through five table examples.
Column headers and striped rows on a light background.
Type | Size | Signed | Example |
|---|---|---|---|
| Unbounded | No |
|
| Unbounded | Yes |
|
| 64-bit | Yes |
|
Striped columns and row headers on a dark background.
Tactic | Closes? | Rewrites? | New goals? |
|---|---|---|---|
| ✓ | — | — |
| — | — | ✓ |
| — | ✓ | — |
| partial | ✓ | — |
| ✓ | — | — |
Column headers and row separators, no stripes or border.
Transition | Effect |
|---|---|
| Default horizontal motion |
| Cross-fade between slides |
| Angled away from viewer |
| Angled toward viewer |
| Zoom in from center |
| Instant cut |
Row separators and an outer border.
Directive | Arguments | Effect |
|---|---|---|
| — | Speaker notes |
| style, index | Progressive reveal |
| — | Auto-sizes text to fit |
| — | Fills remaining slide height |
| — | Horizontal side-by-side layout |
Striped
(A, B) | A ∧ B | A ∨ B | A → B | A ↔ B |
|---|---|---|---|---|
(T, T) | T | T | T | T |
(T, F) | F | T | F | F |
(F, T) | F | T | T | F |
(F, F) | F | F | T | T |
That concludes the VersoSlides demo.
Questions?