Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 31 additions & 36 deletions docs/guide/12_posters.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The examples in `examples/poster/` show four kinds, and `examples/py-doc.yml` li

| Example | What it shows |
|---|---|
| `poster.md` | Portrait A1 in the default theme: a picture, a Mermaid diagram, bar and line charts, segments, flow, lanes and `lcd` screens. Also a timeline, a JSON code block and a full-width section. A QR code is in the footer. Every setting is in its front matter |
| `poster.md` | Portrait A1 in the default theme: a picture, a Mermaid diagram, bar and line charts, segments, flow, lanes and `lcd` screens. Also a timeline, a JSON code block, a full-width section, and a band of three columns (`{cols=3}`) under a band of two. A QR code is in the footer. Every setting is in its front matter |
| `landscape.md` | Landscape A1 in three columns, in the theme of a made-up company, with its web fonts inside the page (`embed_fonts: [latin]`) and a partner logo in the footer. A numbered Mermaid sequence from `diagrams.mermaid`, a gallery of mounting drawings, an acceptance checklist, handover steps, a QR block and an included table. The words and the layout (orientation, paper) are in the front matter, and the company's look (theme, header, footer) is in `py-doc.yml` |
| `release.md` | Portrait A3 in the dark theme: a column chart with two series, a before and after `compare` and a Mermaid sequence with notes. Also title cards, a vertical timeline, callouts, `people`, references and a `{{version}}` variable |
| `reliability.md` | Portrait A0 in the print theme, in three columns set by `columns` and `split`, with the logo on the right and `version: git`. PlantUML, Graphviz, Vega-Lite and ditaa (PNG) diagrams, a `figure` block, a line chart with `max`, `height` and `colours`, `highlight` figures, `progress` bars, `[[INCLUDE:]]`, `[[INCLUDE-CODE:]]`, `[[IF:]]` and `[[NOT:]]` with `conditions` from `py-doc.yml`, and table and figure captions |
Expand Down Expand Up @@ -94,53 +94,48 @@ A mistake in `py-doc.yml`, such as an unknown key or a mapping where a value sho

## Page structure

A poster is laid out from the top down, always in this order:
A poster is its header, then its sections in the order of the file, then its footer. What each section is, and how wide, is said in braces at the end of its heading. No heading name has a meaning of its own, so the headings are yours to choose.

1. **Header**: `title`, `subtitle`, `byline` and `logo` from the settings. Without a title, the first `#` heading is the title.
1. **Stats** and **abstract**: `## Stats` and `## Abstract`, full width, wherever they are in the file.
1. **The bands**, in the order of the sections. A section whose heading ends in `{.wide}` is a full-width band of its own. The sections between two wide ones are a band of columns, balanced by height.
1. **Summary** and **references**: `## Summary` and `## References`, full width, wherever they are in the file.
1. **Footer**: from the `footer` setting, full width at the bottom.

So a poster that goes full width, two columns, full width, two columns, full width is written as:

```markdown
## 1. Overview {.wide}
## 2. Left of the first band
## 3. Right of the first band
## 4. Results {.wide}
## 5. Left of the second band
## 6. Right of the second band
## 7. Next steps {.wide}
## Summary
```
| Braces | The section is |
|---|---|
| None | A section in a band of columns |
| `{.wide}` | A section that spans every column, a band of its own |
| `{.stats}` | The strip of figures: a table of value, label, and optionally a change and a verdict. The header row is ignored |
| `{.abstract}` | The introduction box |
| `{.summary}` | The banner, from its first paragraph, then a block for each `###` |
| `{.references}` | A list in small type, in two columns, under its own heading |

`columns:` sets how many columns every band of columns has.
A stats strip, abstract, summary or references list is full width and has no heading bar: the heading names it in the file, and only a references list shows it. Each goes where it is in the file, so a second stats strip can sit halfway down.

| Heading | Becomes |
|---|---|
| `## Stats` | A table of value, label, and optionally a change and a verdict, shown as the strip of figures. The header row is ignored |
| `## Abstract` | The introduction box |
| `## 1. Heading: accent` | A section. The text after the first colon is coloured |
| `## Summary` | The first paragraph is the banner, and each `###` is a block |
| `## References` | A list in small type above the footer, in two columns |
The other braces change one section:

A section heading can end with attributes in braces:
- `{cols=3}` gives its band of columns three columns. Give it on any one section of the band. Without it, the band has `columns:` columns.
- `{.flow}` lets the section go on in the next column, between two of its blocks, under its heading again with "(continued)". Use it for a section much taller than the rest. A caption stays with its picture or table.
- `{colour=coral}` colours its heading bar, or the box of an abstract or the banner of a summary, with any block colour.

- `{.wide}` makes the section span every column. The sections before it are balanced into the columns above it, and those after it into the columns below. `split` cannot be used with a wide section.
- `{.flow}` lets the section go on in the next column, between two of its blocks, under its heading again with "(continued)". Use it for a section much taller than the rest. A caption stays with its picture or table. It has no effect with `split` or on a wide section.
- `{colour=coral}` colours its heading bar, with any block colour.
The sections between two full-width parts are a band of columns, balanced by height. Of every way to share them out, in order, the page takes those whose tallest column is shortest, and of those the one whose columns are most even. `split` chooses the columns by hand instead, on a poster with one band of columns.

Of every way to share the sections out, in order, the page takes those whose tallest column is shortest, and of those the one whose columns are most even.
So a poster that goes full width, two columns, full width, three columns, then a summary is written as:

```markdown
## 5. Roadmap: what comes next {.wide}
## 6. Troubleshoot: when a node will not join {.wide colour=slate}
## Key figures {.stats}
## Why this matters {.abstract}
## 1. Overview {.wide}
## 2. Left of the first band {cols=2}
## 3. Right of the first band
## 4. Results {.wide colour=slate}
## 5. First of three {cols=3}
## 6. Second of three
## 7. Third of three
## In short {.summary}
## Sources {.references}
```

The header comes from the `title`, `subtitle`, `byline`, `logo` and `header` settings, and the footer from the `footer` setting. They have no section, because they are the same on every page of a project. Without a `title`, the first `#` heading is the title. In a section heading, the text after the first colon is coloured.

### Trends

A third column in `## Stats` is a change, shown under the label with an arrow. A change that starts with `+` or `up` points up, one that starts with `-` or `down` points down, and anything else points sideways. Up and sideways are good news (`good` colour) and down is bad news (`bad` colour), unless a fourth column says `good` or `bad`:
A third column in a `{.stats}` table is a change, shown under the label with an arrow. A change that starts with `+` or `up` points up, one that starts with `-` or `down` points down, and anything else points sideways. Up and sideways are good news (`good` colour) and down is bad news (`bad` colour), unless a fourth column says `good` or `bad`:

```markdown
| Value | Label | Change | Verdict |
Expand Down
35 changes: 18 additions & 17 deletions docs/guide/13_writing_posters.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ Open `sn100.html` in a browser. Keep it open as you write: build again and reloa

## The parts of the page

A poster is built from its `##` headings. Four headings are special, and every other one is a section:
A poster is built from its `##` headings, in the order you write them. A heading is an ordinary section unless the braces at its end say otherwise, and the heading text is always yours:

| You write | It becomes | Advice |
|---|---|---|
| Front matter `title`, `subtitle`, `byline` | The header | A title of up to six words. The subtitle says why it matters |
| `## Stats` | The strip of figures under the header | Three or four figures that make the case at a glance |
| `## Abstract` | The introduction box | Two or three sentences: the problem and what the poster shows |
| `## Key figures {.stats}` | A strip of figures | Three or four figures that make the case at a glance |
| `## Introduction {.abstract}` | The introduction box | Two or three sentences: the problem and what the poster shows |
| `## 1. Heading: accent` | A section, in columns | Number the sections in reading order |
| `## Summary` | The banner and the closing blocks | The one message, then one block for each thing to remember |
| `## References` | A small list above the footer | Only what a reader would look up |
| `## In short {.summary}` | The banner and the closing blocks | The one message, then one block for each thing to remember |
| `## References {.references}` | A small list | Only what a reader would look up |

The parts always appear in the order of this table, whatever order you write them in. Sections keep your order, top to bottom, then left to right.
Write them in the order of this table, as most posters go. Every part is placed where it is in the file, so you can move one, such as a second strip of figures halfway down.

## The header

Expand All @@ -70,10 +70,10 @@ A left-aligned header suits a long title. A centred one suits a short title and

## The stats strip

`## Stats` is a table of a value and a label. The header row is ignored, so it can say anything:
`{.stats}` makes a table of a value and a label into the strip. The header row is ignored, so it can say anything:

```markdown
## Stats
## Key figures {.stats}

| Value | Label | Change | Verdict |
|---|---|---|---|
Expand All @@ -88,7 +88,7 @@ Keep each value short, such as `5 years` or `0.2 °C`, so it reads from across a

## The introduction

`## Abstract` is the blue box under the stats. Write two or three sentences that a reader can take in before deciding to read on. It is ordinary Markdown, so **bold** and links work.
`{.abstract}` makes a section the blue box: `## Introduction {.abstract}`. Write two or three sentences that a reader can take in before deciding to read on. It is ordinary Markdown, so **bold** and links work.

## Sections

Expand All @@ -98,17 +98,18 @@ Every other `##` heading is a section. The text before the first colon is the he
## 2. Power: where the charge goes
```

The sections are shared out between the columns, in order: two columns for a portrait poster and three for a landscape one. The page measures each section, charts and diagrams included, and balances the columns by height. Change that with `columns:` and `split:` in the front matter:
The sections are shared out between the columns, in order: two columns for a portrait poster and three for a landscape one. The page measures each section, charts and diagrams included, and balances the columns by height. Change the number for the whole poster with `columns:` in the front matter, or for one band with `{cols=3}` on any of its sections. `split:` chooses the columns by hand, on a poster with one band:

```yaml
columns: 3
split: 2, 2 # two sections in the first column, two in the second, the rest in the third
```

Three attributes in braces after a heading change one section:
Four attributes in braces after a heading change one section:

- `{.wide}` makes the section span every column. Use it for a timeline, a wide diagram or a table with many columns. The sections before it are balanced into columns above it, and the ones after it below.
- `{.flow}` lets a long section go on in the next column, between two of its blocks, under its heading marked "(continued)". The page breaks it only when that makes the columns more even.
- `{cols=3}` gives its band of sections three columns, so one band can have two and the next three.
- `{colour=red}` colours its heading bar, to mark a warning or a section that stands apart.

```markdown
Expand Down Expand Up @@ -319,10 +320,10 @@ A local picture, `![Board](board.svg)`, is embedded in the page. A table is show

## The summary and references

`## Summary` closes the poster. Its first paragraph is the banner, so make it the one message from your plan. Each `###` under it is a block, for the two or three things a reader should take away:
`{.summary}` closes the poster: `## In short {.summary}`. Its first paragraph is the banner, so make it the one message from your plan. Each `###` under it is a block, for the two or three things a reader should take away:

```markdown
## Summary
## In short {.summary}

One coin cell, five years, one message only when something changes.

Expand All @@ -335,7 +336,7 @@ A reading a minute costs little, because measuring is cheap.
The radio is the cost, so the node sends only what is new.
```

`## References` is a list in small type above the footer. Number it, and cite its entries in the text as `[1]`.
`{.references}` makes a list in small type, under its own heading, such as `## References {.references}`. Number it, and cite its entries in the text as `[1]`.

## The footer

Expand Down Expand Up @@ -454,14 +455,14 @@ footer:
qr-label: Full notes
---

## Stats
## Key figures {.stats}

| Value | Label | Change | Verdict |
|---|---|---|---|
| 5.7 years | Battery life | +14 % | |
| 4 s | Typical join | -7 s | good |

## Abstract
## Introduction {.abstract}

Firmware 2.1 sends less, joins faster and can always go back to the last version that worked.

Expand All @@ -484,7 +485,7 @@ Roll back | A failed self-test returns to the old copy | amber

> **Warning:** do not update a node whose battery is below 2.4 V.

## Summary
## In short {.summary}

Install 2.1 everywhere: it costs one message and saves months of battery.

Expand Down
1 change: 1 addition & 0 deletions docs/requirements/01_functional.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ title: Functional requirements
| FR-157 | `version: git` on a poster shall take its version from Git, as on a document. | Could | Met |
| FR-158 | `py-doc lint` and `py-doc build --lint` shall lint the posters of `py-doc.yml` with every rule but the document structure, acronym and passive voice rules. | Should | Met |
| FR-159 | `py-doc poster --watch` shall build the posters again on every save of their sources and reload them in the browser, and show a failed build's error over the last good page. | Could | Met |
| FR-160 | A poster's sections shall say in braces what they are and how they are laid out: `{.stats}`, `{.abstract}`, `{.summary}`, `{.references}`, `{.wide}` and `{cols=}`. No heading name shall have a meaning of its own, and every part shall be placed in the order of the file. | Should | Met |

## Tool container

Expand Down
4 changes: 2 additions & 2 deletions docs/requirements/04_traceability.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ title: Traceability
| FR-080 to FR-086, QR-081 | `c4/` | `test_c4.py` |
| FR-100 to FR-106 | `lint/`, `markdown/` | `test_lint.py`, `test_lint_cli.py`, `test_structure.py`, `test_vale.py`, `test_markdownlint.py`, `test_markdown_ast.py` |
| FR-120 to FR-127, QR-082 | `site/`, `pandoc/resources/site.lua` | `test_site.py` |
| FR-130 to FR-139, FR-150 to FR-159 | `poster.py`, `poster_blocks.py`, `poster_fonts.py`, `poster_settings.py`, `poster_themes.py`, `poster_cli.py`, `poster_watch.py`, `config.py`, `app.py`, `lint/linter.py`, `diagrams/tools/poster_pdf.js` | `test_poster.py`, `test_poster_browser.py` |
| FR-130 to FR-139, FR-150 to FR-160 | `poster.py`, `poster_blocks.py`, `poster_fonts.py`, `poster_settings.py`, `poster_themes.py`, `poster_cli.py`, `poster_watch.py`, `config.py`, `app.py`, `lint/linter.py`, `diagrams/tools/poster_pdf.js` | `test_poster.py`, `test_poster_browser.py` |
| FR-028 | `diagrams/render.py`, `config.py` | `test_diagrams.py` |
| FR-128 | `site/pages.py`, `site/engines.py` | `test_site.py` |
| FR-140 to FR-143, QR-040 to QR-043 | `runtime/`, `tools_cli.py` | `test_runtime.py`, `test_image.py`, `test_setup.py`, `test_doctor.py`, `test_platform.py` |
Expand Down Expand Up @@ -51,7 +51,7 @@ The issues of the repository, as reviewed on 18 October 2026, and the requiremen
| #48 | Site navigation from document metadata | FR-122 | Done: navigation from the documents, their titles and order, `site.groups`, and a hand-made navigation kept |
| #149 | HTML posters from Markdown: py-doc poster, themes and orientation | FR-130 to FR-135 | Done: `py-doc poster`, portrait and landscape, columns, built-in and file themes, examples |
| #150 | Poster: full-width sections | FR-137 | Done: `{.wide}` on a section heading, and `{colour=}` for its heading bar |
| #151 | Poster: callout types, timeline, trend stats and references | FR-136, FR-137 | Done: callouts in both spellings, `timeline`, trends in `## Stats`, `## References`, and `chart` |
| #151 | Poster: callout types, timeline, trend stats and references | FR-136, FR-137 | Done: callouts in both spellings, `timeline`, trends in the `{.stats}` strip, a `{.references}` list, and `chart` |
| #152 | Poster: QR code and partner logos in the footer | FR-137 | Done: `footer.qr`, `footer.logos`, and a `qr` block |
| #153 | Poster: embed theme fonts so a poster looks the same offline | FR-150 | Done: `fonts.files` in a theme, and `embed_fonts` (or `--embed-fonts`) for the stylesheet's web fonts, cached |
| #161 | A host runtime, to build with the tools on the PATH instead of the container | None yet | Open, low priority |
Expand Down
6 changes: 3 additions & 3 deletions examples/poster/landscape.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ orientation: landscape # the sections are written for three columns, so the lay
paper: a1
---

## Stats
## Key figures {.stats}

| Value | Label |
|---|---|
Expand All @@ -15,7 +15,7 @@ paper: a1
| -95 dBm | Weakest signal accepted |
| 0 | Tools beyond a phone and a ladder |

## Abstract
## Introduction {.abstract}

A network of SN-100 nodes reports through gateways to an MQTT broker. Commissioning places the gateways, joins each node, checks its signal and readings, and records where it is. This poster is the checklist the field team follows.

Expand Down Expand Up @@ -135,7 +135,7 @@ https://example.com/commissioning/upload
| `E01` | The sensor is not found: return the node, do not open it |
| `RETRY 5/5` | The broker did not answer: check the gateway's Ethernet, then call support |

## Summary
## In short {.summary}

Plan the gateways, fit them first, join each node and record where it is.

Expand Down
27 changes: 24 additions & 3 deletions examples/poster/poster.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ footer:
qr-label: Datasheet
---

## Stats
## Key figures {.stats}

| Value | Label | Change | Verdict |
|---|---|---|---|
Expand All @@ -22,7 +22,7 @@ footer:
| 0.2 °C | Temperature accuracy | | |
| 1 KB | Firmware update block | | |

## Abstract
## Introduction {.abstract}

The SN-100 measures temperature and humidity and publishes each reading over MQTT. It sleeps between readings, so one coin cell lasts five years. This poster shows how it wakes, measures, sends and goes back to sleep.

Expand Down Expand Up @@ -144,7 +144,28 @@ Jul 2026 | Display option | For installers | green
Oct 2026 | Ten-year cell | Twice the life | amber
```

## Summary
## 8. SN-100-T: temperature only {cols=3}

Order code `SN100-T-868`. For rooms where only the temperature matters, such as server rooms.

- Temperature, ±0.2 °C
- Cell life 6.5 years

## 9. SN-100-TH: temperature and humidity

Order code `SN100-TH-868`. The standard node, and the one this poster describes.

- Humidity, ±1.8 % RH
- Cell life 5 years

## 10. SN-100-THD: with a display

Order code `SN100-THD-868`. For installers and for rooms a person checks by eye.

- The display of section 5
- Cell life 4.5 years

## In short {.summary}

One coin cell, five years, one message only when something changes.

Expand Down
Loading
Loading