{"id":23116169,"url":"https://github.com/web-alchemy/fonttools","last_synced_at":"2025-10-24T03:21:17.473Z","repository":{"id":169510653,"uuid":"645233311","full_name":"web-alchemy/fonttools","owner":"web-alchemy","description":"Node.js adapter of python font tools via Pyodide","archived":false,"fork":false,"pushed_at":"2025-07-22T18:25:31.000Z","size":34,"stargazers_count":13,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-22T20:27:27.676Z","etag":null,"topics":["fonts","fonttools","pyodide","subset","woff2"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/web-alchemy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-05-25T07:55:14.000Z","updated_at":"2025-07-22T18:25:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"f5701f2c-48fb-4e04-addf-0ea2536163a1","html_url":"https://github.com/web-alchemy/fonttools","commit_stats":null,"previous_names":["web-alchemy/fonttools"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/web-alchemy/fonttools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-alchemy%2Ffonttools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-alchemy%2Ffonttools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-alchemy%2Ffonttools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-alchemy%2Ffonttools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/web-alchemy","download_url":"https://codeload.github.com/web-alchemy/fonttools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-alchemy%2Ffonttools/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268554909,"owners_count":24269062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-03T02:00:12.545Z","response_time":2577,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fonts","fonttools","pyodide","subset","woff2"],"created_at":"2024-12-17T04:13:49.673Z","updated_at":"2025-10-24T03:21:12.434Z","avatar_url":"https://github.com/web-alchemy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Font tools\n\nThis is the Node.js adapter of [python font tools](https://github.com/fonttools/fonttools) via [Pyodide](https://pyodide.org) without having to install python and its dependencies.\n\nFont tools library usually used for optimizing fonts – subseting, format converting, deleting of unused variable font axes, etc.\n\n## Using as a CLI\n\nYou can install the library as a global dependency:\n\n```shell\nnpm install --global @web-alchemy/fonttools\n```\n\nAfter installing [font utilities](https://fonttools.readthedocs.io/en/latest/#utilities) will be available globally:\n\n```shell\nfonttools \u003cparams\u003e\npyftsubset \u003cparams\u003e\npyftmerge \u003cparams\u003e\nttx \u003cparams\u003e\n```\n\nAlso you can use this tool via [npx](https://docs.npmjs.com/cli/commands/npx):\n\n```shell\nnpx -p @web-alchemy/fonttools \u003cparams\u003e\nnpx -p @web-alchemy/fonttools pyftsubset \u003cparams\u003e\nnpx -p @web-alchemy/fonttools pyftmerge \u003cparams\u003e\nnpx -p @web-alchemy/fonttools ttx \u003cparams\u003e\n```\n\nExample of converting `ttf` to `woff2`:\n\n```shell\nnpx -p @web-alchemy/fonttools pyftsubset \\\n  \"./some/path/to/font.ttf\" \\\n  \"*\" \\  # keep all glyphs and just convert format\n  --output-file=\"./some/path/to/font.woff2\" \\\n  --flavor=\"woff2\"\n```\n\nExample of converting `ttf` to `woff2` and subseting with text and unicodes options:\n\n```shell\nnpx -p @web-alchemy/fonttools pyftsubset \\\n  \"./some/path/to/font.ttf\" \\\n  --output-file=\"./some/path/to/font.woff2\" \\\n  --flavor=\"woff2\" \\\n  --text=\"The text whose characters will be included in the font file\" \\\n  --unicodes=\"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD\" \\\n  --desubroutinize \\\n  --no-hinting \\\n  --layout-features=\"*\"\n```\n\nExample of [customizing variable font's axes](https://fonttools.readthedocs.io/en/latest/varLib/instancer.html):\n\n```shell\nnpx @web-alchemy/fonttools varLib.instancer \\\n  \"./src/font.woff2\" \\\n  # decrease `wght` axis range\n  wght=400:600 \\\n  # delete `wdth` axis\n  wdth=drop \\ \n  --output=\"./dist/font.woff2\"\n```\n\n## Using as a module\n\nLibrary provides few JavaScript specific methods:\n\n```javascript\nconst {\n  subset,\n  instantiateVariableFont,\n  ttx\n} = require('@web-alchemy/fonttools')\n```\n\nExample of converting `ttf` to `woff2`:\n\n```javascript\nconst fs = require('node:fs')\nconst { subset } = require('@web-alchemy/fonttools')\n\nasync function main() {\n  const inputFileBuffer = await fs.promises.readFile('./font.ttf')\n\n  const outputFileBuffer = await subset(inputFileBuffer, {\n    '*': true, // keep all glyphs and just convert format\n    'flavor': 'woff2',\n  })\n\n  await fs.promises.writeFile('./font.woff2', outputFileBuffer)\n}\n\nmain()\n```\n\nExample of converting `ttf` to `woff2` and subseting with text and unicodes options:\n\n```javascript\nconst fs = require('node:fs')\nconst { subset } = require('@web-alchemy/fonttools')\n\nasync function main() {\n  const inputFileBuffer = await fs.promises.readFile('./font.ttf')\n\n  const outputFileBuffer = await subset(inputFileBuffer, {\n    'text': \"The text whose characters will be included in the font file\",\n    'unicodes': \"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD\",\n    'flavor': 'woff2',\n  })\n\n  await fs.promises.writeFile('./font.woff2', outputFileBuffer)\n}\n\nmain()\n```\n\nMethod `subset` takes same params as [original `pyftsubset` utility](https://fonttools.readthedocs.io/en/latest/subset/index.html)(without dashes `--`).\n\nExample of [customizing variable font's axes](https://fonttools.readthedocs.io/en/latest/varLib/instancer.html):\n\n```javascript\nconst fs = require('node:fs')\nconst { instantiateVariableFont } = require('@web-alchemy/fonttools')\n\nasync function main() {\n  const inputFileBuffer = await fs.promises.readFile('./src/font.woff2')\n\n  const outputFileBuffer = await instantiateVariableFont(inputFileBuffer, {\n    wght: [300, 500], // decrease `wght` axis range\n    wdth: null // delete `wdth` axis\n  })\n\n  await fs.promises.writeFile('dist/font.woff2', outputFileBuffer)\n}\n\nmain()\n```\n\nThis is port of [method `varLib.instancer.instantiateVariableFont`](https://fonttools.readthedocs.io/en/latest/varLib/instancer.html#fontTools.varLib.instancer.instantiateVariableFont).\n\nMethod `ttx` can convert binary font files (.otf, .ttf, etc) to the TTX XML format and convert them back to binary format.\n\nExample of converting binary files to xml:\n\n```javascript\nconst fs = require('node:fs');\nconst { ttx } = require('@web-alchemy/fonttools');\n\n(async () =\u003e {\n  const outputTtxBuffer = await ttx('./font.ttf'); // also accept `URL` and `Buffer`\n  await fs.promises.writeFile('./font.ttx', outputTtxBuffer);\n  \n  const outputOtxBuffer = await ttx('./font.otf');\n  await fs.promises.writeFile('./font.otx', outputOtxBuffer);\n})();\n```\n\nExample of converting xml files to binary files:\n\n```javascript\nconst fs = require('node:fs');\nconst { ttx } = require('@web-alchemy/fonttools');\n\n(async () =\u003e {\n  const ttfBuffer = await ttx('./font.ttx');\n  await fs.promises.writeFile('./font.ttf', ttfBuffer);\n  \n  const otfBuffer = await ttx('./font.otx');\n  await fs.promises.writeFile('./font.otf', otfBuffer);\n})();\n```\n\nExample of converting xml files to binary files with encoding to `woff2`:\n\n```javascript\nconst fs = require('node:fs');\nconst { ttx } = require('@web-alchemy/fonttools');\n\n(async () =\u003e {\n  const ttfBuffer = await ttx('./font.ttx', [\n    ['--flavor', 'woff2']\n  ]);\n  await fs.promises.writeFile('./font.woff2', ttfBuffer);\n  \n  const otfBuffer = await ttx('./font.otx', [\n    ['--flavor', 'woff2']\n  ]);\n  await fs.promises.writeFile('./font.woff2', otfBuffer);\n})();\n```\n\n## Limitations\n\n- Doesn't support [zopfli](https://pypi.org/project/zopfli/) package for better optimizing woff files.\n- In CLI all file paths should be relative to `cwd` (current working directory).\n\n## References\n\n- Python font tools. [Github](https://github.com/fonttools/fonttools), [Site](https://fonttools.readthedocs.io/en/latest/).\n- Pyodide. [Github](https://github.com/pyodide), [Site](https://pyodide.org).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweb-alchemy%2Ffonttools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweb-alchemy%2Ffonttools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweb-alchemy%2Ffonttools/lists"}