`vibe3d add @medieval-kit` resolves the namespace through `models.json` and
stops dead without it:
Registry @medieval-kit is not configured in models.json
The registry README printed the two install commands FIRST and the
`models.json` entry underneath, introduced with the word "first". A reader
copies the top block, runs it, gets that error, and leaves. `vibe3d init`
seeds only `@scifi-kit`, so this is every new reader, not an edge case.
Config block first now, commands after it.
The cover card said `bunx vibe3d add @medieval-kit/wooden-chest`. Both address
forms are valid, but the bare namespace resolves through the registry's
`defaultItem` and installs the whole kit, which is what someone looking at a
card of the whole kit is being offered. A card has room for a command and not
for the `models.json` entry that command needs, so the shorter promise is the
honest one — and naming one arbitrary model implied a precision the card cannot
deliver.
Verified against the CLI rather than inferred from it:
add @medieval-kit/registry -> Registry @medieval-kit has no item named registry
add @medieval-kit -> Would install @medieval-kit · 46 files
add @medieval-kit/grindstone -> Would install @medieval-kit/grindstone · 10 files
The card a shared link unfurls to was a picture of the models with no title on
it, and the models on it were too small to tell apart. Both are fixed, but the
part worth writing down is how.
The first attempt was an HTML page composed in the site's own fonts and
screenshotted. It looked right and it was wrong: the model count on it becomes
a picture of a number the moment the shutter closes, and `check-docs.ts`
cannot read a picture. That is the exact failure that check exists for — the
READMEs claimed 27 models when there were 37 — and a card is the worse place
to have it, because nobody reading one can see the kit to know it is stale.
So `bun run cover:build` counts the catalogue and draws the numbers it counted.
`site:build` runs it, which means the published card cannot be older than the
models it shows, and the day a model is added the card says 38 without anyone
remembering to make it.
Drawing type needed type. `scripts/text.ts` reads the outlines out of a `.ttf`
and fills them with a scanline pass — four sub-scanlines a row with exact
horizontal coverage, which is more code than sampling a 4x4 grid and visibly
better at the 16px the two mono lines are set in. It is deliberately partial:
format 4 cmap, simple and composite outlines, advances, no kerning or shaping.
What it cannot draw it throws on, because a headline missing a letter is not
something you notice before it is published. Archivo and IBM Plex Mono come
with it under the OFL, the same two faces the site is set in.
The renderer moved to `scripts/raster.ts` so the card and the contact sheet
draw from the same code and cannot disagree about what a barrel looks like;
`render.ts` is now the command line over it, unchanged in what it does. Its
one new flag is `--ground`, a flat background instead of the per-cell
gradient: forty gradients side by side read as banding, and on the page's own
ink the models float on the card as one field instead of sitting on it as a
grey slab.
Ten columns by four, because 1.91:1 and 37 models want 40 cells and at that
shape the cells come out square, which is what lets a barrel look like a barrel
at 116 pixels. The last row is centred — three empty cells left flush is a
notch in the corner, and a short row centred is how a contact sheet ends.
Byte-identical across runs, so it does not churn the diff on every build.
A link to the site showed a URL and a blank square. It now carries a title, a
description, a canonical URL, an icon and a full set of OpenGraph and Twitter
tags, so a page nobody has opened yet arrives as something you can look at.
Two of those tags have to be ABSOLUTE and it is not a style question: a
scraper fetching the page has no base to resolve `/cover.png` against and
drops it silently. `build-site.ts` now copies the images into the output as
well, because an `og:image` pointing at this host has to have the file ON this
host — a card that 404s shows nothing, and nothing about the page itself looks
wrong while it happens.
The cover is a real 1200x630 render rather than a crop of a square one, which
took a change to the renderer worth having anyway. `newFrame` and
`frameCamera` both took a width and a height already; only `renderOne` was
insisting they be equal. And with a non-square frame the old camera fit showed
its flaw: it fitted the bounding SPHERE, which is one number and wrong for
anything not roughly round. The kit scene is wide and flat, so its sphere is
far taller than the scene is, and fitting that into the vertical field left the
models in a band across the middle with empty air above and below — most of a
1.91:1 card. It now fits the BOX, iteratively, because perspective is not
linear in distance: place the camera, project the eight corners, move by how
far the worst one lands past the edge. Two passes is inside a pixel.
That change improves every render, not just the card: on the contact sheet
every model is visibly larger in its cell and nothing crops.
`check-docs` now watches `viewer.html` too. Its description quotes the model
count and the triangle total, which is the same sentence that went stale three
times in the READMEs before that check existed — and a stale number in a card
is worse than one in a README, because nobody reading the card can see the kit
to know it is wrong. The description says "37" rather than "thirty-seven" for
exactly that reason: a word is not a number the check can find.
Also repointing the npm README's two images from `raw.githubusercontent.com`
to the live site. They were pointing into a private repository and would have
404'd on npmjs.com; now they do not depend on the repository being readable at
all.