Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Forme

The locked-up type every Plausible Venture is printed from.

A forme is the assembled type and blocks, clamped in a chase, that a press takes its impression from. Every sheet off it is the same shape; what changes is the ink. That is the arrangement here: this package is the shape, and a venture supplies one colour and its own content.

Extracted from Punchcutter and Foley, which arrived at the same design independently and then had to be diffed to find out what was actually shared.

npm i github:plausibleventures/forme
import '@plausibleventures/forme/forme.css';
import { $, el, createLens, fitCanvas, readVar } from '@plausibleventures/forme';

Then set your one colour, and nothing else about colour:

:root {
  --spot: #1d6b5b;
  --spot-lit: #2f9d83;
  --spot-wash: rgba(29, 107, 91, 0.09);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) { --spot: #4fbfa3; --spot-lit: #7fd9c2; --spot-wash: rgba(79, 191, 163, 0.11); }
}
:root[data-theme='dark'] { --spot: #4fbfa3; --spot-lit: #7fd9c2; --spot-wash: rgba(79, 191, 163, 0.11); }

Open proof.html to see every primitive in both themes. It is the fastest way to find out what exists, and it is also the test — if something looks wrong there, it is wrong.


The five decisions this package is

Paper and ink, not a UI kit. One near-white, one near-black, four greys between. No elevation levels, no surface tints, no shadows — depth is a hairline or it is nothing. A page built from this reads as a printed document rather than a stack of cards, and printed documents are what people trust with dense information.

One spot colour, and it means one thing. It marks the live value: the thing being made, the number that just moved, the control under the pointer. Never decoration, never a heading, never a button that does not act. The moment a second meaning is put on it, the page stops being readable at a glance — which is the only advantage this palette has over a normal one.

Everything is mono, and small. --mono for reading, --tech for labels. tabular-nums is set on body rather than sprinkled about, because these pages are mostly numbers and a column of figures that does not line up is a column you cannot compare down. Body text sits around 0.79rem — smaller than a web app, about right for a specimen sheet.

The work takes the width; the numbers live in a rail. .sheet is that split and it is the most load-bearing thing here. The thing being made is never in a modal, never behind a tab, never smaller than the controls that change it.

The interface explains itself. .note, .axis__note and .lens exist because a control whose effect you cannot predict is a control you move at random. On these ventures the prose is not bolted to the bottom as an afterthought; it is half of what people come back for.

Choosing your spot colour

Pick one that belongs to the subject rather than to a palette. Verdigris for a type foundry, because that is what a copper matrix goes when it oxidises. Ferric oxide for a sound foundry, because that is the coating on magnetic tape. A colour with a reason survives the first person who asks why it is that colour.

Then check it twice: it has to clear 4.5:1 against --paper in light and against --paper in dark, and those are two different colours. A spot that works in one and fails in the other is the single most common way these pages break.

What is in it

Layout .sheet .work .console .block .panel .eyebrow .eyebrow__hint
Masthead .bar .bar__name .bar__what .bar__spacer .rooms .state .hush
Stage .stage .stage__id .stage__name .stage__tag .stage__canvas .stage__foot .readout
Buttons .solid .ghost .ghost--wide .ghost--tiny .icon .row
Choices .picks .pick .pick__name .pick__tag
Controls input[type=range] .axis .axis__head .axis__label .axis__value .axis__ends .axis__note .lens .mini
Fields .field .field__label .field__input .toggle
Words .note .prose .rules .status .check .code
Utilities .hidden .scroller .skip
JavaScript $ el clear debounce fitCanvas readVar createLens download copy

Every rule carries a comment saying why it is the way it is. Read the CSS; it is the documentation.

The bits that are load-bearing and look like details

.readout sets min-width: 0. A flex item defaults to a min-width of its own max-content, so a long readout pushes the whole document wider than the screen and every phone gets a page that slides sideways. This shipped once and took a while to find.

.state needs a min-width if its label changes. A chip that resizes on the first press shifts whatever sits beside it out from under the pointer that pressed it, and the click lands somewhere else. That looks exactly like nothing happening.

.skip is clipped, not parked at -9999px. An off-screen box is still a box, and one more thing that can widen the document.

fitCanvas goes at the top of every draw, not once at boot. A canvas measured while its panel was hidden has a client width of zero, so the first draw after a tab switch silently produces nothing.

readVar is called inside the draw, not cached. These tokens change when the visitor switches their system between light and dark, and a cached colour is a canvas that stops matching the page around it.

The three-block theme pattern. The prefers-color-scheme rule is guarded with :not([data-theme='light']) and the [data-theme='dark'] values are repeated. Without the guard, a venture's "always light" switch is silently ignored by anybody whose system is dark.

Why plain JavaScript

forme.js is JavaScript with a hand-written forme.d.ts beside it. The alternative is a build step, and a build step on a dependency installed straight from a git remote is a thing that breaks on somebody else's machine six months from now for reasons nobody will enjoy finding. A hundred and fifty lines do not need a compiler.

Nothing in it touches the DOM at import time, so it is safe to import in a test.

The skill

SKILL.md in this repo is the Claude Code skill that goes with the package — the house style, the shape of the page, the writing voice, the gate that runs before deploy, and the traps that have already cost a session. It is the half of this that carries judgment rather than CSS.

Install it into the ventures working directory so Claude picks it up:

mkdir -p .claude/skills/forme
ln -s ../../../forme/SKILL.md .claude/skills/forme/SKILL.md

A symlink rather than a copy, so there is one source of truth and it is the one under version control. Skills are discovered when a session starts, so a new one needs a fresh session.

Licence

MIT.

About

The locked-up type every Plausible Venture is printed from — tokens, layout and primitives for tool-shaped pages.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages