FrameSeq

API reference#

This page lists the complete types and the lower-level object API. For Typst-style entries that combine a definition, minimal example, signature, parameters, and return value, start with the Function reference. Lowercase functions belong to the linear document API. Uppercase functions belong to the explicit object API.

Document#

presentation(titleOrOptions?)#

presentation(title?: string): SlidesDefinition
presentation(options?: SlidesOptions): SlidesDefinition

Starts a new active presentation. It must be called before slide().

interface SlidesOptions {
  title?: string;
  subtitle?: string;
  author?: string;
  institute?: string;
  date?: string;
  ratio?: "16:9" | "4:3";
  width?: number;
  height?: number;
  background?: string;
  theme?: BuiltInThemeName | ThemeDefinition;
  font?: PresentationFontOptions;
}

interface FontStyleOptions {
  family?: string;
  size?: Length;
  weight?: number | string;
  lineHeight?: number | string;
}

interface PresentationFontOptions extends FontStyleOptions {
  heading?: FontStyleOptions;
  code?: FontStyleOptions;
}

The default theme is blank. background is a compatibility shortcut that overrides the selected theme's normal and cover backgrounds.

font changes presentation-wide typography without defining a complete theme. Its top-level values apply to body text, heading applies to cover and slide headings, and code applies to code blocks. A local builder modifier such as .size(30) takes precedence over these defaults.

Themes#

defineTheme(options)#

Creates a complete reusable theme from partial tokens:

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

presentation({ title: "Ocean", theme: ocean });
interface ThemeOptions {
  name: string;
  extends?: BuiltInThemeName | ThemeDefinition;
  family?: "frameseq" | "beamer";
  coverLayout?: "default" | "center" | "academic-left";
  colors?: Partial<ThemeColors>;
  fonts?: Partial<ThemeFonts>;
  spacing?: Partial<ThemeSpacing>;
  radii?: Partial<ThemeRadii>;
  chrome?: Partial<ThemeChrome>;
  coverBackground?: string;
}

type BuiltInThemeName =
  | "blank"
  | "midnight"
  | "paper"
  | "beamer-default"
  | "beamer-madrid"
  | "beamer-cambridge-us"
  | "minimal-academic";

Color tokens:

interface ThemeColors {
  background: string;
  foreground: string;
  muted: string;
  subtle: string;
  accent: string;
  accentForeground: string;
  surface: string;
  surfaceStrong: string;
  border: string;
  codeBackground: string;
  codeForeground: string;
  error: string;
  stage: string;
  shadow: string;
}

Other tokens:

interface ThemeFonts {
  body: string;
  heading: string;
  mono: string;
}

interface ThemeSpacing {
  slideX: string;
  slideY: string;
  coverX: string;
  coverY: string;
  contentGap: string;
  regionGap: string;
  splitGap: string;
  gridGap: string;
  cardPadding: string;
}

interface ThemeRadii {
  small: string;
  medium: string;
  large: string;
  pill: string;
}

interface ThemeChrome {
  titleBar: boolean;
  titleBarStyle: "solid" | "underline";
  footer: boolean;
  footerLayout: "metadata" | "title";
  slideNumber: boolean;
  showOnCover: boolean;
  autoTitlePage: boolean;
  titleBarHeight: string;
  footerHeight: string;
  titleBarBackground: string;
  titleBarForeground: string;
  footerBackground: string;
  footerForeground: string;
  footerAccentBackground: string;
  footerAccentForeground: string;
  footerBorderColor: string;
}

themes#

An object containing all seven complete built-in theme definitions. Theme names are usually more concise when selecting or extending a built-in theme; this export is useful when a complete theme object is needed.

slide(nameOrOptions?)#

slide(name?: string): ContentSlideBuilder
slide(options?: SlideOptions): ContentSlideBuilder

Starts the next slide and resets the active region.

interface SlideOptions {
  name?: string;
  title?: string;
  notes?: string;
  allowEmpty?: boolean;
}

The string form sets both name and title. name is metadata; title is rendered.

notes(content)#

notes(content: string): ContentSlideBuilder

Stores private speaker notes on the current slide. Notes are displayed in presenter view, omitted from the audience page and PDF, and preserved as PowerPoint speaker notes in PPTX export.

note(content)#

note(content: string): ContentSlideBuilder

Adds speaker notes to the current slide, the linear form of slide().notes(content). It returns the slide, so slide methods still chain. Repeated calls append a line to the existing notes rather than replacing them.

allowEmpty(enabled?)#

allowEmpty(enabled?: boolean): ContentSlideBuilder

Marks the current slide as intentionally blank so frameseq check does not report empty-slide. Prefer adding visible content unless the blank page is part of the presentation's pacing.

Content#

text(content)#

text(content: string): TextBoxBuilder
text(strings: TemplateStringsArray, ...values: unknown[]): TextBoxBuilder

Adds text to the current region. $...$ inside the content renders inline math. The tagged-template form preserves backslashes.

Text roles:

text("...").body()
text("...").title()
text("...").hero()
text("...").subtitle()
text("...").author()
text("...").eyebrow()
text("...").lead()
text("...").caption()
text("...").quote()

spacer(size?)#

spacer(size?: number): ElementBuilder

Adds empty space that takes the room left over in the current region, pushing what follows it to the far end. size is the share relative to other spacers in the same region and defaults to 1. It only has an effect inside a row(), column(), or grid.

image(src, alt?)#

image(src: string, alt?: string): ElementBuilder

Adds an image to the current region.

code(content, language?)#

code(content: string, language?: string): ElementBuilder

Adds preformatted code. The default language is "ts".

math(content)#

math(content: string): ElementBuilder
math(strings: TemplateStringsArray, ...values: unknown[]): ElementBuilder

Adds a display equation. Prefer the tagged-template form for LaTeX-style input.

typst(content)#

typst(content: string): ElementBuilder
typst(strings: TemplateStringsArray): ElementBuilder

Adds a static Typst fragment to the current region. The Vite build compiles the fragment to inline SVG. JavaScript interpolation inside the tagged template is not currently supported. Install the optional @myriaddreamin/typst-ts-node-compiler package before using this command.

typstFile(path)#

typstFile(path: string): ElementBuilder

Adds a Typst fragment from a static path relative to the slide document. The file must stay inside the slide document directory. Vite watches it for changes during development.

latex(content)#

latex(content: string): ElementBuilder
latex(strings: TemplateStringsArray): ElementBuilder

Adds a static LaTeX body fragment to the current region. The Vite build uses the optional node-tectonic compiler and embeds the typeset result and its fonts. JavaScript interpolation is not supported. Complete documents with \documentclass or \begin{document} are rejected.

latexFile(path)#

latexFile(path: string): ElementBuilder

Adds a LaTeX body fragment from a static path relative to the slide document. The file must stay inside that directory and is watched by Vite. Install node-tectonic before using either LaTeX command.

rect(label?)#

rect(label?: string): ShapeBuilder

Adds a rectangular diagram node. The optional label supports inline math and is centered by default.

circle(label?)#

circle(label?: string): ShapeBuilder

Adds a circular diagram node. Set its width to change the diameter while preserving the default square aspect ratio.

line(points)#

interface LinePoints {
  x1: number;
  y1: number;
  x2: number;
  y2: number;
}

line(points?: Partial<LinePoints>): LineBuilder

Adds an SVG line whose coordinates are numeric pixels relative to the current canvas region. Lines are intended for slides using canvas(). Omit the points when both ends are attached with from() and to().

bullets(...items)#

bullets(...items: string[]): ElementBuilder

Adds a static unordered list.

steps(...items)#

steps(...items: string[]): ElementBuilder

Adds a numbered list revealed one item at a time.

metric(value, label)#

metric(value: string, label: string): GroupBuilder

Adds a large value and smaller label to the current region and returns the metric object. The returned object can be styled or passed directly to gridSection().

card(title, content?)#

card(title: string, content?: string): GroupBuilder

Adds a semantic title-and-copy card to the current flow.

group(...items)#

group(...items: Array<ElementBuilder | string>): GroupBuilder

Combines adjacent content objects into one vertical object. Chain .card() when the group should receive the standard card surface.

gridSection(columns, ...items)#

type GridColumns = number | string;
gridSection(columns: GridColumns, ...items: Array<ElementBuilder | string>): GridSectionBuilder

Places a local grid in the current document flow. Every supplied object becomes one grid cell. Numeric columns accept integers from 1 through 12; a CSS grid-template string such as "1fr 2fr" creates unequal columns. Use .gap(value) to change spacing or .columns(value) to replace the template.

ref(name)#

ref(name: string): ElementBuilder

Selects an object or region on the current slide by the name given to it with .as() or at(). The returned builder matches the object: ShapeBuilder for rect() and circle(), LineBuilder for line(), RegionBuilder for containers, and ElementBuilder for everything else. group() and gridSection() accept the same names directly, so regrouping needs no local variables.

Region selection#

main()#

Selects the slide's primary region.

left() / right()#

Selects a split region. The slide must already use split().

cell(index)#

cell(index: number): RegionBuilder

Selects a zero-based grid cell. The slide must already use grid().

at(path)#

at(path: string): RegionBuilder

Selects the region addressed by a / separated path and creates the containers it names. The first segment may be main, left, right, or cell<n>; every other segment is created on first use. An empty path is the same as main(). Revisiting a path selects the same region, paths are scoped to the current slide, and each path is registered as an anchor name.

gap(rows, columns?)#

gap(rows: Length, columns?: Length): RegionBuilder

Sets the child gap on the active region. One value covers both axes; a second value spaces the columns separately from the rows.

Slide layouts#

These methods are chained from the object returned by slide().

slide("Title").split("40:60")
slide("Title").grid(3, 20)
slide({ name: "Quote" }).center()
slide({ name: "Photo" }).fullBleed(src, alt)
slide({ name: "Canvas" }).canvas()

cover()#

Applies the cover layout to the current slide.

split(ratio?)#

type SplitRatio = `${number}:${number}` | number | [number, number];

Creates left and right regions. The default is "1:1".

grid(columns, gap?)#

Creates 1–12 equal-width regions.

This method controls the whole slide body. Use gridSection() when only one portion of the slide should form a grid.

center()#

Centers the normal content region.

fullBleed(src, alt?)#

Adds an image and applies the full-bleed image layout.

canvas()#

Switches the slide body to freeform placement, so objects position themselves with .position({ x, y }). Detached objects created with the explicit object API reach the slide through custom(...elements).

Element modifiers#

All content builders inherit these methods:

style(classes: string): this
style(properties: Record<string, string | number>): this
width(value: Length): this
height(value: Length): this
minWidth(value: Length): this
minHeight(value: Length): this
maxWidth(value: Length): this
maxHeight(value: Length): this
padding(value: Length, horizontal?: Length): this
padding(sides: { top?: Length; right?: Length; bottom?: Length; left?: Length }): this
margin(value: Length, horizontal?: Length): this
margin(sides: { top?: Length; right?: Length; bottom?: Length; left?: Length }): this
gap(rows: Length, columns?: Length): this
background(value: string): this
color(value: string): this
border(value: string): this
radius(value: Length): this
fontSize(value: Length): this
size(value: Length): this
fontWeight(value: number | string): this
weight(value: number | string): this
bold(): this
lineHeight(value: number | string): this
textAlign(value: "left" | "center" | "right"): this
selfAlign(value: "start" | "center" | "end" | "stretch"): this
centerSelf(): this
align(value: "start" | "center" | "end" | "stretch"): this
justify(value: "start" | "center" | "end" | "space-between" | "space-around" | "space-evenly"): this
alignContent(value: "start" | "center" | "end" | "stretch" | "space-between" | "space-around" | "space-evenly"): this
grow(value?: number): this
wrap(enabled?: boolean): this
opacity(value: number): this
clip(enabled?: boolean): this
position(position: { x?: Length; y?: Length }): this
as(name: string): this
rightOf(target: string, gap?: number): this
leftOf(target: string, gap?: number): this
above(target: string, gap?: number): this
below(target: string, gap?: number): this
centerOn(target: string): this
alignTop(target: string): this
alignLeft(target: string): this
anchor(position: AnchorSide, margin?: number): this
rotate(degrees: number): this
showAt(step: number): this
className(value: string): this

The string overload appends zero-configuration Tailwind CSS utility classes. The object overload applies inline CSS properties and therefore takes precedence over utility classes.

Container builders also provide:

add(...children: ElementBuilder[]): this
row(): this
column(): this
stack(): this
grid(columns: GridColumns, gap?: Length): this
canvas(): this
center(): this

Rectangle and circle builders additionally provide:

fill(value: string): this
stroke(value: string): this
strokeWidth(value: Length): this

Line builders provide:

type AnchorSide =
  | "center" | "top" | "bottom" | "left" | "right"
  | "top-left" | "top-right" | "bottom-left" | "bottom-right";

stroke(value: string): this
strokeWidth(value: Length): this
arrow(value?: "none" | "start" | "end" | "both"): this
from(reference: string, offset?: { dx?: number; dy?: number }): this
to(reference: string, offset?: { dx?: number; dy?: number }): this

Calling arrow() without an argument adds an end arrow. A line has no arrow by default.

from() and to() take the name given to an object by as(), optionally followed by an anchor: "encoder" or "encoder.top-right". Without an anchor FrameSeq uses the edges that face the other end of the connector.

as(), the placement modifiers, and connector anchors are resolved by resolveAnchors(root) before rendering. mountSlides() calls it, so linear documents need nothing further; the function is exported for tools that consume the node tree directly. Names are scoped to a slide, may be referenced before they are defined, and require both objects to share a coordinate system — the same canvas(), or a container positioned with position().

Unit helpers#

px(value: number): string
pt(value: number): string
rem(value: number): string
percent(value: number): string
vw(value: number): string
vh(value: number): string

Plain numeric lengths are interpreted as pixels.

Internal interfaces#

getActivePresentation() and FrameSeqNode are exported for the compiler and renderer. They are not part of the recommended authoring surface and may change as the compiler evolves.