A slide is a frame, and the frame can carry more than a column of text.
Slide Decoration
What a slide can carry besides a column of text
Dominik Herrmann
Otto-Friedrich-Universität Bamberg
A slide is a frame, and the frame can carry more than a column of text.
What a slide can carry besides a column of text
Dominik Herrmann
Otto-Friedrich-Universität Bamberg
The ways psi-slides can decorate a slide, each one used on the slide that describes it – and, in the last part, the settings for the type and the colours of a whole lecture.
Each slide in this lecture uses the construct it describes, so its chunk in
source.md is a working example of that construct. Find the heading you see
on the slide in the source, and the lines under it are what drew the slide.
Build the lecture with --watch and change one of those lines: the open
views reload on every save, which is the quickest way to learn what a word in
a card row's braces or a backdrop's reveal does.
All ten covers are in the gallery, each shot from a real build. This deck wears
quote.
cover: in the frontmatter picks one of the ten below, ordered from the
quietest opening slide to the loudest.
A name and a sentence carry the idea; they do not carry the shape it makes. Each of the ten is shot from a real build in the gallery.
cover-image: names the picture, and four of the ten draw one: split,
hero, beside and above. On the last two it is only the fallback – they
take whatever you write under the ## title: heading, so a ::: draw can be
the cover.
cover-ratio: is how much of the slide the picture takes, as a percentage
between 15 and 75. Only the three that divide the slide read it – split,
beside and above. A percentage and not a W:H ratio: the shape of the
frame comes from the projector, and this splits it.
cover-align: puts the block of text at the top, the middle or the
bottom. The seven compositions that leave the block any freedom read it.
cover-ground: is paper or ink: ink opens a light deck on a dark
slide with no photograph behind it. A backdrop's own scrim wins over it.
Set cover-ratio: or cover-align: on a composition that has already settled
the question and the build stops with an error rather than ignoring the line.
closing-image: is the closing slide's counterpart of cover-image: – see the
closing slide below.
quote draws no quotation markA sentence set alone on a slide with a name under it already reads as a quotation, so there is no mark: no hanging curly quote, no glyph behind the words, no rule beside them.
The claim is what you write under the ## title: heading. A quote cover
without one fails the build.
subtitle: says what the talk is about. Under it, the credit block sets who gives the talk, from where, and how to reach them, in four ranks of type.
title: How Caches Forget
subtitle: Eviction, Staleness and the Cost of Being Wrong
presenter: Jana Wieland
affiliation: Otto-Friedrich-Universität Bamberg
contact: uni.example/ds
notice: Slides go up on Friday.
info: |
Distributed Systems · Lecture 7 · Room WE5/00.019
presenter:your name, set apart from everything under itaffiliation:the institution, quieter, directly beneath the namecontact: / notice:one row along the foot – the address flush left, the notice flush right and in italicsThe presenter and the institution introduce the speaker; the address and the notice answer what the audience will ask afterwards, so the two share one row at the foot. info: keeps the date, the room and the course line, as many lines as you give it.
## closing: draws the last slide in whatever composition cover: names,
so the lecture ends in the shape it opened with.
What it carries is different: your own heading, sub-heading and text. The
presenter line and the info block stay off it by default, because the audience
has known since the first slide who is talking and where. closing-credits: contact brings
back the row along the foot – this lecture sets it, so its last slide carries the
address – and cover brings back the whole credit block. closing-image: cover
ends the deck on the picture it opened with; any other value names a different
one.
A divider says that a new part starts here, and that the part belongs to the lecture already under way. All six are quieter than the cover, so none of them can be mistaken for the title slide.
The six are in the same gallery as the covers, under the same rule: a lecture picks one and wears it at every part.
The agenda says which part starts, out of how many, and how far into the lecture you are. The audience sees the same list at every divider and learns the shape of the lecture from it.
That only works while the list stays the same from divider to divider, so the heading is the live item in the list rather than a second copy set beside it.
The live part is set larger and in full ink; the parts before and after it recede. What carries progress is where the live item sits as it walks down the list, so the recession only has to say not this one. The live part is a size and not a third shade: two greys read from the back of a room, three do not.
section-mark: puts a short word over the heading. This lecture writes Part.
Write nothing and nothing is drawn there.
# heading are the divider's slideWhatever you write between a # Heading and the first ## heading under it
becomes the divider's slide. Ordinary markdown is the words, a
::: backdrop is the picture, a ::: draw is the figure.
{.stack}, under it.
Parts 3 and 7 doThose three are what a divider takes; the other directives belong inside a
## slide. The words do print, as a short paragraph under the part title. The
divider slide itself never prints.
A > note: written there is the divider's own: the cockpit shows it while
the divider is on screen, and print-notes.html prints it under the part
title.
When a divider's body is nothing but a figure, the figure goes beside the heading – stacked, a part title, an agenda and a drawing are three blocks down one axis with nothing across it.
Prose under a heading is an opening paragraph and stays stacked, which is how the quotation divider in Part 1 comes out.
# Heading {.stack} puts the content under the heading at the full measure
and sets the heading above it, a step smaller than on a plain divider. Beside the heading a
figure gets about half the frame, which is right for a drawing that balances a
part title and unreadable for one with six cells and a label in each. Part 7's
divider wears it; Part 3's is the other layout.
The class goes on the one heading, because it concerns one divider's content;
section: sets how every divider looks. A {.stack} over a divider with nothing under its heading
is refused.
::: cards makes boxes, not columns::: cards 3 puts three boxes side by side, and an item is whole or it is
nowhere. ::: cols 3 is the other thing: one flow of text the browser
balances across three columns, so a paragraph can spill from the foot of one
into the head of the next. Use cards for three things, columns for one long
argument.
How you open a card decides what the bold does, and the two below are written the two ways:
The ground word says what is behind the text, and a row wears one at a time:
these two are set to accent and to the default panel, whatever their cards
say. outline is on the slide before this one, and corner is a separate
question.
::: cards 3 {.outline .middle}::: rows, which has a body to line a term up withThat row is ::: cards 3 {.outline .middle}, so its tail answers two questions at once: ground, and anchor – where the text sits in a card taller than its content. A row is as tall as its longest card, so every other card in it is taller than what it holds.
size: auto counts the words in the longest card: three or fewer sets the
row large, twelve or fewer medium, more than twelve small. One size for the
whole row, never one per card.
Alignment then follows the size, a single word centring and a sentence ranging
left. A row that carries a second level ranges left whatever its heads measure,
so the heads do not jump when the reader presses C.
detail: fold is the default, so the levels under the first are in the
printed hand-out and off the projection, and C switches between the two. This
deck opens with everything showing, because its frontmatter says
collapse: none; press C once here and the second level folds away.
C switches::: rows turns a card row on its sideA term in a small card on the left, its explanation beside it, several
stacked. It takes the same words in braces as ::: cards, the same automatic
size, the same fold and the same print rules. Only the arrangement of an item
differs.
Every term gets the same column width, so the explanations line up down the slide however long the terms are.
The explanation is optional – a term written on its own is a labelled row with nothing beside it, which is what an agenda or a list of names wants.
It takes no count, a row block having one column by definition, and it takes every word a card row takes. Three defaults differ: anchor follows the ground, align says how the term sits in its card while the explanation ranges left, and the automatic size stops at medium, a term being a label in a column rather than a headline across the slide.
A row block adds one anchor word, baseline, and picks between two by ground. On a fill the term is a visible slab, and a one-line slab against a three-line explanation's first line reads as a mistake, so a grounded row centres it. Under {.clear} there is no slab and no padding, so the term is bare words in a column, and those read best on the baseline, as a hanging indent. {.baseline} on a ::: cards block is an error: a card has nothing beside it to line up with.
Use rows when a term needs a sentence, and cards when a comparison needs counting.
::: side takes a ratio::: side 2:1 splits the slide into two panes, two parts to one. Write
::: side on its own for equal panes, and ::: flip between them to start the
second one. Any two numbers work.
On paper the panes stack one after the other and the ratio is ignored.
::: side 2:1 {.middle}This slide is ::: side 2:1 {.middle}: two parts of prose to one part figure, which is the shape a diagram with its commentary usually wants. The drawing is a ::: draw block inside the second pane.
A short pane sits at the top of its half unless you say otherwise, and {.middle} centres it against the taller one. Here the figure is the short pane, so {.middle} is what puts it level with the middle of this column instead of at the top. {.top} is the default and often right – a caption over a figure should be aligned from the top. The word belongs to the block and not to either pane, because the taller pane is what makes the row tall, so centring can only move the shorter one.
A figure above or below the text needs nothing – put the block first or last in the chunk body. ::: cols is the one place a figure does not belong: the columns are one run of text, and a figure breaks it. A ::: draw written there is refused, and the message points you at ::: side.
::: backdrop dusk {.cover} reveal full, right 52% gives the picture one
place per beat – one press of Space – and the last place stays. Two moves come
out of it: a picture that retreats to free the space the words need, and one
that grows over the words and covers them.
What moves is the window, not the picture. The photograph is painted across the whole slide either way and the frame opens and closes over it, so nothing zooms or slides about while it is being revealed.
from holds an overlay back until a beat::: overlay {…} from 1 keeps the block off the slide until the first press
of Space. One number, not a list: an overlay is either on the slide or it is
not, where the backdrop's list says where the picture is at each beat.
An overlay and a reveal segment both fade in, and neither moves anything: the
segment has its box in the text from the first beat, and the overlay has its
cell over the picture. What from adds is the number – a segment takes the
next beat in order unless it is written --- from N, where an overlay says
which beat it waits for and nothing else can reach it first.
Five groups of words go in the braces after ::: backdrop, at most one from
each, and the first of every group is the default.
covercontainmiddletopbottomveilclearinvertsharpblurunderoverveil puts the theme's own page colour over the picture, not white, so
ordinary text stays readable on a photograph in all seven themes. invert
darkens the picture and turns the text light instead, which is what the divider
at the start of Part 2 does.
Nine places, five backgrounds, four widths, two shapes. Aim two overlays
at the same corner and they stack rather than landing on top of each other.
A panel is the card grown to the frame – the next part shows the three
compositions – and third / half are a band's height.
center and the eight compass pointspaperinkaccentclearglassnarrowstandardwidefullcardpanel (an edge or center, never a corner)snugthirdhalf (bands only)An overlay lies over the slide; a dock takes its room from it. The list on
the left is one ::: dock {.left .every} written under this part's # heading,
and every chunk of the part carries it. The entry for the slide on screen lights
up, because each entry is a link to a chunk's {#id}.
Four edges, six grounds, three widths. A left or right dock is a
column the full height of the slide and the text column narrows beside it; a
top or bottom dock is a band across the whole width and the text sits above or
below it. A chunk that writes its own ::: dock replaces the inherited one for
that slide.
A .wide chunk keeps ::: cols 2 beside the inherited dock. The chunk
reserves the dock's track as padding, so the content column is what the
slide leaves – and the linter says when that falls under the measure
(dock-narrows-measure) or under what a column needs (layout-too-narrow).
The dock's ground is tint by default: the card row's panel tint, five per
cent of the ink on the paper, which is what gives a column on the slide's own
paper an edge. paper has none there and stays a choice for a dock over a
picture; ink is the loud version.
The dock's type is the overlay's, 0.92 of the slide's and zoomed with it, but its track is a share of the frame, so the list stays in place from slide to slide.
This chunk writes ::: dock {.bottom .accent .third} of its own, so the
part's list steps aside for one slide and a band a third of the slide high
carries the line under the words.
::: dock {.top .accent} is a line above the words, as wide as the slide
and as tall as its own text. The slide number and the note button, which live
at the head, move to the foot under it.
from 2 holds this remark back until the second beat. The text column
has been narrow from the start, so nothing moves when the dock slides in – the
same rule an overlay card follows.
The first beat shows this line.
The second brings the dock.
Four edges, six grounds, three widths, three heights, two scopes. One
dock per slide; a #id link in the body is the live marker.
leftrighttopbottomtintpaperinkaccentclearglassnarrowstandardwidesnugthirdhalf (bands only)onceevery (under a # heading only)A --- inside a pane, a card row or a dock is a beat on the slide's own
counter. Left one, left two, right one, right two, then the card row, then
its third card – the order they were written in, top-level and nested mixed.
Left one. A nested beat keeps its box: the pane stands at its final height from the first press.
Left two. So nothing above or beside it moves when it arrives.
Right one. The right pane waited for the third beat, because its first line
is a ---.
Right two. The fourth.
A --- between two rows shows the second on the next press, and the
first does not move: the block is laid out with both rows from beat 0.
{.bare} gives up the projection and nothing else{.bare} keeps a heading out of the projection and leaves it everywhere
else. Writing no heading would cost the slide, the printed document and
the search index together; a talk that is a run of figures with speaker notes
usually wants to lose only the first.
So ## figure: How a crawl is scored {.full #id .bare} prints the heading,
indexes it, and draws nothing on screen. style: {headings: off} says the same
for a whole deck. Press / and search for measurement loop: it matches this
slide and the next one, and the next one carries no heading on screen.
The two revealed photographs in Part 4 are the case the class was written for: each is a picture and a speaker note, each would have read wrong with a line of type above it, and each is still a row in the search index.
{.bare .bleed} hands the whole frame to one figureThe settings in this part are written once, in the frontmatter, and change
every slide of a lecture together: the style: block, and the typefaces the
four views carry. This lecture sets none of them, so its slides show the
settings in YAML rather than wearing them.
style: blockThe style: block holds the settings you make once for a whole lecture.
style:
headings: left # auto | left | center | off
rules: off # on | off – the hairline over a principle
labels: off # on | off – the type word over a chunk
link-codes: off # on | off – the mark after an external link
blocks: left # center | left – a code block, a figure, a formula
wrap: none # balance | none – even line lengths
print-body: sans # serif | sans – the printed document's face
neutrals: tinted # neutral | tinted | warm | cool – the greys
print-neutrals: warm # the same four, for the printed pages
headline: eyebrow # stacked | eyebrow – the title pair
caps: on # off | on – small type round a title
bold: accent-bold # plain | bold | italic | accent |
print-bold: italic # accent-bold | accent-italic – live, then paper
code: tint # plain | tint | spaced – code inside a sentence
heading-scale: 1.15 # with body-scale, bounded to 0.6 … 1.8
headings: auto is the default: the chunk type decides, so a figure's caption sits over its artwork. left overrides that for one line of alignment down the lecture; off takes headings off the projection and keeps them in print, the contents list and search.
wrap, blocks, print-body, the bold pair and the scaleswrap applies to headings and prose both, which its name does not say: balance evens the line lengths of a heading and protects the last line of a paragraph, and none turns both off. blocks and wrap are the two keys a single chunk can answer for itself, with {.blocks-left} and {.wrap-none} in its attribute tail.
print-body sets the face of the printed pages. In the live views the face is picked with F; the printed pages have no such key, so sans is how you ask for a document set in the sans. Code stays in the monospace, and so does everything the document already draws in the sans – the type word, a caption, the contents list.
bold and print-bold set how a bold phrase looks, and plain is a legal answer: the bold marks a phrase for the slide, and its weight is only one possible look. Live the default is plain, so a promoted bullet is set like the sentence above it; on paper it is bold, in the ink. accent-bold in both gives the accent-coloured bold of psi-slides 1.0. A word stressed with *em* inside the phrase is bold and in the accent whatever the key says – except under accent-bold, where it stays italic.
The two scales multiply the tool's own sizes rather than replacing them, and they are bounded to 0.6–1.8: outside that, the shortened view, the width limit on a line of code and the automatic zoom disagree.
style: {code: …}A space in a monospaced face is about twice as wide as the word space around it, so a span like async def opens a hole in its middle and reads as three words where you wrote two. A single token like await has no inner gap to go wrong.
spacedthe default: the gaps around a multi-word span are widened a hair and the ones inside it pulled in. A single token is left alonetinta quiet ground behind every span, padded left and right onlyplainthe mono face at a flat 0.92em and nothing else, as psi-slides 1.0 drew itBoth of the first two also size the code to the x-height of the face around it, so a lecture that changes its serif changes this with it. A face you supplied yourself carries no measurement; the build says so and leaves the size alone.
neutrals, and its counterpart for the pageIn the four light themes, A moves only the accent. The ink stays on a cool hue, and every tinted surface – a card, a dock, an overlay card – is mixed out of that ink, so a card under a warm accent is a cool grey under a warm word.
neutralthe default: the greys stay on the ink's cool huetintedthe greys take the accent's own hue, so the slide reads as one palette whichever accent is onwarm / coola fixed hue, the accent notwithstandingprint-neutrals asks the same question for the two printed views, and it is a second key because the printed page is warm already where the projection is not. Leave it out and it follows neutrals.
headline, and caps beside itA cover carries a pair of lines, and so do a divider and a closing slide – title: and subtitle: in the frontmatter, Heading | Sub in a chunk heading. headline says which of the two is set large.
style:
headline: eyebrow # stacked | eyebrow
caps: on # off | on
stacked is the default: the title large, the subtitle quieter under it. eyebrow turns it over, so the title sits small above a subtitle that carries the weight – the shape a lecture title takes when the first line names the field and the second asks the question.
The words stay where they are and only their type changes, so one key serves the cover, the dividers and the closing slide. Keep the lecture's own name in title:, which is also the browser tab, the contents entry and what search reads.
caps sets the small type round a title in capitals: the eyebrow, the presenter, the affiliation, never the headline. The tracking is not a second setting – the build spaces out any line already in capitals, including one you typed that way.
style: {labels: off}The type word above a chunk is drawn in two places, and one setting takes it out of both.
print.html and print-notes.html set a small line of capitals over every typed chunk. Every type but free, figure and statement has one, so that is where most of them are.style:
labels: off
rules is the neighbouring key and switches the lines – the bar above a principle, the hairline above a definition. labels switches the words.
A figure's heading, set in capitals, is your own text and needs no key. It is the chunk's heading, drawn that way because the type is figure, so ## figure: {.wide #id} with no heading text leaves it off the slide. The cost is that the chunk then has no text for search to find and no heading in print.html. (The contents list is unaffected – T lists the lecture's columns, never its chunks.)
Three families are embedded in any one file, and you pick which three. Nine come with the tool, so naming one of those needs no font file at all. A fourth role, display, is optional: fonts: {display: Anton} names one of 32 more faces for the cover, the closing slide and the section dividers, and nothing else in the lecture wears it.
fonts:
serif: Bitter # or Literata, the default; also Source
# Serif 4, Noto Serif, Roboto Serif
sans: Inter Tight # or IBM Plex Sans, the default
mono: Noto Sans Mono Condensed # or JetBrains Mono, the default
Only the three a lecture actually asks for are read, so choosing an alternative costs that lecture and no other. A name that is neither one of the nine nor a file in fonts/ stops the build, and the message lists the names available for that role.
Among the serifs, Bitter has the lowest stroke contrast, which keeps it legible in a lit room, and the smallest file; Roboto Serif has the strongest bold but sets 8% wider, so it re-wraps a deck written against another face.
The typefaces page sets all nine on a slide and on a printed page, in any pairing you pick.
ligatures:The condensed monospace is 17% narrower – 0.50 em against 0.60 em per character, measured in a browser – so a line of code can run a fifth longer before it reaches the slide's edge. It is Noto Sans Mono with its width axis pinned rather than a different typeface, so it costs 54 KB. Slashed zero, and I, l and 1 are three visibly different shapes.
ligatures: decides whether letter pairs are drawn joined, and answers separately for prose and for code. text is the default: fi and fl joined up in prose, nothing joined in code. none takes them out of prose as well. all puts the code ones back, so JetBrains Mono draws -> as a single arrow. The code ones are off by default because in the figure language -> and -- are two different arrows, and every listing on a slide is source somebody may retype.
fonts/ beside source.md, plus a frontmatter blockA typeface that is not embedded in the file may be missing on the lecture-hall machine. Safari does not tell a page which fonts a machine has, so a lecture that merely names one takes whatever that browser decides instead. The three a lecture carries are embedded in every output it writes, cost about 280 KB per file, and fonts: none leaves them out; the bundled three are under the SIL Open Font License, which permits exactly this.
Each of the three text roles is answered on its own, so you can replace one and leave the others alone. Put your files in a fonts/ folder beside source.md:
fonts:
serif: Vollkorn # yours – the files are in fonts/
mono: JetBrains Mono # one of the nine that ship, so no file
# sans: not written, so it stays the default
A file's name says which weight and style it is: Vollkorn-Regular.woff2, then -Bold, -Italic, -BoldItalic, -600, -600italic – or one file, Vollkorn[wght].woff2, carrying every weight. A family that is neither one of the nine nor a file in fonts/ stops the build.
Putting a font inside the file redistributes it, so check the licence first. The SIL Open Font License and Apache-2.0 – between them nearly all of Google Fonts – allow that; most commercial desktop licences do not, and want a separate web licence. The build prints a reminder and checks nothing.
and the frame can carry more than a column of text
All ten covers and all six dividers are shot from real builds in the
gallery; the
psi-slides-decoration skill has the vocabulary of each.