Around typeface #
Around is Cameron's custom geometric unicase display face for
cameron.stream. It was drawn and refined as a
cosmological instrument: precise, austere, slightly uncanny, and more like
an artifact than a conventional brand font.
This repository contains everything required to rebuild and revisit it. No FontLab, Glyphs, Illustrator, or private source file exists elsewhere.
Source of truth #
| File | Role |
|---|---|
scripts/generate-around-font.py |
Canonical glyph geometry, metrics, mappings, kerning, metadata, and font build |
scripts/requirements-font-build.txt |
Shared pinned build-only Python dependencies |
public/fonts/around-regular.ttf |
Generated desktop font committed for serving and download |
public/fonts/around-regular.woff2 |
Generated web font committed for serving |
src/components/type-specimen.tsx |
Public /type specimen and design statement |
public/type.css |
Specimen composition and responsive behavior |
public/site.css |
Site-wide @font-face, display-font integration, and font cache key |
src/components/shell.tsx |
Shared WOFF2 preload and its matching cache key |
src/index.tsx |
Immutable font response policy |
The Python generator is the editable source. The TTF and WOFF2 files are build artifacts and should never be edited directly.
Build from a clean checkout #
The font toolchain is deliberately separate from the website's Node runtime.
python3 -m venv .venv-font
.venv-font/bin/python -m pip install -r scripts/requirements-font-build.txt
.venv-font/bin/python scripts/generate-around-font.py
The generator writes both files under public/fonts/. Builds are reproducible:
it uses a fixed SOURCE_DATE_EPOCH unless that standard environment variable
is explicitly supplied by the caller. Rebuilding unchanged source should
therefore leave the committed font binaries unchanged.
After a real font change, increment the cache query attached to both font URLs
in public/site.css and the matching WOFF2 preload in
src/components/shell.tsx. Font responses are cached for one year with
immutable, so changing the query is what makes browsers request a new binary.
Browsers can otherwise retain an older WOFF2 while the server is already
serving the new one.
Design grammar #
- 1000 units per em with an 800-unit cap/unicase body.
- 70-unit monoline construction is the default skeleton grammar.
- Letters are built from lines, sampled arcs, cubic curves, and a small number of precision geometries converted into TrueType outlines through Shapely.
- Uppercase and lowercase Unicode codepoints map to the same unicase glyphs.
- Character widths are proportional. Around is geometric, not monospaced.
- The ring
○is a first-class glyph and recurring visual primitive. - Inter remains the body and navigation face. Around is for names, titles, statements, and display-scale moments.
The generator has two construction layers:
GLYPHSdefines centerline skeletons for the broad family.precision_geometry()replaces forms that need optical or contour-level control after a generic stroked skeleton proves insufficient.
That distinction is intentional. Do not force every glyph through one clever abstraction. The face became good when the system allowed optical exceptions.
Settled forms and relationships #
These are design decisions, not unfinished cleanup:
- S is the characteristic form. Preserve its distributed curvature and current silhouette unless a real-scale proof exposes a concrete problem.
- R is deliberately upright and left-anchored. Its diagonal leg must not extend beyond the bowl's right edge; the generator enforces this invariant.
- P and R share bowl dimensions through
PR_BOWL_RXandPR_BOWL_RY. - The M, J, and 1 retain their unusual constructions. A review proposed conventionalizing them; proofs did not justify losing their character.
- Current word spacing is 330 units. The original 430-unit space made sentences fragment into isolated word objects.
- Kerning is sparse and optical. Existing pairs should be judged in words, rather than expanded mechanically into a large generic table.
The current R leg centerline is [(535, 500), (810, -50)]. Treat that as a
protected relationship to the bowl, not an arbitrary pair of coordinates.
How to refine it #
- Change the Python source, never the generated binaries.
- Regenerate both font formats.
- Open
/typeand inspect the face at hero, sentence, alphabet, numeral, and small-display scales. - Inspect real site routes too. At minimum:
/,/travel,/blog, one post with a long title, and/annotations. - Check desktop, ordinary mobile, and a narrow 320px viewport. The specimen contains intentionally oversized compositions, so hidden clipping can look like successful overflow handling.
- Proof changes in words containing the affected pair. For example, a
P/Achange should be judged inSPACE,PAPER, andPAIR, not onlyPA. - Run the checks below, inspect the binary diff, and bump the font cache key.
Useful proof strings:
SPACE DISPLAY PAPER TYPEFACE
PAIR APPROACH SHAPE OPEN
AVATAR WAYWARD YOUTH ATLAS
LOVE OVER MOVE ROUND
NEVER MEMORY SIGNAL SYSTEM
LA TYPE TO TA FO PA PO PE PR
Do not assess only enlarged isolated glyphs. Several forms that look peculiar alone become coherent in words, while spacing defects often appear only in a sentence or on a real page.
Validation #
Run the site type checker:
pnpm typecheck
git diff --check
Confirm that the generated files can be fully parsed and contain the expected metadata:
.venv-font/bin/python - <<'PY'
from fontTools.ttLib import TTFont
for path in ("public/fonts/around-regular.ttf", "public/fonts/around-regular.woff2"):
font = TTFont(path)
font.ensureDecompiled()
cmap = font.getBestCmap()
required = (
set(range(ord("A"), ord("Z") + 1))
| set(range(ord("a"), ord("z") + 1))
| set(range(ord("0"), ord("9") + 1))
| {0x25CB, 0x2018, 0x2019, 0x201C, 0x201D}
)
assert required <= set(cmap)
assert font["OS/2"].usWeightClass == 400
assert "GPOS" in font
print(path, len(font.getGlyphOrder()), "glyphs", len(cmap), "codepoints")
PY
At the time this document was written, both formats contain 58 glyphs and map 88 codepoints. A deliberate character-set expansion will change those figures; update this document when it does.
Known limits #
- Around is a display font, not a general-purpose text face.
- It currently covers the Latin alphabet, decimal numerals, selected punctuation, typographic quotes, and the ring. It is not broad multilingual coverage.
- There is one regular weight and no variable axis.
- Browser and page-level proofing remains part of the build. Binary validity cannot tell whether a word rhythm or silhouette is actually good.
Deployment #
The font and specimen deploy with the rest of cameron.stream:
fly deploy
After deployment, verify https://cameron.stream/type and confirm the WOFF2
request uses the new cache key from public/site.css.