Files for my website bwc9876.dev

Add Critters

bwc9876.dev cc0e1d95 97b96ac5

verified
+422 -60
+3 -1
astro.config.mjs
··· 3 3 import sitemap from "@astrojs/sitemap"; 4 4 import icon from "astro-icon"; 5 5 6 + import critters from "astro-critters"; 7 + 6 8 // https://astro.build/config 7 9 export default defineConfig({ 8 10 site: "https://bwc9876.dev", 9 11 compressHTML: true, 10 - integrations: [mdx(), icon(), sitemap()], 12 + integrations: [mdx(), icon(), sitemap(), critters()], 11 13 vite: { 12 14 css: { 13 15 transformer: "lightningcss",
+347
package-lock.json
··· 16 16 "@iconify-json/mdi": "^1.2.1", 17 17 "@iconify-json/simple-icons": "^1.2.54", 18 18 "astro": "^5.14.1", 19 + "astro-critters": "^2.2.1", 19 20 "astro-icon": "^1.1.4", 20 21 "cowsay": "^1.6.0", 21 22 "lightningcss": "^1.30.2", ··· 1250 1251 "url": "https://opencollective.com/unified" 1251 1252 } 1252 1253 }, 1254 + "node_modules/@nodelib/fs.scandir": { 1255 + "version": "2.1.5", 1256 + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 1257 + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 1258 + "license": "MIT", 1259 + "dependencies": { 1260 + "@nodelib/fs.stat": "2.0.5", 1261 + "run-parallel": "^1.1.9" 1262 + }, 1263 + "engines": { 1264 + "node": ">= 8" 1265 + } 1266 + }, 1267 + "node_modules/@nodelib/fs.stat": { 1268 + "version": "2.0.5", 1269 + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 1270 + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 1271 + "license": "MIT", 1272 + "engines": { 1273 + "node": ">= 8" 1274 + } 1275 + }, 1276 + "node_modules/@nodelib/fs.walk": { 1277 + "version": "1.2.8", 1278 + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 1279 + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 1280 + "license": "MIT", 1281 + "dependencies": { 1282 + "@nodelib/fs.scandir": "2.1.5", 1283 + "fastq": "^1.6.0" 1284 + }, 1285 + "engines": { 1286 + "node": ">= 8" 1287 + } 1288 + }, 1253 1289 "node_modules/@oslojs/encoding": { 1254 1290 "version": "1.1.0", 1255 1291 "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", 1256 1292 "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", 1257 1293 "license": "MIT" 1258 1294 }, 1295 + "node_modules/@playform/pipe": { 1296 + "version": "0.1.2", 1297 + "resolved": "https://registry.npmjs.org/@playform/pipe/-/pipe-0.1.2.tgz", 1298 + "integrity": "sha512-fMZyPQXweet44Apz5F+9kAjrmy9RbMX7ajZJmw40lWarWI380D/b0bnJOvOmmZztx3pJZxbBMht2QLd8AG4V2w==", 1299 + "license": "SEE LICENSE IN LICENSE", 1300 + "dependencies": { 1301 + "@types/node": "22.10.5", 1302 + "deepmerge-ts": "7.1.3", 1303 + "fast-glob": "3.3.3" 1304 + } 1305 + }, 1306 + "node_modules/@playform/pipe/node_modules/@types/node": { 1307 + "version": "22.10.5", 1308 + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", 1309 + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", 1310 + "license": "MIT", 1311 + "dependencies": { 1312 + "undici-types": "~6.20.0" 1313 + } 1314 + }, 1315 + "node_modules/@playform/pipe/node_modules/undici-types": { 1316 + "version": "6.20.0", 1317 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 1318 + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", 1319 + "license": "MIT" 1320 + }, 1259 1321 "node_modules/@rollup/pluginutils": { 1260 1322 "version": "5.3.0", 1261 1323 "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", ··· 2057 2119 "sharp": "^0.34.0" 2058 2120 } 2059 2121 }, 2122 + "node_modules/astro-critters": { 2123 + "version": "2.2.1", 2124 + "resolved": "https://registry.npmjs.org/astro-critters/-/astro-critters-2.2.1.tgz", 2125 + "integrity": "sha512-C9wYbSWEqvBZ65/tarpR56GjuxH7psILuzwtV3MCHWfT5rfI3ESo8DfxQab1bTAjinBDla0ohAtM7GdXo/OJKQ==", 2126 + "license": "SEE LICENSE IN LICENSE", 2127 + "dependencies": { 2128 + "@playform/pipe": "0.1.2", 2129 + "astro": "*", 2130 + "critters": "0.0.25", 2131 + "deepmerge-ts": "7.1.3" 2132 + } 2133 + }, 2060 2134 "node_modules/astro-icon": { 2061 2135 "version": "1.1.5", 2062 2136 "resolved": "https://registry.npmjs.org/astro-icon/-/astro-icon-1.1.5.tgz", ··· 2582 2656 "url": "https://github.com/sponsors/sindresorhus" 2583 2657 } 2584 2658 }, 2659 + "node_modules/braces": { 2660 + "version": "3.0.3", 2661 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 2662 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 2663 + "license": "MIT", 2664 + "dependencies": { 2665 + "fill-range": "^7.1.1" 2666 + }, 2667 + "engines": { 2668 + "node": ">=8" 2669 + } 2670 + }, 2585 2671 "node_modules/brotli": { 2586 2672 "version": "1.3.3", 2587 2673 "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", ··· 3069 3155 "node": ">=4" 3070 3156 } 3071 3157 }, 3158 + "node_modules/critters": { 3159 + "version": "0.0.25", 3160 + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.25.tgz", 3161 + "integrity": "sha512-ROF/tjJyyRdM8/6W0VqoN5Ql05xAGnkf5b7f3sTEl1bI5jTQQf8O918RD/V9tEb9pRY/TKcvJekDbJtniHyPtQ==", 3162 + "deprecated": "Ownership of Critters has moved to the Nuxt team, who will be maintaining the project going forward. If you'd like to keep using Critters, please switch to the actively-maintained fork at https://github.com/danielroe/beasties", 3163 + "license": "Apache-2.0", 3164 + "dependencies": { 3165 + "chalk": "^4.1.0", 3166 + "css-select": "^5.1.0", 3167 + "dom-serializer": "^2.0.0", 3168 + "domhandler": "^5.0.2", 3169 + "htmlparser2": "^8.0.2", 3170 + "postcss": "^8.4.23", 3171 + "postcss-media-query-parser": "^0.2.3" 3172 + } 3173 + }, 3174 + "node_modules/critters/node_modules/ansi-styles": { 3175 + "version": "4.3.0", 3176 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 3177 + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 3178 + "license": "MIT", 3179 + "dependencies": { 3180 + "color-convert": "^2.0.1" 3181 + }, 3182 + "engines": { 3183 + "node": ">=8" 3184 + }, 3185 + "funding": { 3186 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 3187 + } 3188 + }, 3189 + "node_modules/critters/node_modules/chalk": { 3190 + "version": "4.1.2", 3191 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 3192 + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 3193 + "license": "MIT", 3194 + "dependencies": { 3195 + "ansi-styles": "^4.1.0", 3196 + "supports-color": "^7.1.0" 3197 + }, 3198 + "engines": { 3199 + "node": ">=10" 3200 + }, 3201 + "funding": { 3202 + "url": "https://github.com/chalk/chalk?sponsor=1" 3203 + } 3204 + }, 3072 3205 "node_modules/cross-fetch": { 3073 3206 "version": "3.2.0", 3074 3207 "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", ··· 3219 3352 "license": "MIT", 3220 3353 "engines": { 3221 3354 "node": ">=0.10.0" 3355 + } 3356 + }, 3357 + "node_modules/deepmerge-ts": { 3358 + "version": "7.1.3", 3359 + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.3.tgz", 3360 + "integrity": "sha512-qCSH6I0INPxd9Y1VtAiLpnYvz5O//6rCfJXKk0z66Up9/VOSr+1yS8XSKA5IWRxjocFGlzPyaZYe+jxq7OOLtQ==", 3361 + "license": "BSD-3-Clause", 3362 + "engines": { 3363 + "node": ">=16.0.0" 3222 3364 } 3223 3365 }, 3224 3366 "node_modules/defu": { ··· 3701 3843 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 3702 3844 "license": "MIT" 3703 3845 }, 3846 + "node_modules/fast-glob": { 3847 + "version": "3.3.3", 3848 + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 3849 + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 3850 + "license": "MIT", 3851 + "dependencies": { 3852 + "@nodelib/fs.stat": "^2.0.2", 3853 + "@nodelib/fs.walk": "^1.2.3", 3854 + "glob-parent": "^5.1.2", 3855 + "merge2": "^1.3.0", 3856 + "micromatch": "^4.0.8" 3857 + }, 3858 + "engines": { 3859 + "node": ">=8.6.0" 3860 + } 3861 + }, 3704 3862 "node_modules/fast-xml-parser": { 3705 3863 "version": "5.3.0", 3706 3864 "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.0.tgz", ··· 3719 3877 "fxparser": "src/cli/cli.js" 3720 3878 } 3721 3879 }, 3880 + "node_modules/fastq": { 3881 + "version": "1.19.1", 3882 + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", 3883 + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", 3884 + "license": "ISC", 3885 + "dependencies": { 3886 + "reusify": "^1.0.4" 3887 + } 3888 + }, 3722 3889 "node_modules/fd-slicer": { 3723 3890 "version": "1.1.0", 3724 3891 "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", ··· 3745 3912 } 3746 3913 } 3747 3914 }, 3915 + "node_modules/fill-range": { 3916 + "version": "7.1.1", 3917 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 3918 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 3919 + "license": "MIT", 3920 + "dependencies": { 3921 + "to-regex-range": "^5.0.1" 3922 + }, 3923 + "engines": { 3924 + "node": ">=8" 3925 + } 3926 + }, 3748 3927 "node_modules/find-up": { 3749 3928 "version": "4.1.0", 3750 3929 "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", ··· 3968 4147 "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", 3969 4148 "license": "ISC" 3970 4149 }, 4150 + "node_modules/glob-parent": { 4151 + "version": "5.1.2", 4152 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 4153 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 4154 + "license": "ISC", 4155 + "dependencies": { 4156 + "is-glob": "^4.0.1" 4157 + }, 4158 + "engines": { 4159 + "node": ">= 6" 4160 + } 4161 + }, 3971 4162 "node_modules/globals": { 3972 4163 "version": "15.15.0", 3973 4164 "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", ··· 4007 4198 "radix3": "^1.1.2", 4008 4199 "ufo": "^1.6.1", 4009 4200 "uncrypto": "^0.1.3" 4201 + } 4202 + }, 4203 + "node_modules/has-flag": { 4204 + "version": "4.0.0", 4205 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 4206 + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 4207 + "license": "MIT", 4208 + "engines": { 4209 + "node": ">=8" 4010 4210 } 4011 4211 }, 4012 4212 "node_modules/has-symbols": { ··· 4423 4623 "url": "https://github.com/sponsors/sindresorhus" 4424 4624 } 4425 4625 }, 4626 + "node_modules/is-extglob": { 4627 + "version": "2.1.1", 4628 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 4629 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 4630 + "license": "MIT", 4631 + "engines": { 4632 + "node": ">=0.10.0" 4633 + } 4634 + }, 4426 4635 "node_modules/is-fullwidth-code-point": { 4427 4636 "version": "3.0.0", 4428 4637 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", ··· 4432 4641 "node": ">=8" 4433 4642 } 4434 4643 }, 4644 + "node_modules/is-glob": { 4645 + "version": "4.0.3", 4646 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 4647 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 4648 + "license": "MIT", 4649 + "dependencies": { 4650 + "is-extglob": "^2.1.1" 4651 + }, 4652 + "engines": { 4653 + "node": ">=0.10.0" 4654 + } 4655 + }, 4435 4656 "node_modules/is-hexadecimal": { 4436 4657 "version": "2.0.1", 4437 4658 "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", ··· 4460 4681 "url": "https://github.com/sponsors/sindresorhus" 4461 4682 } 4462 4683 }, 4684 + "node_modules/is-number": { 4685 + "version": "7.0.0", 4686 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 4687 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 4688 + "license": "MIT", 4689 + "engines": { 4690 + "node": ">=0.12.0" 4691 + } 4692 + }, 4463 4693 "node_modules/is-plain-obj": { 4464 4694 "version": "4.1.0", 4465 4695 "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", ··· 5207 5437 "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", 5208 5438 "license": "MIT" 5209 5439 }, 5440 + "node_modules/merge2": { 5441 + "version": "1.4.1", 5442 + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 5443 + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 5444 + "license": "MIT", 5445 + "engines": { 5446 + "node": ">= 8" 5447 + } 5448 + }, 5210 5449 "node_modules/micromark": { 5211 5450 "version": "4.0.2", 5212 5451 "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", ··· 5924 6163 ], 5925 6164 "license": "MIT" 5926 6165 }, 6166 + "node_modules/micromatch": { 6167 + "version": "4.0.8", 6168 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 6169 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 6170 + "license": "MIT", 6171 + "dependencies": { 6172 + "braces": "^3.0.3", 6173 + "picomatch": "^2.3.1" 6174 + }, 6175 + "engines": { 6176 + "node": ">=8.6" 6177 + } 6178 + }, 6179 + "node_modules/micromatch/node_modules/picomatch": { 6180 + "version": "2.3.1", 6181 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 6182 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 6183 + "license": "MIT", 6184 + "engines": { 6185 + "node": ">=8.6" 6186 + }, 6187 + "funding": { 6188 + "url": "https://github.com/sponsors/jonschlinkert" 6189 + } 6190 + }, 5927 6191 "node_modules/mime-db": { 5928 6192 "version": "1.52.0", 5929 6193 "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", ··· 6433 6697 "node": "^10 || ^12 || >=14" 6434 6698 } 6435 6699 }, 6700 + "node_modules/postcss-media-query-parser": { 6701 + "version": "0.2.3", 6702 + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", 6703 + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", 6704 + "license": "MIT" 6705 + }, 6436 6706 "node_modules/prettier": { 6437 6707 "version": "3.6.2", 6438 6708 "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", ··· 6546 6816 ], 6547 6817 "license": "MIT" 6548 6818 }, 6819 + "node_modules/queue-microtask": { 6820 + "version": "1.2.3", 6821 + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 6822 + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 6823 + "funding": [ 6824 + { 6825 + "type": "github", 6826 + "url": "https://github.com/sponsors/feross" 6827 + }, 6828 + { 6829 + "type": "patreon", 6830 + "url": "https://www.patreon.com/feross" 6831 + }, 6832 + { 6833 + "type": "consulting", 6834 + "url": "https://feross.org/support" 6835 + } 6836 + ], 6837 + "license": "MIT" 6838 + }, 6549 6839 "node_modules/radix3": { 6550 6840 "version": "1.1.2", 6551 6841 "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", ··· 6909 7199 "url": "https://opencollective.com/unified" 6910 7200 } 6911 7201 }, 7202 + "node_modules/reusify": { 7203 + "version": "1.1.0", 7204 + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", 7205 + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", 7206 + "license": "MIT", 7207 + "engines": { 7208 + "iojs": ">=1.0.0", 7209 + "node": ">=0.10.0" 7210 + } 7211 + }, 6912 7212 "node_modules/rollup": { 6913 7213 "version": "4.52.4", 6914 7214 "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", ··· 6950 7250 "fsevents": "~2.3.2" 6951 7251 } 6952 7252 }, 7253 + "node_modules/run-parallel": { 7254 + "version": "1.2.0", 7255 + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 7256 + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 7257 + "funding": [ 7258 + { 7259 + "type": "github", 7260 + "url": "https://github.com/sponsors/feross" 7261 + }, 7262 + { 7263 + "type": "patreon", 7264 + "url": "https://www.patreon.com/feross" 7265 + }, 7266 + { 7267 + "type": "consulting", 7268 + "url": "https://feross.org/support" 7269 + } 7270 + ], 7271 + "license": "MIT", 7272 + "dependencies": { 7273 + "queue-microtask": "^1.2.2" 7274 + } 7275 + }, 6953 7276 "node_modules/s.color": { 6954 7277 "version": "0.0.15", 6955 7278 "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", ··· 7269 7592 "s.color": "0.0.15" 7270 7593 } 7271 7594 }, 7595 + "node_modules/supports-color": { 7596 + "version": "7.2.0", 7597 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 7598 + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 7599 + "license": "MIT", 7600 + "dependencies": { 7601 + "has-flag": "^4.0.0" 7602 + }, 7603 + "engines": { 7604 + "node": ">=8" 7605 + } 7606 + }, 7272 7607 "node_modules/svgo": { 7273 7608 "version": "3.3.2", 7274 7609 "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", ··· 7346 7681 }, 7347 7682 "funding": { 7348 7683 "url": "https://github.com/sponsors/SuperchupuDev" 7684 + } 7685 + }, 7686 + "node_modules/to-regex-range": { 7687 + "version": "5.0.1", 7688 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 7689 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 7690 + "license": "MIT", 7691 + "dependencies": { 7692 + "is-number": "^7.0.0" 7693 + }, 7694 + "engines": { 7695 + "node": ">=8.0" 7349 7696 } 7350 7697 }, 7351 7698 "node_modules/tr46": {
+1
package.json
··· 21 21 "@iconify-json/mdi": "^1.2.1", 22 22 "@iconify-json/simple-icons": "^1.2.54", 23 23 "astro": "^5.14.1", 24 + "astro-critters": "^2.2.1", 24 25 "astro-icon": "^1.1.4", 25 26 "cowsay": "^1.6.0", 26 27 "lightningcss": "^1.30.2",
+71 -59
src/content/posts/wip_screen_captures.md
··· 5 5 cowsay: A picture is worth a thousand words 6 6 --- 7 7 8 - I've recently been going down the path of madness known as customizing my desktop and 9 - I figured I'd share some neat scripts and setups I've done along the way. 8 + I've recently been going down the path of madness known as customizing my desktop and I figured I'd 9 + share some neat scripts and setups I've done along the way. 10 10 11 - Today I'll go into some scripts I've been working on to capture screen shots and recordings. 12 - They allow selecting regions of the screen and specific windows, and I also made it so you 13 - can edit them afterwards. 11 + Today I'll go into some scripts I've been working on to capture screen shots and recordings. They 12 + allow selecting regions of the screen and specific windows, and I also made it so you can edit them 13 + afterwards. 14 14 15 15 ## Background 16 16 17 17 My entire system and home folder is managed by [NixOS](https://nixos.org), so I have a 18 - [configuration repository](https://github.com/Bwc9876/nix-conf) where all my scripts and configs 19 - can be found, I'll reference them throughout this post and provide links to the current version of each so you 20 - can see if I've updated them since this post. 18 + [configuration repository](https://github.com/Bwc9876/nix-conf) where all my scripts and configs can 19 + be found, I'll reference them throughout this post and provide links to the current version of each 20 + so you can see if I've updated them since this post. 21 21 22 - Currently I use [Hyprland](https://hyprland.org) as my window manager, and have been duct-taping components together to make my own little Desktop Environment around it. 22 + Currently I use [Hyprland](https://hyprland.org) as my window manager, and have been duct-taping 23 + components together to make my own little Desktop Environment around it. 23 24 24 - I also like to use [NuShell](https://nushell.sh) as my shell, and these scripts 25 - will be written in it. If you haven't checked out NuShell yet, I highly recommend it! 25 + I also like to use [NuShell](https://nushell.sh) as my shell, and these scripts will be written in 26 + it. If you haven't checked out NuShell yet, I highly recommend it! 26 27 27 28 ## Screenshots 28 29 29 - First is the script to take screenshots. This is a relatively simple script as it simply builds 30 - on top of [grimblast](https://github.com/hyprwm/contrib/tree/main/grimblast) with some nice QoL 30 + First is the script to take screenshots. This is a relatively simple script as it simply builds on 31 + top of [grimblast](https://github.com/hyprwm/contrib/tree/main/grimblast) with some nice QoL 31 32 features. 32 33 33 34 To install grimblast, all I have to do is add it to my `environment.systemPackages`: ··· 42 43 ]; 43 44 ``` 44 45 45 - Grimblast will automatically save screenshots to `XDG_SCREENSHOTS_DIR`, I 46 - manually set this in my _home manager_ config with: 46 + Grimblast will automatically save screenshots to `XDG_SCREENSHOTS_DIR`, I manually set this in my 47 + _home manager_ config with: 47 48 48 49 ```nix 49 50 xdg.userDirs.extraConfig.XDG_SCREENSHOTS_DIR = "${config.home.homeDirectory}/Pictures/Screenshots"; ··· 51 52 52 53 Grimblast will name the screenshots with the current date and time, which works for me. 53 54 54 - Now along to actually using grimblast, I'll create a new script and put in in my config somewhere, we'll 55 - call it `screenshot.nu`. I usually like to place any non-nix files in a folder called `res` at the root 56 - of my config, we'll get to actually calling this script once we're done writing it. 55 + Now along to actually using grimblast, I'll create a new script and put in in my config somewhere, 56 + we'll call it `screenshot.nu`. I usually like to place any non-nix files in a folder called `res` at 57 + the root of my config, we'll get to actually calling this script once we're done writing it. 57 58 58 59 To start out we need to call grimblast, I like to use `copysave` as the action as I like having it 59 60 immediately in my clipboard, and having it saved for later. I'll also add `--freeze` which simply ··· 63 64 let file_path = grimblast --freeze copysave 64 65 ``` 65 66 66 - grimblast will then return the path to the saved screenshot, which we save in `file_path`. 67 - If the user were to cancel the selection (press escape), `file_path` would be empty, so we want to make sure 68 - to check for that so we're not trying to open a non-existent file. 67 + grimblast will then return the path to the saved screenshot, which we save in `file_path`. If the 68 + user were to cancel the selection (press escape), `file_path` would be empty, so we want to make 69 + sure to check for that so we're not trying to open a non-existent file. 69 70 70 71 ```nushell 71 72 if $file_path == "" { ··· 88 89 let choice = notify-send --app-name=screengrab -i $file_path -t 7500 --action=open=Open --action=folder="Show In Folder" --action=edit=Edit --action=delete=Delete "Screenshot taken" $"Screenshot saved to ($file_path) and copied to clipboard" 89 90 ``` 90 91 91 - A long command here, `notify-send` allows us to send a notification to the currently running notification daemon. 92 - In my case I'm using [swaync](https://github.com/ErikReider/SwayNotificationCenter). 92 + A long command here, `notify-send` allows us to send a notification to the currently running 93 + notification daemon. In my case I'm using 94 + [swaync](https://github.com/ErikReider/SwayNotificationCenter). 93 95 94 - - `--app-name` is the name of the application that sent the notification, I say screengrab here so swaync will show an icon in addition to the image, also so I can play a camera shutter sound when the notification is sent. 96 + - `--app-name` is the name of the application that sent the notification, I say screengrab here so 97 + swaync will show an icon in addition to the image, also so I can play a camera shutter sound when 98 + the notification is sent. 95 99 - `-i` is the icon to display in the notification, in this case the screenshot we just took. 96 100 - `-t` is the time in milliseconds to show the notification 97 101 - `--action` is actions to display in the notification, `name=Text` ··· 101 105 102 106 ![A notification that I just took a screenshot with the screenshot visible](@assets/blog/wip1_screenshot_notif.png) 103 107 104 - Now we need to handle each action, the chosen action is returned by notify-send, so we can match on that. 108 + Now we need to handle each action, the chosen action is returned by notify-send, so we can match on 109 + that. 105 110 106 - - "Open" and "Open Folder" are pretty simple, just pass `$file_path` and `$file_path | path dirname` to `xdg-open` 107 - - "Edit" I'll simply pass the file path to my editor, I chose [swappy](https://github.com/jtheoof/swappy) because of it's simplicity and ease of use. 111 + - "Open" and "Open Folder" are pretty simple, just pass `$file_path` and `$file_path | path dirname` 112 + to `xdg-open` 113 + - "Edit" I'll simply pass the file path to my editor, I chose 114 + [swappy](https://github.com/jtheoof/swappy) because of it's simplicity and ease of use. 108 115 - "Delete" I'll just remove the file. 109 116 110 117 ```nushell ··· 128 135 129 136 ### Calling the Screenshot script 130 137 131 - Now in terms of actually calling it I'll be binding it to `Win` + `Shift` + `S` in Hyprland, as 132 - well as `PrintScreen`. 138 + Now in terms of actually calling it I'll be binding it to `Win` + `Shift` + `S` in Hyprland, as well 139 + as `PrintScreen`. 133 140 134 141 In home manager I simply have to add these strings to my Hyprland binds 135 142 ··· 142 149 ]; 143 150 ``` 144 151 145 - Now by switching to my new config (and making sure to stage `screenshot.nu` of course), 146 - I can take screenshots with a keybind! 152 + Now by switching to my new config (and making sure to stage `screenshot.nu` of course), I can take 153 + screenshots with a keybind! 147 154 148 155 ## Screen Recordings 149 156 150 - This will be a bit more involved mainly because something like grimblast doesn't exist for screen recordings. 151 - Looking at existing solutions I couldn't find any that I really liked, mostly because they involved 152 - some additional UI. To be clear this script will be for _simple_, _short_ recordings, long-term stuff 153 - I'll still prefer to use something like OBS. 157 + This will be a bit more involved mainly because something like grimblast doesn't exist for screen 158 + recordings. Looking at existing solutions I couldn't find any that I really liked, mostly because 159 + they involved some additional UI. To be clear this script will be for _simple_, _short_ recordings, 160 + long-term stuff I'll still prefer to use something like OBS. 154 161 155 162 For the actual screen recording I'll be using [wf-recorder](https://github.com/ammen99/wf-recorder). 156 163 ··· 165 172 ]; 166 173 ``` 167 174 168 - First and foremost location, I chose to use `~/Videos/Captures` for my recordings. I didn't 169 - set an environment variable for this, it'll be hardcoded in the script. 175 + First and foremost location, I chose to use `~/Videos/Captures` for my recordings. I didn't set an 176 + environment variable for this, it'll be hardcoded in the script. 170 177 171 178 ```nushell 172 179 let date_format = "%Y-%m-%d_%H-%M-%S" ··· 180 187 let out_name = date now | format date $"($captures_folder)/($date_format).mp4" 181 188 ``` 182 189 183 - This will handle determining the folder and name for the recordings, 184 - and creating the folder if it doesn't exist. 190 + This will handle determining the folder and name for the recordings, and creating the folder if it 191 + doesn't exist. 185 192 186 193 Next up I want to have a similar selection process to the screenshot script, to do this I'll use 187 - [slurp](https://github.com/emersion/slurp) to select areas of the screen, 188 - which is what grimblast uses under the hood. 194 + [slurp](https://github.com/emersion/slurp) to select areas of the screen, which is what grimblast 195 + uses under the hood. 189 196 190 197 In addition, grimblast does some communication with Hyprland to get window information such as 191 - position and size, this lets you select a window to take a screenshot of. I'll be getting that info manually from 192 - Hyprland using NuShell instead: 198 + position and size, this lets you select a window to take a screenshot of. I'll be getting that info 199 + manually from Hyprland using NuShell instead: 193 200 194 201 ```nushell 195 202 let workspaces = hyprctl monitors -j | from json | get activeWorkspace.id ··· 208 215 } 209 216 ``` 210 217 211 - I do `complete` here to get the exit code of the slurp command, if it's 1 then the user cancelled the selection 212 - and similar to the screenshot script I'll exit. 218 + I do `complete` here to get the exit code of the slurp command, if it's 1 then the user cancelled 219 + the selection and similar to the screenshot script I'll exit. 213 220 214 - Now it's time to actually record, the stdout of `slurp` contains the geometry that we want to capture, 215 - so we'll pass that to `wf-recorder` with the `-g` flag: 221 + Now it's time to actually record, the stdout of `slurp` contains the geometry that we want to 222 + capture, so we'll pass that to `wf-recorder` with the `-g` flag: 216 223 217 224 ```nushell 218 225 wf-recorder -g ($stat.stdout) -F fps=30 -f $out_name 219 226 ``` 220 227 221 - Pretty simple command, `-g` is the geometry to record, `-F` is the format options, and `-f` is the output file. 228 + Pretty simple command, `-g` is the geometry to record, `-F` is the format options, and `-f` is the 229 + output file. 222 230 223 231 Now we'll run into an issue if we run this script and start recording, there's no way to stop it! 224 232 I'll cover how we're going to get around that when it comes to setting up keybinds. ··· 231 239 232 240 ![A notification that I just took a screen recording with a video camera icon visible](@assets/blog/wip1_screenrec_notif.png) 233 241 234 - Most arguments are the same here as the screenshot script, the only difference is the icon and app name. 235 - The actions are also basically the same, so I'll leave out the explanation and just show the handler: 242 + Most arguments are the same here as the screenshot script, the only difference is the icon and app 243 + name. The actions are also basically the same, so I'll leave out the explanation and just show the 244 + handler: 236 245 237 246 ```nushell 238 247 match $action { ··· 252 261 253 262 Now to actually call the script, I'll bind it to `Win` + `Shift` + `R` in Hyprland. 254 263 255 - However, we're going to do something special with the `exec` line here. Instead of simply calling the script 256 - we're going to check if `wf-recorder` is already running, if this is the case we can send 257 - `SIGINT` to it to make it stop recording, meaning our script will continue and show the notification. 264 + However, we're going to do something special with the `exec` line here. Instead of simply calling 265 + the script we're going to check if `wf-recorder` is already running, if this is the case we can send 266 + `SIGINT` to it to make it stop recording, meaning our script will continue and show the 267 + notification. 258 268 259 269 ```nix 260 270 wayland.windowManager.hyprland.settings.bindr = [ ··· 264 274 ]; 265 275 ``` 266 276 267 - `pkill` here will exit with code `1` if it doesn't find any processes to kill, so the `||` will run our script if `pkill` fails. 277 + `pkill` here will exit with code `1` if it doesn't find any processes to kill, so the `||` will run 278 + our script if `pkill` fails. 268 279 269 - Note that I did this on `bindr`, this means the keybind will only happen once the R key is _released_ rather than 270 - pressed. This is to prevent a weird issue I ran into where the recording would stop immediately after starting. 280 + Note that I did this on `bindr`, this means the keybind will only happen once the R key is 281 + _released_ rather than pressed. This is to prevent a weird issue I ran into where the recording 282 + would stop immediately after starting. 271 283 272 - And that's it! We can now screen record with ease. It won't record audio 273 - (might do an additional keybind in the future) and it also doesn't copy the recording to the clipboard, but 274 - it works pretty well for short videos. 284 + And that's it! We can now screen record with ease. It won't record audio (might do an additional 285 + keybind in the future) and it also doesn't copy the recording to the clipboard, but it works pretty 286 + well for short videos. 275 287 276 288 ## Full Scripts 277 289