Die erste Präsentation#
Ziel dieses Kapitels: eine vollständige, vorführbare Präsentation, ohne Umwege.
Eine Datei genügt#
Mehr braucht es nicht als Import, Show-Regel und Überschriften. Diese Datei ist vollständig und lässt sich abtippen:
#import "@preview/typstage:0.2.0": *
#show: presentation.with(
title: [Der Satz des Pythagoras],
subtitle: [Eine Herleitung in vier Schritten],
author: [Mathematik · Klasse 9],
date: datetime.today(),
transition: "slide",
)
= Worum es geht
== Die Behauptung
#speaker-note[Erst die Zerlegung zeigen, dann die Formel -- nicht umgekehrt.]
#stagger[
- Ein rechtwinkliges Dreieck hat zwei Katheten und eine Hypotenuse.
- Über jeder Seite steht ein Quadrat.
- Die beiden kleinen sind zusammen so groß wie das große.
]
#v(1em)
#anim(callout[Genau das behauptet der Satz.], enter: "scale")
== Und das ist die Formel
#statement[$ a^2 + b^2 = c^2 $]Daraus entstehen vier Folien: die Titelfolie aus title, eine Abschnittsfolie aus =, und je eine gewöhnliche Folie aus den beiden ==. Der Text bis zur nächsten Überschrift ist der Rumpf einer Folie.
So sieht der Rumpf der Folie „Die Behauptung“ aus, wenn alle Schritte abgelaufen sind:
#stagger[
- Ein rechtwinkliges Dreieck hat zwei Katheten und eine Hypotenuse.
- Über jeder Seite steht ein Quadrat.
- Die beiden kleinen sind zusammen so groß wie das große.
]
#v(1em)
#anim(callout[Genau das behauptet der Satz.], enter: "scale")Im Browser erscheinen die drei Punkte nacheinander, der Merksatz auf dem vierten Tastendruck.
Zweimal übersetzen#
Dieselbe Datei ergibt zwei Ausgaben, ohne Nachbearbeitung dazwischen.
typst compile vortrag.typ vortrag.html --format html --features html
typst compile vortrag.typ vortrag.pdfDie erste Zeile ergibt die animierte Präsentation als eine einzige Datei, die ein Doppelklick öffnet – ohne Server und ohne Netz. Die zweite ergibt den Foliensatz zum Ausdrucken.
--features html. Die Warnung, die Typst dabei ausgibt, betrifft den Export im Allgemeinen, nicht dieses Paket.#set heading nach der Show-Regel erreicht die Folientitel nicht mehr – dafür gibt es style, siehe „Das eigene Aussehen„.Während du schreibst#
Die beiden Zeilen oben übersetzen einmal. Solange ein Deck noch entsteht, nimmt typst watch das ab: Es übersetzt bei jedem Speichern neu, und beim HTML-Export bringt es einen kleinen Server mit und hängt eine Zeile in die ausgelieferte Seite, mit der der Browser sich selbst neu lädt.
typst watch vortrag.typ vortrag.html --format html --features html --port 3000http://127.0.0.1:3000 einmal öffnen und den Tab stehen lassen. Ein Deck aus achtundzwanzig Folien – vier Megabyte HTML – ist rund siebzig Millisekunden nach dem Speichern wieder da, und zwar auf dem Schritt, auf dem es stand: Der Schritt steht in der Adresse, und das Deck liest ihn beim Laden.
--port darf fehlen; Typst nimmt dann den ersten freien Port zwischen 3000 und 3005 und schreibt ihn hin. Ihn zu nennen hält die Adresse jedes Mal gleich, und ein zweiter Lauf auf demselben Port sagt port 3000 is already in use, statt still woanders zu bedienen.--no-serve und --no-reload schalten beides einzeln ab.In VS Code ist das ein Tastendruck. Das Folgende in .vscode/tasks.json, und das Kürzel für den Build-Task – Umschalt+Cmd+B unter macOS, sonst Strg+Umschalt+B – startet den Lauf für die Datei, die gerade vorne liegt; Fehler landen in der Problemliste mit einer Zeile zum Anklicken.
{
"version": "2.0.0",
"tasks": [{
"label": "Deck live",
"type": "shell",
"command": "typst",
"args": ["watch", "${file}",
"${fileDirname}/${fileBasenameNoExtension}.html",
"--format", "html", "--features", "html",
"--root", "${workspaceFolder}", "--port", "3000"],
"isBackground": true,
"group": { "kind": "build", "isDefault": true },
"problemMatcher": {
"owner": "typst",
"pattern": [
{ "regexp": "^(error|warning): (.*)$", "severity": 1, "message": 2 },
{ "regexp": "^\\s*┌─ (.+):(\\d+):(\\d+)\\s*$",
"file": 1, "line": 2, "column": 3 }
],
"background": {
"activeOnStart": true,
"beginsPattern": "compiling \\.\\.\\.",
"endsPattern": "(compiled |is already in use)"
}
}
}]
}Mehr als zwei Ebenen#
Die Vorgabe schneidet das Deck an der zweiten Ebene: = wird eine Abschnittsfolie, == eine Folie. slide-level verschiebt diesen Schnitt. Eine Überschrift über der Ebene wird zur Abschnittsfolie, eine Überschrift auf ihr oder darunter wird zur Folie.
#show: presentation.with(title: [Analysis I], slide-level: 3)
= Teil I -- Grenzwerte
== Folgen
=== Was eine Folge ist
Eine Abbildung von den natürlichen in die reellen Zahlen.
=== Konvergenz
Für jedes Epsilon gibt es ein N.
== Reihen
=== Partialsummen
Die Summe der ersten n Glieder.Aus = Teil I und == Folgen werden Abschnittsfolien, aus jedem === eine Folie. Die Trennfolien für beide Ebenen fallen von selbst an. slide-level: 1 macht jede Überschrift zu einer Folie; das Deck hat dann keine Struktur-Ebene mehr.
Auch eine Überschrift als Funktionsaufruf zählt nach ihrer Ebene, #heading(level: 3)[…] wie === und #heading[…] ohne Ebene wie =. Eine Zwischenüberschrift, die im Rumpf bleibt und keine Folie beginnt, steht in einem Block: #block(heading(level: 3)[…]).
Die fünf mitgelieferten Themes zeichnen eine tiefere Ebene ruhiger: der Titel wird kleiner, und darüber steht, worunter der Abschnitt hängt. Ein eigenes Theme liest dafür s.depth und s.parents und darf beide übergehen.
Was das Deck über seine Gliederung weiß, steht in info(): section ist die Ebene direkt über der Folie, levels hat einen Eintrag je Struktur-Ebene, und outline ist die ganze Gliederung.
Text, der zu keiner Folie gehört#
Eine Abschnittsfolie ist ein ganzes Bild, das das Theme zeichnet; sie hat keinen Rumpf. Text zwischen ihrer Überschrift und der nächsten bricht das Übersetzen deshalb ab. Ein Satz zwischen = Der Beweis und == Die Zerlegung meldet content between the heading "Der Beweis" and the next one belongs to no:
slide
#show: presentation.with()
= Der Beweis
Dieser Satz gehört zu keiner Folie und hält das Übersetzen an.
== Die ZerlegungEr gehört unter die Folienüberschrift:
#show: presentation.with()
= Der Beweis
== Die Zerlegung
Dieser Satz gehört zur Folie und wird gesetzt.Zweierlei schränkt die Prüfung ein: Text vor der ersten Überschrift wird nur abgewiesen, wenn das Deck überhaupt eine Überschrift hat. Und geprüft wird nur in der Überschriften-Schreibweise; wer Folien als Argumente übergibt, schreibt jeden Rumpf ohnehin selbst hin.
Wenn die Folien berechnet werden#
Auch Überschriften, die erst beim Setzen entstehen, werden zu Folien. Eine Schleife über eine Liste ergibt so eine Folie je Eintrag:
#for stoff in ("Wasser", "Luft", "Erde") [
== #stoff
Etwas über #stoff.
]Wo die Folien vollständig aus Daten entstehen, lassen sie sich auch einzeln übergeben. Dann ist jede Folie ein Funktionsaufruf, und eine Liste von Folien lässt sich mit .. weiterreichen wie jedes andere Array:
#presentation(
title-slide(title: [Der Satz des Pythagoras], author: [A. Schulz]),
section[Der Beweis],
slide([Die Zerlegung], note: [Zuerst das Quadrat zeigen.])[
Der Text der Folie.
],
)Beide Schreibweisen ergeben dieselbe Ausgabe; presentation erkennt an dem, was es bekommt, welche gemeint ist. Die Form mit Überschriften ist der Normalfall.