From 2a8a27644557562624f8a80bc06f1a3ff46cf6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?George=20P=C3=AErlea?= Date: Wed, 21 Jan 2026 16:54:49 +0800 Subject: [PATCH] fix: use a subset of the font glyphs; fixes #12 --- package-lock.json | 627 ++++++++++++++++++++++++++++ package.json | 5 +- scripts/README.md | 21 + scripts/emoji-glyphs.json | 5 + scripts/subset-font.ts | 47 +++ src/fonts/NotoColorEmoji-Subset.ttf | Bin 0 -> 6876 bytes src/leanmonaco.ts | 2 +- 7 files changed, 705 insertions(+), 2 deletions(-) create mode 100644 scripts/README.md create mode 100644 scripts/emoji-glyphs.json create mode 100644 scripts/subset-font.ts create mode 100644 src/fonts/NotoColorEmoji-Subset.ttf diff --git a/package-lock.json b/package-lock.json index bca53d9..7ab9cb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,9 @@ "cypress": "^15.8.2", "cypress-iframe": "^1.0.1", "nodemon": "^3.1.4", + "subset-font": "^2.4.0", "ts-loader": "^9.5.1", + "tsx": "^4.21.0", "typescript": "^5.4.5", "wait-on": "^9.0.3", "webpack": "^5.93.0", @@ -378,6 +380,448 @@ "node": ">=14.17.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@hapi/address": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", @@ -1228,6 +1672,13 @@ ], "license": "MIT" }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -2183,6 +2634,48 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2460,6 +2953,17 @@ } } }, + "node_modules/fontverter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fontverter/-/fontverter-2.0.0.tgz", + "integrity": "sha512-DFVX5hvXuhi1Jven1tbpebYTCT9XYnvx6/Z+HFUPb7ZRMCW+pj2clU9VMhoTPgWKPhAs7JJDSk3CW1jNUvKCZQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "wawoff2": "^2.0.0", + "woff2sfnt-sfnt2woff": "^1.0.0" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2600,6 +3104,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2704,6 +3221,13 @@ "dev": true, "license": "ISC" }, + "node_modules/harfbuzzjs": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/harfbuzzjs/-/harfbuzzjs-0.4.15.tgz", + "integrity": "sha512-p1edvnlc+vpRe2kz7OKzcscf0gyFiDZpco+miDxAiiZ67cu1oNlbuOkmP/A/i1l/w938VrkF2FdZ8scNcnkPrQ==", + "dev": true, + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3821,6 +4345,13 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4127,6 +4658,16 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -4490,6 +5031,35 @@ "node": ">=6" } }, + "node_modules/subset-font": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/subset-font/-/subset-font-2.4.0.tgz", + "integrity": "sha512-DA/45nIj4NiseVdfHxVdVGL7hvNo3Ol6HjEm3KSYtPyDcsr6jh8Q37vSgz+A722wMfUd6nL8kgsi7uGv9DExXQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fontverter": "^2.0.0", + "harfbuzzjs": "^0.4.0", + "lodash": "^4.17.21", + "p-limit": "^3.1.0" + } + }, + "node_modules/subset-font/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4831,6 +5401,26 @@ "license": "0BSD", "peer": true }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5129,6 +5719,20 @@ "node": ">=10.13.0" } }, + "node_modules/wawoff2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wawoff2/-/wawoff2-2.0.1.tgz", + "integrity": "sha512-r0CEmvpH63r4T15ebFqeOjGqU4+EgTx4I510NtK35EMciSdcTxCw3Byy3JnBonz7iyIFZ0AbVo0bbFpEVuhCYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "woff2_compress.js": "bin/woff2_compress.js", + "woff2_decompress.js": "bin/woff2_decompress.js" + } + }, "node_modules/webpack": { "version": "5.104.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", @@ -5288,6 +5892,16 @@ "dev": true, "license": "MIT" }, + "node_modules/woff2sfnt-sfnt2woff": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/woff2sfnt-sfnt2woff/-/woff2sfnt-sfnt2woff-1.0.0.tgz", + "integrity": "sha512-edK4COc1c1EpRfMqCZO1xJOvdUtM5dbVb9iz97rScvnTevqEB3GllnLWCmMVp1MfQBdF1DFg/11I0rSyAdS4qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^1.0.7" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5373,6 +5987,19 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", diff --git a/package.json b/package.json index 0d124e0..66d94fc 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "test:bare": "wait-on http://localhost:5173 && cypress run", "test": "npm run demo:setup && concurrently --hide 0 --kill-others \"npm start\" \"npm run test:bare\" -n server,cypress -s command-cypress", "test:windows:bare": "wait-on http://localhost:5173 && CYPRESS_USER_AGENT_OS=\"Windows NT 10.0; Win64; x64\" cypress run --browser chromium", - "test:windows": "npm run demo:setup && concurrently --hide 0 --kill-others \"npm start\" \"npm run test:windows:bare\" -n server,cypress -s command-cypress" + "test:windows": "npm run demo:setup && concurrently --hide 0 --kill-others \"npm start\" \"npm run test:windows:bare\" -n server,cypress -s command-cypress", + "font:subset": "npx tsx scripts/subset-font.ts" }, "dependencies": { "@leanprover/infoview": "~0.8.5", @@ -66,7 +67,9 @@ "cypress": "^15.8.2", "cypress-iframe": "^1.0.1", "nodemon": "^3.1.4", + "subset-font": "^2.4.0", "ts-loader": "^9.5.1", + "tsx": "^4.21.0", "typescript": "^5.4.5", "wait-on": "^9.0.3", "webpack": "^5.93.0", diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..f3c9070 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,21 @@ +# Font Subsetting Script + +This script creates a subset of the NotoColorEmoji font containing only the glyphs used by lean4monaco. + +## Usage + +```bash +npm run font:subset +``` + +This reads the glyph list from `emoji-glyphs.json`, subsets the original 23MB font, and outputs a ~7KB font to `src/fonts/NotoColorEmoji-Subset.ttf`. + +## Adding New Glyphs + +1. Edit `emoji-glyphs.json` and add the emoji character to the `glyphs` array +2. Run `npm run font:subset` +3. Commit the updated `src/fonts/NotoColorEmoji-Subset.ttf` + +## Requirements + +The original font file must exist at `src/fonts/NotoColorEmoji-Regular.ttf`. If missing, download it from [Google Fonts](https://fonts.google.com/noto/specimen/Noto+Color+Emoji). diff --git a/scripts/emoji-glyphs.json b/scripts/emoji-glyphs.json new file mode 100644 index 0000000..eaa082d --- /dev/null +++ b/scripts/emoji-glyphs.json @@ -0,0 +1,5 @@ +{ + "glyphs": ["🎉", "❌", "✅", "💥", "▼", "▶", "🎭", "✝", "⏳"], + "inputFont": "../src/fonts/NotoColorEmoji-Regular.ttf", + "outputFont": "../src/fonts/NotoColorEmoji-Subset.ttf" +} diff --git a/scripts/subset-font.ts b/scripts/subset-font.ts new file mode 100644 index 0000000..a40384e --- /dev/null +++ b/scripts/subset-font.ts @@ -0,0 +1,47 @@ +import subsetFont from 'subset-font'; +import { readFile, writeFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +interface GlyphConfig { + glyphs: string[]; + inputFont: string; + outputFont: string; +} + +async function main(): Promise { + const configPath = resolve(__dirname, 'emoji-glyphs.json'); + const config: GlyphConfig = JSON.parse(await readFile(configPath, 'utf-8')); + + const inputPath = resolve(__dirname, config.inputFont); + const outputPath = resolve(__dirname, config.outputFont); + + console.log(`Loading font from: ${inputPath}`); + const inputBuffer = await readFile(inputPath); + + const glyphText = config.glyphs.join(''); + console.log(`Subsetting font with ${config.glyphs.length} glyphs: ${glyphText}`); + + const subsetBuffer = await subsetFont(inputBuffer, glyphText, { + targetFormat: 'truetype', + }); + + await writeFile(outputPath, subsetBuffer); + + const originalSize = inputBuffer.length; + const subsetSize = subsetBuffer.length; + const reduction = ((1 - subsetSize / originalSize) * 100).toFixed(1); + + console.log(`\nFont subset created successfully!`); + console.log(` Original: ${(originalSize / 1024 / 1024).toFixed(2)} MB`); + console.log(` Subset: ${(subsetSize / 1024).toFixed(2)} KB`); + console.log(` Reduction: ${reduction}%`); + console.log(`\nOutput: ${outputPath}`); +} + +main().catch((error) => { + console.error('Error creating font subset:', error); + process.exit(1); +}); diff --git a/src/fonts/NotoColorEmoji-Subset.ttf b/src/fonts/NotoColorEmoji-Subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ad0a1c6c92e97285f47e831f853c7bd40ca7f996 GIT binary patch literal 6876 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 UccBoNZlpz2(7Iu|K7`Q!0Q+<~oB#j- literal 0 HcmV?d00001 diff --git a/src/leanmonaco.ts b/src/leanmonaco.ts index 4a35337..1a004e8 100644 --- a/src/leanmonaco.ts +++ b/src/leanmonaco.ts @@ -189,7 +189,7 @@ export type LeanMonacoOptions = { ), new FontFace( "Noto Color Emoji", - `url(${new URL("./fonts/NotoColorEmoji-Regular.ttf", import.meta.url)})`, + `url(${new URL("./fonts/NotoColorEmoji-Subset.ttf", import.meta.url)})`, ), // new FontFace( // "LeanWeb",