Browse Source
src/scriptapps/tools/fontprep/: pinned monospace web font for the punk-native html doc pipeline, closing the glyph-coverage gap the probe identified - unicode 16 octants (U+1CC00-1CEBF) and Symbols for Legacy Computing (U+1FB00-1FBFF) needed by ansicat/textblock rendering are absent from commonly-installed monospace fonts (even system Cascadia copies are commonly pre-2404 and lack them). - punkdoc-mono.woff2: glyph subset of Cascadia Mono v2404.23 VARIABLE ttf (wght axis 200-700 kept - true bold from one ~80KB file; 1561 cmap codepoints incl. full CP437 repertoire, box/blocks/geometric, braille, legacy computing + octants). Coverage verified 157/160 against the measured glyph inventory - identical to the full source font (misses are deliberate: em-space + fullwidth forms are converter-normalization/fallback territory). - renaming is REQUIRED by licence: Cascadia's SIL OFL 1.1 declares Reserved Font Name "Cascadia Code" and subsetting is modification. Name table is surgical: family records renamed, Microsoft copyright preserved verbatim (OFL requirement), trademark record removed (a renamed copy must not assert Microsoft's mark), OFL statement/url in licence records, provenance credit in the description record. - LICENSE-cascadia-OFL.txt (from the v2404.23 tag), punkdoc-unicodes.txt (whole-block ranges with headroom), make_punkdoc_mono.py (fonttools subset+ rename script), README.md (full provenance: source/output sha256s, exact command, regeneration steps). Python fonttools is one-time prep tooling only - the doc build never invokes it; generators just read the .woff2. Track licence in the G-063 inventory. punkargs_punknative.tcl: new -assets option consuming the vendored font: embed (default) = data-uri @font-face, fully self-contained page; link = copy punkdoc-mono.woff2 beside the output and reference relatively (shared+cached across a doc set); none = css stack only, with warn-and-degrade when the asset is missing. font-weight 200 700 descriptor, punkdoc-mono prepended to the fallback stack. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
6 changed files with 345 additions and 6 deletions
@ -0,0 +1,94 @@
|
||||
Copyright (c) 2019 - Present, Microsoft Corporation, |
||||
with Reserved Font Name Cascadia Code. |
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1. |
||||
This license is copied below, and is also available with a FAQ at: |
||||
http://scripts.sil.org/OFL |
||||
|
||||
|
||||
----------------------------------------------------------- |
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 |
||||
----------------------------------------------------------- |
||||
|
||||
PREAMBLE |
||||
The goals of the Open Font License (OFL) are to stimulate worldwide |
||||
development of collaborative font projects, to support the font creation |
||||
efforts of academic and linguistic communities, and to provide a free and |
||||
open framework in which fonts may be shared and improved in partnership |
||||
with others. |
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and |
||||
redistributed freely as long as they are not sold by themselves. The |
||||
fonts, including any derivative works, can be bundled, embedded, |
||||
redistributed and/or sold with any software provided that any reserved |
||||
names are not used by derivative works. The fonts and derivatives, |
||||
however, cannot be released under any other type of license. The |
||||
requirement for fonts to remain under this license does not apply |
||||
to any document created using the fonts or their derivatives. |
||||
|
||||
DEFINITIONS |
||||
"Font Software" refers to the set of files released by the Copyright |
||||
Holder(s) under this license and clearly marked as such. This may |
||||
include source files, build scripts and documentation. |
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the |
||||
copyright statement(s). |
||||
|
||||
"Original Version" refers to the collection of Font Software components as |
||||
distributed by the Copyright Holder(s). |
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting, |
||||
or substituting -- in part or in whole -- any of the components of the |
||||
Original Version, by changing formats or by porting the Font Software to a |
||||
new environment. |
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical |
||||
writer or other person who contributed to the Font Software. |
||||
|
||||
PERMISSION & CONDITIONS |
||||
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify, |
||||
redistribute, and sell modified and unmodified copies of the Font |
||||
Software, subject to the following conditions: |
||||
|
||||
1) Neither the Font Software nor any of its individual components, |
||||
in Original or Modified Versions, may be sold by itself. |
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, |
||||
redistributed and/or sold with any software, provided that each copy |
||||
contains the above copyright notice and this license. These can be |
||||
included either as stand-alone text files, human-readable headers or |
||||
in the appropriate machine-readable metadata fields within text or |
||||
binary files as long as those fields can be easily viewed by the user. |
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font |
||||
Name(s) unless explicit written permission is granted by the corresponding |
||||
Copyright Holder. This restriction only applies to the primary font name as |
||||
presented to the users. |
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font |
||||
Software shall not be used to promote, endorse or advertise any |
||||
Modified Version, except to acknowledge the contribution(s) of the |
||||
Copyright Holder(s) and the Author(s) or with their explicit written |
||||
permission. |
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, |
||||
must be distributed entirely under this license, and must not be |
||||
distributed under any other license. The requirement for fonts to |
||||
remain under this license does not apply to any document created |
||||
using the Font Software. |
||||
|
||||
TERMINATION |
||||
This license becomes null and void if any of the above conditions are |
||||
not met. |
||||
|
||||
DISCLAIMER |
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT |
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE |
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL |
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM |
||||
OTHER DEALINGS IN THE FONT SOFTWARE. |
||||
@ -0,0 +1,70 @@
|
||||
# fontprep - punkdoc-mono web font for the punk-native documentation pipeline |
||||
|
||||
`punkdoc-mono.woff2` is the pinned monospace web font consumed by the |
||||
punk-native html doc generation (`../punkargs_punknative.tcl` and its |
||||
successors). It exists because the ansi->html rendering of punk::args usage |
||||
tables, textblock output and cp437/ansi art (src/testansi) needs glyphs - |
||||
Unicode 16 octants (U+1CC00-1CEBF) and Symbols for Legacy Computing |
||||
(U+1FB00-1FBFF) in particular - that are absent from the monospace fonts |
||||
commonly installed on reader machines. Coverage was measured empirically: |
||||
see the glyph inventory probe notes below. |
||||
|
||||
## What it is |
||||
|
||||
A glyph subset of **Cascadia Mono v2404.23** (variable font, `wght` axis |
||||
200-700 retained so browsers render true bold from this single file), |
||||
renamed to **punkdoc-mono**. |
||||
|
||||
- Renaming is REQUIRED, not cosmetic: Cascadia's SIL OFL 1.1 licence declares |
||||
the Reserved Font Name "Cascadia Code", and a modified version (subsetting |
||||
is modification) must not use it. `punkdoc-mono` avoids the Cascadia name |
||||
entirely. The font's embedded name table carries the original Microsoft |
||||
copyright (nameID 0, preserved verbatim as the OFL requires), the OFL |
||||
licence statement/url (nameID 13/14), and a provenance description |
||||
(nameID 10). The original trademark record was removed (a renamed copy must |
||||
not assert Microsoft's trademark). |
||||
- Licence: SIL OFL 1.1 - full text in `LICENSE-cascadia-OFL.txt` (fetched from |
||||
the v2404.23 source tag). The OFL applies to the font only; it places no |
||||
conditions on punkshell (BSD) or on documents rendered with the font. |
||||
Track in the project licence inventory (G-063). |
||||
- No italic face is included: browsers synthesize oblique for italic spans |
||||
(advance widths are preserved, so terminal-grid alignment holds). |
||||
|
||||
## Provenance (reproducibility) |
||||
|
||||
- Source: https://github.com/microsoft/cascadia-code/releases/download/v2404.23/CascadiaCode-2404.23.zip |
||||
- release zip sha256: A911410626C0E09D03FA3FDDA827188FDA96607DF50FECC3C5FEE5906E33251B |
||||
- input file within zip: ttf/CascadiaMono.ttf (variable) |
||||
- input ttf sha256: 056F33BA2D9DA954750320EC6ECFB7D83CFB5F93AD593722170CD4498F5D4E95 |
||||
- Tooling: python fonttools 4.63.0 + brotli (one-time prep only - the doc |
||||
BUILD never invokes python; it just reads/copies/base64s the .woff2) |
||||
- Command: |
||||
`python make_punkdoc_mono.py CascadiaMono.ttf punkdoc-unicodes.txt <outdir>` |
||||
- Output punkdoc-mono.woff2 sha256: 3476B6C12B3306D25A787C01882B0F484C3E11C3E05A59969065B199056641A4 |
||||
(1561 cmap codepoints, 4319 glyphs, 79780 bytes) |
||||
|
||||
## Subset ranges |
||||
|
||||
`punkdoc-unicodes.txt` - whole blocks (with headroom) covering the demand |
||||
measured 2026-07-13 by the glyph inventory probe (scratch trial folder |
||||
argdoc2man-trial-2026-07-13: glyph_inventory.tcl over src/testansi decoded as |
||||
ansicat does + textblock::periodic + all textblock frametypes + |
||||
punk::args::usage = 160 unique non-ascii codepoints), plus the full CP437 |
||||
repertoire and braille (U+2800-28FF) for future plot rendering. |
||||
Verified: the subset covers 157/160 of the measured inventory - identical to |
||||
the full source font. The 3 misses are deliberate non-goals: em-space U+2003 |
||||
(converters should normalize exotic spaces to plain spaces - terminals treat |
||||
them as one cell) and fullwidth forms U+FF30/FF31 (inherently double-width; |
||||
CJK-font fallback territory). |
||||
|
||||
## Regenerating (when the glyph domain grows) |
||||
|
||||
1. Re-run the glyph inventory probe over the current content; if new |
||||
codepoints fall outside `punkdoc-unicodes.txt`, widen the ranges. |
||||
2. `pip install fonttools brotli` (any machine; a venv is fine) |
||||
3. Fetch the pinned Cascadia release (or a newer one - update shas here) |
||||
4. Run the command above; verify coverage (e.g. via |
||||
Windows.Media.GlyphTypeface against the inventory - see font_coverage.ps1 |
||||
in the trial scratch folder) and that name records contain no "Cascadia" |
||||
outside the nameID 10 provenance credit. |
||||
5. Commit the new .woff2 together with updated shas in this README. |
||||
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3 |
||||
"""make_punkdoc_mono.py - one-time font-prep for the punkshell doc pipeline. |
||||
|
||||
Subsets the Cascadia Mono VARIABLE font (weight axis kept, so browsers get |
||||
true bold from one file) to the punkdoc unicode ranges, renames the family to |
||||
'punkdoc-mono' (REQUIRED: Cascadia's OFL declares Reserved Font Name |
||||
'Cascadia Code' - a modified version must not use the reserved name), and |
||||
writes woff2 (for the web) + ttf (for cmap verification tooling). |
||||
|
||||
usage: python make_punkdoc_mono.py <CascadiaMono.ttf> <unicodes.txt> <outdir> |
||||
""" |
||||
import sys |
||||
import os |
||||
from fontTools import version as fonttools_version |
||||
from fontTools.ttLib import TTFont |
||||
from fontTools.subset import Subsetter, Options |
||||
|
||||
SRC_FAMILY_NAMES = ["Cascadia Mono", "CascadiaMono", "Cascadia Code", "CascadiaCode"] |
||||
NEW_FAMILY = "punkdoc-mono" |
||||
|
||||
def parse_unicodes(path): |
||||
cps = set() |
||||
with open(path, encoding="utf-8") as f: |
||||
for line in f: |
||||
line = line.strip() |
||||
if not line or line.startswith("#"): |
||||
continue |
||||
if "-" in line: |
||||
lo, hi = line.split("-") |
||||
cps.update(range(int(lo, 16), int(hi, 16) + 1)) |
||||
else: |
||||
cps.add(int(line, 16)) |
||||
return cps |
||||
|
||||
# name records that carry the FAMILY NAME and must be renamed (OFL Reserved |
||||
# Font Name requirement). Copyright (0), designer/vendor credits (8,9,11,12) |
||||
# are preserved untouched - the OFL requires the copyright notice be retained. |
||||
FAMILY_NAME_IDS = (1, 3, 4, 6, 16, 17, 21, 22, 25) |
||||
OFL_ID13 = ("This Font Software is licensed under the SIL Open Font License, " |
||||
"Version 1.1.") |
||||
PROVENANCE_ID10 = ("punkdoc-mono is a glyph subset of Cascadia Mono v2404.23 " |
||||
"(c) Microsoft Corporation, renamed as required by the SIL " |
||||
"OFL 1.1 Reserved Font Name condition. Prepared for the " |
||||
"punkshell documentation pipeline.") |
||||
|
||||
def rename(font): |
||||
name = font["name"] |
||||
keep = [] |
||||
for rec in name.names: |
||||
# drop the trademark record entirely: the original text is about the |
||||
# Cascadia name (which this font no longer uses) and a renamed copy |
||||
# must not assert Microsoft's trademark over the new name |
||||
if rec.nameID == 7: |
||||
continue |
||||
if rec.nameID in FAMILY_NAME_IDS: |
||||
s = rec.toUnicode() |
||||
for old in SRC_FAMILY_NAMES: |
||||
s = s.replace(old, NEW_FAMILY) |
||||
s = s.replace(old.replace(" ", ""), NEW_FAMILY) |
||||
if rec.nameID == 6: |
||||
s = s.replace(" ", "") |
||||
rec.string = s |
||||
elif rec.nameID == 13: |
||||
rec.string = OFL_ID13 |
||||
keep.append(rec) |
||||
name.names = keep |
||||
# embedded provenance/description (mentioning the source font as credit is |
||||
# permitted - the RFN restriction is on naming the font, not attribution) |
||||
for platformID, platEncID, langID in ((3, 1, 0x409), (1, 0, 0)): |
||||
name.setName(PROVENANCE_ID10, 10, platformID, platEncID, langID) |
||||
|
||||
def main(): |
||||
src, unifile, outdir = sys.argv[1], sys.argv[2], sys.argv[3] |
||||
os.makedirs(outdir, exist_ok=True) |
||||
cps = parse_unicodes(unifile) |
||||
print(f"fonttools {fonttools_version}; requested codepoints: {len(cps)}") |
||||
|
||||
font = TTFont(src) |
||||
opts = Options() |
||||
opts.layout_features = ["*"] # keep default layout behaviour |
||||
opts.name_IDs = ["*"] # keep all name records (license notice ids too) |
||||
opts.name_legacy = True |
||||
opts.name_languages = ["*"] |
||||
opts.notdef_outline = True |
||||
opts.recalc_bounds = True |
||||
opts.recalc_average_width = True |
||||
opts.prune_unicode_ranges = True |
||||
subsetter = Subsetter(options=opts) |
||||
subsetter.populate(unicodes=cps) |
||||
subsetter.subset(font) |
||||
|
||||
covered = set() |
||||
for table in font["cmap"].tables: |
||||
covered.update(table.cmap.keys()) |
||||
print(f"glyphs in subset: {font['maxp'].numGlyphs}; cmap codepoints: {len(covered)}") |
||||
|
||||
rename(font) |
||||
|
||||
ttf_path = os.path.join(outdir, "punkdoc-mono.ttf") |
||||
font.save(ttf_path) |
||||
print(f"wrote {ttf_path} ({os.path.getsize(ttf_path)} bytes)") |
||||
|
||||
font.flavor = "woff2" |
||||
woff2_path = os.path.join(outdir, "punkdoc-mono.woff2") |
||||
font.save(woff2_path) |
||||
print(f"wrote {woff2_path} ({os.path.getsize(woff2_path)} bytes)") |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
Binary file not shown.
@ -0,0 +1,21 @@
|
||||
# punkdoc-mono subset ranges - whole blocks covering (with headroom) the |
||||
# glyph demand measured by glyph_inventory.tcl over src/testansi + |
||||
# textblock::periodic/frames + punk::args::usage (2026-07-13, 160 codepoints) |
||||
# plus the full CP437 repertoire and braille for future plot rendering. |
||||
0020-007E |
||||
00A0-00FF |
||||
0180-024F |
||||
0370-03FF |
||||
2000-206F |
||||
2070-209F |
||||
20A0-20CF |
||||
2190-21FF |
||||
2200-22FF |
||||
2300-23FF |
||||
2400-243F |
||||
2500-25FF |
||||
2600-26FF |
||||
2700-27BF |
||||
2800-28FF |
||||
1CC00-1CEBF |
||||
1FB00-1FBFF |
||||
Loading…
Reference in new issue