# Reports and templates A report is built on the **Reporting** canvas as a chain of nodes (New Report → Add Heading → Add Value → … → Render PDF) and rebuilt on every run, so it never falls out of step with the calculation. **Render PDF** typesets it with [Typst](https://typst.app) and a **template**, which decides how it looks: an engineering report, a journal article, a calculation note. The tutorial's chapter *A first report* builds one and then switches its template (Help › Tutorial). ## The templates | Template | What it is | Fields it asks for | |---|---|---| | **Report** (`default`) | A numbered A4 report: title block, abstract, sections and lettered appendices | authors (optional) | | **IEEE-style article** (`ieee-article`) | Two columns on US letter, Roman-numbered sections, "Fig." and "TABLE" captions, IEEE-style references, index terms. Written for noodlelab, not IEEE's official template: check your venue's instructions | authors, keywords | | **Calculation note** (`calc-note`) | A document number, revision, who prepared, checked and approved it, a revision history, and "sheet n of m" on every page | **doc_number**, **revision**, project, prepared_by, checked_by, approved_by, status, revisions | | **Test report** (`test-report`) | Opens with the verdict and the compliance matrix, then the test article, procedure and details | **test_article**, report_number, procedure, facility, tested_by, witness | | **One-page summary** (`summary`) | The title, abstract, key values, the verdict and the first figure, on one page; everything else is left out | – | | **Slides** (`slides`) | A 16:9 deck: a title slide, then a slide for every top-level heading | – | Fields in bold are required: Render PDF warns while you edit when one is empty, and the PDF still renders. ![The Template section of a Render PDF node, with a preview of the calculation note](images/report-templates.png) ## Choosing a template Select a **Render PDF** node. The inspector's **Template** section has: - a dropdown of every template: noodlelab's, your plugins', and your workspace's (see below); - a form for the fields the chosen template asks for; - **Preview**: a page of a specimen report in that template, with your fields. The specimen shows every kind of block; your own report appears when the graph runs. The fields are stored on the node as **Template fields**, one `name: value` per line, so the graph keeps them and a script or an agent can set them too: ```text doc_number: CN-0042 revision: B checked_by: A. Person revisions: A | 2026-09-01 | First issue | NK revisions: B | 2026-10-01 | Added Monte Carlo | NK authors: Ada Lovelace; Analytical Society; ada@example.org authors: Charles Babbage; Analytical Society ``` A field of kind *list* (`revisions`, `keywords`) takes one value per line, as does *people* (`authors`), whose values are `Name; Affiliation; email`. Without `authors`, templates use New Report's author line. ## Cross-references, citations and concise values - **Labels.** Add Figure, Add Image, Add Table, Add Key Values and Add Equation take a `label` (`fig-drag`, `tab-inputs`, `eq-period`). Text with *markup* on refers to it as `@fig-drag`, which becomes "Figure 2" (or "Fig. 2" in the article), numbered by the template. - **Citations.** **Add Bibliography** reads a BibTeX (`.bib`) or Hayagriva (`.yml`) file and places the reference list where it sits in the chain. Text with markup cites an entry by its key, `@gum2008`, and the template numbers and styles it (IEEE style in the article). A report without Add Bibliography has no references, and `@key` in it is an error. - **Concise notation.** Add Value's *style* `concise` writes an uncertain result as journals and CODATA do, `9.806(12) m/s²` instead of `(9.806 ± 0.012) m/s²`, rounded to two significant digits of the uncertainty as the GUM recommends. ## Your own templates Copy one of noodlelab's template folders ([`src/noodlelab/reports/templates/`](https://github.com/nkalis/noodlelab/tree/main/src/noodlelab/reports/templates)) into a `templates/` folder in your workspace and change it. It appears in the dropdown at once (press ↻ next to it); one with the same name as noodlelab's replaces it, so a `templates/default/` with your letterhead becomes every report's look. A template is a folder: ```text templates/letterhead/ template.typ # the Typst file that is compiled template.toml # optional: its title, description and fields logo.svg # anything else it uses ``` A single `templates/memo.typ` file is a template too, without fields or assets. **template.toml** describes the template and the fields its title block reads: ```toml title = "Calculation note" description = "A numbered calculation with a revision table" [[fields]] name = "doc_number" # an identifier: what the Template fields line starts with label = "Document number" # shown on the form required = true [[fields]] name = "revisions" kind = "list" # text (the default), list, date or people help = "One per line: Rev | Date | Description | By" ``` **template.typ** receives the report as JSON and styles it. Every template can import the blocks every report has from `noodlelab.typ`, which noodlelab puts next to it when it compiles, so a template only has to style its pages and its title block: ```typst #import "noodlelab.typ": * #let doc = load-doc() #set page(paper: "a4", margin: 2cm) #image("logo.svg", width: 3cm) = #doc.title Document #field(doc, "doc_number", default: "—") #render-blocks(doc) ``` What `noodlelab.typ` gives a template: | Name | What it is | |---|---| | `load-doc()` | The report: `title`, `subtitle`, `author`, `authors` (`name`, `affiliation`, `email`), `abstract`, `toc`, `created`, `meta` (the fields), `bibliography` and `blocks` | | `field(doc, name, default: "")` | One field's value | | `field-list(doc, name)` | A field as an array (for list and people fields) | | `author-names(doc)` | The authors' names | | `render-blocks(doc, only: none, bib-style: "ieee", appendix-numbering: "A.1", wide-columns: none)` | Every block in order. `only`: a function of a block saying whether to show it. `wide-columns`: on a page of several columns, tables with more columns than this span the page | | `render-block(b, doc: doc)` | One block | | `is-compliance(b)` | Whether a block is the compliance matrix (or its summary sentence), which a test report or summary can put first | | `data-table(columns, rows, ...)`, `markup(text, on)`, `labelled(body, b)` | The pieces the blocks are made of | Typst reads only the files in the template's folder: a template cannot reach the rest of the computer. **Plugins** can ship templates too, listed in their manifest: ```toml templates = ["reports/datasheet"] # folders (or .typ files) inside the package ``` See {doc}`plugins/writing`. ## Choosing a template from code Render PDF's `template` and `fields` are ordinary inputs, so a graph written as JSON or by an agent sets them like any other value: ```json {"id": "pdf", "type": "report.render_report", "inputs": {"report": {"link": {"node": "value", "output": "result"}}, "template": {"value": "calc-note"}, "fields": {"value": "doc_number: CN-0042\nrevision: A"}}} ``` In Python, `noodlelab.reports.render_pdf(doc, path, "ieee-article", root=workspace)` renders a `ReportDoc`, and `noodlelab.reports.find_templates(root)` lists the templates a workspace can use.