One JSON file and one Python script build a standalone report with paper texture, ink drawings, and a stage that changes as the reader scrolls.
A swatch repaints this page, so you can read a theme before you take it. It changes nothing in the kit: the theme block of report.json holds the five colors, and that block is what you copy into your own report.
To load the stylesheet and the script from this folder instead of embedding them, pass the base URL. That export needs the network; the default one does not.
Every drawing holds 12 marks. Stroke count, size, weight, and jitter come from the mark's own index, so each one is a sibling of the others and none is a copy. They are an illustration, not a chart.
The palette
paper #f6f3ebPage and card background
ink #292925Text, marks, primary button
accent #a33e36Highlights, numerals, focus ring
secondary #466958Connection lines and cover caption
wash #e7e4d9Dividers, code, methods band
Every other color on the page is mixed from these five, so a new theme moves the whole report and leaves no stranded gray behind.
The type
A story is only the beginning.
Display: the cover, the headings, the large numerals.
Follow the connections.
Body: the sentences, and the labels beside them.
Three roles carry the page, and a preset fills all three. Four presets ship with the kit. A report that names none of them sets in the reader's own faces and asks no font server for anything.
A preset names the display face, the body face and the label face at once, and every one of them carries a display weight of 800 or more. The files are latin subsets under fonts/, each with its OFL licence beside it, and the build writes the ones your preset needs into the page as data, so an export still opens from a disk with no network. The system preset embeds nothing.
system
The reader's own faces, and no file to download. The display weight is 800, which the stack draws where the face has it.
{
"fonts": {
"preset": "system"
}
}
Example cover
A story is only the beginning.
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story.
1231
field
Figtree gets out of the way of the drawing; Bricolage Grotesque at 800 carries the cover and the numerals.
{
"fonts": {
"preset": "field"
}
}
Example cover
A story is only the beginning.
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story.
1231
quill
Fraunces at 900, soft and wonky, echoes the hand-drawn marks; Nunito Sans keeps the body warm.
{
"fonts": {
"preset": "quill"
}
}
Example cover
A story is only the beginning.
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story.
1231
ink
One variable file for the whole page: casual at 1000 for display, linear at 400 for the body.
{
"fonts": {
"preset": "ink"
}
}
Example cover
A story is only the beginning.
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story.
Both layouts set the reading column at 34em, so a line holds 62 to 66 characters in every preset. The wide layout moves that column to the left gutter and opens a rail beside it for the notes, the pull quotes and any figure or table you mark with "rail": true. Below 1000 pixels the rail folds into the column at the place you wrote each block, so a phone reads one column in both layouts.
reading
The centered column the kit shipped with. A note goes to the margin beside it where the window is wide enough, and to the foot of the section where it is not.
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story. Each exchange gives information a place to go.1
Each exchange gives information a place to go.
The column holds 34em in both layouts, so no line runs past 66 characters. What changes is where the column sits and what stands beside it.
Notes
An invented example. The wide layout puts this note in the rail. Every narrower window puts it at the foot of the section. Back to the text
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story. Each exchange gives information a place to go.1
Each exchange gives information a place to go.
The column holds 34em in both layouts, so no line runs past 66 characters. What changes is where the column sits and what stands beside it.
Notes
An invented example. The wide layout puts this note in the rail. Every narrower window puts it at the foot of the section. Back to the text
Give every section a unique id that starts with a lowercase letter, such as key-findings. Use letters, digits, and hyphens. The ids main and top are reserved. The contents menu follows the order of the sections, and quote sections are left out of it because they carry no title.
Type
Fields beyond type and id
summary
title, text (under 100 words)
takeaways
label, title, items (list of text, 2 to 5)
prose
label, title, paragraphs (list of text, or a block object)
steps
label, title, items: each has title and text
glossary
title, terms: each has term and definition
scrolly
label, title, optional center_label, steps
waterfall
label, title, dataset (title, unit, totalSquares, status, source, caveat, groups)
findings
label, title, items: each has value, title, text, and optional unit, note and trend
figure
label, title, chart: kind, unit, value_format and the values the kind reads, caption, and optional source, note and rail
table
title, caption, columns: each has label, type and optional unit, rows, sort, and optional note, source and rail
quote
text, attribution
tabs
label, title, panels: each has label and paragraphs
accordion
label, title, items: each has summary and paragraphs; optional exclusive
timeline
label, title, events: each has date, title, text
image
src, alt, optional caption, credit, decorative, lightbox, and width of reading, figure or bleed
compare
label, title, before and after: each has src, alt, label; optional caption
gallery
label, title, items: each has src, alt, caption
diagram
label, title, nodes: id, label; edges: from, to, optional label; layout of row, column or ring; optional caption
part
number, title, optional deck
methods
title, paragraphs, optional brief, sources: each has label, url
A scrolly section needs at least one step, and each step names a layout of scatter, groups, network, or orbit, a caption describing the state in plain text, and a highlight. The README.md in the download lists every field and what it accepts.
A compressed abstract with its own landmark, for the top of a report.
Use it when a reader decides in one screen whether to read on.
{
"type": "summary",
"id": "summary-specimen",
"title": "In brief",
"text": "An invented example. This block states what the report holds, so a reader can decide to continue. Write it last, after the report is finished. Do not repeat the standfirst: the standfirst offers the report and this block states its content."
}
An invented example. This block states what the report holds, so a reader can decide to continue. Write it last, after the report is finished. Do not repeat the standfirst: the standfirst offers the report and this block states its content.
takeaways
A short list of the points a reader keeps, on a tinted block.
Use it at the top, when a reader who stops here needs the result.
{
"type": "takeaways",
"id": "takeaways-specimen",
"label": "Example takeaways",
"title": "Keep these three points.",
"items": [
"Shared reporting reaches readers that one newsroom cannot reach alone.",
"A collaboration needs one editor who holds the schedule.",
"An invented example. Replace each line with a point your report proves."
]
}
Shared reporting reaches readers that one newsroom cannot reach alone.
A collaboration needs one editor who holds the schedule.
An invented example. Replace each line with a point your report proves.
prose
A heading and a run of paragraphs, with five blocks a run can hold.
Use it when the reader needs the argument in sentences.
{
"type": "prose",
"id": "prose-specimen",
"label": "The question",
"title": "A story is only the beginning.",
"paragraphs": [
"A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story. Each exchange gives information a place to go.[^1] When two newsrooms answer one question together, the work becomes {collaborative reporting}.",
{
"pullquote": "Each exchange gives information a place to go."
},
{
"subhead": "What a block does"
},
"A paragraph can also be a block. Every block keeps the reading column, and none of them adds a card, an icon or a color.",
{
"list": [
"A subhead opens one part of the argument.",
"A list holds items a reader scans.",
"A pull quote lifts one sentence the reader has already read."
],
"ordered": false
},
{
"callout": {
"title": "One fact, set aside",
"text": "An invented example. A callout holds a fact that matters and would break the sentence beside it."
}
},
{
"caveat": {
"text": "An invented example. The sample is too small to carry a claim about the whole state."
}
}
],
"notes": [
"An invented example. A note holds the source or the limit that would break the sentence."
]
}
A reporter asks a question. A resident shares what they know. An editor connects the account to a wider story. Each exchange gives information a place to go.1 When two newsrooms answer one question together, the work becomes collaborative reporting.
Each exchange gives information a place to go.
What a block does
A paragraph can also be a block. Every block keeps the reading column, and none of them adds a card, an icon or a color.
A subhead opens one part of the argument.
A list holds items a reader scans.
A pull quote lifts one sentence the reader has already read.
Notes
An invented example. A note holds the source or the limit that would break the sentence. Back to the text
steps
A numbered sequence, one numeral and one instruction a step.
Use it when the reader has to do the work in order.
{
"type": "steps",
"id": "steps-specimen",
"label": "Example steps",
"title": "Start a shared reporting project.",
"items": [
{
"title": "Agree on one question",
"text": "An invented example. Write the question every partner answers, and keep it to one sentence."
},
{
"title": "Name one editor",
"text": "One editor holds the schedule and answers every partner. The role moves between projects."
},
{
"title": "Set the publication date",
"text": "Every partner publishes on the same day, so the work reaches readers as one story."
}
]
}
An invented example. Write the question every partner answers, and keep it to one sentence.
Name one editor
One editor holds the schedule and answers every partner. The role moves between projects.
Set the publication date
Every partner publishes on the same day, so the work reaches readers as one story.
glossary
An alphabetized list of terms, with an anchor on every term.
Use it when the report needs words a general reader does not hold.
{
"type": "glossary",
"id": "glossary-specimen",
"title": "Terms used in this report",
"terms": [
{
"term": "shared beat",
"definition": "One reporter who covers a subject for several newsrooms at once. The newsrooms share the cost and publish the same reporting."
},
{
"term": "collaborative reporting",
"definition": "Two or more newsrooms that report one story together. A {shared beat} is one form of it."
}
]
}
A drawing that holds its place while short cards change it.
Use it when one picture carries the whole argument and each step changes it.
{
"type": "scrolly",
"id": "scrolly-specimen",
"label": "Follow the connections",
"title": "From one newsroom to a shared network.",
"steps": [
{
"title": "Start with the people doing the work.",
"text": "Each mark stands for one imagined newsroom. At first, the marks sit apart.",
"caption": "12 imagined newsrooms, working independently",
"layout": "scatter",
"highlight": 0
},
{
"title": "Keep the community at the center.",
"text": "The shared work matters when people can find and use it.",
"caption": "Shared work returns to a common public purpose",
"layout": "orbit",
"highlight": 0
}
]
}
Each mark stands for one imagined newsroom. At first, the marks sit apart.
12 imagined newsrooms, working independently
2 of 2
Keep the community at the center.
The shared work matters when people can find and use it.
Shared work returns to a common public purpose
The live version pins the drawing while the reader scrolls past each step: see it in the sample report.
waterfall
Equal squares fall into place as the reader scrolls, from small groups to the whole population.
Use it for non-overlapping groups with a known total. Readers can edit the data and export their own chart.
{
"type": "waterfall",
"id": "waterfall-specimen",
"label": "A matter of scale",
"title": "See the whole audience.",
"dataset": {
"version": 1,
"title": "Program reach, in perspective",
"unit": "people",
"totalSquares": 2500,
"status": "Fictional example · not a measured population",
"source": "Entirely invented figures for demonstrating the storytelling template. These are not results from a real program, organization, or community.",
"caveat": "The four example groups are mutually exclusive and total 50,000 people. Replace all figures and narration with your own validated data before publication. “Not yet reached” should only be used when the full target population is known.",
"summaryHeadline": "The audience you know\nis not the whole audience.",
"groups": [
{
"id": "regular",
"label": "Regular participants",
"shortLabel": "Regular",
"value": 420,
"color": "#ec3864",
"headline": "The people\nyou know best.",
"description": "The regulars: {value} {unit}. They are highly visible, but occupy only {tiles} squares in this fictional population."
},
{
"id": "occasional",
"label": "Occasional participants",
"shortLabel": "Occasional",
"value": 1680,
"color": "#e7bb27",
"headline": "A wider\ncircle.",
"description": "Add the occasional participants. The picture grows, but the people actively involved are still a small group."
},
{
"id": "aware",
"label": "Reached, not participating",
"shortLabel": "Reached",
"value": 7900,
"color": "#00b982",
"headline": "Awareness\nis not engagement.",
"description": "These people have been reached by the fictional program but do not participate. A different relationship, and a bigger band."
},
{
"id": "unreached",
"label": "Not yet reached",
"shortLabel": "Not reached",
"value": 40000,
"color": "#3e4740",
"headline": "Beyond\nthe usual circle.",
"description": "The largest group: people the fictional program has not yet reached. This is what a participant-only view would leave out."
}
]
}
}
Entirely invented figures for demonstrating the storytelling template. These are not results from a real program, organization, or community.
The four example groups are mutually exclusive and total 50,000 people. Replace all figures and narration with your own validated data before publication. “Not yet reached” should only be used when the full target population is known.
A few squares in a field of 2,500. Start here, then keep scrolling.
One world. 2,500 squares.~8.3B people
Every square has the same weight. The scale never changes.↓
0.14%
12M people
1 square ≈ 3.3M people4 / 2,500 squares
The full picture
Most of the picture was still missing.
Data used in this illustration
Group
People
Share
Squares
About the numbers and the animation
Source and limitations
What the squares mean
The labels use the input values; the drawing uses whole squares. Categories must be mutually exclusive and cover the intended population. A person, dollar, or other unit cannot belong to two groups at once.
How the reveal works
Scroll position controls the cascade. Each group has a filling interval followed by a reading interval: the squares stop at the color boundary while its label remains visible. The final group gets more scrolling room. There is no forced scrolling, snapping, or autoplay. Reverse scrolling reverses the reveal. “Less motion” places new squares directly in the grid.
findings
A row of statistics, each with a numeral, a heading and a sentence.
Use it when three or four numbers carry the result.
{
"type": "findings",
"id": "findings-specimen",
"label": "Example findings",
"title": "Give the evidence space.",
"items": [
{
"value": "12",
"title": "Participating newsrooms",
"text": "An illustrative count. Replace this with a verified result and its source.",
"unit": "newsrooms",
"note": "Illustrative count for 2024 to 2026.",
"trend": [
4,
6,
9,
11,
12
]
},
{
"value": "3",
"title": "Shared reporting groups",
"text": "Explain what this number measures and the period it covers.",
"unit": "groups"
}
]
}
An illustrative count. Replace this with a verified result and its source.
Illustrative count for 2024 to 2026.
3groups
Shared reporting groups
Explain what this number measures and the period it covers.
figure
A chart with direct labels, a one-sentence trend, and its values in a table.
Use it when the shape of the numbers carries the point.
{
"type": "figure",
"id": "figure-specimen",
"label": "Example figure",
"title": "Partner newsrooms grew in every year of the example set.",
"chart": {
"kind": "bar",
"unit": "newsrooms",
"value_format": "integer",
"sort": false,
"bars": [
{
"label": "2022",
"value": 210
},
{
"label": "2023",
"value": 268
},
{
"label": "2024",
"value": 305
},
{
"label": "2025",
"value": 330
}
]
},
"caption": "The count rose by 120 newsrooms across the four years. These numbers are invented for the guide.",
"source": {
"label": "Invented for this specimen",
"url": "https://centerforcooperativemedia.org/"
}
}
Every value here is invented for the guide. Replace them with verified figures.
Local reporting
12
34
Civic technology
5
11
Language access
8
19
quote
One sentence at display size, opened by a short accent rule.
Use it when one voice states the point better than the report can.
{
"type": "quote",
"id": "quote-specimen",
"text": "A useful report lets the reader see the evidence, follow the reasoning, and ask a better question.",
"attribution": "Template editorial principle"
}
A useful report lets the reader see the evidence, follow the reasoning, and ask a better question.
Template editorial principle
tabs
Two to five panels of prose under a row of text tabs.
Use it when a reader compares parallel views instead of reading them in order.
{
"type": "tabs",
"id": "tabs-specimen",
"label": "Example views",
"title": "One question, three answers.",
"panels": [
{
"label": "Reporters",
"paragraphs": [
"An invented view for the template. State what this group gains and what it gives up.",
"Keep each panel about the same length, so no view reads as the important one."
]
},
{
"label": "Editors",
"paragraphs": [
"An invented view for the template. Replace it with the second position and its evidence."
]
},
{
"label": "Readers",
"paragraphs": [
"An invented view for the template. Replace it with the third position and its evidence."
]
}
]
}
An invented view for the template. State what this group gains and what it gives up.
Keep each panel about the same length, so no view reads as the important one.
Editors
An invented view for the template. Replace it with the second position and its evidence.
Readers
An invented view for the template. Replace it with the third position and its evidence.
accordion
Summaries a reader opens for the detail under each one.
Use it when most readers skip the detail and a few readers need all of it.
{
"type": "accordion",
"id": "accordion-specimen",
"label": "Example questions",
"title": "The questions readers ask most.",
"exclusive": true,
"items": [
{
"summary": "How were the newsrooms selected?",
"paragraphs": [
"An invented answer for the template. State the sampling frame and who it leaves out."
]
},
{
"summary": "What does the count measure?",
"paragraphs": [
"An invented answer for the template. State the unit, the period, and the source.",
"Keep the summary above useful on its own, because many readers never open it."
]
}
]
}
An invented answer for the template. State the sampling frame and who it leaves out.
What does the count measure?
An invented answer for the template. State the unit, the period, and the source.
Keep the summary above useful on its own, because many readers never open it.
timeline
Dated events in one column, with the date beside each one.
Use it when the order of the events is the argument.
{
"type": "timeline",
"id": "timeline-specimen",
"label": "Example chronology",
"title": "How the work moved.",
"events": [
{
"date": "March 2024",
"title": "The partners agree on one question",
"text": "An invented event. Replace it with a dated step of your own work."
},
{
"date": "September 2024",
"title": "The first shared story runs",
"text": "State what happened and why the date matters. Keep each event to one or two sentences."
},
{
"date": "Spring 2025",
"title": "The group reports on the result",
"text": "A date is text, so \"Spring 2025\" and \"12 May 2025\" both hold their own form."
}
]
}
An invented event. Replace it with a dated step of your own work.
September 2024
The first shared story runs
State what happened and why the date matters. Keep each event to one or two sentences.
Spring 2025
The group reports on the result
A date is text, so "Spring 2025" and "12 May 2025" both hold their own form.
image
One picture on the reading column, the figure column or the full page.
Use it when a picture carries evidence a sentence cannot.
{
"type": "image",
"id": "image-specimen",
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23292925%22%20d=%22M46%20107Q33%20170%2054%20233M85%20124Q72%20167%2093%20210M124%20141Q111%20164%20132%20187M163%20104Q150%20165%20171%20226M202%20121Q189%20162%20210%20203M241%20138Q228%20190%20249%20242M280%20101Q267%20160%20288%20219M319%20118Q306%20157%20327%20196M358%20135Q345%20185%20366%20235M397%2098Q384%20155%20405%20212M436%20115Q423%20152%20444%20189M475%20132Q462%20180%20483%20228M514%20149Q501%20177%20522%20205%22/%3E%3C/svg%3E",
"alt": "A field of bowed ink strokes of different heights on a tinted ground.",
"caption": "This picture is a placeholder. Point src at your own file.",
"credit": "Drawn by the template",
"width": "figure",
"lightbox": true
}
This picture is a placeholder. Point src at your own file.Drawn by the template
compare
Two pictures side by side, with a divider a reader can move.
Use it when one picture changes and the change is the point.
{
"type": "compare",
"id": "compare-specimen",
"label": "Example comparison",
"title": "Show the change, do not describe it.",
"before": {
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23292925%22%20d=%22M46%20118Q33%20169%2054%20220M85%20135Q72%20166%2093%20197M124%2098Q111%20167%20132%20236M163%20115Q150%20164%20171%20213M202%20132Q189%20161%20210%20190M241%20149Q228%20189%20249%20229M280%20112Q267%20159%20288%20206M319%20129Q306%20187%20327%20245M358%20146Q345%20184%20366%20222M397%20109Q384%20154%20405%20199M436%20126Q423%20182%20444%20238M475%20143Q462%20179%20483%20215M514%20106Q501%20149%20522%20192%22/%3E%3C/svg%3E",
"alt": "A field of bowed ink strokes on a tinted ground.",
"label": "Before"
},
"after": {
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23a33e36%22%20d=%22M46%20118Q33%20169%2054%20220M85%20135Q72%20166%2093%20197M124%2098Q111%20167%20132%20236M163%20115Q150%20164%20171%20213M202%20132Q189%20161%20210%20190M241%20149Q228%20189%20249%20229M280%20112Q267%20159%20288%20206M319%20129Q306%20187%20327%20245M358%20146Q345%20184%20366%20222M397%20109Q384%20154%20405%20199M436%20126Q423%20182%20444%20238M475%20143Q462%20179%20483%20215M514%20106Q501%20149%20522%20192%22/%3E%3C/svg%3E",
"alt": "The same field of strokes, drawn in the accent color.",
"label": "After"
},
"caption": "Both pictures are placeholders. Point src at your own two files, cropped to one size."
}
Both pictures are placeholders. Point src at your own two files, cropped to one size.
gallery
Pictures in one strip, with a caption on each and buttons that step through them.
Use it when a report holds more pictures than the column can carry.
{
"type": "gallery",
"id": "gallery-specimen",
"label": "Example gallery",
"title": "Let the reader set the pace.",
"items": [
{
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23292925%22%20d=%22M46%20129Q33%20168%2054%20207M85%20146Q72%20196%2093%20246M124%20109Q111%20166%20132%20223M163%20126Q150%20163%20171%20200M202%20143Q189%20191%20210%20239M241%20106Q228%20161%20249%20216M280%20123Q267%20158%20288%20193M319%20140Q306%20186%20327%20232M358%20103Q345%20156%20366%20209M397%20120Q384%20153%20405%20186M436%20137Q423%20181%20444%20225M475%20100Q462%20151%20483%20202M514%20117Q501%20179%20522%20241%22/%3E%3C/svg%3E",
"alt": "A field of bowed ink strokes, the tallest on the left.",
"caption": "This picture is a placeholder. Give every picture its own caption."
},
{
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23292925%22%20d=%22M46%20119Q33%20168%2054%20217M85%20136Q72%20165%2093%20194M124%2099Q111%20166%20132%20233M163%20116Q150%20163%20171%20210M202%20133Q189%20160%20210%20187M241%2096Q228%20161%20249%20226M280%20113Q267%20158%20288%20203M319%20130Q306%20186%20327%20242M358%20147Q345%20183%20366%20219M397%20110Q384%20153%20405%20196M436%20127Q423%20181%20444%20235M475%20144Q462%20178%20483%20212M514%20107Q501%20148%20522%20189%22/%3E%3C/svg%3E",
"alt": "A field of bowed ink strokes at even heights.",
"caption": "A caption says what the reader is looking at, not what the set is about."
},
{
"src": "data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22560%22%20height=%22315%22%20viewBox=%220%200%20560%20315%22%3E%3Crect%20width=%22560%22%20height=%22315%22%20fill=%22%23e7e4d9%22/%3E%3Cpath%20fill=%22none%22%20stroke-linecap=%22round%22%20stroke-width=%222%22%20stroke=%22%23a33e36%22%20d=%22M46%20109Q33%20168%2054%20227M85%20126Q72%20165%2093%20204M124%20143Q111%20193%20132%20243M163%20106Q150%20163%20171%20220M202%20123Q189%20160%20210%20197M241%20140Q228%20188%20249%20236M280%20103Q267%20158%20288%20213M319%20120Q306%20155%20327%20190M358%20137Q345%20183%20366%20229M397%20100Q384%20153%20405%20206M436%20117Q423%20181%20444%20245M475%20134Q462%20178%20483%20222M514%2097Q501%20148%20522%20199%22/%3E%3C/svg%3E",
"alt": "A field of bowed ink strokes in the accent color.",
"caption": "Nothing here moves on its own. The reader steps through the strip."
}
]
}
An invented flow. Replace the nodes and the edges with your own.
part
A part number and a part title, with space above and below.
Use it when a report is long enough to read as chapters.
{
"type": "part",
"id": "part-specimen",
"number": 2,
"title": "What the partners found",
"deck": "An invented deck. Say in one sentence what this part of the report covers."
}
An invented deck. Say in one sentence what this part of the report covers.
methods
A tinted band that carries the method note and the citation list.
Use it at the end, when the reader needs the method and the sources.
{
"type": "methods",
"id": "methods-specimen",
"title": "Methods and sources",
"brief": "Replace this lead with two plain sentences on what you counted and how you counted it. The note under it carries the detail.",
"paragraphs": [
"Replace this note with the study period, the sample, the method, the limits, the funding, and the disclosures."
],
"sources": [
{
"label": "Center for Cooperative Media",
"url": "https://centerforcooperativemedia.org/"
},
{
"label": "Montclair State University",
"url": "https://www.montclair.edu/"
}
]
}
A row for each author with the role, the bio and a link.
Use it when the reader needs to know who did the work.
{
"authors": [
{
"name": "Robin Vega",
"role": "Lead researcher",
"bio": "An invented author for this specimen. Replace the name, the role and the bio with your own.",
"url": "https://example.org/people/robin-vega"
},
{
"name": "Sam Okafor",
"role": "Data reporter",
"bio": "A second invented author. The cover byline joins the two names."
}
]
}
About the authors
Robin Vega
Lead researcher
An invented author for this specimen. Replace the name, the role and the bio with your own.
A "Read next" row of one to three reports with a line each.
Use it when the site holds other reports on the same subject.
{
"related": [
{
"title": "What the network counted in 2025",
"url": "https://example.org/reports/2025",
"description": "An invented earlier report. Say what the reader gets from it."
},
{
"title": "How the partners share a story",
"url": "https://example.org/reports/sharing",
"description": "A second invented report, to show the row with two items."
}
]
}
A second invented report, to show the row with two items.
series_links
The report before this one and the report after it, by title.
Use it when the report is one part of a numbered series.
{
"series_links": {
"previous": {
"title": "Part one: what the partners asked for",
"url": "https://example.org/reports/part-one"
},
"next": {
"title": "Part three: what the network does next",
"url": "https://example.org/reports/part-three"
}
}
}
More in this series
form
A one-column form that posts to your endpoint and states what the reader gets.
Use it when a real list is behind it and you can name what it sends.
{
"form": {
"endpoint": "https://example.org/subscribe",
"heading": "Get the next report",
"reason": "One email a month with the next report and what it found. This specimen sends inline, and the endpoint is a placeholder: a real deployment needs an endpoint that answers with CORS headers, so a send from this page fails.",
"button": "Subscribe",
"inline": true
}
}
Get the next report
corrections
A dated log of what changed after publication.
Use it as soon as you change a published number or a name.
{
"corrections": [
{
"date": "4 March 2026",
"text": "An invented entry. Corrected the partner count in the findings from 320 to 330."
},
{
"date": "19 March 2026",
"text": "A second invented entry. Named the county the sample was drawn from."
}
]
}
Corrections
4 March 2026
An invented entry. Corrected the partner count in the findings from 320 to 330.
19 March 2026
A second invented entry. Named the county the sample was drawn from.
downloads
A file list inside the methods band that states the format and the size.
Use it when the reader can check your work against the data.
Each page is built by build.py from the JSON file beside it, in one of the four themes, and each one opens from disk. Every sentence, name, number and result on all six is invented for a design showcase. The six links below go to the hosted copies, because the ZIP does not carry the folder.
The ZIP holds the whole kit: build.py, package.py, report.json, report.css, report.js, favicon.svg, the fonts/ folder with the five faces and their licences, the built index.html, the hosted-asset starter.html, this guide and the template it is built from, README.md, and DESIGN.md. It leaves out the social image, because every published report needs its own.
Four of those files open from here:
report.json holds the content of the sample report, including the waterfall chart, its data editor, and the end matter.
starter.html loads the stylesheet and the script from this folder.
DESIGN.md states the design system and the rules it holds to.
Every number, name and quotation in the sample report is invented. Replace the content, the notice, the header links and the template link with your own verified work before you publish.