Editing
This page explains how to change the site: correcting a wrong value, adding a component, writing guidance a page is missing, or reporting a page that is wrong.
Measured facts and authored prose
Every fact on a page is one of two kinds, and the kind decides where a change is made.
| what it is | where it changes | |
|---|---|---|
| measured | token values, resolution chains, which components exist, what uses them, what Figma publishes, counts, and gaps | in the product, or in the pipeline that reads it. Not on the page |
| authored | when to use a thing, when not to, what goes wrong, and what a picture shows | in one file, which the page names in its footer |
Measured facts cannot be edited on the page. They are read from a pinned commit of appsignal/appsignal-server on every build, so a value that is wrong here is either wrong in the product or was read incorrectly by the pipeline. The first is fixed in the product; the second is a bug to report.
The predecessor guide published these facts by hand, and by the time it was retired it listed twenty-five class names that no longer existed. Generating them is how this site avoids the same drift.
/colophon.md says where each kind of fact comes from.
Common changes
A token's value is wrong
Change it in the product's stylesheets. The new value appears here at the next build, everywhere it is used. There is no copy on the site to update.
A component is missing
A component gets a page as soon as it exists in the product and meets any one of these conditions: it is importable from the shared library, it carries a class root, or it has a Storybook module. You do not add components to this site. The generated page will have no guidance, will say so, and will name the file where guidance goes.
A page has no guidance
This is the most common gap, and filling it is the contribution the pipeline cannot make. Every page prints the path of its authored file in the footer, whether or not the file exists yet. Write that file and the prose appears at the next build.
One rule governs authored prose: it may not restate a derivable fact. Do not include token values, prop tables, or lists of class names. Those are generated and cannot go stale. Write what generation cannot produce: when to use the thing, when not to, and what goes wrong. Advice such as "sentence case, primary action rightmost" stays true in a way a list of class names does not.
A page is wrong
There are two kinds of report, and it helps to say which one you have.
- A measured fact is wrong. A count that does not add up, a value that disagrees with the product, a component listed that no longer exists. This is a pipeline bug. Report the page, the value, and what you expected.
- Authored prose is wrong or out of date. The advice no longer matches how we build. Edit the file the page names in its footer.
An empty cell is neither. Generated pages print all of their axes, populated or not, and an empty one means the pipeline looked and found nothing. /gaps.md describes each kind of absence and who can close it.
Illustrations
Use illustrations where they make something clearer, but carry the key information in text. Coding agents read this site and cannot see images. Both renderings come from the same source, so a screenshot placed for a human reader is also on the page an agent reads, and whatever it conveys visually is lost there.
Split the job in two:
| where it goes | |
|---|---|
| what the picture is | the alt text |
| what the picture shows | ordinary prose, or a table cell beside it |
Alt text reaches every reader, including screen readers and agents, because it is written in the file rather than added at render time. Write it as a description, not a label: "rounded rectangle, dashed purple border" is useful; "legend" is not. Keep it to one sentence. A paragraph in an alt attribute is tiring to hear read out.
The legend on /patterns/map.md is a good model. Its first column holds ten small screenshots, and each row also states in words what the treatment is and what the state means. The test is simple: cover the pictures and check that the table still answers the question.
The same test applies to every visual and structural device on a page. Each one is redundant encoding, and the passage should be complete and correct with all of it stripped. If removing the device changes the meaning, the device is doing work that belongs in the text.
Two things to avoid:
- Do not screenshot a value. A hex code, a size, a class name, or a count in an image cannot be checked by the build and cannot be searched.
- Do not screenshot a table. It stops being sortable, searchable, readable at a narrow width, and readable by a screen reader.
Images do not need to be small. An oversized image is fitted to the column rather than allowed to widen the page.
Where image files go
Images live in site-art/, in one of two directories.
| what it holds | how it is shown | |
|---|---|---|
site-art/illustrations/ | drawings made for this site | bare, on the page's own background |
site-art/screens/ | captures of the product | on a white ground, inside a rounded border |
The directory decides the treatment, and the file format does not. A capture is opaque light-mode product UI whatever it is saved as, so the frame gives it an edge of ours rather than a torn one where the capture stops. A drawing is made on a transparent ground against this site's palette, and a white ground behind it would wash it out.
Put a capture in a subdirectory named after the page that shows it, so the pictures on /patterns/map.md are in site-art/screens/patterns/map/.
The build enforces two rules here. Only .svg and .png files are copied to the site. Every file in site-art/ has to be referenced by a page, because a picture nothing shows should be deleted rather than half-kept.
Adding an image to a page
Write a markdown image reference: an exclamation mark, the alt text in square brackets, then the route in parentheses. The route is /assets/ followed by the file's path below site-art/.
The Map legend's selected-service swatch is stored at site-art/screens/patterns/map/legend-service-selected@2x.png, so the page that shows it contains this line:

which puts this on the page:
![]()
Start the route with /. Without it the route is read relative to the page, which resolves differently depending on where the page sits, and the build rejects it. Alt text is not optional either: an image without it fails the build.
Cards
A card is a box around one heading and a short passage. Reach for one to lift a single point out of the flow of a page: a recommendation, a warning, an example worth copying. Use an ordinary heading for anything the reader has to read in order, and for anything longer than a few sentences.
A card is written as a fence. The kind is required, and it says what the reader should do with the passage.
| kind | the reader should |
|---|---|
information | know this |
implementation | do this |
prefer | copy this |
avoid | not copy this |
caution | watch out for this |
This is the whole syntax:
:::card{kind=caution}
### A card is not a section
A card holds one point. A passage that has an order to it, or that runs past a
few sentences, is a section and wants an ordinary heading. A page of cards reads
as a menu rather than a document.
:::
which puts this on the page:
A card is not a section
A card holds one point. A passage that has an order to it, or that runs past a few sentences, is a section and wants an ordinary heading. A page of cards reads as a menu rather than a document.
The build enforces four rules.
- The heading comes first, there is exactly one, and it is an
h3. A card sits under the##that introduces it, so anh2would make the card a sibling of its own heading. - A blank line comes before the closing
:::. Without it the closer is read as part of the last sentence and prints as… :::. - A card holds prose and pictures. It does not hold a code block, a table, or another card.
- A page carries at most three runs of cards. Consecutive cards are one run.
Two things the build does not check. Put the polarity in an avoid card's own heading, so that "Don't use two primary buttons" reads correctly when it is quoted without the card around it. A prefer card beside an avoid is usually better than the avoid alone, with the prefer first.
The kinds are not drawn differently yet. All five render as the same box, so a card's meaning has to be in its heading and its prose, which is the same test the illustrations above have to pass.