diff --git a/README.md b/README.md index 93fa3d10..a2c731b3 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,13 @@ Render every palette and layout combination configured in `render.json`: bun run generate ``` -The generated PNG assets are written to `bitmaps/`. +The generated PNG assets are written to `bitmaps/`. Rendering uses up +to four workers by default. Override the worker count when more CPU and memory +are available: + +```bash +BIBATA_GENERATE_JOBS=8 bun run generate +``` To change or add a color variant, add another entry to `render.json`. Each color mapping replaces the source SVG's base, outline, or activity color during diff --git a/bun.lock b/bun.lock index d541ff85..b29f5afa 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,10 @@ "dependencies": { "cbmp": "^1.1.1", }, + "devDependencies": { + "@types/bun": "^1.3.14", + "typescript": "^7.0.2", + }, }, }, "packages": { @@ -47,10 +51,52 @@ "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="], + "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + "@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="], "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "24.5.2" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], + + "@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="], + + "@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA=="], + + "@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ=="], + + "@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw=="], + + "@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ=="], + + "@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ=="], + + "@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ=="], + + "@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA=="], + + "@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA=="], + + "@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ=="], + + "@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw=="], + + "@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A=="], + + "@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA=="], + + "@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.2", "", { "os": "none", "cpu": "x64" }, "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA=="], + + "@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ=="], + + "@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg=="], + + "@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g=="], + + "@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ=="], + + "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -79,6 +125,8 @@ "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "cbmp": ["cbmp@1.1.1", "", { "dependencies": { "@resvg/resvg-js": "2.6.2", "chalk": "5.6.2", "commander": "11.1.0", "glob": "10.4.5", "ora": "7.0.1", "pixelmatch": "5.3.0", "pngjs": "7.0.0", "puppeteer": "21.11.0" }, "bin": { "cbmp": "bin/cbmp.js" } }, "sha512-G2CstvZ8bgX85hzA9nDhKRglGyjZWIp8V01SXtQ6f4NNFe7Xy+lL+z7MrtWCnpKPbBUtr2VJWwZRJaexJDm5kA=="], @@ -291,6 +339,8 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], + "unbzip2-stream": ["unbzip2-stream@1.4.3", "", { "dependencies": { "buffer": "5.7.1", "through": "2.3.8" } }, "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg=="], "undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="], diff --git a/package.json b/package.json index f7471c88..c2e69903 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,16 @@ "scripts": { "build:hyprcursor": "bash scripts/build-hyprcursor.sh", "clean": "rm -rf bin bitmaps dist hyprcursor-build", - "generate": "cbmp render.json", - "link": "python3 scripts/link-svg-layouts.py" + "generate": "bun scripts/generate-bitmaps.ts", + "link": "python3 scripts/link-svg-layouts.py", + "typecheck": "tsc --noEmit" }, "dependencies": { "cbmp": "^1.1.1" }, + "devDependencies": { + "@types/bun": "^1.3.14", + "typescript": "^7.0.2" + }, "packageManager": "bun@1.3.13" } diff --git a/render.json b/render.json index 9feda1da..d68d6ec8 100644 --- a/render.json +++ b/render.json @@ -4,15 +4,15 @@ "out": "bitmaps/Bibata-Modern-Classic", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#000000" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#FFFFFF" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#000000" } ] @@ -22,15 +22,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#26233a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#191724" } ] @@ -40,15 +40,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine-Moon", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#393552" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#232136" } ] @@ -58,15 +58,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine-Dawn", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#f2e9e1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#464261" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#faf4ed" } ] @@ -76,15 +76,15 @@ "out": "bitmaps/Bibata-Modern-Gruvbox-Dark", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#504945" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#fbf1c7" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#282828" } ] @@ -94,15 +94,15 @@ "out": "bitmaps/Bibata-Modern-Gruvbox-Light", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#d5c4a1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#282828" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#fbf1c7" } ] @@ -112,15 +112,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Latte", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#eff1f5" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#4c4f69" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#e6e9ef" } ] @@ -130,15 +130,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Frappe", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#303446" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#c6d0f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#292c3c" } ] @@ -148,15 +148,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Macchiato", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#24273a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cad3f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#1e2030" } ] @@ -166,15 +166,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Mocha", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#1e1e2e" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cdd6f4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#181825" } ] @@ -184,15 +184,15 @@ "out": "bitmaps/Bibata-Modern-Classic-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#000000" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#FFFFFF" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#000000" } ] @@ -202,15 +202,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#26233a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#191724" } ] @@ -220,15 +220,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine-Moon-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#393552" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#232136" } ] @@ -238,15 +238,15 @@ "out": "bitmaps/Bibata-Modern-Rosepine-Dawn-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#f2e9e1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#464261" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#faf4ed" } ] @@ -256,15 +256,15 @@ "out": "bitmaps/Bibata-Modern-Gruvbox-Dark-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#504945" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#fbf1c7" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#282828" } ] @@ -274,15 +274,15 @@ "out": "bitmaps/Bibata-Modern-Gruvbox-Light-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#d5c4a1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#282828" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#fbf1c7" } ] @@ -292,15 +292,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Latte-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#eff1f5" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#4c4f69" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#e6e9ef" } ] @@ -310,15 +310,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Frappe-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#303446" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#c6d0f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#292c3c" } ] @@ -328,15 +328,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Macchiato-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#24273a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cad3f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#1e2030" } ] @@ -346,15 +346,15 @@ "out": "bitmaps/Bibata-Modern-Catppuccin-Mocha-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#1e1e2e" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cdd6f4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#181825" } ] @@ -364,15 +364,15 @@ "out": "bitmaps/Bibata-Original-Classic", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#000000" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#FFFFFF" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#000000" } ] @@ -382,15 +382,15 @@ "out": "bitmaps/Bibata-Original-Rosepine", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#26233a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#191724" } ] @@ -400,15 +400,15 @@ "out": "bitmaps/Bibata-Original-Rosepine-Moon", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#393552" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#232136" } ] @@ -418,15 +418,15 @@ "out": "bitmaps/Bibata-Original-Rosepine-Dawn", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#f2e9e1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#464261" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#faf4ed" } ] @@ -436,15 +436,15 @@ "out": "bitmaps/Bibata-Original-Gruvbox-Dark", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#504945" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#fbf1c7" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#282828" } ] @@ -454,15 +454,15 @@ "out": "bitmaps/Bibata-Original-Gruvbox-Light", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#d5c4a1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#282828" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#fbf1c7" } ] @@ -472,15 +472,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Latte", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#eff1f5" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#4c4f69" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#e6e9ef" } ] @@ -490,15 +490,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Frappe", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#303446" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#c6d0f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#292c3c" } ] @@ -508,15 +508,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Macchiato", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#24273a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cad3f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#1e2030" } ] @@ -526,15 +526,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Mocha", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#1e1e2e" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cdd6f4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#181825" } ] @@ -544,15 +544,15 @@ "out": "bitmaps/Bibata-Original-Classic-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#000000" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#FFFFFF" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#000000" } ] @@ -562,15 +562,15 @@ "out": "bitmaps/Bibata-Original-Rosepine-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#26233a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#191724" } ] @@ -580,15 +580,15 @@ "out": "bitmaps/Bibata-Original-Rosepine-Moon-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#393552" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#e0def4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#232136" } ] @@ -598,15 +598,15 @@ "out": "bitmaps/Bibata-Original-Rosepine-Dawn-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#f2e9e1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#464261" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#faf4ed" } ] @@ -616,15 +616,15 @@ "out": "bitmaps/Bibata-Original-Gruvbox-Dark-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#504945" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#fbf1c7" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#282828" } ] @@ -634,15 +634,15 @@ "out": "bitmaps/Bibata-Original-Gruvbox-Light-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#d5c4a1" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#282828" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#fbf1c7" } ] @@ -652,15 +652,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Latte-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#eff1f5" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#4c4f69" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#e6e9ef" } ] @@ -670,15 +670,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Frappe-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#303446" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#c6d0f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#292c3c" } ] @@ -688,15 +688,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Macchiato-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#24273a" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cad3f5" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#1e2030" } ] @@ -706,15 +706,15 @@ "out": "bitmaps/Bibata-Original-Catppuccin-Mocha-Right", "colors": [ { - "match": "#00FF00", + "match": "#0f0", "replace": "#1e1e2e" }, { - "match": "#0000FF", + "match": "#00f", "replace": "#cdd6f4" }, { - "match": "#FF0000", + "match": "#fe0000", "replace": "#181825" } ] diff --git a/scripts/generate-bitmaps.ts b/scripts/generate-bitmaps.ts new file mode 100644 index 00000000..9ddb922a --- /dev/null +++ b/scripts/generate-bitmaps.ts @@ -0,0 +1,110 @@ +#!/usr/bin/env bun + +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { availableParallelism, tmpdir } from "node:os"; +import path from "node:path"; + +type ColorReplacement = { + match: string; + replace: string; +}; + +type RenderOptions = { + dir: string; + out: string; + colors?: ColorReplacement[]; + fps?: number; + use?: "default" | "puppeteer"; +}; + +type RenderConfig = Record; + +type WorkerResult = { + index: number; + exitCode: number; + stderr: string; +}; + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function isColorReplacement(value: unknown): value is ColorReplacement { + return isRecord(value) && typeof value.match === "string" && typeof value.replace === "string"; +} + +function isRenderOptions(value: unknown): value is RenderOptions { + return ( + isRecord(value) && + typeof value.dir === "string" && + typeof value.out === "string" && + (value.colors === undefined || + (Array.isArray(value.colors) && value.colors.every(isColorReplacement))) && + (value.fps === undefined || typeof value.fps === "number") && + (value.use === undefined || value.use === "default" || value.use === "puppeteer") + ); +} + +function isRenderConfig(value: unknown): value is RenderConfig { + return isRecord(value) && Object.values(value).every(isRenderOptions); +} + +const configPath = process.argv[2] ?? "render.json"; +const config: unknown = await Bun.file(configPath).json(); + +if (!isRenderConfig(config)) { + throw new TypeError(`Invalid render configuration in ${configPath}`); +} + +const entries = Object.entries(config); + +if (entries.length === 0) { + throw new Error(`No render configurations found in ${configPath}`); +} + +const requestedJobs = Number.parseInt(process.env.BIBATA_GENERATE_JOBS ?? "", 10); +const defaultJobs = Math.min(4, availableParallelism()); +const jobCount = Math.min( + entries.length, + Number.isInteger(requestedJobs) && requestedJobs > 0 ? requestedJobs : defaultJobs, +); +const entriesPerJob = Math.ceil(entries.length / jobCount); +const shards = Array.from({ length: jobCount }, (_, index) => + entries.slice(index * entriesPerJob, (index + 1) * entriesPerJob), +).filter((shard) => shard.length > 0); + +const temporaryDirectory = await mkdtemp(path.join(tmpdir(), "bibata-render-")); +const cbmpPath = path.resolve(import.meta.dir, "../node_modules/cbmp/bin/cbmp.js"); + +console.log(`Rendering ${entries.length} configurations with ${shards.length} workers`); + +try { + const results = await Promise.all( + shards.map(async (shard, index) => { + const shardPath = path.join(temporaryDirectory, `${index}.json`); + await writeFile(shardPath, JSON.stringify(Object.fromEntries(shard))); + + const child = Bun.spawn([process.execPath, cbmpPath, shardPath], { + cwd: process.cwd(), + stdout: "ignore", + stderr: "pipe", + }); + const stderr = new Response(child.stderr).text(); + const exitCode = await child.exited; + return { index, exitCode, stderr: await stderr } satisfies WorkerResult; + }), + ); + + const failures = results.filter(({ exitCode }) => exitCode !== 0); + if (failures.length > 0) { + for (const { index, exitCode, stderr } of failures) { + console.error(`Worker ${index + 1} failed with exit code ${exitCode}`); + console.error(stderr.trim()); + } + process.exitCode = 1; + } else { + console.log("Bitmap generation completed"); + } +} finally { + await rm(temporaryDirectory, { recursive: true, force: true }); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..399ff8cd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "allowImportingTsExtensions": true, + "lib": ["ESNext"], + "module": "Preserve", + "moduleDetection": "force", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noUncheckedIndexedAccess": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "types": ["bun"], + "verbatimModuleSyntax": true + }, + "include": ["scripts/**/*.ts"] +}