146 lines
5.9 KiB
Bash
Executable File
146 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# subset-fonts.sh — Subset and convert TTF system fonts to WOFF2 for web use.
|
|
#
|
|
# Requires: fonttools (pyftsubset) — `pip install fonttools brotli`
|
|
# Output: static/fonts/
|
|
#
|
|
# ─── Font directories ────────────────────────────────────────────────────────
|
|
# Override any of these via the matching env var when your distro lays the
|
|
# fonts out differently. The script tries each candidate path in order and
|
|
# fails with a clear message if none resolve.
|
|
#
|
|
# SPECTRAL_DIR Spectral-{Regular,Italic,SemiBold,SemiBoldItalic,Bold,BoldItalic}.ttf
|
|
# FIRA_DIR FiraSans-{Regular,SemiBold}.ttf
|
|
# JBM_DIR JetBrainsMono-{Regular,Italic}.ttf
|
|
#
|
|
# Common locations:
|
|
# Arch: /usr/share/fonts/ttf-spectral, /usr/share/fonts/TTF
|
|
# Debian: /usr/share/fonts/truetype/spectral, /usr/share/fonts/truetype/firasans,
|
|
# /usr/share/fonts/truetype/jetbrains-mono
|
|
# macOS (brew): /opt/homebrew/share/fonts, ~/Library/Fonts
|
|
# Manual: wherever you unzipped the upstream releases
|
|
|
|
set -euo pipefail
|
|
|
|
OUTDIR="$(dirname "$0")/../static/fonts"
|
|
mkdir -p "$OUTDIR"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Locate font directories (env var override > candidate list > error)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Resolve a font dir by checking, in order:
|
|
# 1. The override env var (passed by name), if non-empty
|
|
# 2. Each candidate path
|
|
# Sets the global RESOLVED_DIR on success; exits with a descriptive message
|
|
# on failure. Sets the global rather than echoing because `exit 1` inside a
|
|
# `$(...)` substitution only exits the subshell, not the script.
|
|
resolve_font_dir() {
|
|
local label="$1" # human-readable name, e.g. "Spectral"
|
|
local env_var="$2" # env var name, e.g. "SPECTRAL_DIR"
|
|
shift 2
|
|
local candidates=("$@")
|
|
|
|
# Indirection: ${!env_var} reads the env var named in $env_var.
|
|
if [ -n "${!env_var:-}" ]; then
|
|
if [ ! -d "${!env_var}" ]; then
|
|
echo "Error: $env_var=${!env_var} is not a directory." >&2
|
|
exit 1
|
|
fi
|
|
RESOLVED_DIR="${!env_var}"
|
|
return
|
|
fi
|
|
|
|
for dir in "${candidates[@]}"; do
|
|
if [ -d "$dir" ]; then
|
|
RESOLVED_DIR="$dir"
|
|
return
|
|
fi
|
|
done
|
|
|
|
echo "Error: $label fonts not found in any of:" >&2
|
|
printf ' %s\n' "${candidates[@]}" >&2
|
|
echo "Set $env_var to point at the directory containing the .ttf files." >&2
|
|
exit 1
|
|
}
|
|
|
|
resolve_font_dir "Spectral" "SPECTRAL_DIR" \
|
|
/usr/share/fonts/ttf-spectral \
|
|
/usr/share/fonts/truetype/spectral \
|
|
/opt/homebrew/share/fonts \
|
|
"$HOME/Library/Fonts"
|
|
SPECTRAL="$RESOLVED_DIR"
|
|
|
|
resolve_font_dir "Fira Sans" "FIRA_DIR" \
|
|
/usr/share/fonts/TTF \
|
|
/usr/share/fonts/truetype/firasans \
|
|
/usr/share/fonts/truetype/fira-sans \
|
|
/opt/homebrew/share/fonts \
|
|
"$HOME/Library/Fonts"
|
|
FIRA="$RESOLVED_DIR"
|
|
|
|
resolve_font_dir "JetBrains Mono" "JBM_DIR" \
|
|
/usr/share/fonts/TTF \
|
|
/usr/share/fonts/truetype/jetbrains-mono \
|
|
/usr/share/fonts/truetype/jetbrainsmono \
|
|
/opt/homebrew/share/fonts \
|
|
"$HOME/Library/Fonts"
|
|
JBM="$RESOLVED_DIR"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Subset configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Unicode range: Latin, Latin Extended-A, General Punctuation, common symbols
|
|
UNICODES="U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD"
|
|
|
|
SPECTRAL_FEATURES="liga,dlig,smcp,c2sc,onum,lnum,pnum,tnum,frac,ordn,sups,subs,ss01,ss02,ss03,ss04,ss05,kern"
|
|
FIRA_FEATURES="smcp,liga,kern"
|
|
JBM_FEATURES="liga,kern,calt"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Subset helper — fails fast if a source file is missing
|
|
# ---------------------------------------------------------------------------
|
|
|
|
subset() {
|
|
local src="$1" dest="$2" features="$3"
|
|
if [ ! -f "$src" ]; then
|
|
echo "Error: source font not found: $src" >&2
|
|
echo " Adjust the directory env var (SPECTRAL_DIR / FIRA_DIR / JBM_DIR)" >&2
|
|
echo " or install the corresponding font package." >&2
|
|
exit 1
|
|
fi
|
|
echo " → $(basename "$dest")"
|
|
pyftsubset "$src" \
|
|
--output-file="$dest" \
|
|
--flavor=woff2 \
|
|
--layout-features="$features" \
|
|
--unicodes="$UNICODES" \
|
|
--no-hinting \
|
|
--desubroutinize
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Run
|
|
# ---------------------------------------------------------------------------
|
|
|
|
echo "Spectral... ($SPECTRAL)"
|
|
subset "$SPECTRAL/Spectral-Regular.ttf" "$OUTDIR/spectral-regular.woff2" "$SPECTRAL_FEATURES"
|
|
subset "$SPECTRAL/Spectral-Italic.ttf" "$OUTDIR/spectral-italic.woff2" "$SPECTRAL_FEATURES"
|
|
subset "$SPECTRAL/Spectral-SemiBold.ttf" "$OUTDIR/spectral-semibold.woff2" "$SPECTRAL_FEATURES"
|
|
subset "$SPECTRAL/Spectral-SemiBoldItalic.ttf" "$OUTDIR/spectral-semibold-italic.woff2" "$SPECTRAL_FEATURES"
|
|
subset "$SPECTRAL/Spectral-Bold.ttf" "$OUTDIR/spectral-bold.woff2" "$SPECTRAL_FEATURES"
|
|
subset "$SPECTRAL/Spectral-BoldItalic.ttf" "$OUTDIR/spectral-bold-italic.woff2" "$SPECTRAL_FEATURES"
|
|
|
|
echo "Fira Sans... ($FIRA)"
|
|
subset "$FIRA/FiraSans-Regular.ttf" "$OUTDIR/fira-sans-regular.woff2" "$FIRA_FEATURES"
|
|
subset "$FIRA/FiraSans-SemiBold.ttf" "$OUTDIR/fira-sans-semibold.woff2" "$FIRA_FEATURES"
|
|
|
|
echo "JetBrains Mono... ($JBM)"
|
|
subset "$JBM/JetBrainsMono-Regular.ttf" "$OUTDIR/jetbrains-mono-regular.woff2" "$JBM_FEATURES"
|
|
subset "$JBM/JetBrainsMono-Italic.ttf" "$OUTDIR/jetbrains-mono-italic.woff2" "$JBM_FEATURES"
|
|
|
|
echo ""
|
|
echo "Done. Output:"
|
|
ls -lh "$OUTDIR"/*.woff2
|