Skip to main content

Interactive Answer

Productivity skill, available on Zeplik

Interactive Answer is a ready-to-run productivity skill on Zeplik. The answer is worth more as something the reader can USE than as prose: a calculator, a comparison, a plan, a what-if. Ask in plain language and Zeplik applies the skill's method for you inside the conversation, on whichever AI model you prefer. It returns a structured dashboard you can keep and reuse: One zeplik-ui fenced block holding an OpenUI Lang program, rendered inline in the reply as working components (and projected to text for exports and shared pages).

The Interactive Answer skill loads automatically when your request matches it, or you can invoke it directly by typing /interactive-answer in any chat. It works with attachments, connectors, and any model that supports the task, so you get the same expert method every time without setting anything up.

What the Interactive Answer skill can do

Try these prompts on Zeplik

Pick a prompt to open it in the Zeplik app. If you are not signed in yet, your prompt is waiting for you the moment you do.

How the Interactive Answer skill works

An INTERACTIVE ANSWER is a small program you write instead of prose, and the reader can use it: a calculator whose sliders move, a comparison that becomes a chart, a plan with tick boxes, a what-if the reader re-runs without asking you again. Write one when the reader's question has a number they will want to change, several options to weigh, or a result that depends on an assumption. Write ordinary prose for everything else -- an interactive answer to a question that wanted a sentence is worse than the sentence.

Syntax Rules

  1. Each statement is on its own line: identifier = Expression
  2. root is the entry point — every program must define root = Col(...)
  3. Expressions are: strings ("..."), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)
  4. Use references for readability: define name = ... on one line, then use name later
  5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.
  6. Arguments are POSITIONAL (order matters, not names). Write SomeComp([children], "row", "l") NOT SomeComp([children], direction: "row", gap: "l") — colon syntax is NOT supported and silently breaks
  7. Optional arguments can be omitted from the end
  • Strings use double quotes with backslash escaping

Component Signatures

Arguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming. Props typed ActionExpression accept one @step, or Action([@steps...]) for several. See the Action section for available steps (@ToAssistant, @OpenUrl). Props marked $binding<type> accept a $variable reference for two-way binding.

Col(children: any[], gap?: "xs" | "sm" | "md" | "lg") — Vertical stack. The root of every answer. Row(children: any[], gap?: "xs" | "sm" | "md" | "lg") — Horizontal row of children; wraps onto more lines on a narrow screen. Card(children: any[], title?: string) — A bordered surface that groups related children, with an optional title. Divider() — A thin rule between sections. Title(text: string, level?: "1" | "2" | "3") — A section heading. Text(text: string | number) — A paragraph. Inline bold, italic, code and links render. Caption(text: string | number) — Small secondary text: an assumption, a note, a source. Badge(text: string | number, tone?: "neutral" | "info" | "success" | "warning" | "danger") — A small coloured label. List(items: (string | number)[], ordered?: boolean) — A bulleted or numbered list of lines. Stat(label: string, value: string | number, caption?: string | number) — One large figure with a label. Use it for every computed result. Table(columns: string[], rows: (string | number)[][]) — A comparison table. Every row must have as many cells as there are columns. Chart(kind: "bar" | "line" | "area" | "pie" | "donut", data: any[], x: string, y: string[]) — A chart over rows of data. Slider(value: $binding<number>, min: number, max: number, step?: number, label?: string) — A numeric slider. Bind it to a $variable WITH a default. Field(value: $binding<string | number>, label?: string, kind?: "text" | "number") — A one-line text or number input bound to a $variable. Select(value: $binding<string>, options: string[], label?: string) — A dropdown bound to a $variable. Checkbox(value: $binding<boolean>, label: string) — A tick box bound to a $variable. Choice(value: $binding<string>, options: string[]) — A segmented control, for two to four options, bound to a $variable. Button(label: string, onPress?: ActionExpression, variant?: "solid" | "soft" | "ghost") — A button that runs an action: @Set a $variable, @Reset the answer, or @ToAssistant to ask a follow-up. Icon(name: "check" | "close" | "alert" | "info" | "star" | "clock" | "trending-up" | "plus" | "minus" | "target" | "idea" | "calendar" | "bolt" | "dot", tone?: "neutral" | "info" | "success" | "warning" | "danger") — A small icon, for a yes/no cell or a direction. Formula(latex: string, display?: boolean) — A mathematical formula written in LaTeX.

Built-in Functions

@Pow(base: number, exponent: number) → number — base raised to exponent. There is NO ** or ^ operator -- use this @Money(amount: number, currency?: string) → string — format an amount as money: @Money(1284.5) or @Money(1284.5, "EUR") @Num(value: number, decimals?: number) → string — format a number with thousands separators and N decimals: @Num(1284.4567, 1) @Percent(part: number, total: number, decimals?: number) → string — part of total as a percentage string: @Percent(3, 4) -> 75% @Clamp(value: number, min: number, max: number) → number — hold a number between a low and a high bound @Range(start: number, end: number) → number[] — a list of whole numbers from start to end inclusive, for @Each

Action — Button Behavior

An action wires a button click to operations. Pass one @-prefixed step bare, e.g. Button("Ask", @ToAssistant("Tell me more")). Put several steps in Action([...]), e.g. Button("Read", Action([@OpenUrl("https://example.com"), @ToAssistant("Summarize this page")])). Steps execute in order. Buttons without an action automatically send their label to the assistant (equivalent to @ToAssistant(label)).

Available steps:

  • @ToAssistant(message: string, context?: any) — Send a message to the assistant (for conversational buttons like "Tell me more", "Explain this"). The optional context is any value (object, array, string, number) passed to the assistant as hidden data, e.g. @ToAssistant("Show details", {orderId: 42})
  • @OpenUrl(url: string) — Navigate to a URL

Example — simple nav:

viewBtn = Button("View", @OpenUrl("https://example.com"))
  • An action can be assigned to a variable or inlined: Button("Go", onSubmit) and Button("Go", Action([...])) both work

Hoisting & Streaming (CRITICAL)

openui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.

During streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.

Recommended statement order for optimal streaming:

  1. root = Col(...) — UI shell appears immediately
  2. Component definitions — fill in as they stream
  3. Data values — leaf content last

Always write the root = Col(...) statement first so the UI shell appears immediately, even before child data has streamed in.

Examples

$amount = 450000 $rate = 6.4 $years = 25 root = Col([heading, controls, figures, note], "md") heading = Title("What the loan costs", "1") controls = Card([amount, rate, years], "Your loan") amount = Slider($amount, 50000, 1000000, 5000, "Amount borrowed") rate = Slider($rate, 0.5, 15, 0.1, "Rate (% a year)") years = Slider($years, 5, 40, 1, "Term (years)") monthlyRate = $rate / 100 / 12 payments = $years * 12 growth = @Pow(1 + monthlyRate, payments) monthly = $amount * monthlyRate * growth / (growth - 1) figures = Row([perMonth, inAll], "md") perMonth = Stat("Every month", @Money(monthly)) inAll = Stat("Paid in all", @Money(monthly * payments), "Principal and interest") note = Caption("A fixed rate, no fees, and no overpayments.")

Important Rules

  • Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)

Final Verification

Before finishing, walk your output and verify:

  1. root = Col(...) is the FIRST line (for optimal streaming).
  2. Every referenced name is defined. Every defined name (other than root) is reachable from root.
  • Put the program in ONE fenced block tagged zeplik-ui. Write at most a sentence before it and nothing after it.
  • ARITHMETIC: + - * / % and parentheses work, and so do comparisons and cond ? a : b. THERE IS NO ** AND NO ^ OPERATOR. 2 ** 10 evaluates to 0 and 2 ^ 10 evaluates to 2, both silently. Write @Pow(base, exponent) for every power, including compound interest and loan payments.
  • DECLARE EVERY $variable ON ITS OWN LINE FIRST, then bind it BARE: $rate = 6.4 and then Slider($rate, 0.5, 15, 0.1, "Rate"). Writing the default inside the prop -- Slider($rate = 6.4, ...) -- produces a control that LOOKS right and is dead: the default never lands, so every figure derived from it reads as nothing, and dragging the control writes the literal back instead of what the reader chose.
  • Define every name you reference, and reference every name you define. Both halves are silent failures: an undefined name renders as nothing, and a statement nothing reaches is dropped.
  • Compute what you show. Bind the inputs, derive the figures from them, and let the reader change them -- do not print a worked number and ask them to come back for another.
  • Round what you show: @Money(x) for currency, @Num(x, 1) for everything else. A raw 1284.4567891 reads as a bug.
  • Say what the answer assumes, in a Caption. Every calculator rests on something.
  • Keep it to the answer: around forty statements is plenty, and a program that stops mid-way renders half an answer.
  • No prose duplicated in both places. If the program says it, do not also write it above the fence.

How to use the Interactive Answer skill

  1. Sign in to Zeplik

    Create a free Zeplik account or sign in. New accounts start with free credits, so you can try the Interactive Answer skill right away.

  2. Describe your productivity task

    Ask in plain language, or type /interactive-answer to invoke the skill directly. Zeplik recognizes the Interactive Answer skill and applies its method.

  3. Review and refine the result

    Zeplik returns a structured dashboard you can edit, download, and reuse. Ask follow-ups to refine it.

Source and credit

Author
zeplik
License
MIT

Original Zeplik skill. Built and maintained by the Zeplik team.

Frequently asked questions

What is the Interactive Answer skill?
Interactive Answer is a ready-to-run productivity skill on Zeplik. The answer is worth more as something the reader can USE than as prose: a calculator, a comparison, a plan, a what-if. Ask in plain language and Zeplik applies the skill's method for you inside the conversation, on whichever AI model you prefer. It returns a structured dashboard you can keep and reuse: One zeplik-ui fenced block holding an OpenUI Lang program, rendered inline in the reply as working components (and projected to text for exports and shared pages).
How do I use Interactive Answer on Zeplik?
Sign in to Zeplik and ask in plain language, or type /interactive-answer in any chat to invoke it directly. The skill applies its method and returns a result you can refine in the same conversation.
Which AI model does the Interactive Answer skill use?
Any model you choose. Zeplik works across every model in one chat, so the Interactive Answer skill runs on your preferred model for the task.
Where does the Interactive Answer skill come from?
The Interactive Answer skill is an original Zeplik skill, maintained by the Zeplik team.
How much does the Interactive Answer skill cost?
Using the skill is free to start. You only spend Zeplik credits when the assistant runs, and new accounts begin with free credits.

Related productivity skills

More on Zeplik

Try Interactive Answer on Zeplik

Every model, one chat. Bring the Interactive Answer skill into your next conversation and let the assistant do the work.

Browse all skills