Skip to content
Work with us

Plate: deterministic project marks

The generator behind every mark on this site. One module per project, seeded by name: the seed varies how many and how heavy, never what. Same input, same bytes, every time.

Read README.md

Deterministic project marks for nullsilver. One generator per project, seeded by name, emitting SVG for the Svelte site and baked PNGs for Hugging Face and GitHub. Marks only — text, cards and layout are assembled elsewhere.

The name: a plate is both the thing you print from and the word for a figure in a paper. Both readings are the intent — these are figures, not decoration.

Use

pip install -e .
python -m plate build --tokens ../nullsilver.com/src/app.css
python -m plate build --ink "#dedad2" --paper "#0a0a0a"
python -m plate params remora
python3 tests/test_plate.py

Colour only ever applies to baked pixels. --tokens reads --ns-silver and --ns-black out of the site's stylesheet and follows @import, so the entry sheet works as well as tokens.css — point it at the real file and the PNGs cannot drift from the site. --ink and --paper override it. Light output is the inversion, matching how the site's accent already works.

Outputs land in out/:

Path For
svg/<seed>.svg Svelte inlines this; currentColor picks up the theme
svg/<seed>.min.svg coarse variant for favicons and small use
png/<seed>@<w>.png transparent, for READMEs and HF
png/<seed>@<w>-dark.png silver on black
png/<seed>@<w>-light.png black on silver
<mark>-contact-{dark,light}.png the sheets you judge the mark by

In Svelte

Inline the SVG so currentColor resolves against your theme. Serving it through <img> breaks that and costs you a request per mark.

<script>
  import Remora from '$lib/marks/remora.svg?raw';
</script>

<span class="mark">{@html Remora}</span>

<!-- `color` is load-bearing: bars are fill="currentColor". Without it they
     inherit the CSS initial value and render black. -->

<style>
  .mark { color: var(--color-text); display: inline-flex; }
  .mark :global(svg) { width: 52px; height: auto; }
</style>

Copy out/svg/*.svg into src/lib/marks/ as a build step, or commit them — they are deterministic, so the diff is empty unless a generator changed.

The marks

Seed Project Grammar
remora calls large models only where the work needs them a field ramping hairline to heavy, with a disc knocked out of the dense end
sieve scores recall on only the spans an answer rests on a uniform mesh of dashes, crossed by a few solid spans
budget a loop spending against a deadline that does not move runs decaying toward a heavy wall they never reach
plate this generator an engraved block and its identical impressions

sieve, budget and plate were built for placeholder projects on the site, to see the home page carrying four different figures rather than one repeated. They skipped the sign-off gate in specs/new-mark.md on those grounds; if any of those projects becomes real, run its brief through the spec properly.

Adding a mark

See specs/new-mark.md. The short version: one module in plate/marks/, subclass Mark, seed quantity and weight but never shape, and implement the coarse variant properly or the mark dies below 48px.

Design invariants

  • Stroke only. One colour. No gradients, no fills that aren't load-bearing.
  • The seed varies how many and how heavy, never what.
  • Every mark encodes its project's mechanism, not its name.
  • Negative space is cut by stopping strokes at the edge of the void, never by painting over them with a background colour. The background is not ours to assume — currentColor is the only colour a mark knows, and no hex may appear in emitted SVG. There is a test for this.
  • Heavy elements are filled rects via bar(), not thick strokes. A round linecap adds half a stroke-width of radius at each end, so a 6-unit stroke gains a 3-unit bulge and any silhouette cut from it goes soft. CORNER sets the house radius as a fraction of a bar's short dimension; pass corner=0 for square.