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
- Apply the Interactive Answer method to your productivity task
- The answer is worth more as something the reader can USE than as prose: a calculator, a comparison, a plan, a what-if
- Handle related work: calculator, interactive, slider, what-if
- Produce a reusable dashboard you can save and share
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
- Each statement is on its own line:
identifier = Expression rootis the entry point — every program must defineroot = Col(...)- Expressions are: strings ("..."), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)
- Use references for readability: define
name = ...on one line, then usenamelater - 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.
- Arguments are POSITIONAL (order matters, not names). Write
SomeComp([children], "row", "l")NOTSomeComp([children], direction: "row", gap: "l")— colon syntax is NOT supported and silently breaks - 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:
root = Col(...)— UI shell appears immediately- Component definitions — fill in as they stream
- 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:
- root = Col(...) is the FIRST line (for optimal streaming).
- 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 ** 10evaluates to 0 and2 ^ 10evaluates 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.4and thenSlider($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
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.
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.
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
- Audio TranscriberUse when the user attaches audio or voice recordings to transcribe -- cleanup, speaker labels, timestamps, minutes or notes from a recording. Not for summarizing documents (use summarize-anything).
- Deadline PrepUse when a demo, standup, or delivery deadline looms: turn git history and notes into a structured demo outline. Not for sprint ceremonies (use sprint-planning) or capacity math (use capacity-plan).
- File OrganizerUse when designing a folder structure and reorganization plan for messy files -- downloads cleanup, duplicates, naming, archive rules. Not for converting file formats (use file-conversion).
- Linear Issue AssistantUse when the user pastes Linear issues, CSV exports, or cycle data -- triage, well-formed issue writeups, cycle plans, updates in Linear conventions. Not for sprint ceremonies (use sprint-planning).
- Marp Slide DecksUse when creating Markdown/Marp slide decks with themed embedded CSS the user renders via Marp CLI or VS Code. Not for general presentation building (use slides).
- Notion WorkflowsUse when designing Notion databases, templates, formulas, or workspace systems -- knowledge capture, meeting docs, specs, template businesses. Not for generic note-taking advice.
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.