Publish a render pack
A pack is a self contained folder that turns artifact state into a picture. Anyone can publish one, and nobody needs permission.
- What goes in the folder, and why every font and asset ships inside it rather than being fetched.
- Which five manifest fields are promises you can be held to, and why
network_accessis false in every honest pack. - The shape of the render function, and why it must fail loudly instead of drawing Raw for missing state.
- The five kinds of sample a pack ships at a minimum, and which pair proves it tells the truth about a reset.
- The eleven checks to run before publishing, from comparing hashes to contrast.
Layout
Seven entries, and everything the render reads while drawing is one of them.
my-pack/
manifest.json what this pack is and what it claims
render.js the pure render function
tiers/ one asset set per tier, if the pack uses assets
fonts/ any font the pack needs, bundled not linked
samples/ rendered examples with their inputs
README.md how to use it, and the derivation the pack uses
LICENSE
Everything the render needs ships inside the folder. A pack that fetches an asset from someone else's server stops working the day that server does, and it stops being verifiable long before that.
Manifest
The manifest is the pack's claim about itself, and the five fields below are the ones anyone can check against your samples. Write it once the render works, so it describes what the code does rather than what you meant. The eight tier names are spelled the way the tiers page spells them.
{
"name": "my-pack",
"author": "who made it",
"license": "SPDX identifier",
"protocol_id": "PTNA",
"inputs": ["artifact_id", "founding", "status", "depth", "tier", "rings", "height"],
"outputs": ["svg"],
"tiers": ["Raw", "Sheen", "Cast", "Verdigris", "Umber", "Bronze", "Oxide", "Elder"],
"deterministic": true,
"network_access": false,
"reduced_motion": "static output only",
"derivation": "how per artifact variation is derived from artifact_id"
}
| Field | Promise |
|---|---|
inputs | These are the only inputs the render reads. Listing an input you do not read is sloppy. Reading one you did not list is dishonest. |
deterministic | Same inputs produce identical output bytes |
network_access | False, always. A render that needs the network is not a render pack. |
derivation | Anyone can reproduce your variant choices from the artifact id |
tiers | All eight names, spelled as the protocol spells them |
The render function
// Returns a string of SVG, or a buffer, depending on the declared output.
// No network, no clock, no randomness, no globals.
function render(state) {
// state: { artifact_id, founding, status, depth, tier, rings, height }
// ...
return svg;
}
- Take the whole state object and read only what you declared.
- Do not mutate the input.
- Handle every case: depth zero, Elder, relic, zero rings, many rings.
- Fail loudly on missing fields rather than substituting a default. A render that quietly draws Raw when it was given nothing is a render that lies.
Samples are part of the pack
Ship at least these, each with the exact input JSON that produced it:
- One per tier, Raw through Elder.
- A founding artifact and a non founding one at the same tier.
- A relic.
- An artifact with zero rings and one with at least three.
- An artifact that is deep now, and one that was deep once and is Raw now.
The last pair is the important one. It shows whether the pack tells the truth about a reset.
Checks before you publish
Eleven checks, run against every sample rather than a favourite one. The first four are the determinism checks, and they are the reason anyone can trust a pack they did not write.
| Check | How |
|---|---|
| Determinism | Render each sample twice, compare hashes |
| Portability | Render on a second machine, compare hashes |
| Offline | Disconnect the network and render every sample |
| No external requests | Grep the source for URLs, and watch the network panel while rendering |
| Tier legibility | Put all eight side by side. Each must be tellable from its neighbours. |
| Relic legibility | A relic must not be mistakable for a live artifact |
| Height stamp | Present and readable at the smallest size the pack supports |
| Contrast | Any text passes AA against its background |
| Reduced motion | Animation is optional, and the static form carries the same facts |
| Text alternative | Every meaningful element has one |
| Size | Reasonable for a share card. State the output size in the README. |
Publishing
- Put the folder in a public repository with its license.
- Include the manifest, the samples, and their inputs.
- State plainly that the pack is a view of the state, not the state, and that the protocol does not endorse it.
- If you change the pack, publish it as a separate pack rather than silently changing the pictures people already shared. A render is a claim about state at a height, and rewriting it later breaks that.
Name a revised pack for what changed, not with a number. The program has no version labels in names, folders, or URLs anywhere, and packs follow the same rule.
What a pack may never do
The full list is on Rules that keep renders honest. The short form: a pack may make an artifact beautiful, and may not make it look like something it is not.