mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-09-03 14:37:55 +00:00
Landing performance: flag font subset, responsive mascots, AVIF cache, HTML minify
- Flag font: ship a committed fontTools subset (43 KB, -45%) of TwemojiCountryFlags.woff2 with only the 15 flags the site uses, under a content-hashed name with a preload on every flag-bearing page. The build validates the subset against a manifest and fails when a new flag appears without regenerating (npm run subset-flags). JS subsetters (subset-font/harfbuzzjs) were rejected: their wasm builds silently drop the COLR/CPAL color tables, rendering all flags invisible. - Responsive mascots: legal/join/404 pages served 434-500px sources for 175-180px slots; the build now emits 180w/360w variants (AVIF 1x: ~7 KB vs ~22 KB) and the pages use srcset. Small logo spots (14-42px) now use the existing 64/128px variants instead of the 256px file. - injectAvifPictures copies the img sizes attribute onto the AVIF <source>; without it Chrome mis-selects w-descriptor candidates and can drop the image entirely. - AVIF conversion is cached by content hash (.avif-cache.json); the old mtime check never hit because copyDirSync refreshes mtimes, so every verify re-encoded all 26 files. - HTML output is minified (comments + indentation, <pre> preserved, newlines kept for inline-script safety): index.html 121 KB -> 93 KB. - unicode-range trimmed to U+1F1E6-1F1FF; tag-sequence flags fall through to the system emoji font. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Regenerate the committed country-flag font subset.
|
||||
*
|
||||
* npm run subset-flags (or: node website/tools/subset-flag-font.mjs)
|
||||
*
|
||||
* Extracts every flag emoji used in website HTML/locales, subsets
|
||||
* assets/TwemojiCountryFlags.woff2 down to exactly those flags via Python
|
||||
* fontTools (harfbuzz-based JS subsetters drop the COLR color tables and
|
||||
* produce invisible flags), and writes:
|
||||
*
|
||||
* assets/TwemojiCountryFlags.subset.woff2 (committed)
|
||||
* assets/TwemojiCountryFlags.subset.json (committed manifest)
|
||||
*
|
||||
* The website build (build.cjs) is pure Node: it only validates the
|
||||
* manifest and fails when a flag was added without re-running this tool.
|
||||
*
|
||||
* Requires python3 with fonttools + brotli. Override the interpreter with
|
||||
* the PYTHON env var, e.g. PYTHON=.venv/bin/python npm run subset-flags
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const websiteDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const { collectFlagSourceFiles, extractUsedFlags, flagToCountryCode } = require(path.join(websiteDir, 'flag-font-utils.cjs'));
|
||||
|
||||
const sourceFont = path.join(websiteDir, 'assets', 'TwemojiCountryFlags.woff2');
|
||||
const outputFont = path.join(websiteDir, 'assets', 'TwemojiCountryFlags.subset.woff2');
|
||||
const manifestPath = path.join(websiteDir, 'assets', 'TwemojiCountryFlags.subset.json');
|
||||
|
||||
const python = process.env.PYTHON || 'python3';
|
||||
try {
|
||||
execFileSync(python, ['-c', 'import fontTools.subset, brotli'], { stdio: 'pipe' });
|
||||
} catch {
|
||||
console.error(`error: ${python} lacks fonttools/brotli.`);
|
||||
console.error('Install them (e.g. "pip3 install fonttools brotli") or point PYTHON at an interpreter that has them:');
|
||||
console.error(' PYTHON=/path/to/venv/bin/python npm run subset-flags');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const flags = extractUsedFlags(collectFlagSourceFiles(websiteDir));
|
||||
if (flags.length === 0) {
|
||||
console.error('error: no flag emoji found in website sources — extraction is broken');
|
||||
process.exit(1);
|
||||
}
|
||||
const codes = flags.map(flagToCountryCode);
|
||||
console.log(`Found ${codes.length} flags: ${codes.join(' ')}`);
|
||||
|
||||
execFileSync(python, [
|
||||
path.join(websiteDir, 'tools', 'subset_flag_font.py'),
|
||||
sourceFont,
|
||||
outputFont,
|
||||
codes.join(',')
|
||||
], { stdio: 'inherit' });
|
||||
|
||||
const sha = buf => crypto.createHash('sha256').update(buf).digest('hex');
|
||||
const manifest = {
|
||||
comment: 'Generated by tools/subset-flag-font.mjs — do not edit. build.cjs fails when site flags and this manifest diverge.',
|
||||
flags: codes,
|
||||
sourceFontSha256: sha(fs.readFileSync(sourceFont)),
|
||||
subsetSha256: sha(fs.readFileSync(outputFont))
|
||||
};
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
||||
|
||||
const before = fs.statSync(sourceFont).size;
|
||||
const after = fs.statSync(outputFont).size;
|
||||
console.log(`Wrote ${path.relative(process.cwd(), outputFont)} (${(after / 1024).toFixed(1)} KB, -${((1 - after / before) * 100).toFixed(0)}% vs source) + manifest.`);
|
||||
console.log('Commit both files.');
|
||||
@@ -0,0 +1,90 @@
|
||||
"""Subset TwemojiCountryFlags.woff2 to the given country flags.
|
||||
|
||||
Invoked by subset-flag-font.mjs — do not run directly unless debugging:
|
||||
python3 subset_flag_font.py <source.woff2> <output.woff2> DE,FR,GB,...
|
||||
|
||||
Requires: fonttools, brotli (pip install fonttools brotli).
|
||||
|
||||
harfbuzz-based JS subsetters (subset-font/harfbuzzjs) silently drop the
|
||||
COLR/CPAL color tables of this font, producing invisible flags — fontTools
|
||||
subsets them correctly. Each requested flag is validated to have a GSUB
|
||||
ligature AND COLR color layers so a broken subset can never be emitted.
|
||||
"""
|
||||
import io
|
||||
import sys
|
||||
|
||||
from fontTools import subset
|
||||
from fontTools.ttLib import TTFont
|
||||
|
||||
|
||||
def flag_codepoints(code):
|
||||
return [0x1F1E6 + ord(ch) - ord("A") for ch in code]
|
||||
|
||||
|
||||
def ligature_glyph(font, first, second):
|
||||
"""Return the GSUB ligature glyph for a regional-indicator pair."""
|
||||
gsub = font["GSUB"].table
|
||||
for lookup in gsub.LookupList.Lookup:
|
||||
subtables = []
|
||||
if lookup.LookupType == 4:
|
||||
subtables = lookup.SubTable
|
||||
elif lookup.LookupType == 7: # extension
|
||||
subtables = [st.ExtSubTable for st in lookup.SubTable if st.ExtensionLookupType == 4]
|
||||
for st in subtables:
|
||||
for lig in st.ligatures.get(first, []):
|
||||
if lig.Component == [second]:
|
||||
return lig.LigGlyph
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
src_path, out_path, codes_arg = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
codes = sorted(codes_arg.split(","))
|
||||
|
||||
font = TTFont(src_path)
|
||||
if "COLR" not in font or "CPAL" not in font:
|
||||
sys.exit("source font has no COLR/CPAL tables")
|
||||
|
||||
text = "".join(chr(cp) for code in codes for cp in flag_codepoints(code))
|
||||
options = subset.Options()
|
||||
options.flavor = "woff2"
|
||||
subsetter = subset.Subsetter(options=options)
|
||||
subsetter.populate(text=text)
|
||||
subsetter.subset(font)
|
||||
|
||||
buf = io.BytesIO()
|
||||
font.save(buf)
|
||||
result = TTFont(io.BytesIO(buf.getvalue()))
|
||||
|
||||
for table in ("COLR", "CPAL", "GSUB", "cmap"):
|
||||
if table not in result:
|
||||
sys.exit(f"subset lost the {table} table")
|
||||
|
||||
cmap = result.getBestCmap()
|
||||
glyph_name = {}
|
||||
for code in codes:
|
||||
for cp in flag_codepoints(code):
|
||||
if cp not in cmap:
|
||||
sys.exit(f"flag {code}: regional indicator U+{cp:X} missing from subset cmap")
|
||||
first, second = (cmap[cp] for cp in flag_codepoints(code))
|
||||
lig = ligature_glyph(result, first, second)
|
||||
if lig is None:
|
||||
sys.exit(f"flag {code}: no GSUB ligature in subset — font has no artwork for it")
|
||||
glyph_name[code] = lig
|
||||
|
||||
colr = result["COLR"]
|
||||
if colr.version == 0:
|
||||
for code, lig in glyph_name.items():
|
||||
if not colr.ColorLayers.get(lig):
|
||||
sys.exit(f"flag {code}: ligature glyph {lig} has no COLR color layers")
|
||||
# COLR v1 would need different traversal; Twemoji country flags is v0
|
||||
elif colr.version != 0:
|
||||
sys.exit(f"unexpected COLR version {colr.version} — validation only supports v0")
|
||||
|
||||
with open(out_path, "wb") as f:
|
||||
f.write(buf.getvalue())
|
||||
print(f"subset OK: {len(codes)} flags, {len(buf.getvalue())} bytes")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user