Skip to content

Commit a0aade6

Browse files
committed
docs: write for a reader who is not a programmer
Every font and rasterizing term now carries a plain gloss the first time a page uses it, and keeps its own name beside it. Hinting had no explanation anywhere: a stem straddling two pixels comes out as two pale columns, and hinting nudges the outline onto the grid. The same for the quantizer, gamma, thresholds, stem darkening, grayscale hinting, mono, dropout control, em, advance, line pitch, kerning, ligatures, GPOS and GSUB, codepoints, variable font axes, WASI and Docker Compose. fonts.md and preview.md both opened on syntax. They now say what a build makes and what the preview is for first, and fonts.md defines family, style and face before using them. Numbers that go stale are out: the Literata build timings, the worker cap, the render module size and its language count, the glyph count and download sizes in the README, two preset sizes, an eighteen file folder. The limits the format and the firmware fix are kept, with their citations, and so are the measurements that state their conditions. Two claims were wrong and are corrected. Only gamma, thresholds and the export controls carry a ? tooltip, not every control. Four shades of grey is what these readers draw, not what e-ink draws. docker.md loses a paragraph about an upload interface that does not exist. CONTRIBUTING.md carries the writing rules, since a contributor cannot see the standard they live in.
1 parent 14b5afa commit a0aade6

6 files changed

Lines changed: 293 additions & 184 deletions

File tree

CONTRIBUTING.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,26 @@ would be a second name. `crossglyph --version` reports what the stamp says.
397397

398398
## Writing
399399

400-
Comments explain why, not what. They describe what the code does now, never
401-
what it used to do: git has that, and a comment retelling it is wrong by the
402-
next change. A firmware behaviour a value works around is worth a citation, and
400+
This covers the README, `docs/`, `--help` text, error messages, the strings in
401+
the preview, the release notes and the comments in the code.
402+
403+
Write for somebody who wants to build a font and is not a programmer. Plain
404+
English, short common words, no em dashes and no `--` standing in for one,
405+
straight quotes, no emoji, sentence case in headings.
406+
407+
Font and rasterizing terms are the point of this tool and strange to most
408+
readers. Gloss each one the first time a page uses it. "Stem darkening thickens
409+
the strokes, which helps on a screen where thin letters look washed out" tells
410+
the reader something; "stem darkening applies a stem darkening factor" does
411+
not. Name settings the way the reader's own surface names them: the label for
412+
anything about the preview, the config key for anything about `build`.
413+
414+
Leave out numbers that go stale. Version numbers, glyph counts, download sizes
415+
and benchmark timings are all wrong a few commits later and nobody notices.
416+
Give the shape instead, and keep a number when something fixed holds it in
417+
place, such as the four greys the screen draws.
418+
419+
Comments explain why, not what. Both comments and pages describe what the code
420+
does now. Git holds the rest, and a comment retelling it is wrong by the next
421+
change. A firmware behaviour a value works around is worth a citation, and
403422
those citations are why several comments here are long.

README.md

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
Tune a font for an Xteink reader running
44
[CrossPoint](https://github.com/crosspoint-reader/crosspoint-reader), and watch
5-
the page redraw as you move each control. A change lands in 10 to 300 ms,
6-
depending on your hardware and how much of the font is being built.
5+
the page redraw as you move each control. Changes appear as fast as your
6+
machine can rebuild that part of the font, which is fast enough to keep turning
7+
a knob and watching what happens.
78

8-
Most fonts need tuning to read well at two bits per pixel. Without a preview
9-
every guess costs a card swap or an emulator run, which is why most people stop
10-
at the point size.
9+
These readers draw in four shades of grey and nothing else, so most fonts need
10+
work before they read well on one. Without a preview, every guess costs a card
11+
swap or an emulator run, which is why most people stop at the point size.
1112

1213
<p align="center">
1314
<a href="docs/images/tune.png"><img src="docs/images/tune.png" width="32%"
@@ -18,36 +19,43 @@ at the point size.
1819
alt="The Export panel with sizes, coverage, fallbacks and build controls"></a>
1920
</p>
2021

21-
- the firmware's own renderer, its C++ compiled to WebAssembly, so the page
22-
shows what the device draws and not an impression of it
23-
- rasterizing controls for gamma, the three grey thresholds, weight, slant,
24-
hinting mode, grayscale hinting, mono rasterizing, stem darkening, line
25-
height, letter and word spacing, kerning strength, ligatures, proportional
26-
figures
27-
- page controls, so the page you judge is set up like the device you are
28-
judging for: margin, alignment, line spacing, hyphenation and the language
29-
its patterns come from, paragraph spacing, anti-aliasing and night mode
30-
- the page inside the reader itself, rendered from XTEINK's own models, at one
31-
screen pixel to one of your monitor's with neither the page nor the body
32-
resampled, shaded to the cast measured off a real device and adjustable from
33-
there, and copied out as an image in one press
34-
- variable fonts build at the weight their designer named, or at any weight you
35-
pick: left alone, Merriweather would ship its Light as your Regular
36-
- four sizes of a four-style family, 795 glyphs each with kerning, built in
37-
about a second, one process per size
38-
- the bundled Noto families on request, so a missing arrow or Greek letter is not
39-
a hole in the page. Each lends its own bold or italic to a run set that way,
40-
where it has one
41-
- Arabic comes out joined with any face, because the joining rules a modern one
42-
stores are run here and the joined shapes built in, which the device has no
43-
room to do for itself
44-
- nothing installed system wide, since the launcher fetches uv, Python and the
45-
dependencies into a cache directory you can delete
46-
47-
CrossGlyph turns TTF and OTF files into `.cpfont`, the format the device
48-
reads: glyph bitmaps at two bits per pixel, one file per point size, with
49-
kerning and ligature tables baked in. The device has no rasterizer, so every size is a
50-
separate build.
22+
- **The reader's own renderer.** The firmware's drawing code, compiled to run
23+
in the browser, so the page shows what the device will draw and not an
24+
impression of it.
25+
- **Controls for the letters.** How dark the type is (gamma, and the three grey
26+
cut points), how thick or thin the strokes are (weight, and stem darkening),
27+
a slant for a face with no italic of its own, how the outline is snapped onto
28+
the pixel grid (hinting, grayscale hinting, and a one-bit mode that drops the
29+
greys), the space between letters, words and lines, how hard pairs are pulled
30+
together (kerning), whether `fi` joins into one shape (ligatures), and
31+
whether digits are all one width. [docs/fonts.md](docs/fonts.md) explains
32+
what every one of them does to the type.
33+
- **Controls for the page.** Margins, alignment, line and paragraph spacing,
34+
hyphenation and the language its rules come from, anti-aliasing and night
35+
mode, so the page you are judging is set up like the device you are judging
36+
it for.
37+
- **The page inside the reader.** Drawn from XTEINK's own models, one screen
38+
pixel to one of your monitor's, shaded to match a real device and adjustable
39+
from there. One press copies it out as an image.
40+
- **Variable fonts.** These carry a range of weights in a single file. Build
41+
one at the weight its designer named, or at any weight you pick. Left alone,
42+
Merriweather would hand you its Light as your Regular.
43+
- **A family in seconds.** Regular, bold, italic and bold italic, at every
44+
point size you asked for, one process per size.
45+
- **The bundled Noto faces on request**, so a missing arrow or Greek letter is
46+
not a hole in the page. Each one lends its own bold or italic to text set
47+
that way, where it has one.
48+
- **Arabic comes out joined** with any face. A modern Arabic font carries the
49+
rules for how letters connect, and CrossGlyph runs them and builds the joined
50+
shapes in. The device has no room to do that itself.
51+
- **Nothing installed system wide.** The launcher fetches uv, Python and the
52+
dependencies into a cache directory you can delete.
53+
54+
CrossGlyph turns TTF and OTF files into `.cpfont`, the format the device reads.
55+
A `.cpfont` holds a picture of every letter at one point size, in the four
56+
greys the screen has, along with the tables that space letter pairs and join
57+
`fi` into one shape. The device cannot scale type itself, so each point size is
58+
a separate file and a separate build.
5159

5260
## Quick start
5361

@@ -134,13 +142,13 @@ fonts/
134142
`$CROSSGLYPH_FONTS` names another workspace, and so does `--fonts DIR`. Builds
135143
land in `cpfonts` unless `out` in `all.conf` says otherwise.
136144

137-
A family needs no config at all. Drop four files in, name them the way their
138-
foundry did, and they build on the next run. `all.conf` holds settings shared
139-
by every family. It is yours and starts absent; copy `all.conf.example` beside
140-
it to start from a commented list of every key. Write a `<family>.conf` when
141-
one family needs settings the others do not. See
142-
[docs/fonts.md](docs/fonts.md) for every key, and for what the tuning controls
143-
actually do.
145+
A family needs no config at all. Drop the regular, bold, italic and bold italic
146+
files in, name them the way their foundry did, and they build on the next run.
147+
`all.conf` holds settings shared by every family. It is yours and starts
148+
absent; copy `all.conf.example` beside it to start from a commented list of
149+
every key. Write a `<family>.conf` when one family needs settings the others do
150+
not. See [docs/fonts.md](docs/fonts.md) for every key, and for what the tuning
151+
controls actually do.
144152

145153
## Getting the fonts onto the device
146154

@@ -153,10 +161,11 @@ offers three of them.
153161

154162
## Fallback faces
155163

156-
CrossPoint draws nothing for a codepoint no font in the chain has, so a family
157-
that lacks an arrow leaves a gap where it should be. The bundled Noto faces fill
158-
those holes, covering Hebrew, Arabic, Thai, Bengali, Armenian, Georgian,
159-
Ethiopic, Cherokee, Tifinagh, Coptic, mathematics, symbols and emoji.
164+
A codepoint is one character as the computer stores it, and CrossPoint draws
165+
nothing at all for one that no font in the chain has. A family with no arrow in
166+
it leaves a gap where the arrow should be. The bundled Noto faces fill those
167+
gaps, covering Hebrew, Arabic, Thai, Bengali, Armenian, Georgian, Ethiopic,
168+
Cherokee, Tifinagh, Coptic, mathematics, symbols and emoji.
160169

161170
They are OFL licensed and unmodified, so they are downloaded on request and
162171
not shipped here:
@@ -165,16 +174,17 @@ not shipped here:
165174
./crossglyph.sh fetch-fallbacks
166175
```
167176

168-
That is 3.4 MB, and it puts `OFL.txt` beside them. A CJK face is another
169-
15.7 MB and comes only when something has asked for it: a config naming a CJK
170-
script, or, in the preview, text on the page that cannot be drawn without one.
171-
One face answers all four languages, Korean included, so there is no choice to
172-
make between them.
177+
That is a few megabytes, and it puts `OFL.txt` beside them. The face for
178+
Chinese, Japanese and Korean is a much larger download on its own, and it comes
179+
only when something has asked for it: a config naming one of those scripts, or,
180+
in the preview, text on the page that cannot be drawn without it. That one face
181+
covers Chinese in both its written forms, Japanese and Korean, so there is no
182+
choice to make between them.
173183

174184
The preview offers the same download as a button, with a bar, since it takes a
175185
while. Bundled fallbacks are off by default, which keeps a first build
176-
self-contained and makes a narrow face about twelve times smaller. After
177-
fetching them, turn on **bundled fallback faces** in the preview or set
186+
self-contained and makes a narrow face a fraction of the size. After fetching
187+
them, turn on **bundled fallback faces** in the preview or set
178188
`fallbacks = yes` in a config to fill codepoints the family lacks.
179189

180190
## What is here

docs/docker.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ on the host. The container can read and write one mounted workspace. That
55
folder holds the source fonts, configuration files, downloaded fallback faces
66
and built `.cpfont` families.
77

8-
The preview has no authentication. The supplied Compose service publishes it
9-
on `127.0.0.1` so that only the Docker host can open it.
8+
The preview has no login. Anyone who can reach the address can retune a
9+
family, save a config and start a build, so the supplied Compose service
10+
publishes it on `127.0.0.1` and only the Docker host can open it.
1011

1112
## Command cheat sheet
1213

1314
Run every command from the folder that contains `compose.yaml`. That can be a
1415
Git checkout or an unpacked release ZIP.
1516

16-
| Folder | `docker compose` uses | Local build context |
17+
| Folder | `docker compose` uses | What `--local` builds from |
1718
|---|---|---|
1819
| Git checkout | `ghcr.io/crazycoder/crossglyph:latest` | Current checkout |
1920
| Unpacked release | Image tagged with the release version | `versions/<release>` |
@@ -45,6 +46,10 @@ running CrossGlyph directly instead.
4546

4647
### Run Compose directly
4748

49+
Compose is the part of Docker that reads a `compose.yaml` file and runs what
50+
it describes. CrossGlyph ships those files, so the commands below work as
51+
printed from the folder that holds them.
52+
4853
To use the published image:
4954

5055
```sh
@@ -124,9 +129,9 @@ of this cleanup.
124129

125130
## Run builds and other commands
126131

127-
The image entrypoint is `crossglyph`. A command after the Compose service name
128-
replaces the default preview command while keeping the workspace mount and the
129-
container restrictions.
132+
Everything in the image runs `crossglyph`, so a word after the Compose service
133+
name is a CrossGlyph command. It replaces the default preview command and keeps
134+
the mounted workspace and the container restrictions.
130135

131136
```sh
132137
docker compose run --rm crossglyph build
@@ -204,11 +209,11 @@ docker run --rm \
204209

205210
## Update the image
206211

207-
The preview checks the release manifest at startup and when you press
208-
**Check now**. If the selected image is behind, the version row names the
209-
release and says to pull the new image. The check state stays in the
210-
container's private temporary filesystem rather than adding a file to the
211-
mounted workspace.
212+
The preview checks `latest.json`, the small file on the web that names the
213+
newest release, at startup and when you press **Check now**. If the selected
214+
image is behind, the version row names the release and says to pull the new
215+
image. The check state stays in the container's private temporary filesystem
216+
rather than adding a file to the mounted workspace.
212217

213218
An installed ZIP defaults to its own version so native and container launches
214219
run the same code. Set `CROSSGLYPH_TAG` in `.env` to move a container-only
@@ -230,7 +235,8 @@ deployment settings in `.env` so the managed Compose files can update without
230235
a conflict.
231236

232237
Published images support `linux/amd64` and `linux/arm64`. Each release also
233-
carries build provenance and an SBOM in the GitHub Container Registry.
238+
carries build provenance in the GitHub Container Registry, along with an SBOM,
239+
which is a list of everything that went into the image.
234240

235241
## Security boundary
236242

@@ -248,7 +254,4 @@ login, and its save and build endpoints write to the workspace. Put an
248254
authenticated TLS reverse proxy in front of CrossGlyph before making it
249255
available on another machine.
250256

251-
The bind mount is the current input and output path. A future upload and
252-
download interface can use the same `/workspace` contract with a Docker volume
253-
instead of a host folder. That change does not require another image entrypoint
254-
or another internal storage layout.
257+
The mounted folder is the only way fonts get in and builds get out.

0 commit comments

Comments
 (0)