Slides

The contents below link to each definition. Function entries show the signature, then a description, then the parameters with their types and defaults; variable entries show the declared type.

Creates one logical slide command.

slide(
  layout: auto,
  numbered: auto,
  invert: false,
  cells: (:),
  background: auto,
  foreground: auto,
  ..bodies
) -> content
Description

A logical slide is one unit of content, which may render as several physical frames once incremental steps are applied.

#mosaic.slide[
  == Structure
  Every slide resolves to a grid tree.
]

Choosing a layout

The selection is the one positional subject, so slide("content", variant: "body")[...] and slide(layout: "content", variant: "body")[...] are the same slide.

Supplying content

Use one of the two forms, never both on the same slide:

#mosaic.slide(cells: (
  header: [== Named cells],
  body: [Order does not matter here.],
))

Planes

background: and foreground: are full-slide layers rather than grid cells, so they have parameters of their own. auto inherits the plane declared on setup, none suppresses it for this slide, and content overrides it.

#mosaic.slide(
  cells: (body: [Over a photograph.]),
  background: mosaic.components.image("cover.webp"),
)

Layout fields

Any other named argument is a field of the selected layout, so the slide refines the configured layout rather than replacing it, and fields the theme set survive:

#mosaic.slide(layout: "title", variant: "academic")

This requires layout: auto or a layout name. With an explicit mosaic.layouts.* value the constructor is already at hand, so pass the fields to it instead.

Arguments
layoutauto | str | dictionary
Which layout resolves this slide: auto for the configured content layout, one of the names "content", "title", "section", or "image", a mosaic.layouts.* value, or a raw mosaic.grids.* tree. Also accepted as the leading positional argument.
numberedauto | bool
Whether the slide contributes to logical slide numbering. auto numbers every layout except title and section, which are deck chrome; an explicit boolean always wins.
invertbool
Whether to invert this slide’s polarity: the slide ground takes the deck’s text color, type is knocked out in the canvas color, and the muted and line colors are derived to match. Works with any layout, so an inverted title, section plate, or big-number slide are all one flag. Cell text and components follow the inverted palette, including fills a theme pins on <mosaic-cell-*> labels; colors applied inside the content itself, such as an explicit text(fill: ..), keep their own values.
cellsdictionary
Cell bodies keyed by cell id. Mutually exclusive with positional bodies.
backgroundauto | content | none
Full-slide layer drawn behind the grid. auto inherits the deck background from setup, none suppresses it.
foregroundauto | content | none
Full-slide layer drawn over the grid. auto inherits the deck foreground from setup, none suppresses it.
..bodiesarguments
Positional cell bodies in depth-first layout order, plus any named arguments forwarded as fields of the selected layout.

Reads what the deck knows about itself: the metadata declared on setup, and the position of the slide being rendered. This is what a custom composition reads instead of restating the deck, and what deck chrome reads instead of counting for itself.

info() -> dictionary
Description

Returns a dictionary with six fields. Four are the deck metadata, exactly as setup received it:

Two are the position of the slide being rendered, which is what makes the reader contextual:

Call it inside a context block (slide bodies, planes, and show rules already are one):

#mosaic.slide(
  background: mosaic.components.image("cover.webp", scrim: black.transparentize(45%)),
)[
  #context {
    let deck = mosaic.info()
    place(top + left, text(size: 2.2em, weight: "bold", deck.title))
    place(bottom + left, deck.authors.map(author => author.name).join([, ]))
  }
]

The metadata half is the escape hatch for title pages the built-in variants do not draw: declare the information once on setup, and a hand-built cover reads it back instead of duplicating it. The position half is what a footline or a headline is made of, and it is the same reading components.progress does, so a theme drawing its own chrome keeps no counters of its own:

#let footline = context {
  let deck = mosaic.info()
  grid(
    columns: (1fr, 1fr),
    deck.section.title,
    align(right)[#deck.slide.number\/#deck.slide.total],
  )
}

Attaches non-rendering speaker notes to a logical slide.

note(body) -> content
Description

Notes never appear in the slides themselves. They are collected and shown by the "speaker" and "notes" outputs of setup.

#show: mosaic.setup.with(output: "speaker")

#mosaic.slide[
  == Results
  #mosaic.note[Mention the confidence interval before the table.]
  The estimate holds under both specifications.
]

Multiple note blocks on one slide accumulate in source order. Wrap a note in steps.on, steps.reveal, or steps.replace to tie it to the same physical frames as the incremental content it belongs with, so the speaker view shows it beside the frame it describes.

Arguments
bodycontent
The note text. Ordinary content, so lists and emphasis work as usual.

Scales one block of content to the space it is given.

fit(
  body,
  width: auto,
  height: auto,
  wrap: true,
  grow: false,
  shrink: true
) -> content
Description

Mosaic never resizes body content on its own, so a slide holding more than it can show reports an overflow rather than shrinking. fit is the explicit per-block exception, for content whose size the author does not control: a wide table, a chart, a generated list, a number meant to fill the slide.

It measures the content against the region the call sits in and scales it geometrically, so proportions are preserved and the surrounding layout accounts for the new size. With no width or height it fits the whole region.

#mosaic.slide[
  == A long argument
  #mosaic.fit(generated-list)
]

Fitting works in cells, in the background and foreground planes, and in ordinary content. Pass grow: true for display type that should fill its cell rather than merely avoid overflowing it:

#mosaic.fit(grow: true)[42%]

Content that must not be re-laid out

By default the content is offered the region’s width first, so text and lists wrap into the cell and are scaled only if they are still too tall. A table, chart, or diagram would rearrange its own columns instead, which changes the composition rather than its size. Pass wrap: false to scale such a block exactly as it stands:

#mosaic.fit(wrap: false, my-wide-table)

Overflow

A fitted block cannot overflow, so it emits no <mosaic-overflow-warning> record and never fails an overflow: "error" compile. A cell that fits its content therefore stops reporting how full it is.

Incremental content and speaker notes

Fitting measures its body, which means holding it inside a closure that the slide runtime cannot look into. Incremental markers and speaker notes are found by walking the slide’s content, so anything inside a fitted block would be invisible to that walk: the reveals would collapse into one frame and the notes would vanish. fit rejects such a body rather than dropping it silently. Keep pause, steps, and note outside the fitted block, or fit each revealed part on its own.

Arguments
bodycontent
The content to scale.
widthauto | length | relative | fraction
Width to fit into. auto uses the full width of the region.
heightauto | length | relative | fraction
Height to fit into. auto uses the full height of the region.
wrapbool
Let the content re-lay out at the available width before it is measured. Pass false for a block whose own arrangement must be preserved.
growbool
Scale content up when it is smaller than the space available.
shrinkbool
Scale content down when it is larger than the space available.