typstage

0.2.0

Animated HTML presentations from a single Typst file, and a PDF handout from the same source. Typst typesets, the browser moves: magic-move morphing, step-by-step reveals, slide transitions, media and a speaker view in the same file.

Giving the talk#

Everything that happens between opening the file and the last slide, including the second window.

The keys#

KeyWhat it does
→ space PageDownone step forward
← PageUpone step back
Home Endto the first or the last step
o Escthe overview, and a click there goes to that slide
ffull screen
?a line with the main keys; the deck’s sound keys stand in the speaker view’s key row
nopen the speaker view, or bring the talk forward
1 to 9, 0the class clock for that many minutes, 0 ends it; on a slide with a cue group the digits call its points
the deck’s sound keysplay their sound in the hall, see “A sound on a key”

A click pages forward, a click in the left quarter pages back. The address bar carries the running step, #12 being the twelfth, so a reloaded window stands in the same place and a number typed by hand jumps there.

In the overview a tile is split. The upper two thirds belong to the slide: a click there goes to its first step. The lower third holds one field per step – hovering shows that step in the thumbnail, clicking goes straight to it. The marks stand there always, not only on hover: whoever wants the start of the slide can see beforehand where not to aim. A slide that reveals nothing has nothing to choose and gets no fields.

A frame that has the focus#

Click an embedded frame and it holds the focus: every key then lands inside it and the talk stops paging. The talk’s own keys are therefore handed back out of the frame, under three conditions – the embedded document has not already taken the key, the key is one the talk uses, and the focused element is not a text field. Otherwise an n typed into a form would open a second window.

Everything else stays with the frame. Delete is the example: it belongs to whatever is embedded, and the talk never sees it.

On a phone or a tablet#

A tap pages, in the same two halves as a click. A swipe pages in the natural direction: the finger pushes the slide out to the left, so the next one comes. Vertical swipes and two fingers are left to the browser: one is scrolling and the other is zooming.

The speaker view#

n opens the same file a second time, with #speaker on the address, in a second window: one for the projector, one for the machine in front of you. The two talk over postMessage, which works between two local files, so no server is needed.

The view is a lectern made of tiles. The running slide stands on top, across the whole width; under it the note, and beside the note the next step; under those a row of four small tiles:

TileWhat stands in it
elapsedthe time since the first keypress, and small below it the time of day
slideslide / slides, below it step / steps, and the progress bar along its foot
target (min)the planned duration – d goes into it –, below it remaining and pace, once one is set
class clockthe clock that stands on the wall in the hall; t starts it
next stepthe preview: what the next keypress does

The seam between the slide and the note is a handle: drag it down for more slide, up for more note. Tab reaches it; the arrow keys then move it by 16 pixels, by 64 with Shift, Home and End take it to the stops, and a double-click or Enter puts it back. A reload keeps the split. A second divider sets the notes/next-slide width ratio independently of slide height. h or the ? button toggles the shortcut bar; speaker-view: (shortcuts: false) hides it initially. Presenter media controls provide playback buttons and timelines for video and audio. A deck without notes has nothing to divide and gets no handle.

Under the tiles the tool row – pen, pointer and eraser, the four colours, undo and clear, light or dark –, and under that the key row with every key of the view, the deck’s sound keys at its end. The state of the hall – black, frozen, no talk window – stands at the top right inside the slide tile.

The keys of the view, which ? also shows inside it:

KeyWhat it does
← →one step; Home End to the first or the last
↑ ↓scroll the note
othe overview
bblack out the hall
efreeze the hall on this step
nbring the talk window forward
1…9that many minutes as a clock on the slide; 0 ends it
tthe class clock, full screen in the hall
⇧tthe same clock, but on the slide instead of over it
⇧← ⇧→one minute less or more, while a clock runs
dthe target duration in minutes
rset the elapsed time back to zero
mswitch between pen and pointer
cthe next drawing colour
ztake back the last stroke
xclear the strokes on this slide
⇧Llight or dark, for the view alone
htoggle the shortcut bar
kpause or resume video and audio
j lseek ten seconds backward or forward
+ -the size of the note
ffull screen
?this table, in the view

What the view should show#

speaker-view cancels what is not wanted, so an unused tile does not take room the note could use:

#show: presentation.with(speaker-view: (
  clock: false,                                  // no class clock
  target: false,                                 // no planned length
  pen: (colors: (red, green, rgb("#FF99DD"))),   // your own pen colours
))

What is not named is on: a deck that says nothing gets the whole view. tools: false takes the drawing bar away.

A tile that is switched off takes its keys with it: with clock: false, t and ⇧t do nothing and no longer stand in the key bar.

The colours are Typst colours, not strings, and there may be more or fewer than four. c steps through them in turn.

Light or dark#

The view follows the system setting of the machine it stands on (prefers-color-scheme), and l contradicts it when the room is not what the operating system thinks. The choice holds for the session and survives a reload.

It is expressly not the deck’s palette: the lectern is a tool and should read the same whatever the room does.

Tip
The preview shows the next step, not the next slide: what the next keypress does, be it a new slide or one more reveal on the current one. The label above it says which.

Drawing#

You draw on the running slide in the speaker view and the strokes appear on the projected one: the presenter has a trackpad in front of them, and the canvas is across the room.

Strokes stick to their slide, so paging away and back brings them with you. x clears the current slide, z takes back the last stroke, c changes colour.

A clock the class can see#

t asks for a number of minutes, and the wall then carries nothing but a clock: black ground, white digits, mm:ss, large enough to read from the back row. It replaces the slide rather than sitting on it – the twin of b, only with something on it. It is meant for the break, the group work, the experiment being set up.

KeyWhat it does
task for minutes; Enter starts it, Esc leaves it
t (while it runs)end the clock, the slide is back
⇧→, ⇧←one minute more or less, while it runs as well
→ (or any other paging key)ends it and uncovers the slide

In the speaker view it has a tile of its own, class clock, beside the tile target (min). The two do not look alike: the target duration is a field of whole minutes you set once per talk, the class clock a running m:ss with a bar that empties. While none runs a dash stands there, and while no talk window answers a longer one.

At zero it does not stop but carries on to +00:01 in the deck’s accent colour, with the word “over” above it. Nothing blinks and nothing chimes. The overtime is capped at the duration itself and at thirty minutes. At the lectern the whole tile turns over at the same moment, in the warning colour, so that the teacher sees the overtime no later than the class does.

Careful
t when nothing else is on the wall. No clock while you are talking: a clock running beside a sentence pulls the eye for the whole talk. It is therefore not laid over the slide but replaces it, and whoever goes on talking presses it away.
Note
Like black and freeze, the clock lifts on its own if the speaker window goes away; the talk window has no key against it. Reload the talk window and the clock comes back – further along, not from the start.

The pointer#

m switches between the pen and the pointer. What the pointer does is point: move the mouse across the slide copy in the speaker view and a lit dot appears at the same spot on the wall. Hovering is enough – no button, no key. The dot carries the accent colour at 2.2% of the slide width, and it travels as a fraction of the stage, so the small window in front of you and the large canvas behind you agree on where it is.

It goes out when you leave the slide copy, when the window loses focus, when you reach for the pen, and on a change of slide. It survives a change of step: whoever points at a term and uncovers the next line means the same term still. Letting go of the button parks it where it stands – a dot left standing is an intention, not an oversight, and one keypress away from gone.

Note
What the dot does not do is leave a trail. Whatever should stay on the slide belongs to the pen, which is exactly one keypress away.

The same mode has a second ability, and it is the older one: a press on an embedded frame lands in the talk window’s copy of that frame instead of on the slide. Press, drag, release and wheel travel as fractions of the stage, so both windows hit the same point of the document. Hovering does not reach into a frame – pointing at something is not operating it – and the dot stands on the frame while you do, which is deliberate: the class should see where the hand is about to land.

Where the embedded document can mirror itself, as a GeoGebra applet does, the live one in front of you is operated instead and the projected copy follows. The dot stays out over such a frame: it takes the pointer for itself, and the stage never sees the movement.

Careful
It reaches listeners, not the browser’s own widgets. A checkbox toggles and a button fires, because a click carries its activation behaviour along; an input type=range does not move, because a browser only drags its own slider for input it trusts. Whoever builds for this listens rather than relying on a native control.

Blacking out and freezing#

b blacks the room out, e freezes the projected image while you page ahead in private. Steering works from either window, and either one may be reloaded: they find each other again, and the strokes come back.

Careful
Both lift by themselves shortly after the speaker window is closed. If that window stays open but no longer carries a deck, a one-minute deadline applies instead – and a stalling talk window on top of that can put it off indefinitely. That is the one known corner in which the room stays dark.

The speaker view opens on one keypress, and a real keypress is the condition: window.open without a user gesture falls to the popup blocker.

Less motion#

Someone who has turned on “reduce motion” in their operating system gets a quieter deck. The runtime asks for prefers-reduced-motion: reduce afresh on every step and every frame, so switching it on in the middle of a talk takes effect at the next keypress. There is nothing to configure.

The setting says “less motion”, not “no motion”: opacity stays, travel goes. An entrance still says “this is new”, but nothing crosses the slide any more.

WhatWhat becomes of it
EntrancesEvery effect keeps its opacity and loses its travel: fade-up, fade-down, fade-left, fade-right, scale, scale-down, rise and blur become a plain cross-fade. fade and none are left as they are. duration and delay do not change.
enter: "draw"The pen holds still, the fade remains. The drawing is the travel, and what is left when it is taken out is exactly the cross-fade that ran underneath it anyway.
Slide transitionsEvery kind but none becomes the cross-fade, over the same transition-duration. none stays the hard cut.
Magic moveDoes not happen. Nothing flies, and the slide changes the way it would change without a morph.
Flip bookStands still on one frame. Without loop and without pingpong that is the last one, where it would have come to rest anyway; only the way there falls away. With loop or pingpong it is frame zero. still does not apply: the frame for paper is typeset content and is not in the HTML at all, which carries only the frames themselves.
sceneJumps from stop to stop. The frames in between still sit in the file, but none of them is shown. What falls away is exactly the travel; the stops themselves are not travel, they are the content.
after: "dimmed"Stays. A point stepping back changes its opacity and does not move.
The progress bar in the speaker viewJumps to its new width instead of gliding there.

Two things are deliberately left alone.

Video. A video is content, not decoration. Whoever does not want it to start by itself writes autoplay: false.

Embedded documents. The runtime does not reach into a foreign document. The setting does: matchMedia("(prefers-reduced-motion: reduce)").matches is true inside the frame as well, so anyone animating something there writes their own @media rule.

Note
No switch lets a deck overrule the setting. Where a motion really carries the argument, it belongs in words as well – and those are read by the people who never see it run.