View templates and results#
A script that prints to the console gives you text that scrolls away. A script that renders a template gives you a page.
view.present("research/evidence", {
title = "Does a four day week maintain output?",
rows = findings,
caveats = { "small samples", "two of four are funded by an interested party" },
})
In Volt that is present(brief, template: "research/evidence").
Templates#
A template is markdown with a deliberately boring subset of mustache.
{{name}} |
a value, HTML-escaped |
{{{name}}} |
a value, raw — for markdown you built on purpose |
{{a.b.c}} |
a path into nested data |
{{#rows}}…{{/rows}} |
the block once per item; {{.}} is the item |
{{^rows}}…{{/rows}} |
the block only when rows is empty or missing |
{{! note }} |
a comment, dropped |
There are no partials, no lambdas, and nothing that can execute. A template formats data and that is the whole of what it can do.
Two details worth knowing. An empty list counts as absent, so {{^rows}} is how you write
"nothing found" — but 0 counts as present, because a measured zero is a result. And the
nearest scope wins, so a row's own name shadows the document's.
An unclosed or mismatched section is an error rather than silently swallowing the rest of the page.
The ones that ship#
| Template | For |
|---|---|
research/summary |
A question, an answer, and the sources it came from |
research/matrix |
A grid: one row per subject, one column per question |
research/comparison |
Side-by-side findings with an explicit "where they disagree" |
research/evidence |
A weighed table — what each source says, how big it is, who paid |
research/brief |
One page: the answer first, then the working |
They live in the same place as prompts and Lua functions — Settings → Library — so they get the same editor, the same storage, and the same "reset to the shipped version". Edit one and your version is used; delete your changes and the original comes back.
Writing your own#
Add an entry in Settings → Library with kind template. The name is how scripts ask for
it; a / in the name is just part of the name, which is why the shipped ones are grouped
under research/.
The data is whatever your script passes. A template that expects rows and is handed
nothing renders the empty case rather than failing — which is the right behaviour for a
view, and the reason sections treat missing and empty the same way.
Results#
view.show(text, title, format) puts anything in the Results panel; view.present(name, data, title) renders a template and shows it, which is what almost every script wants.
Results arrive as the script produces them, not when it finishes — a long run fills the
panel as it goes. The store is bounded at the most recent fifty, and view.results() reads
the whole list back inside a script.
From a script#
local rows = {}
for _, study in ipairs(studies) do
rows[#rows + 1] = { source = study.id, n = study.n, finding = study.effect, funding = study.funding }
end
view.present("research/evidence", { title = "Four studies", rows = rows })
And without a template, when the text is already what you want:
view.show(report, "Weekly scan", "markdown")
See the script API for the full view.* surface.