Type a word. A small, fast model weighs it against sixteen fixed colours, and the bar is that weighting drawn to scale — widest first.
Live: https://jev-colour.zammitpaul.com
His idea, his colours. Matt DesLauriers — @mattdesl on X,
mattdesl on GitHub —
posted this on 18 September 2026 and
said how it worked: sixteen predefined colours,
"just rendering their weighted probabilities". He linked no source, so I built a version that lives on a
page you can type into. The sixteen colours are his too, from
docs/palette.md in
Bitframes (MIT) — copied into palette.js, sRGB and Display P3.
Sixteen football clubs and nations, typed straight into the live page (docs/teams.mp4):
| phrase | Jev |
|---|---|
man utd |
red 100% |
liverpool |
red 91%, dark blue 5%, green 2% |
juventus |
black 57%, white 27%, gray 7% |
borussia dortmund |
yellow 95%, black 3%, orange 1% |
barcelona |
dark blue 44%, red 29%, light blue 16% |
real madrid |
white 99%, red 1% |
inter |
gray 33%, indigo 14%, green 13% |
inter milan |
dark blue 72%, black 18%, light blue 5% |
inter miami |
hot pink 60%, light pink 18%, dark blue 5% |
la galaxy |
dark blue 57%, black 29%, indigo 7% |
seattle sounders |
teal 31%, green 27%, dark blue 26% |
brazil |
green 89%, yellow 11% |
argentina |
light blue 91%, dark blue 4%, white 2% |
netherlands |
orange 85%, green 6%, light blue 4% |
italy |
green 59%, red 17%, yellow 10% |
jamaica |
green 72%, yellow 20%, teal 4% |
inter alone is a prefix, not a club, and the answer says so; one more word and it is nerazzurri blue.
italy comes back as the flag rather than the azzurri, which is the kind of disagreement the bar is
good at showing.
Jev is TypeSafe AI's System One model: it answers typed questions with
probabilities and cannot generate text. The whole page is one question (jev.js):
{
colour: {
type: 'choice',
instructions: 'A person typed a word or phrase. If they had to paint it using only these sixteen
colours, which one would they reach for? Judge the phrase as a whole.',
criteria: { beige: null, black: null, white: null, /* … all sixteen … */ },
}
}The answer comes back as a probability per colour, and that is the picture: a band is a colour's
probability, the order is the ranking, and the only thing code does is drop anything below 0.05% and
renormalise. The options are the palette's own names, except index 0, which the spec calls background
(the beige of the paper) and Jev is shown as beige.
Typical answers, and what they cost (Jev's input tokens at $0.042 per million):
| phrase | Jev | time | cost |
|---|---|---|---|
tomato |
red 100% | 466 ms | $0.000017 |
london bus |
red 99%, black 1% | 848 ms | $0.000017 |
canada |
red 78%, white 12%, green 6%, light blue 3%, dark blue 1% | 292 ms | $0.000017 |
the matrix |
green 59%, black 41% | 356 ms | $0.000017 |
stormclouds |
gray 92%, dark blue 5%, black 2%, indigo 1% | 417 ms | $0.000017 |
retro |
orange 33%, teal 13%, brown 11%, hot pink 11%, beige 7%, … | 779 ms | $0.000017 |
npm install
TYPESAFE_API_KEY=… npm start # http://localhost:8080Without a key the server answers with weights derived from a hash of the phrase and says so on the page; the shape of everything else is the same.
GET /api/palette |
the sixteen colours, who is answering, what has been spent today |
POST /api/colour |
{ "phrase": "london bus" } → the distribution |
GET /up |
healthcheck |
/?q=london+bus |
a link to an answer |
Identical phrases are answered from memory, each visitor gets forty questions a minute, and the day
stops when DAILY_USD_CAP is spent.
config/deploy.example.yml is a Kamal config:
copy it to config/deploy.yml, put TYPESAFE_API_KEY in .kamal/secrets, and kamal deploy.
MIT. The sixteen colour values come from Bitframes by Matt DesLauriers, also MIT.
