FrameSeq

Function reference#

This page explains the common FrameSeq authoring functions. Each entry follows the same order: what the function creates, a minimal example, a readable signature, its parameters, and its return value.

Generated slides.ts files expose these lowercase functions globally, so imports are not required. Signatures here emphasize how a function is used; for exact TypeScript overloads, complete option interfaces, and the uppercase object API, see the API reference.

On this page#

Document#

presentation()#

Starts a new presentation and sets document-wide metadata, canvas size, theme, and typography.

presentation({
  title: "Quarterly Review",
  author: "Ada Lovelace",
  theme: "minimal-academic",
});

Signature

presentation(title) → SlidesDefinition
presentation(options) → SlidesDefinition

Parameters

  • titlestring, optional. A short form for setting only the presentation title.
  • optionsSlidesOptions, optional. Sets metadata, theme, ratio, custom width and height, background, and presentation-wide font defaults.

Returns SlidesDefinition, the presentation root. Most linear documents do not need to store it.

Call presentation() once, before the first slide(). Calling it again starts a new authoring context.

slide()#

Starts a slide. Every content command after it belongs to that slide until the next slide() call.

slide("Results");
text("Revenue increased by 42%.");

Signature

slide(name) → ContentSlideBuilder
slide(options) → ContentSlideBuilder

Parameters

  • namestring, optional. Sets both the internal name and the visible slide title.
  • optionsSlideOptions, optional. Separates name, visible title, speaker notes, and allowEmpty metadata.
slide({ name: "result-details", title: "Detailed results" });
slide({ name: "photo" }); // no automatic visible title

Returns ContentSlideBuilder, which provides slide layout methods such as .split() and .canvas().

.notes()#

Adds private speaker notes to a slide.

slide("Results").notes("Pause here and explain the comparison.");

Signature notes(content) → slide

Parameters

  • contentstring, required. Text shown in presenter view and exported to PowerPoint speaker notes.

Notes are not shown on the audience page or in PDF output.

note()#

Adds speaker notes to the current slide without chaining them onto slide(). note(content) and slide().notes(content) produce the same result.

slide("Results");
text("Revenue increased by 42%.");
note("Compare the trend, not the absolute value.");

Signature note(content) → ContentSlideBuilder

Parameters

  • contentstring, required. Text shown in presenter view and exported to PowerPoint speaker notes.

Returns the current slide, so slide methods still chain: note("Pause here").allowEmpty().

Repeated calls append a line instead of replacing the previous note, so a reminder can stay beside the content it explains:

slide("Two comparisons");
text("First measurement");
note("Explain how it was collected.");
text("Second measurement");
note("Contrast it with the first.");

Notes written with slide().notes() are kept and extended in the same way.

.allowEmpty()#

Marks a slide as intentionally empty for the layout checker.

slide({ name: "Pause" }).allowEmpty();

Signature allowEmpty(enabled) → slide

Parameters

  • enabledboolean, optional. Defaults to true.

Text#

text()#

Creates a text object in the current slide region.

text("A normal paragraph");
text("An emphasized sentence").size(30).bold().color("#2563eb");

Signature

text(content) → TextBoxBuilder
text`...` → TextBoxBuilder

Parameters

  • contentstring, required. The text to display.
  • strings and values — tagged-template input. Use this form when the text contains inline LaTeX so backslashes remain intact.
text`Energy and mass satisfy $E = mc^2$.`;

Returns TextBoxBuilder. It supports normal object modifiers and the text roles below.

Text roles#

A role supplies presentation-aware typography. The most recently called role replaces any earlier role on the same text object.

Method Meaning Example
.body() Normal paragraph text; the default role text("Explanation").body()
.title() A manually placed slide heading text("Architecture").title()
.hero() The primary title on a cover or section slide text("FrameSeq").hero()
.subtitle() Supporting text below a hero title text("Slides as code").subtitle()
.author() Author or presenter name text("Ada Lovelace").author()
.eyebrow() A small uppercase section label text("Section 01").eyebrow()
.lead() The leading statement on a content slide text("Latency fell by 42%.").lead()
.caption() A source, footnote, or image caption text("Source: Example data").caption()
.quote() A short quotation text("Simplicity is a feature.").quote()

Every role returns the same TextBoxBuilder, so further modifiers can be chained.

Lists and reveals#

bullets()#

Creates an unordered list whose items are all visible immediately.

bullets("Readable source", "Useful defaults", "Portable output");

Signature bullets(...items) → ElementBuilder

Parameters

  • itemsstring[], required. One or more strings, in display order.

Returns ElementBuilder, representing the complete list rather than an individual item.

steps()#

Creates a numbered list whose items are revealed one at a time.

steps("Parse the source", "Build the slide tree", "Render the result");

Signature steps(...items) → ElementBuilder

Parameters

  • itemsstring[], required. Item one appears at step 1, item two at step 2, and so on.

Returns ElementBuilder. PDF and PPTX output include every item.

.showAt()#

Assigns an individual object to a reveal step.

text("First result").showAt(1);
image(chart, "Result chart").showAt(2);

Signature showAt(step) → same object

Parameters

  • stepnumber, required. A positive reveal step; steps begin at 1.

Print, PDF, and PPTX output show all steps.

Semantic objects#

metric()#

Displays a prominent value with a smaller label that explains it.

metric("42%", "Revenue growth");

Signature metric(value, label) → GroupBuilder

Parameters

  • valuestring, required. The emphasized value, such as "42%" or "18K".
  • labelstring, required. A short description of what the value means.

Returns GroupBuilder, so the metric can be styled, placed in a grid, or converted to a card.

metric("42%", "Revenue growth").card().background("#eff6ff");

metric() only displays the supplied strings; it does not calculate data or format values. Use text() when the content is a sentence rather than a value-label pair.

card()#

Creates a bordered surface containing a title and optional supporting text.

card("Portable", "Export HTML, PDF, and editable PPTX.");

Signature card(title, content) → GroupBuilder

Parameters

  • titlestring, required. The card heading.
  • contentstring, optional. Short supporting copy below the heading.

Returns GroupBuilder, representing the whole card as one styleable object.

group()#

Combines existing objects into one vertical, independently styleable object.

group(
  text("Revenue").bold(),
  text("$1.2M").size(42),
).card();

Signature group(...items?) → GroupBuilder

Parameters

  • itemsArray<ElementBuilder | string>, optional. Existing FrameSeq objects, in vertical order. A string selects an object by the name given to it with .as(), so grouping needs no local variables:
rect("Parse").as("parse");
rect("Build").as("build");
group("parse", "build").row().gap(16);

Returns GroupBuilder.

The child objects are removed from the current region and inserted once inside the group. This keeps the linear syntax: create the children first, then define their parent.

With no items, group() creates an empty container in the current flow. To write the container first and its contents afterwards, name it with at() instead:

at("panel").card().padding(24);
text("Revenue").bold();
text("$1.2M").size(42);

ref()#

Selects an object or region by the name given to it with .as() or at(), so styling can happen after the content is written.

rect("Parse").as("parse");
rect("Build").as("build");

ref("parse").fill("#dbeafe");
ref("build").fill("#dbeafe");

Signature ref(name) → ElementBuilder

Parameters

  • namestring, required. A name from .as() or a region path from at().

Returns the builder that matches the object: shapes keep .fill(), .stroke(), and .strokeWidth(), connectors keep .arrow(), .from(), and .to(), and containers keep .row(), .gap(), and the content methods. Every object keeps the common modifiers, including .style({ ... }) for CSS that has no dedicated method.

ref() searches the current slide, and reports the available names when it finds nothing.

gridSection()#

Arranges supplied objects in a local grid inside the normal top-to-bottom slide flow.

gridSection(
  3,
  metric("42%", "Growth").card(),
  metric("18K", "Users").card(),
  metric("99.9%", "Uptime").card(),
).gap(20);

Signature

gridSection(columns, ...items) → GridSectionBuilder

Parameters

  • columnsnumber | string, required. An integer from 1 to 12 creates equal columns. A CSS grid-template string creates custom tracks, for example "1fr 2fr".
  • itemsArray<ElementBuilder | string>, optional. Every supplied object becomes one cell, in source order. Strings select objects by name, as in group().

In the direct form, every following object becomes one cell.

Returns GridSectionBuilder, with .columns() and container modifiers such as .gap(), .align(), and .padding().

Content written before and after gridSection() stays in the ordinary slide flow. Use slide().grid() when the entire slide body should be divided into regions.

Calling gridSection(columns) without items creates an empty grid in the current flow. When the objects should be written before the grid, name them with .as() and collect them afterwards: gridSection(2, "quality", "accuracy").

Media and typesetting#

image()#

Creates an image object in the current region.

const diagram = new URL("./assets/diagram.png", import.meta.url).href;
image(diagram, "Compiler pipeline").width(percent(100)).radius(18);

Signature image(src, alt) → ElementBuilder

Parameters

  • srcstring, required. An imported asset URL, data URL, or public URL.
  • altstring, optional. Accessible alternative text. Defaults to an empty string.

Returns ElementBuilder.

code()#

Creates a preformatted code block.

code(`const answer = 42;`, "ts");

Signature code(content, language) → ElementBuilder

Parameters

  • contentstring, required. Literal code to display.
  • languagestring, optional. Language metadata; defaults to "ts". FrameSeq does not currently apply syntax highlighting from this value.

Returns ElementBuilder.

math()#

Renders one standalone LaTeX-compatible equation with KaTeX.

math`\int_0^1 x^2\,dx = \frac{1}{3}`;

Signature

math(content) → ElementBuilder
math`...` → ElementBuilder

Parameters

  • contentstring, required. Equation source without $$ delimiters. The tagged-template form preserves LaTeX backslashes.

Returns ElementBuilder.

Use inline $...$ inside text when a formula belongs in a sentence.

typst()#

Compiles a static Typst fragment to SVG during development and export.

typst`
  #table(columns: 2, [Model], [Accuracy], [A], [94.6%])
`.width(720);

Signature

typst(content) → ElementBuilder
typst`...` → ElementBuilder

Parameters

  • contentstring, required. A Typst fragment, not a complete project. Tagged fragments are static and do not accept JavaScript interpolation.

Returns ElementBuilder containing the compiled graphic.

Requires the optional @myriaddreamin/typst-ts-node-compiler package.

typstFile()#

Loads and compiles a Typst fragment from a separate file.

typstFile("./figures/results.typ").width(720);

Signature typstFile(path) → ElementBuilder

Parameters

  • pathstring, required. A path relative to slides.ts. The file is watched during development.

Returns ElementBuilder containing the compiled graphic.

latex()#

Compiles a static LaTeX body fragment to an embedded graphic.

latex`
  \begin{tabular}{lr}
    Model & Accuracy \\
    FrameSeq & 94.6\% \\
  \end{tabular}
`.width(720);

Signature

latex(content) → ElementBuilder
latex`...` → ElementBuilder

Parameters

  • contentstring, required. A LaTeX body fragment. Do not include \documentclass or a complete document.

Returns ElementBuilder containing the compiled graphic.

Requires the optional node-tectonic package. Use math() for ordinary equations; latex() is most useful for existing tabular content or package-based typesetting.

latexFile()#

Loads and compiles a LaTeX body fragment from a separate file.

latexFile("./tables/results.tex").width(720);

Signature latexFile(path) → ElementBuilder

Parameters

  • pathstring, required. A path relative to slides.ts.

Returns ElementBuilder containing the compiled graphic.

Slide layouts#

Without a layout method, content is placed in one vertical column in source order.

.cover()#

Applies the cover-slide layout and cover text styles.

slide({ name: "Cover" }).cover();
text("FrameSeq").hero();
text("Write slides as TypeScript").subtitle();
text("Ada Lovelace").author();

Signature cover() → slide

Use text roles to create the visible cover content; .cover() does not generate a title by itself.

.split()#

Divides the whole slide body into left and right regions.

slide("Architecture").split("40:60");
image(diagram, "Pipeline");

right();
bullets("Parse", "Render", "Export");

Signature split(ratio) → slide

Parameters

  • ratio"left:right" | number | [number, number], optional. Defaults to "1:1". Examples: "40:60", 0.4, 40, and [2, 3].

Existing content moves to the left region. Subsequent content also starts on the left; call right() to switch regions.

.grid()#

Divides the whole slide body into equal-width regions.

slide("Results").grid(3);
cell(0); metric("42%", "Growth");
cell(1); metric("18K", "Users");
cell(2); metric("99.9%", "Uptime");

Signature grid(columns, gap) → slide

Parameters

  • columnsnumber, required. An integer from 1 to 12.
  • gapnumber | string, optional. Space between the regions; the active theme supplies the default.

Use cell(index) to select a zero-based region. Use gridSection() for a grid between ordinary content above and below it.

.center()#

Centers the normal slide body horizontally and vertically.

slide({ name: "Conclusion" }).center();
text("Make the structure visible.").quote();

Signature center() → slide

This is intended for a single quotation, conclusion, or key message.

.fullBleed()#

Fills the slide body with one image.

slide({ name: "Landscape" }).fullBleed(photo, "Mountain landscape");

Signature fullBleed(src, alt) → slide

Parameters

  • srcstring, required. The image URL.
  • altstring, optional. Accessible alternative text; defaults to an empty string.

Use a slide without a visible title when the image should occupy all available space.

.canvas()#

Changes the slide body into a freeform coordinate system.

slide({ name: "System map" }).canvas();
text("Compiler").position({ x: 80, y: 90 }).width(300).size(32).bold();

Signature canvas() → slide

Canvas coordinates use the presentation canvas, which defaults to 1600 × 900. Prefer normal flow, .split(), .grid(), or gridSection() for ordinary content slides.

Regions#

left() and right()#

Select the destination for subsequent content on a slide using .split().

left();
text("Before");
right();
text("After");

Signature

left() → RegionBuilder
right() → RegionBuilder

Returns the selected RegionBuilder. Calling either function changes the active authoring region.

cell()#

Selects a region on a slide using .grid().

cell(1);
text("This goes in the second cell.");

Signature cell(index) → RegionBuilder

Parameters

  • indexnumber, required. A zero-based cell number; 0 is the first cell.

Returns the selected RegionBuilder and makes it active.

at()#

Moves the authoring cursor to a region addressed by a path, creating the containers on the way. Composition therefore stays flat: one statement per object, no nesting and no closing call.

at("cell0/now").card();
text("Q3").eyebrow();
bullets("Anchors", "Region paths");

at("cell1/next").card();
text("Q4").eyebrow();

at("cell0/now");
text("Merged into main").caption();

Signature at(path) → RegionBuilder

Parameters

  • pathstring, required. Segments separated by /. The first segment may name a region the layout already owns: main, left, right, or cell0, cell1, and so on. Every other segment is a container that FrameSeq creates the first time it is used. An empty path is the same as main().

Returns the selected RegionBuilder and makes it active. Revisiting a path returns the same region and appends to it, so a page can be written in whatever order reads best. Paths are scoped to their slide, and FrameSeq also registers them as anchor names, so line().from("stages.left") can connect to a positioned region.

Set the layout of a region where it first appears: at("pipeline").row().gap(24).

main()#

Returns content placement to the slide's primary region.

right();
text("Right side");
main();
text("Back to the primary region");

Signature main() → RegionBuilder

Returns the normal body, left split region, or first whole-slide grid cell, depending on the current layout.

gap()#

Changes the spacing between children in the active region.

gap(32);
bullets("More", "Space", "Between objects");

Signature gap(value) → RegionBuilder

Parameters

  • valuenumber | string, required. Numbers mean pixels; strings may use CSS units.

Returns the active RegionBuilder. To change a local grid, chain the method instead: gridSection(...items).gap(20).

Shapes and connectors#

Shapes are normal FrameSeq objects. Exact placement is intended for a slide using .canvas().

rect()#

Creates a rectangular diagram node with an optional centered label.

rect("Input")
  .position({ x: 80, y: 140 })
  .width(240)
  .height(100)
  .fill("#dbeafe")
  .stroke("#2563eb");

Signature rect(label) → ShapeBuilder

Parameters

  • labelstring, optional. Defaults to an empty string.

Returns ShapeBuilder, which adds .fill(), .stroke(), and .strokeWidth() to the common modifiers.

circle()#

Creates a circular diagram node with an optional centered label.

circle("Model").position({ x: 520, y: 110 }).width(160);

Signature circle(label) → ShapeBuilder

Parameters

  • labelstring, optional. Defaults to an empty string.

Returns ShapeBuilder. Its width controls the diameter unless a height is set explicitly.

line()#

Creates a vector connector between two canvas coordinates.

line({ x1: 320, y1: 190, x2: 520, y2: 190 })
  .stroke("#2563eb")
  .strokeWidth(4)
  .arrow("end");

Signature line(points) → LineBuilder

Parameters

  • points{ x1: number; y1: number; x2: number; y2: number }, optional. Omit it when both ends use .from() and .to().

Returns LineBuilder, which provides .stroke(), .strokeWidth(), .arrow("none" | "start" | "end" | "both"), .from(), and .to().

.as()#

Names a diagram object so connectors and placements can reference it instead of repeating coordinates. Names are unique within a slide.

rect("Encoder").as("enc").position({ x: 80, y: 140 }).width(200).height(100);

Signature .as(name) → the same object

Parameters

  • namestring, required. Letters, digits, _, and -, starting with a letter or _.

.from() and .to()#

Attach a connector to named objects. FrameSeq resolves the endpoints before rendering, so a connector follows its nodes when their coordinates change.

line().from("enc").to("dec").arrow("end");
line().from("enc.right", { dy: -20 }).to("dec.top-left");

Signature .from(reference, offset) → the same connector, .to(reference, offset) → the same connector

Parameters

  • referencestring, required. A name such as "enc", or a name and an anchor such as "enc.right". Anchors are center, top, bottom, left, right, top-left, top-right, bottom-left, and bottom-right. Without an anchor FrameSeq uses the edges that face the other end.
  • offset{ dx?: number; dy?: number }, optional. Shifts the endpoint in canvas pixels.

.rightOf(), .leftOf(), .above(), and .below()#

Place an object next to a named object instead of computing its coordinates.

rect("Decoder").as("dec").rightOf("enc", 140);
text("shared vocabulary").caption().below("enc", 16);

Signature .rightOf(name, gap) → the same object, and likewise for the other three

Parameters

  • namestring, required. The name of a positioned object on the same canvas.
  • gapnumber, optional. Canvas pixels between the two objects. Defaults to 40 horizontally and 24 vertically.

The placed object is centred on the other axis and needs no size of its own. The referenced object needs a resolvable box: rect() defaults to 240 x 96 and circle() to 160 x 160.

.centerOn(), .alignTop(), and .alignLeft()#

Centre an object on a named object, or match one of its edges. alignTop() and alignLeft() change one axis only, so they chain onto another placement.

circle("Badge").as("badge").centerOn("dec").width(48);
rect("Cache").as("cache").rightOf("enc", 60).alignTop("enc");

Signature .centerOn(name) → the same object, .alignTop(name) → the same object, .alignLeft(name) → the same object

Parameters

  • namestring, required.

spacer()#

Adds empty space that takes whatever room is left over, which pushes the objects after it to the far end of the region.

at("footer").row().gap(0);
text("FrameSeq").caption();
spacer();
text("2026").caption();

Signature spacer(size) → the spacer object

Parameters

  • sizenumber, optional. The share of the free space this spacer takes, relative to the other spacers in the same region. Defaults to 1.

A spacer only means something inside a row(), column(), or grid, because a block container has no free space to hand out. It renders nothing and is never reported as an empty slide.

.selfAlign() and .centerSelf()#

Align one object across the axis of the row or column that holds it, without moving its siblings and without a canvas. A column aligns horizontally, a row aligns vertically.

text("A framed pull quote").width(520).centerSelf();
image(logo, "Logo").width(160).selfAlign("end");

Signature .selfAlign(value) → the same object, .centerSelf() → the same object

Parameters

  • value"start" | "center" | "end" | "stretch", required. .centerSelf() is .selfAlign("center").

Objects stretch across the axis by default, so an object only moves once it has a size of its own: give it .width(...) in a column or .height(...) in a row. .align() sets the same alignment for every child of a container, while .selfAlign() overrides it for one object. To move the text inside an object instead of the object itself, use .textAlign(); to move it along the region rather than across it, use .justify() on the container or a spacer().

.anchor()#

Positions an object against its container instead of by coordinates.

at("stages").row().gap(80).anchor("center");
at("legend").column().gap(8).anchor("bottom-right", 40);

Signature .anchor(position, margin) → the same object

Parameters

  • positionstring, required. One of center, top, bottom, left, right, top-left, top-right, bottom-left, bottom-right.
  • marginnumber, optional. Distance from the edge in canvas pixels; defaults to 0 and is ignored for center.

The browser resolves the result, so an object placed this way becomes its own coordinate space. Anchor connectors to the objects inside it rather than across it, and put those connectors inside the same container.

A row or column placed this way still resolves its children, so a diagram can be written without a single coordinate:

slide("Pipeline").canvas();

at("stages").row().gap(80).anchor("center");
rect("Parse").as("parse");
rect("Build").as("build");
line().from("parse").to("build").arrow("end");

See Shapes and connectors for the full anchor model and its limits.

Themes#

themes#

Contains the complete definitions of all built-in themes.

presentation({ title: "My Talk", theme: themes.paper });

Most documents can use the shorter theme name, such as theme: "paper". The themes object is useful when code needs a complete theme definition.

defineTheme()#

Creates a reusable theme by overriding selected design tokens.

const ocean = defineTheme({
  name: "ocean",
  extends: "blank",
  colors: { accent: "#007c91" },
});

presentation({ title: "Ocean", theme: ocean });

Signature defineTheme(options) → ThemeDefinition

Parameters

  • options.name — unique theme name, required.
  • options.extends — built-in theme name or theme definition, optional. Defaults to "blank".
  • options.colors, fonts, spacing, radii, chrome — partial token groups.
  • options.family, coverLayout, coverBackground — optional theme-level behavior.

Returns a complete ThemeDefinition that can be passed to presentation() or extended by another theme.

See Themes for all token names and built-in previews.

Common object methods#

Content functions return the object they create. These methods change that object and return the same builder, so calls can be chained.

Method Parameters Meaning
.size(value) / .fontSize(value) value: Length Set font size.
.weight(value) / .fontWeight(value) value: number | string Set font weight.
.bold() None Set font weight to 700.
.color(value) value: string Set text or foreground color.
.background(value) value: string Set the background.
.width(value) / .height(value) value: Length Set object dimensions.
.minWidth(value) / .minHeight(value) value: Length Set minimum dimensions.
.maxWidth(value) / .maxHeight(value) value: Length Cap the dimensions; how text is kept to a readable measure.
.padding(vertical, horizontal) vertical: Length; horizontal: Length, optional Set inner spacing.
.padding(sides) sides: { top?, right?, bottom?, left? } Set inner spacing per side; an omitted side is zero.
.margin(vertical, horizontal) vertical: Length; horizontal: Length, optional Set outer spacing.
.margin(sides) sides: { top?, right?, bottom?, left? } Set outer spacing per side; an omitted side is zero.
.gap(rows, columns) rows: Length; columns: Length, optional Set spacing between container children; one value covers both axes.
.border(value) value: string Set a complete CSS border.
.radius(value) value: Length Set corner radius.
.lineHeight(value) value: number | string Set text line height.
.textAlign(value) value: left | center | right Set text alignment.
.selfAlign(value) / .centerSelf() value: start | center | end | stretch Align this object across the axis of its container.
.opacity(value) value: number Set opacity, normally from 0 to 1.
.clip(enabled) enabled: boolean, optional Clip children to this object's bounds; defaults to true.
.position(bounds) bounds: { x?: Length; y?: Length } Use absolute canvas coordinates.
.rotate(degrees) degrees: number Rotate the object.
.style(classes) classes: string Add Tailwind utility classes.
.style(properties) properties: CSS values Add inline CSS properties.
.className(value) value: string Add one or more CSS classes.

All methods in this table return the same object. Objects also provide .row(), .column(), .stack(), .grid(), .canvas(), .center(), .align(), .justify(), .wrap(), and .alignContent(), which arrange their own children, plus .selfAlign(), .centerSelf(), and .grow(), which describe how they sit inside the container that holds them. See Styling for accepted values and precedence rules, and Which axis a modifier moves for choosing between them.

Length helpers#

Length helpers make a CSS unit explicit. They return strings and can be used anywhere FrameSeq accepts Length.

px(20)       // "20px"
pt(20)       // "20pt"
rem(2)       // "2rem"
percent(50)  // "50%"
vw(40)       // "40vw"
vh(30)       // "30vh"

text("Label").size(pt(24)).width(percent(50));

Plain numeric lengths are interpreted as pixels.