Skip to the main content
mkfifo.com

Fonts and colors

planned discovered changed fixed

The fonts of the site come from a FIFO, and the colors of the code come from a font. Neither needs a script in the page.

The fonts come from a FIFO

The fonts of this site were static files at /fonts/NAME.woff2. Now they come from the FIFO /fonts, with the same envelopes that each person can write. mkfifo.com is the first user of a GET with an answer.

The site holds a name, as a person does

fonts is a name of the site, and no FIFO can hold a name of the site. A seed of the site is the only exception: the FIFO mkfifo holds fonts. Its locked editor at /mkfifo shows the two envelopes:

To: fonts
X-HTTP-Method-Override: ^GET$
Content-Type: form

file: ^[A-Za-z0-9-]+\.(woff2|txt)$
To: program:fonts
Reply-To: -

The query of a GET is a form, so file is a field. The program fonts gives the file with that name, and Reply-To: - sends it to the browser. A different name gets 404. The ingress envelope has no note, because a note would give /fonts a page with a letter.

A URL for each version

A browser keeps each font for one year (Cache-Control: immutable). Thus a changed font must have a new URL. The CSS loads /fonts?file=NAME&v=VERSION, and VERSION is the start of the SHA-256 of the file. When I build FIFO Code again and do not change the CSS, a test tells me the new value.

A GET is not a letter

Each Request to a FIFO of the site counted in a limit of 20 in 10 minutes for one address, because a letter to /contact sends an email. One page loads about 6 fonts, so the fourth page would show no fonts. Now a GET counts only in the limit of its FIFO: 120 in one minute. A GET cannot send a letter: only an envelope that asks for a GET gets it.

Colors in a font

The envelopes on this site were plain text: a header name, a pattern, a variable and a call all had one color. A syntax highlighter needs JavaScript in the page, or a parser on the server for each language. I did not want either. Now the colors come from the font.

A font with rules

Heikki Lotvonen made a font with a syntax highlighter in it. Each glyph has colored copies, and OpenType rules change a glyph to a copy from the glyphs around it. Its rules are for HTML, CSS and JavaScript, and its face is not the code font of this site. So I used the same method on IBM Plex Mono, with rules of my own for Elixir, Erlang and envelopes, and later also for HTML, CSS, JavaScript and a shell. IBM Plex reserves the name "Plex", so the result has a different name: FIFO Code.

def render(template, :markdown) do
  {:ok, "text"} |> Enum.map(&String.trim/1) # a comment
end
Subject: ^Order (?<id>\d+)$
Code: ^$email | totp$
Authorization: <sealed:QX7z-k2>
const answer = await fetch(`https://mkfifo.com/${name}`, { method: "POST" });

The parts:

  • Each ASCII glyph has one copy for each color. A copy is a composite of the glyph, so a browser with no color fonts shows the usual glyph.
  • A rule sees the copies that its own lookup made before it. So a lookup is a small state machine: after ", each glyph becomes a copy of the string color, up to the next " with no backslash before it.
  • The name of a function comes before its (. A reverse rule reads from right to left, so the name can have any length.
  • Each language is a stylistic set: Elixir, Erlang, an envelope, one value of an envelope, HTML, CSS, JavaScript and a shell. In the blog, the word after the three backticks of a code block selects it: elixir, erlang, envelope, html, css, js, json, sh, shell, bash or console. JSON uses the rules of JavaScript.
  • The font has two palettes. The code of the blog uses the dark one, with font-palette: dark.

The editor uses the font too. A <textarea> is text, so the fields of an envelope show the colors while you type, with no script.

A shell

The site shows many commands with curl: on the home page, in /docs, and in the editor of an empty FIFO. They have colors now too:

printf 'X-GitHub-Event: ^push$\n' |
  curl -X PUT --data-binary @- https://mkfifo.com/deploys # save
for f in *.eml; do curl -T "$f" "https://mkfifo.com/$NAME"; done

The command is the first word of a line, or the word after |, &&, ; or $(. A line that starts with spaces continues a pipe, so its first word is a command too. A URL keeps no color. With the usual edge of a word, done in https://mkfifo.com/done would be a keyword, and to in ?to=docs would be a variable. So a keyword of a shell is not a keyword after /, ., - or :, and a name before = is a variable only at the start of a command.

Three bugs

The first build colored do and end in comments. The lookups of a feature run in the sequence of their definitions in the font, not in the sequence of the feature block, and my script put the keywords first. Now the list of keywords is a comment in the rule file, in its place. A test with HarfBuzz, the shaper of Chrome and Firefox, shapes sample lines of each language and compares the color of each glyph.

The examples on /docs and on the home page stayed plain. Their <pre> also had the class font-mono of Tailwind. A utility comes after a component, so font-mono won over my class. The two classes of the font are now in no layer.

The fonts are files in the repository, and the continuous integration builds them again from the rules, to make sure that nobody changed a rule and forgot the build. On the first run, the check failed: the runner has Python 3.12, and my computer has 3.11. The two wrote the same tables with their parts in a different sequence. The check now compares the tables, not the bytes.

What a font cannot do

A rule sees one line only. A heredoc, a comment on more lines, or a tag of HTML on more lines shows as text after its first line. One code block has one language, so a <script> in HTML has no colors of JavaScript. I tested the font in Chromium and with HarfBuzz. Safari uses a different shaper, and I will test it there.