FrameSeq Docs

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

  • title — string, optional. A short form for setting only the presentation title.
  • options — SlidesOptions, optional. Sets metadata, theme, ratio, custom width and height, a paper size and orientation, background, presentation-wide font defaults, a bibliography for cite(), and citations options.

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.

poster()#

Starts a poster: a presentation made for paper, A0 portrait in the poster theme unless the options say otherwise, with its one page already begun.

poster({
  title: "Diffusion Language Models",
  author: "Ada Lovelace",
  institute: "University of Cambridge",
}).grid(3);

Signature

poster(title) → ContentSlideBuilder
poster(options) → ContentSlideBuilder

Parameters

  • title — string, optional. A short form for setting only the title.
  • options — SlidesOptions, optional. The same options as presentation(); size, orientation, and theme replace the poster's defaults.

Returns ContentSlideBuilder, the poster's page, so its layout, such as .grid(3), can follow directly. See Posters and print.

figure()#

Starts a figure for a paper: one canvas with no margins, printed at the width it will have on the page, so frameseq pdf gives a page of exactly that size and the layout check judges type in printed points.

figure({ title: "Method", width: 1600, height: 820 });
at("encoder").panel("(a) Encoder layer").canvas().position({ x: 20, y: 20 }).width(620).height(780);

Signature

figure(title) → ContentSlideBuilder
figure(options) → ContentSlideBuilder

Parameters

  • title — string, optional. A short form for setting only the title.
  • options — FigureOptions, optional. width and height are canvas units, 1600 and 900 by default; printWidth is how wide it prints, "170mm" by default, or "85mm" for one column; theme, font, and background work as for presentation().

Returns ContentSlideBuilder, the figure's page, already a canvas. See Posters and print.

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

  • name — string, optional. Sets both the internal name and the visible slide title.
  • options — SlideOptions, 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

  • content — string, 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

  • content — string, 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

  • enabled — boolean, 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

  • content — string, 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

  • items — string[], 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

  • items — string[], 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

  • step — number, 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

  • value — string, required. The emphasized value, such as "42%" or "18K".
  • label — string, 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

  • title — string, required. The card heading.
  • content — string, 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

  • items — Array<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

  • name — string, 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

  • columns — number | string, required. An integer from 1 to 12 creates equal columns. A CSS grid-template string creates custom tracks, for example "1fr 2fr".
  • items — Array<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

  • src — string, required. An imported asset URL, data URL, or public URL.
  • alt — string, 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

  • content — string, required. Literal code to display.
  • language — string, 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

  • content — string, 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

  • content — string, 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

  • path — string, 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

  • content — string, 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

  • path — string, required. A path relative to slides.ts.

Returns ElementBuilder containing the compiled graphic.

Tables, charts, and icons#

table()#

Adds a table. The first row is the heading, and columns whose cells are all quantities align right.

table([
  ["Model", "Accuracy", "Latency"],
  ["Baseline", "91.2%", "18 ms"],
  ["FrameSeq", "94.6%", "12 ms"],
]);

Signature table(rows) → TableBuilder

Parameters

  • rows — Array<Array<string | number>>, required. Each row as an array of cells. Cells may hold inline math between $ signs.

Returns TableBuilder, with the common object methods and:

  • .header(rows) — how many of the first rows are headings: 1 by default, 0 for none.
  • .columnAlign(...alignments) — "left", "center", or "right" for each column from the first.
  • .striped(enabled) — shade every other body row.

PowerPoint export makes it an editable PowerPoint table, and Typst export a native #table.

chart()#

Adds a chart drawn from the data written beside it.

chart("bar", { Q1: 12, Q2: 18, Q3: 25 }).unit("%");
chart("line", { labels: ["Jan", "Feb", "Mar"], series: { Revenue: [3, 5, 4], Cost: [2, 2, 3] } });

Signature chart(kind, data) → ChartBuilder

Parameters

  • kind — "bar" | "hbar" | "line" | "pie" | "donut", required.
  • data — required. One series as { label: value }, or several as { labels: string[]; series: Record<string, number[]> } with one value per label. A pie or donut takes one series of values that are not negative.

Returns ChartBuilder, with the common object methods and:

  • .unit(suffix) — write values with a unit, such as "%" or " ms".
  • .values(show) — show or hide the value beside each bar, point, or slice.
  • .legend(show) — show or hide the legend.
  • .max(value) — fix the top of the value axis.
  • .colors(...colors) — colour the series, or a pie's slices, in order.

The chart fills its region's width at 16:9 unless .width() or .height() says otherwise. PowerPoint export makes it an editable PowerPoint chart.

qr()#

Adds a QR code for a link or any text.

qr("https://pride7.github.io/frameseq/").width(220);

Signature qr(text) → ElementBuilder

Parameters

  • text — string, required. The link or text to encode.

Returns ElementBuilder. The code is 200 pixels square unless .width() says otherwise, dark on light with a quiet margin.

icon()#

Adds an icon from the Lucide set, drawn in the text colour at the font size.

icon("rocket").size(64).color("#2563eb");

Signature icon(name) → ElementBuilder

Parameters

  • name — IconName, required. An icon's name; TypeScript completes the names and rejects one that does not exist.

Returns ElementBuilder; .size() sets the icon's size and .color() its colour. A built presentation includes only the icons its source names as strings.

Citations#

cite()#

Cites works from the presentation's bibliography and returns the marker to write into the text.

text(`Attention replaced recurrence ${cite("vaswani2017")}.`);

Signature cite(...keys) → string

Parameters

  • keys — string[], at least one. Keys of the presentation's bibliography.

Returns string: [1] or [1, 2], numbered in the order works are first cited, or (Vaswani et al., 2017) with citations: { style: "author-year" }. The works a slide cites are listed at its foot unless citations: { footnotes: false }. See Citations and references.

footnote()#

Adds a footnote to the current slide and returns its marker.

text(`Measured on one GPU${footnote("An NVIDIA A100.")}.`);

Signature footnote(content) → string

Parameters

  • content — string, required. The footnote's text.

Returns string, a superscript number such as ¹, counted from 1 on each slide.

references()#

Adds the list of works the presentation cites.

slide("References");
references();

Signature references(options) → GroupBuilder

Parameters

  • options — { all?: boolean }, optional. all: true adds the works the bibliography holds but the talk never cited, after the cited ones.

Returns GroupBuilder. The list is filled once the document has run, so it includes citations made after it.

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

  • columns — number, required. An integer from 1 to 12.
  • gap — number | 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

  • src — string, required. The image URL.
  • alt — string, 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

  • index — number, 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

  • path — string, 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).

.panel()#

Frames a region as one panel of a figure, such as "(a) Encoder layer": a light outline, rounded corners, and a bold title in its top-left corner, with a leading tag such as (a) in a quieter colour.

at("encoder").panel("(a) Encoder layer").canvas().position({ x: 20, y: 20 }).width(620).height(780);
shape("rounded", "Attention").as("attention").position({ x: 190, y: 380 }).width(240).height(58);

Signature .panel(title) → RegionBuilder

Parameters

  • title — string, required. The panel's title. A leading tag in parentheses, such as (a) or (b), is set apart in the muted colour.

Returns the same RegionBuilder. Its contents move with it; content in a row or a column starts below the title, and on a canvas, coordinates count from the panel's corner, so keep objects about 70 pixels down.

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

  • value — number | 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

  • label — string, optional. Defaults to an empty string.

Returns ShapeBuilder, which adds .fill(), .stroke(), .strokeWidth(), .tone(), .shadow(), and .dashed() 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

  • label — string, optional. Defaults to an empty string.

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

shape()#

Creates a diagram shape: a vector outline with an optional label set in the outline's own room. There are 27 kinds, from flowchart symbols to block arrows, and each one exports to PowerPoint as its native shape.

shape("diamond", "Cached?").as("check").tone("amber");
shape("cylinder", "Postgres").position({ x: 980, y: 200 }).tone("purple").shadow();
shape("pill", "Start").tone("green", "solid").width(180).height(56);

Signature shape(kind, label) → ShapeBuilder

Parameters

  • kind — ShapeKind, required. Basic outlines: "rect", "rounded", "pill", "ellipse", "circle", "diamond", "triangle", "pentagon", "hexagon", "octagon", "parallelogram", "trapezoid", "star", "plus". Diagram symbols: "cylinder" (a database), "document", "note", "cube", "cloud", "callout". Arrows and steps: "chevron", "step", "arrow-right", "arrow-left", "arrow-up", "arrow-down", "arrow-both".
  • label — string, optional. Defaults to an empty string. Inline math between $ signs is supported.

Returns ShapeBuilder. Each kind has a usual size that .width() and .height() replace. .tone(color, style) paints it from one colour, "soft" (the default), "solid", or "outline", in one of "accent", "blue", "sky", "teal", "green", "lime", "amber", "orange", "red", "pink", "purple", "indigo", "gray", or any CSS colour. .shadow() casts a soft shadow and .dashed() dashes the outline.

polygon()#

Creates a diagram shape through corners of your own, for an outline no shape() kind has, such as an encoder that narrows from one side to the other. It exports to PowerPoint as an editable freeform.

polygon([[0, 0], [64, 47], [64, 153], [0, 200]], "Encoder").position({ x: 190, y: 370 }).tone("gray");
polygon([[60, 0], [120, 100], [0, 100]]).as("peak").width(180).height(120).tone("amber", "solid");

Signature polygon(points, label) → ShapeBuilder

Parameters

  • points — Array<[number, number]>, required. The corners in order around the outline, in pixels from any origin; at least three, spanning some width and some height.
  • label — string, optional. Defaults to an empty string. Centred in the polygon's box; inline math between $ signs is supported.

Returns ShapeBuilder. The polygon is as large as its corners span, and .width() and .height() stretch it. It takes .tone(), .fill(), .stroke(), .dashed(), .shadow(), and placement by name like any shape.

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(), .to(), .via(...stops), .route("straight" | "elbow" | "curve"), .label(text), and .dashed(). An elbow route turns at right angles and keeps clear of the other objects on the canvas; .via() runs the connector through named objects or [x, y] points on the way; a label sits halfway along the connector.

cells()#

Creates a row of equal cells from a list of values, or a grid from rows: tokens, embeddings, codes, attention masks, and similarity matrices. A number from 0 to 1 shades its cell, words label it, and null masks it.

cells([0.3, 0.9, 0.1, 0.6]).tone("amber").framed().as("codes").position({ x: 80, y: 360 });
cells([[1, 0.1], [0.1, 1]]).tone("indigo").cell(76).labels((r, c) => `$I_${r + 1} \\cdot T_${c + 1}$`);

Signature cells(values) → CellsBuilder

Parameters

  • values — Array<number | string | null> for a row, or rows of them of the same length, required. Numbers run from 0 to 1.

Returns CellsBuilder, which provides .tone(color), .cell(width, height), .gap(pixels), .labels(words), .size(pixels), and .framed(), besides placement and naming; connectors reach the set as a whole.

junction()#

Creates the point where connectors meet or split, such as the place a skip connection leaves the main path, or, with a sign, the small round operator where streams are added or multiplied.

junction().as("split").above("plus", 50);
junction("+").as("plus").above("embedding", 48);
line().from("split.right").to("norm.right").route("elbow").arrow();

Signature junction(sign) → ShapeBuilder

Parameters

  • sign — string, optional. Defaults to an empty string, which draws a 10-pixel dot in the connectors' colour. A sign such as "+" or "×" draws a 32-pixel outlined circle with the sign in it.

Returns ShapeBuilder. Name it with .as(), place it with .position() or a placement such as .above(), and connect to it like any object; .fill(), .stroke(), and .width() restyle it.

.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

  • name — string, 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

  • reference — string, 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

  • name — string, required. The name of a positioned object on the same canvas.
  • gap — number, 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

  • name — string, 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

  • size — number, 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

  • position — string, required. One of center, top, bottom, left, right, top-left, top-right, bottom-left, bottom-right.
  • margin — number, 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.

Masters#

master()#

Starts a master page: objects drawn behind every slide that uses it, as a slide master is in PowerPoint. The objects after it belong to the master until the next slide() or master() call.

master("content");
rect().position({ x: 0, y: 0 }).width(1280).height(96).fill("#1e3a8a");
placeholder("title").position({ x: 60, y: 0 }).width(1160).height(96).color("#ffffff");
text("{page} / {total}").position({ x: 1120, y: 676 }).width(100).textAlign("right").caption();

Signature master(name) → MasterBuilder

Parameters

  • name — string, required. Letters, digits, _, and -, starting with a letter. Covers are drawn on the master named "cover" and every other slide on the one named "content"; any other name is used by the slides that ask for it with .master().

Returns MasterBuilder, the master page. .background() paints the page of every slide drawn on it.

A master page is a canvas: place its objects with .position(). Text on it may show {title}, {subtitle}, {author}, {institute}, and {date} from the presentation, {page} and {total}, and {slide}, the slide's own title. Each name is written once per presentation. See Masters and templates.

placeholder()#

Marks, on a master page, where the slides drawn on it put their own content.

master("cover");
placeholder("title").position({ x: 500, y: 180 }).width(700).height(220).size(60);
placeholder().position({ x: 500, y: 420 }).width(700).height(200);

Signature placeholder(role) → ElementBuilder

Parameters

  • role — "body", "title", "subtitle", or "author", optional. Defaults to "body": everything the slide holds flows inside it. "title" takes a slide's title, or a cover's .hero() text; "subtitle" and "author" take a cover's.

Returns the placeholder. .position(), .width(), and .height() give its box; text settings such as .size(), .color(), .weight(), and .textAlign() style the text it holds on every slide, unless the slide sets them itself; .justify("start" | "center" | "end") puts that text at the top, the middle, or the foot of the box.

A master has at most one placeholder of each role. A placeholder written outside a master is an error.

.master()#

Draws a slide on another master, or on none.

slide("Part two").master("section");
slide({ name: "Photo" }).master(false).fullBleed(photo, "The lab at night");

Signature master(name) → slide

Parameters

  • name — string or false, required. The name of a master the presentation defines, or false for no master. A name the presentation does not define is reported with the slide that asked for it.

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.
.fit(minimum) minimum: number, optional Shrink the text inside until the object holds it, down to minimum of its size; 0.5 by default.
.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"
mm(20)       // "20mm"
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. On a presentation made for paper, pt() and mm() are printed sizes on the sheet, converted to canvas units; see Posters and print.