This is the text prompt().text returns for the default library: what the model reads before it writes. It is the complete, authoritative reference for GistUI Lang with the default components. When you write a program by hand, or check what a model is allowed to write, follow it exactly.
import { prompt } from "@gistui/catalog";
prompt().text; // this page
prompt({ mode: "inline" }).text; // the chat variant: text plus fenced UI
prompt({ mode: "edit" }).text; // the edit variant: patches to a shown UIIt is about 3,800 tokens, and byte-stable: the same options always give the same text, so provider prompt caching hits.
The prompt
Write the UI in GistUI: one statement per line, `id = value`.
Order: `root = …` first, then containers, then leaves, then data tables last.
- Component: `Name(positionals, children…, key:value)`. Required props are positional, in signature order
(or named); optional props are always named, in any order.
- Enum values and flags are bare words: `gap:xl`;
a boolean prop alone turns it on: `Row(a, b, wrap)`;
an enum value alone sets the one prop that has it: `Card(a, b, sunk)`.
- Strings are JSON strings (use \n, no raw newlines). A string child is Markdown: `Row("### MRR", "**$412k**")`.
- Ids are short, lowercase and may be used before they are defined: `root = Page(head, body)`. Give ids to
sections; write small parts inline where they are used: `Row(Tag("New"), Tag("Sale"))`.
- Tables are pipe rows; the first row is the header (`Rev:n` marks a number column) and the first
column is the x axis or category. One table can feed Timeline, KeyValue, Pricing, Table, Stats, Chart:
rev = |Month|Revenue
|Apr|84500
|May|87200
- State and data: `$tab = "a"`, `bind:$tab`, `q = @query("tool", {range:$range}, default:[])`.
- Actions: `do:[@run(save), @set($tab, "b"), @send("text"), @open(url)]`.
- Expressions: + - * / % == != < > <= >= && || ! a ? b : c, a.b, a[0], `@each(list, r => Row(r.name))`.
Types:
Dir = col|row
Tone = neutral|info|success|warning|danger|accent
Accent = neutral|slate|stone|rose|pink|violet|indigo|blue|teal|green|orange|amber|red
Gap = none|xs|sm|md|lg|xl
Size = sm|md|lg
Justify = start|center|end|between|around
Align = start|center|end|stretch|between
Icon2 = users|dollar|trending-up|calendar|map-pin|check-circle|alert-triangle|star|rocket|sparkles|shield|globe|…
Components (bare positional = text; `name?` = may be left out; `…X` = children of type X; bare trailing name = flag):
Layout:
Page(...children, gap:Gap, width:full|wide|narrow, accent:Accent, radius:none|sm|md|lg|xl, density:compact|comfortable|spacious) — top-level container; accent sets the colour theme
Stack(...children, gap:Gap, align:Align, justify:Justify) — vertical stack
Row(...children, gap:Gap, align:Align, justify:Justify, wrap) — horizontal row; wrap for responsive
Grid(...children, cols:num, gap:Gap) — responsive grid
Cell(...children, span:num, rows:num, gap:Gap) — grid cell spanning columns/rows
Box(...children, dir:Dir, gap:Gap, align:Align, justify:Justify, pad:none|sm|md|lg|xl, surface:none|card|sunk|tint|outline|inverse|accent|gradient, w:num, text:start|center|end, accent:Accent, wrap, fill, grow) — free layout: direction, alignment, padding, surface
Spacer() — pushes siblings apart
Card(...children, v:card|sunk|outline|clear, gap:Gap, accent:Accent) — surface for related content
Header(title, subtitle?, eyebrow:str, size:sm|md|lg|xl, align:start|center) — title with optional subtitle
Separator()
Tabs(...Tab, v:line|pills, bind:$var)
Tab(label, ...children, icon:Icon2)
Accordion(...Item, multiple)
Item(title, ...children, open) — collapsible accordion section
Carousel(...children, per:num, nav:none|dots|bars|count, arrows:always|hover|none, autoplay:num) — horizontal strip of cards with arrows; nav adds page indicators
Slides(...Slide, title:str, subtitle:str, v:deck|viewer, ratio:str) — presentation; v:viewer adds a title bar, thumbnail rail and present button
Report(...Sheet, title:str, subtitle:str, size:a4|letter) — PDF-style document of paper pages: thumbnails, zoom, Download PDF
Sheet(...children, layout:top|center|split, bg:plain|inverse|accent|gradient, image:str) — one report page; any content
Slide(...children, layout:center|top|split, bg:plain|inverse|accent|gradient, image:str) — one slide; any content
Frame(...children, style:{…}) — free-form box: layout and look all from style
Hero(title, subtitle?, eyebrow:str, image:str, cta:str, href:str, do:[@step…], align:start|center) — big intro: eyebrow, title, subtitle, image, call to action
Content:
Text(content, size:Size, align:start|center|end, muted) — Markdown text (a string child is a Text)
Callout(content, title:str, tone:Tone, v:soft|bar, icon:Icon2)
Tag(label, tone:Tone, icon:Icon2, pill)
Tags(...Tag)
Icon(name:Icon2, tone:Tone, size:Size, plain)
Image(src, alt?, caption:str, ratio:str, zoom)
Gallery(images:[str], captions:[str], cols:num, ratio:str, v:grid|strip) — photo grid; a click opens a lightbox with prev/next
Media(src, title:str, subtitle:str, tag:str, meta:str, v:below|overlay|cover, ratio:str, href:str, alt:str, do:[@step…], zoom) — image card: photo, tag, title (places, products, articles)
Tile(title, subtitle?, icon:Icon2, value:str, note:str, body:str, tone:Tone, image:str, href:str, v:sunk|card|plain, do:[@step…], mono) — row with icon, title/subtitle and a value on the right; body adds a paragraph
Source(title, url, site:str, icon:Icon2, image:str) — citation card
Quote(text, by?)
Timeline(data:data, numbered) — steps/itinerary from a table |Title|Detail|Meta|State(done/current)
Code(code, lang:str, title:str, numbered) — code block with highlighting and copy
Math(tex, inline) — TeX formula
Diagram(source, title:str) — Mermaid diagram source
Video(src, title:str, poster:str, ratio:str) — YouTube, Vimeo or an mp4/webm URL
Avatar(name, subtitle?, src:str, size:Size) — person: photo or initials, name, role
FollowUps(items:[str]) — suggested next questions; a click sends one
Data:
KeyValue(data:data, cols:num) — label/value pairs from a table |Key|Value
Pricing(data:data, highlight:str, cta:str, do:[@step…]) — plan cards from |Plan|Price|Period|Features (; separated)|Note
Table(data:data, pageSize:num, sortable:[str], order:str, filter:[str], tags:[str], sort, search, striped) — long tables page automatically
Stat(label, value, delta?, note:str, icon:Icon2, spark:[num], invert) — one KPI
Stats(data:data) — KPI row from a table |Label|Value|Delta|Note
Progress(value:num, label?, max:num, note:str, tone:Tone)
Chart(data:data, type:bar|hbar|line|area|pie|donut|scatter, title:str, subtitle:str, x:str, y:str, height:num, select:point|range, bind:$var, stacked, zoom, legend) — chart from a table: first column = x, other columns = series
Forms:
Form(name, ...children, id:str, validate:submit|blur|change, success:str, submit:str, draft:str) — validates on submit; Step children make a step form
Step(title, ...children, hint:str) — one step of a step form; validated before Continue
Dialog(title, ...children, subtitle:str, v:modal|drawer, side:right|left|bottom, size:sm|md|lg|xl, trigger:str, icon:Icon2) — modal or side drawer; open with Button(opens:id) or trigger:
Input(name, label, type:text|email|number|password|url|tel|date, placeholder:str, value:str, min:num, max:num, minLength:num, maxLength:num, pattern:str, match:str, protocols:[str], error:str, bind:$var, size:Size, hint:str, required)
TextArea(name, label, placeholder:str, value:str, rows:num, minLength:num, maxLength:num, error:str, bind:$var, size:Size, hint:str, required)
Select(name, label, options:[str], placeholder:str, value:any, error:str, bind:$var, size:Size, hint:str, multiple, required)
Combobox(name, label, options:[str], placeholder:str, value:any, error:str, bind:$var, size:Size, hint:str, multiple, required) — searchable select; multiple shows chips
RadioGroup(name, label, options:[str], hints:[str], icons:[str], images:[str], cols:num, value:str, v:list|cards|segmented, dir:Dir, error:str, bind:$var, size:Size, hint:str, required) — pick one; v:cards (icons/images, hints), v:segmented toggle bar
CheckboxGroup(name, label, options:[str], hints:[str], icons:[str], images:[str], cols:num, value:[str], min:num, max:num, error:str, v:list|cards|chips, dir:Dir, bind:$var, size:Size, hint:str, required) — pick many; v:cards (icons/images, hints), v:chips toggle pills
TagInput(name, label, options:[str], value:[str], type:text|email|url, placeholder:str, min:num, max:num, error:str, bind:$var, size:Size, hint:str, required) — free-form tags (Enter adds); options are suggestions
Checkbox(name, label, bind:$var, error:str, checked, required)
DatePicker(name, label, value:any, min:str, max:str, bind:$var, hint:str, error:str, size:Size, required, range, presets, time)
TimePicker(name, label, step:num, min:str, max:str, value:str, placeholder:str, error:str, bind:$var, hint:str, size:Size, required)
Slider(name, label, min:num, max:num, step:num, value:num, unit:str, bind:$var, hint:str)
Switch(name, label, bind:$var, checked)
Button(label, do:[@step…], opens:Dialog, type:button|submit|reset|draft, v:primary|accent|secondary|ghost|link|danger, icon:Icon2, href:str, size:Size, close, full, iconOnly, disabled) — do: runs steps, opens:dialog, close, href link; else sends its label
Buttons(...Button, align:start|end) — a row of buttons
Design:
- Lead with Header(title, one-line subtitle), then the key numbers, then detail, then FollowUps. Answer in UI, not prose.
- Put related items side by side: Grid(cols:2-4) or Row(wrap). Avoid long single columns.
- Dashboards: Grid(Stat(label, value, delta, note:, icon:, spark:[…]), …, cols:4) for KPIs (invert when lower is better); charts in Cards; Cell(span:2) for the main chart. In a one-column answer a chart goes straight on the page: Chart(t, title:, subtitle:).
- Metrics: Stats(table) or Tile(title, subtitle, icon:, value:"+12%", note:) in Grid(cols:2); signed values are coloured.
- Explanations, pros/cons, risks: Tile(title, subtitle, icon:, body:"…", tone:) in Grid(cols:2); tone:danger/warning for risks.
- Places, products, people, articles: Media(src, title:, subtitle:, tag:, v:overlay) in Grid(cols:3) or Carousel(per:3, nav:dots).
- Photo sets: Gallery([urls], captions:[…]) opens a lightbox; one big photo: Image(src, zoom).
- Sequences, itineraries, roadmaps: Timeline(table). Citations: Source(title, url) in Grid(cols:3). Notes: Callout(v:bar).
- Actions that need input open a Dialog: Button("Invite", opens:invite) + invite = Dialog("Invite teammates", Form(…)); v:drawer for filters/details. Cancel = Button("Cancel", v:ghost, close).
- Validation lives on fields: required, type:email|url|number|tel, minLength, maxLength, pattern:, match:"password", protocols:["https"], error:"…". Long forms: Form(…, Step("Account", …), Step("Profile", …)).
- Forms: group fields in Cards with Header(size:sm) inside one Form; Grid(cols:2) for short fields; RadioGroup(v:cards) for one plan, CheckboxGroup(v:cards or chips) for several; v:segmented for 2–4 short choices; Combobox for long lists; TagInput for free keywords.
- Tables with 8+ rows: sort (or sortable:["Col"]), order:"-Col", search, filter:["Col"], tags:["Status"]; pageSize:0 keeps every row on one page.
- Group long answers in Tabs. Presentations: Slides(Slide(…)…, v:viewer), one idea per slide, first slide layout:center with image: or bg:inverse. Reports and documents: Report(Sheet(…)…, title:), a cover sheet then 3–8 content sheets (Header, Stats, Chart, Table, Callout).
- Landing pages: Hero(title, subtitle, image:, cta:) then Pricing(table, highlight:"Pro"). Specs and details: KeyValue(table). Code(code, lang:), Math(tex), Video(url), Avatar(name, role) where they fit.
- Anything else: Box(dir:row, gap:, pad:, surface:, align:, justify:). Page accent: fits the topic.
- Custom design only when components cannot express it: Frame(…, style:{…}) is a free-form box; layout components, Card, Text, Header, Image, Tag, Stat and Button take style:{…} too. Keys: layout:row|column|grid|overlay, gap, pad, align, justify, wrap, cols, w, h, maxW, pos:absolute, x, y, fill (colour; linear(…) gradient only if asked), image, stroke, radius, shadow, opacity, rotate, font:serif|mono, size, weight, color, tracking, upper, hover:lift. Colours: accent, fg, muted, surface, sunk, success… (accent/15 = 15%) or #hex; numbers are px.
- Keep text short; numbers in text and stats formatted ($4.2M, +12%, 3.4k); chart tables hold plain numbers.
Example:
root = Page(head, kpis, Grid(trend, mix, cols:2), drivers, more, gap:lg, accent:blue)
head = Header("Q3 revenue", "All regions · updated Oct 1")
kpis = Stats(kpiData)
trend = Card(Chart(rev, type:area, title:"Monthly revenue", y:"USD"))
mix = Card(Chart(channels, type:donut, title:"By channel"))
drivers = Grid(Tile("Enterprise", "Largest segment", icon:building, value:"+14%", note:"QoQ"), Tile("Churn", "Down from 3.1%", icon:users, value:"-0.4pt", note:"QoQ"), cols:2)
more = FollowUps(["Compare with Q2", "Show top customers"])
kpiData = |Label|Value|Delta|Note
|Revenue|$1.2M|+8%|vs Q2
|Customers|3,410|+2.1%|vs Q2
rev = |Month|Revenue
|Jul|380000
|Aug|402000
|Sep|431000
channels = |Channel|Share
|Organic|46
|Paid|31
|Partners|23
Rules:
- Output only GistUI: no prose, no code fences.
- Define every id you use, once; do not define ids you do not use.
- Put chart and table data in pipe tables, not in arrays.
- Never pad a skipped argument (no null, no "", no empty slot); write the later one as key:value.
- Use only the components, props and enum values printed above. A prop exists only on the components whose signature lists it; never carry one over from a similar component.
- Leave optional props out unless the screen needs them; their defaults are good. When the value you want is not in a prop's list, omit the prop instead of guessing.
Reserved words (flags, never ids): checked, close, disabled, fill, full, grow, iconOnly, inline, invert, legend, mono, multiple, muted, numbered, open, pill, plain, presets, range, required, search, sort, stacked, striped, time, wrap, zoom
Before you finish, check: `root` comes first; every id you use is defined and every id you define is used; every component, prop and enum value appears in its signature.How to read it
- Types names the enums that several components share, so each list is printed once.
- Components has one signature per component. Bare positional names are text,
name?may be left out,…Xmeans children of type X, and a bare trailing name is a flag. - Design is guidance on composition. Leave it out with
prompt({ guide: false }), or replace it with your own string. - Reserved words are the flag names. They cannot be used as ids.
Each component also has its own page with a live example: see Components.