feat(brand): write the Sketchi wordmark in Excalifont#295
Merged
Conversation
Collaborator
Author
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
anandpant
marked this pull request as ready for review
July 25, 2026 17:30
Contributor
Sketchi Web PreviewStatus:
Preview Worker cleanup has completed. |
Contributor
Sketchi Icons PreviewStatus:
Preview Worker cleanup has completed. |
Contributor
Sketchi Excalidraw Workspace PreviewStatus:
Preview Worker cleanup has completed. |
Contributor
Sketchi Eval Harness PreviewStatus:
Preview Worker cleanup has completed. |
Contributor
Sketchi Playground / Studio PreviewStatus:
Preview Worker cleanup has completed. |
anandpant
force-pushed
the
feat/excalifont-wordmark
branch
from
July 25, 2026 17:45
6426e11 to
c8ea774
Compare
Merge activity
|
## Why
Dancing Script is the default Google handwriting face — it reads as picked from a dropdown. Excalifont is the exact typeface every Sketchi diagram renders in, so the wordmark stops being decoration and becomes an instance of the product: the name written in the same hand the product draws.
On the playground the wordmark now sits inches from `GitHub push` / `Docker build` / `Run tests` in the same face. That adjacency is the whole point of the change.
## Licence finding
**Excalifont is SIL Open Font License 1.1, and OFL explicitly permits this use.** Verified rather than assumed:
- The vendored files are byte-identical to `excalidraw/excalidraw@master`. The `woff2` name table carries the copyright but **no** licence fields (nameID 13/14 absent), so the licence comes from upstream's `fonts/Excalifont/index.ts` metadata block (`"This Font Software is licensed under the SIL Open Font License, Version 1.1"`) and from `plus.excalidraw.com/excalifont` ("Released under the OFL-1.1 license ... freely available for both personal and commercial use").
- Wordmark use is squarely allowed. OFL clause 5 exempts "any document created using the Font Software", and the OFL FAQ 1.1/1.1.1 answers the logo question directly: *"Can I use the fonts ... to create logos or other graphics ... Yes."* and *"You remain the author and copyright holder of that newly derived graphic."* So the Sketchi wordmark stays ours; no copyleft reaches it.
- **No Reserved Font Name is declared**, so even naming restrictions on derivatives don't bite. We make no derivative regardless.
- Two obligations do apply, and both are now met:
1. Clause 2 — the copyright notice and licence must travel with every redistributed copy. Serving `woff2` from our origins is redistribution, so a `LICENSE` now sits beside the files in every `public/fonts/Excalifont`. Previously the playground served them with no notice at all.
2. Trademark — upstream declares *"Excalifont is a trademark of Excalidraw."* We use the letterforms, never the name, as Sketchi branding. The CLI's `THIRD_PARTY_NOTICES` was missing this line and now carries it.
No blocker. Ship it.
## Legibility pass
Checked in a real browser at every size the wordmark actually appears, on both paper and reversed out of dark ink.
**One adjustment was needed, and it was the important one: every placement drops from `font-weight: 700` to `400`.** Excalifont ships Regular only, so 600/700 was Chrome synthesising the weight — strokes thicken without the letters widening and the counters in `e`/`c` close up, exactly the "turns to mush" failure mode for a hand-drawn face. Regular is the real hand.
**No size changes were needed.** Measured against the outgoing face at 28px, Excalifont is ~12% wider with a taller cap (20 vs 18) but a slightly *smaller* x-height (12 vs 13) — so shrinking it to preserve the old footprint would have made it less legible, not more. At the three real sizes (28px header/playground, 26px dark footer, 25px icons narrow) the counters stay open and reversed strokes don't bloom.
The 404s on all three surfaces turned out to carry no wordmark at all — they're display-font headings only, so there was nothing to adjust there.
## What changed
- `--font-script` in `theme.css` drives everything, so the swap is one token plus the `@font-face` set beside it. All seven cn-font-split subsets are declared with their upstream `unicode-range` — they're subsets of one face, not seven faces, so declaring only the Latin one leaves every other codepoint silently falling back.
- Fonts vendored per surface (each Worker serves its own `public/`), with `diagram-ui` holding the reference copy and serving it to Storybook via `staticDirs`. `tools/vendored-excalifont.test.ts` pins all six copies byte-identical and derives the surface list from the theme imports, so a new theme consumer fails the test instead of shipping a 404 for its own brand face.
- Surfaces that draw the wordmark preload the Latin subset, so the lockup paints in Excalifont rather than reflowing through the sans.
- The og:card — the most-seen wordmark instance of all — is a static PNG a token can't reach. Its wordmark and `yes`/`no` tags are now Excalifont outlines rather than `<text>`, so it doesn't depend on a webfont reaching whichever renderer rasterises it (and outlines are the cleaner licence position: a document, not the font).
- Dancing Script is now unreferenced and leaves every Google Fonts URL.
Kept off `site-header.tsx` and all copy for the parallel declutter agent.
## Proof
- `pnpm nx run-many -t typecheck,test,build` — green (52 tasks)
- `pnpm nx build-storybook diagram-ui` — green
- `pnpm test:tools` — green (82 tests; `run-many` does not cover this)
- `pnpm lint` — green
- Verified in Chrome on web, icons, playground, excalidraw and Storybook: font 200s, `0` errored faces, wordmark computed at `400`, plus the three 404s and the icons narrow breakpoint. Build outputs confirmed to ship the subsets on all five surfaces.
- `codex review --base main` — clean on the third pass. It found two real defects I'd missed: 404ing font URLs on the two theme consumers that don't draw a wordmark, and the stale Dancing Script social card. Both fixed here.
## Rebase onto #294
Rebased onto `ca6b91d` (Product tab dropped, npm mark added, copy cut) and the legibility pass was re-run against the header that will actually ship, not the stale one: wordmark computed `28px`/`400`, `0` errored faces, no overflow at 390px, dark footer and 404 re-checked, and the fresh preview confirms the new three-item nav. The looser nav actually gives the lockup more room than before.
On the three visual languages now in one bar: the wordmark is not the friction — it's ink-toned text that belongs to the same layer as the nav, and the tile+wordmark lockup is separated from the utility cluster by the whole nav. The friction is the **npm mark**, for three reasons: it is the only filled container in the bar besides the Playground CTA (so it reads as a competing button immediately left of the real one), it is the highest-contrast, only-square-cornered element in a system that is otherwise rounded ink-on-paper, and it is optically much heavier than the Octocat sitting next to it, so two same-tier utility links read at different volumes. Recommendation is to render npm as a bare monochrome wordmark in `--ink-2`, matched to the Octocat's cap height, with no filled block — that makes GitHub+npm a coherent quiet pair and gives the CTA back its status as the only filled element. Not changed here: those marks landed in #294 and are not this PR's scope.
graphite-app
Bot
force-pushed
the
feat/excalifont-wordmark
branch
from
July 25, 2026 17:55
c8ea774 to
80dc9f4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
Dancing Script is the default Google handwriting face — it reads as picked from a dropdown. Excalifont is the exact typeface every Sketchi diagram renders in, so the wordmark stops being decoration and becomes an instance of the product: the name written in the same hand the product draws.
On the playground the wordmark now sits inches from
GitHub push/Docker build/Run testsin the same face. That adjacency is the whole point of the change.Licence finding
Excalifont is SIL Open Font License 1.1, and OFL explicitly permits this use. Verified rather than assumed:
excalidraw/excalidraw@master. Thewoff2name table carries the copyright but no licence fields (nameID 13/14 absent), so the licence comes from upstream'sfonts/Excalifont/index.tsmetadata block ("This Font Software is licensed under the SIL Open Font License, Version 1.1") and fromplus.excalidraw.com/excalifont("Released under the OFL-1.1 license ... freely available for both personal and commercial use").woff2from our origins is redistribution, so aLICENSEnow sits beside the files in everypublic/fonts/Excalifont. Previously the playground served them with no notice at all.THIRD_PARTY_NOTICESwas missing this line and now carries it.No blocker. Ship it.
Legibility pass
Checked in a real browser at every size the wordmark actually appears, on both paper and reversed out of dark ink.
One adjustment was needed, and it was the important one: every placement drops from
font-weight: 700to400. Excalifont ships Regular only, so 600/700 was Chrome synthesising the weight — strokes thicken without the letters widening and the counters ine/cclose up, exactly the "turns to mush" failure mode for a hand-drawn face. Regular is the real hand.No size changes were needed. Measured against the outgoing face at 28px, Excalifont is ~12% wider with a taller cap (20 vs 18) but a slightly smaller x-height (12 vs 13) — so shrinking it to preserve the old footprint would have made it less legible, not more. At the three real sizes (28px header/playground, 26px dark footer, 25px icons narrow) the counters stay open and reversed strokes don't bloom.
The 404s on all three surfaces turned out to carry no wordmark at all — they're display-font headings only, so there was nothing to adjust there.
What changed
--font-scriptintheme.cssdrives everything, so the swap is one token plus the@font-faceset beside it. All seven cn-font-split subsets are declared with their upstreamunicode-range— they're subsets of one face, not seven faces, so declaring only the Latin one leaves every other codepoint silently falling back.public/), withdiagram-uiholding the reference copy and serving it to Storybook viastaticDirs.tools/vendored-excalifont.test.tspins all six copies byte-identical and derives the surface list from the theme imports, so a new theme consumer fails the test instead of shipping a 404 for its own brand face.yes/notags are now Excalifont outlines rather than<text>, so it doesn't depend on a webfont reaching whichever renderer rasterises it (and outlines are the cleaner licence position: a document, not the font).Kept off
site-header.tsxand all copy for the parallel declutter agent.Proof
pnpm nx run-many -t typecheck,test,build— green (52 tasks)pnpm nx build-storybook diagram-ui— greenpnpm test:tools— green (82 tests;run-manydoes not cover this)pnpm lint— green0errored faces, wordmark computed at400, plus the three 404s and the icons narrow breakpoint. Build outputs confirmed to ship the subsets on all five surfaces.codex review --base main— clean on the third pass. It found two real defects I'd missed: 404ing font URLs on the two theme consumers that don't draw a wordmark, and the stale Dancing Script social card. Both fixed here.Rebase onto #294
Rebased onto
ca6b91d(Product tab dropped, npm mark added, copy cut) and the legibility pass was re-run against the header that will actually ship, not the stale one: wordmark computed28px/400,0errored faces, no overflow at 390px, dark footer and 404 re-checked, and the fresh preview confirms the new three-item nav. The looser nav actually gives the lockup more room than before.On the three visual languages now in one bar: the wordmark is not the friction — it's ink-toned text that belongs to the same layer as the nav, and the tile+wordmark lockup is separated from the utility cluster by the whole nav. The friction is the npm mark, for three reasons: it is the only filled container in the bar besides the Playground CTA (so it reads as a competing button immediately left of the real one), it is the highest-contrast, only-square-cornered element in a system that is otherwise rounded ink-on-paper, and it is optically much heavier than the Octocat sitting next to it, so two same-tier utility links read at different volumes. Recommendation is to render npm as a bare monochrome wordmark in
--ink-2, matched to the Octocat's cap height, with no filled block — that makes GitHub+npm a coherent quiet pair and gives the CTA back its status as the only filled element. Not changed here: those marks landed in #294 and are not this PR's scope.