Crawl URLs and rank fonts by how much they are actually rendered, to slim down @font-face stacks.
Project description
vecssy-slim
Crawl one or more URLs and find out which fonts are actually rendered — then rank them by how much of the page they occupy, so you can slim down a bloated @font-face stack with confidence.
Most font tools report what your CSS declares. vecssy-slim reports what the browser resolved: for every text node on the page it asks Chromium (via the DevTools Protocol) which font family was really used and how many glyphs it drew, then pairs that with the text's computed size, weight, style, and stretch.
Why coverage, not just counts
A font used once in a giant 72px headline matters more than one buried in a 10px footnote repeated everywhere. So the ranking metric is coverage:
coverage(font) = Σ over every rendered run [ rendered glyphs × font-size in px ]
It approximates the visual area a font occupies. Stats are reported per font-weight / font-style / font-stretch group, and then aggregated per family. Any @font-face family or weight that never shows up as a rendered font is dead weight — a safe candidate for removal or subsetting.
Install
uv venv --python 3.12
uv pip install -e ".[test]"
playwright install chromium # one-time: download the headless browser
Usage
vecssy-slim is a Fire CLI. Give it either a single --url or a --list_urls file (one URL per line; # comments allowed). Both report outputs are optional — without them you still get a terminal summary.
# Single URL, write both reports
vecssy-slim --url https://example.com \
--json_report report.json \
--md_report report.md
# Many URLs from a file
vecssy-slim --list_urls urls.txt --md_report site-fonts.md
# With --list_urls and no report flags, reports are written next to the
# list file: urls.txt -> urls.json + urls.md
vecssy-slim --list_urls urls.txt
# Combine: a single URL plus a list
vecssy-slim --url https://example.com --list_urls more.txt
Run vecssy-slim --help for the full, Fire-generated usage.
Options
| Flag | Default | Meaning |
|---|---|---|
--url |
– | A single URL to analyze. |
--list_urls |
– | Path to a file with one URL per line (# comments allowed). |
--json_report |
– | Write the full JSON report here. With --list_urls and no value, defaults to the list file with a .json extension. |
--md_report |
– | Write a Markdown report here. With --list_urls and no value, defaults to the list file with a .md extension. |
--timeout |
30.0 |
Per-page navigation timeout, seconds. |
--wait_until |
networkidle |
Playwright load state: load, domcontentloaded, or networkidle. |
--headless |
True |
Run Chromium headless; --noheadless to watch it. |
--top |
15 |
Families shown in the terminal summary. |
--verbose |
False |
Debug logging. |
You can provide --url and --list_urls together; URLs are de-duplicated in order.
Output
Both reports contain an aggregate (all URLs combined) and a per-URL breakdown. Each breakdown lists families sorted by coverage descending, and within each family the per-style rows (weight / style / stretch), also sorted by coverage.
JSON shape:
{
"aggregate": {
"url": "ALL URLS",
"error": null,
"total_chars": 12345,
"total_coverage": 234567.0,
"families": [
{
"family": "Inter",
"chars": 8000,
"coverage": 180000.0,
"styles": [
{"family": "Inter", "weight": "400", "style": "normal",
"stretch": "100%", "chars": 6000, "coverage": 120000.0}
]
}
]
},
"urls": [ { "url": "https://example.com", "...": "..." } ]
}
URLs that fail to load are captured (not fatal): the run continues and the failed URL appears with an error field.
How it works
- Crawl each URL in a headless Chromium page (Playwright).
- Walk the DOM — including iframes and shadow roots — for non-empty text nodes.
- For each text node, call CDP
CSS.getPlatformFontsForNodefor the resolved family and glyph count, andCSS.getComputedStyleForNodeon its parent for size / weight / style / stretch. - Aggregate into coverage =
glyphs × size, grouped per style and per family, sorted descending. - Report as JSON and/or Markdown, plus a terminal summary.
This catches fonts loaded dynamically (Adobe Fonts, async Google Fonts) that static CSS parsers miss, because it reads what the browser drew rather than what the stylesheet declared.
Development
uvx hatch test # or: .venv/bin/python -m pytest
The aggregation and reporting logic is pure and fully unit-tested without a browser; only live crawling needs Chromium.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vecssy_slim-1.0.0.tar.gz.
File metadata
- Download URL: vecssy_slim-1.0.0.tar.gz
- Upload date:
- Size: 26.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cebb6af63100bbf71ae3da89dfc08d4b5c2ec9d7d81947b7457b151a982e136
|
|
| MD5 |
423c248a1b46ff7344be263b825ea365
|
|
| BLAKE2b-256 |
eaa1c360ad412afc6fae0e81e17e154ac9b2e03dbf7a44aa4fbd92729ee9359a
|
File details
Details for the file vecssy_slim-1.0.0-py3-none-any.whl.
File metadata
- Download URL: vecssy_slim-1.0.0-py3-none-any.whl
- Upload date:
- Size: 15.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d92484c0d567d68237cb0beeab6b06713f39f205a820cbdba13827c7a2e468dd
|
|
| MD5 |
d2292a78082ef354b8b248b76a3fbd99
|
|
| BLAKE2b-256 |
52344be2acc44311d6cfc4be62d9455987c9f3e68fcfececcfe28485d17a8476
|