diff --git a/package-lock.json b/package-lock.json
index 16a1ec727..928d05edb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,6 +34,7 @@
"aws-cdk-lib": "^2.244.0",
"constructs": "^10.6.0",
"esbuild": "^0.28.0",
+ "sharp": "^0.34.5",
"tsx": "^4.22.4",
"typescript": "^5.9.3"
}
@@ -24052,6 +24053,17 @@
"postcss-selector-parser": "^6.0.10"
}
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emotion/is-prop-valid": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
@@ -25362,6 +25374,544 @@
"deprecated": "Use @eslint/object-schema instead",
"license": "BSD-3-Clause"
},
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.7.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@inquirer/ansi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
@@ -46295,6 +46845,51 @@
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
"license": "MIT"
},
+ "node_modules/sharp": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.7.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.5",
+ "@img/sharp-darwin-x64": "0.34.5",
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
+ "@img/sharp-libvips-linux-arm": "1.2.4",
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
+ "@img/sharp-libvips-linux-x64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+ "@img/sharp-linux-arm": "0.34.5",
+ "@img/sharp-linux-arm64": "0.34.5",
+ "@img/sharp-linux-ppc64": "0.34.5",
+ "@img/sharp-linux-riscv64": "0.34.5",
+ "@img/sharp-linux-s390x": "0.34.5",
+ "@img/sharp-linux-x64": "0.34.5",
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
+ "@img/sharp-linuxmusl-x64": "0.34.5",
+ "@img/sharp-wasm32": "0.34.5",
+ "@img/sharp-win32-arm64": "0.34.5",
+ "@img/sharp-win32-ia32": "0.34.5",
+ "@img/sharp-win32-x64": "0.34.5"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
diff --git a/package.json b/package.json
index 5df65566c..7e19455bd 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"aws-cdk-lib": "^2.244.0",
"constructs": "^10.6.0",
"esbuild": "^0.28.0",
+ "sharp": "^0.34.5",
"tsx": "^4.22.4",
"typescript": "^5.9.3"
}
diff --git a/public/images/AlgorithmComparison-1024.webp b/public/images/AlgorithmComparison-1024.webp
new file mode 100644
index 000000000..b699bb244
Binary files /dev/null and b/public/images/AlgorithmComparison-1024.webp differ
diff --git a/public/images/AlgorithmComparison-320.webp b/public/images/AlgorithmComparison-320.webp
new file mode 100644
index 000000000..527cdbdfe
Binary files /dev/null and b/public/images/AlgorithmComparison-320.webp differ
diff --git a/public/images/AlgorithmComparison-640.webp b/public/images/AlgorithmComparison-640.webp
new file mode 100644
index 000000000..64e60b60f
Binary files /dev/null and b/public/images/AlgorithmComparison-640.webp differ
diff --git a/public/images/EulerCycle-1024.webp b/public/images/EulerCycle-1024.webp
new file mode 100644
index 000000000..b6ef50333
Binary files /dev/null and b/public/images/EulerCycle-1024.webp differ
diff --git a/public/images/EulerCycle-320.webp b/public/images/EulerCycle-320.webp
new file mode 100644
index 000000000..e2863b1e8
Binary files /dev/null and b/public/images/EulerCycle-320.webp differ
diff --git a/public/images/EulerCycle-640.webp b/public/images/EulerCycle-640.webp
new file mode 100644
index 000000000..d1844861d
Binary files /dev/null and b/public/images/EulerCycle-640.webp differ
diff --git a/public/images/EulerExample-1024.webp b/public/images/EulerExample-1024.webp
new file mode 100644
index 000000000..cd25461ae
Binary files /dev/null and b/public/images/EulerExample-1024.webp differ
diff --git a/public/images/EulerExample-320.webp b/public/images/EulerExample-320.webp
new file mode 100644
index 000000000..1ee8f818f
Binary files /dev/null and b/public/images/EulerExample-320.webp differ
diff --git a/public/images/EulerExample-640.webp b/public/images/EulerExample-640.webp
new file mode 100644
index 000000000..4b726e4f7
Binary files /dev/null and b/public/images/EulerExample-640.webp differ
diff --git a/public/images/GitHub_Logo-1024.webp b/public/images/GitHub_Logo-1024.webp
new file mode 100644
index 000000000..2eeaad855
Binary files /dev/null and b/public/images/GitHub_Logo-1024.webp differ
diff --git a/public/images/GitHub_Logo-320.webp b/public/images/GitHub_Logo-320.webp
new file mode 100644
index 000000000..1f3c74936
Binary files /dev/null and b/public/images/GitHub_Logo-320.webp differ
diff --git a/public/images/GitHub_Logo-640.webp b/public/images/GitHub_Logo-640.webp
new file mode 100644
index 000000000..0ff162727
Binary files /dev/null and b/public/images/GitHub_Logo-640.webp differ
diff --git a/public/images/GunControl-1024.webp b/public/images/GunControl-1024.webp
new file mode 100644
index 000000000..bdbf203ba
Binary files /dev/null and b/public/images/GunControl-1024.webp differ
diff --git a/public/images/GunControl-320.webp b/public/images/GunControl-320.webp
new file mode 100644
index 000000000..671e42e69
Binary files /dev/null and b/public/images/GunControl-320.webp differ
diff --git a/public/images/GunControl-640.webp b/public/images/GunControl-640.webp
new file mode 100644
index 000000000..4a9504a74
Binary files /dev/null and b/public/images/GunControl-640.webp differ
diff --git a/public/images/HSV-1024.webp b/public/images/HSV-1024.webp
new file mode 100644
index 000000000..f33c772ca
Binary files /dev/null and b/public/images/HSV-1024.webp differ
diff --git a/public/images/HSV-320.webp b/public/images/HSV-320.webp
new file mode 100644
index 000000000..bc5cc8fee
Binary files /dev/null and b/public/images/HSV-320.webp differ
diff --git a/public/images/HSV-640.webp b/public/images/HSV-640.webp
new file mode 100644
index 000000000..574167fc2
Binary files /dev/null and b/public/images/HSV-640.webp differ
diff --git a/public/images/Hangman-1024.webp b/public/images/Hangman-1024.webp
new file mode 100644
index 000000000..1d9e8f242
Binary files /dev/null and b/public/images/Hangman-1024.webp differ
diff --git a/public/images/Hangman-320.webp b/public/images/Hangman-320.webp
new file mode 100644
index 000000000..58e96a8db
Binary files /dev/null and b/public/images/Hangman-320.webp differ
diff --git a/public/images/Hangman-640.webp b/public/images/Hangman-640.webp
new file mode 100644
index 000000000..96f879550
Binary files /dev/null and b/public/images/Hangman-640.webp differ
diff --git a/public/images/KnightsTour-1024.webp b/public/images/KnightsTour-1024.webp
new file mode 100644
index 000000000..9f2fb5b7d
Binary files /dev/null and b/public/images/KnightsTour-1024.webp differ
diff --git a/public/images/KnightsTour-320.webp b/public/images/KnightsTour-320.webp
new file mode 100644
index 000000000..f2c1f1031
Binary files /dev/null and b/public/images/KnightsTour-320.webp differ
diff --git a/public/images/KnightsTour-640.webp b/public/images/KnightsTour-640.webp
new file mode 100644
index 000000000..fd6222d9b
Binary files /dev/null and b/public/images/KnightsTour-640.webp differ
diff --git a/public/images/LI-Logo-1024.webp b/public/images/LI-Logo-1024.webp
new file mode 100644
index 000000000..54fc56e95
Binary files /dev/null and b/public/images/LI-Logo-1024.webp differ
diff --git a/public/images/LI-Logo-320.webp b/public/images/LI-Logo-320.webp
new file mode 100644
index 000000000..305710b9f
Binary files /dev/null and b/public/images/LI-Logo-320.webp differ
diff --git a/public/images/LI-Logo-640.webp b/public/images/LI-Logo-640.webp
new file mode 100644
index 000000000..408232987
Binary files /dev/null and b/public/images/LI-Logo-640.webp differ
diff --git a/public/images/MJB-1024.webp b/public/images/MJB-1024.webp
new file mode 100644
index 000000000..1327d61e2
Binary files /dev/null and b/public/images/MJB-1024.webp differ
diff --git a/public/images/MJB-320.webp b/public/images/MJB-320.webp
new file mode 100644
index 000000000..e9e6407d1
Binary files /dev/null and b/public/images/MJB-320.webp differ
diff --git a/public/images/MJB-640.webp b/public/images/MJB-640.webp
new file mode 100644
index 000000000..a44ca2a9a
Binary files /dev/null and b/public/images/MJB-640.webp differ
diff --git a/public/images/Me-1024.webp b/public/images/Me-1024.webp
new file mode 100644
index 000000000..a7eb28531
Binary files /dev/null and b/public/images/Me-1024.webp differ
diff --git a/public/images/Me-320.webp b/public/images/Me-320.webp
new file mode 100644
index 000000000..5915b1717
Binary files /dev/null and b/public/images/Me-320.webp differ
diff --git a/public/images/Me-640.webp b/public/images/Me-640.webp
new file mode 100644
index 000000000..a29388109
Binary files /dev/null and b/public/images/Me-640.webp differ
diff --git a/public/images/Palish-1024.webp b/public/images/Palish-1024.webp
new file mode 100644
index 000000000..5756f756c
Binary files /dev/null and b/public/images/Palish-1024.webp differ
diff --git a/public/images/Palish-320.webp b/public/images/Palish-320.webp
new file mode 100644
index 000000000..913e9fddb
Binary files /dev/null and b/public/images/Palish-320.webp differ
diff --git a/public/images/Palish-640.webp b/public/images/Palish-640.webp
new file mode 100644
index 000000000..3579733f2
Binary files /dev/null and b/public/images/Palish-640.webp differ
diff --git a/public/images/Resume-1024.webp b/public/images/Resume-1024.webp
new file mode 100644
index 000000000..2821a3777
Binary files /dev/null and b/public/images/Resume-1024.webp differ
diff --git a/public/images/Resume-320.webp b/public/images/Resume-320.webp
new file mode 100644
index 000000000..b725a8a24
Binary files /dev/null and b/public/images/Resume-320.webp differ
diff --git a/public/images/Resume-640.webp b/public/images/Resume-640.webp
new file mode 100644
index 000000000..784585f34
Binary files /dev/null and b/public/images/Resume-640.webp differ
diff --git a/public/images/SRS-1024.webp b/public/images/SRS-1024.webp
new file mode 100644
index 000000000..927b9cae8
Binary files /dev/null and b/public/images/SRS-1024.webp differ
diff --git a/public/images/SRS-320.webp b/public/images/SRS-320.webp
new file mode 100644
index 000000000..1ce51a1f6
Binary files /dev/null and b/public/images/SRS-320.webp differ
diff --git a/public/images/SRS-640.webp b/public/images/SRS-640.webp
new file mode 100644
index 000000000..ed6893791
Binary files /dev/null and b/public/images/SRS-640.webp differ
diff --git a/public/images/ShowingOff-1024.webp b/public/images/ShowingOff-1024.webp
new file mode 100644
index 000000000..39b04d438
Binary files /dev/null and b/public/images/ShowingOff-1024.webp differ
diff --git a/public/images/ShowingOff-320.webp b/public/images/ShowingOff-320.webp
new file mode 100644
index 000000000..fb8732ae6
Binary files /dev/null and b/public/images/ShowingOff-320.webp differ
diff --git a/public/images/ShowingOff-640.webp b/public/images/ShowingOff-640.webp
new file mode 100644
index 000000000..cc7eae1f4
Binary files /dev/null and b/public/images/ShowingOff-640.webp differ
diff --git a/public/images/StateMachine-1024.webp b/public/images/StateMachine-1024.webp
new file mode 100644
index 000000000..7261b2885
Binary files /dev/null and b/public/images/StateMachine-1024.webp differ
diff --git a/public/images/StateMachine-320.webp b/public/images/StateMachine-320.webp
new file mode 100644
index 000000000..3fe026c2b
Binary files /dev/null and b/public/images/StateMachine-320.webp differ
diff --git a/public/images/StateMachine-640.webp b/public/images/StateMachine-640.webp
new file mode 100644
index 000000000..e07a24ec3
Binary files /dev/null and b/public/images/StateMachine-640.webp differ
diff --git a/public/images/TextAnalyzer-1024.webp b/public/images/TextAnalyzer-1024.webp
new file mode 100644
index 000000000..7eb983486
Binary files /dev/null and b/public/images/TextAnalyzer-1024.webp differ
diff --git a/public/images/TextAnalyzer-320.webp b/public/images/TextAnalyzer-320.webp
new file mode 100644
index 000000000..e22dd2618
Binary files /dev/null and b/public/images/TextAnalyzer-320.webp differ
diff --git a/public/images/TextAnalyzer-640.webp b/public/images/TextAnalyzer-640.webp
new file mode 100644
index 000000000..5d256f208
Binary files /dev/null and b/public/images/TextAnalyzer-640.webp differ
diff --git a/public/images/Twitter-Logo-1024.webp b/public/images/Twitter-Logo-1024.webp
new file mode 100644
index 000000000..8d4ca4762
Binary files /dev/null and b/public/images/Twitter-Logo-1024.webp differ
diff --git a/public/images/Twitter-Logo-320.webp b/public/images/Twitter-Logo-320.webp
new file mode 100644
index 000000000..d3d7d04a6
Binary files /dev/null and b/public/images/Twitter-Logo-320.webp differ
diff --git a/public/images/Twitter-Logo-640.webp b/public/images/Twitter-Logo-640.webp
new file mode 100644
index 000000000..f165a657c
Binary files /dev/null and b/public/images/Twitter-Logo-640.webp differ
diff --git a/public/images/W&H-1024.webp b/public/images/W&H-1024.webp
new file mode 100644
index 000000000..0f2cdf0fc
Binary files /dev/null and b/public/images/W&H-1024.webp differ
diff --git a/public/images/W&H-320.webp b/public/images/W&H-320.webp
new file mode 100644
index 000000000..f80fe41d5
Binary files /dev/null and b/public/images/W&H-320.webp differ
diff --git a/public/images/W&H-640.webp b/public/images/W&H-640.webp
new file mode 100644
index 000000000..460576f90
Binary files /dev/null and b/public/images/W&H-640.webp differ
diff --git a/public/images/background1-1024.webp b/public/images/background1-1024.webp
new file mode 100644
index 000000000..9dc3625c0
Binary files /dev/null and b/public/images/background1-1024.webp differ
diff --git a/public/images/background1-320.webp b/public/images/background1-320.webp
new file mode 100644
index 000000000..11854c233
Binary files /dev/null and b/public/images/background1-320.webp differ
diff --git a/public/images/background1-640.webp b/public/images/background1-640.webp
new file mode 100644
index 000000000..72c9e58ea
Binary files /dev/null and b/public/images/background1-640.webp differ
diff --git a/public/images/background2-1024.webp b/public/images/background2-1024.webp
new file mode 100644
index 000000000..f66625f83
Binary files /dev/null and b/public/images/background2-1024.webp differ
diff --git a/public/images/background2-320.webp b/public/images/background2-320.webp
new file mode 100644
index 000000000..b1c9c475a
Binary files /dev/null and b/public/images/background2-320.webp differ
diff --git a/public/images/background2-640.webp b/public/images/background2-640.webp
new file mode 100644
index 000000000..267d529e0
Binary files /dev/null and b/public/images/background2-640.webp differ
diff --git a/public/images/background3-1024.webp b/public/images/background3-1024.webp
new file mode 100644
index 000000000..cc4610351
Binary files /dev/null and b/public/images/background3-1024.webp differ
diff --git a/public/images/background3-320.webp b/public/images/background3-320.webp
new file mode 100644
index 000000000..f161d2500
Binary files /dev/null and b/public/images/background3-320.webp differ
diff --git a/public/images/background3-640.webp b/public/images/background3-640.webp
new file mode 100644
index 000000000..cb383c02e
Binary files /dev/null and b/public/images/background3-640.webp differ
diff --git a/public/images/itchio-logo-black-1024.webp b/public/images/itchio-logo-black-1024.webp
new file mode 100644
index 000000000..111076b63
Binary files /dev/null and b/public/images/itchio-logo-black-1024.webp differ
diff --git a/public/images/itchio-logo-black-320.webp b/public/images/itchio-logo-black-320.webp
new file mode 100644
index 000000000..8f4f37223
Binary files /dev/null and b/public/images/itchio-logo-black-320.webp differ
diff --git a/public/images/itchio-logo-black-640.webp b/public/images/itchio-logo-black-640.webp
new file mode 100644
index 000000000..f3a3ad06b
Binary files /dev/null and b/public/images/itchio-logo-black-640.webp differ
diff --git a/public/images/skin2-1024.webp b/public/images/skin2-1024.webp
new file mode 100644
index 000000000..23953dbe7
Binary files /dev/null and b/public/images/skin2-1024.webp differ
diff --git a/public/images/skin2-320.webp b/public/images/skin2-320.webp
new file mode 100644
index 000000000..db29d22cb
Binary files /dev/null and b/public/images/skin2-320.webp differ
diff --git a/public/images/skin2-640.webp b/public/images/skin2-640.webp
new file mode 100644
index 000000000..a4f9435b6
Binary files /dev/null and b/public/images/skin2-640.webp differ
diff --git a/src/Home.js b/src/Home.js
index dd05dcf7d..f3f55fb9c 100644
--- a/src/Home.js
+++ b/src/Home.js
@@ -1,6 +1,5 @@
import React from 'react';
import { Helmet } from 'react-helmet-async';
-import Me from './assets/Me.jpeg';
export const Home = () => {
return (
@@ -25,7 +24,15 @@ export const Home = () => {
-
+
);
diff --git a/src/Projects.js b/src/Projects.js
index 97c15910d..bad20e791 100644
--- a/src/Projects.js
+++ b/src/Projects.js
@@ -1,70 +1,62 @@
import React from 'react';
import { Helmet } from 'react-helmet-async';
import ProjectCard from './components/ProjectCard';
-import ShowingOff from './assets/ShowingOff.jpg';
-import StateMachine from './assets/StateMachine.png';
-import Skin2 from './assets/skin2.png';
-import EulerExample from './assets/EulerExample.png';
-import Hangman from './assets/Hangman.png';
-import KngihtsTour from './assets/KnightsTour.png';
-import TextAnalyzer from './assets/TextAnalyzer.png';
-import AlgorithmComparison from './assets/AlgorithmComparison.png';
const projects = [
{
title: 'Python State Machine',
link: 'https://github.com/gjcampbell777/python-state-machine',
description: 'A Python state machine used to emulate a locked/unlocked device.',
- img: StateMachine,
+ imgName: 'StateMachine',
imgAlt: 'Python state machine demo'
},
{
title: 'Python Skin Detection Algorithms',
link: 'https://github.com/gjcampbell777/python-photo-skin-detection',
description: 'Replicated multiple skin detection algorithms in Python and modernized them for Python 3.',
- img: Skin2,
+ imgName: 'skin2',
imgAlt: 'Skin detection before/after',
},
{
title: 'Euler Checking Algorithm',
link: 'https://github.com/gjcampbell777/euler-checking-algorithm',
description: 'C program to check if graphs are Eulerian.',
- img: EulerExample,
+ imgName: 'EulerExample',
imgAlt: 'Euler example'
},
{
title: 'Fortran Hangman',
link: 'https://github.com/gjcampbell777/fortran-hangman',
description: 'Updated a Fortran 77 hangman game to Fortran 95 and improved the code.',
- img: Hangman,
+ imgName: 'Hangman',
imgAlt: 'Hangman game'
},
{
title: "Ada Knights Tour",
link: 'https://github.com/gjcampbell777/ada-knights-tour',
description: "Solves the knight's tour problem in Ada.",
- img: KngihtsTour,
+ imgName: 'KnightsTour',
imgAlt: 'Knights tour output'
},
{
title: 'COBOL Text Analyzer',
link: 'https://github.com/gjcampbell777/cobol-text-analyzer',
description: 'Modernized COBOL text analyzer to report text statistics.',
- img: TextAnalyzer,
+ imgName: 'TextAnalyzer',
imgAlt: 'Text analyzer output'
},
{
title: 'Legacy Algorithm Comparison',
link: 'https://github.com/gjcampbell777/legacy-algorithm-comparison',
description: 'Compare KMP implementations across C, Fortran, and Ada.',
- img: AlgorithmComparison,
+ imgName: 'AlgorithmComparison',
imgAlt: 'Algorithm comparison charts'
},
{
title: 'My Many Games',
link: 'https://gregorysoup.itch.io',
description: 'A selection of games made with Unity and Godot.',
- img: ShowingOff,
+ imgName: 'ShowingOff',
imgAlt: 'Game showcase'
}
];
diff --git a/src/Resume.js b/src/Resume.js
index d8d7642c6..9ebaa420d 100644
--- a/src/Resume.js
+++ b/src/Resume.js
@@ -1,7 +1,6 @@
import React from 'react';
import { Helmet } from 'react-helmet-async';
import pdf from './assets/Gregory Campbell Resume.pdf';
-import pic from './assets/Resume.png';
export const Resume = () => {
return (
@@ -26,7 +25,14 @@ export const Resume = () => {
Written Resume
-
+
diff --git a/src/components/ProjectCard.js b/src/components/ProjectCard.js
index 8ac9ed17e..59bb9e99b 100644
--- a/src/components/ProjectCard.js
+++ b/src/components/ProjectCard.js
@@ -1,18 +1,25 @@
import React from 'react';
-export const ProjectCard = ({ title, description, imgSrc, imgAlt, link, children }) => {
+export const ProjectCard = ({ title, description, imgSrc, imgName, imgAlt, link, children }) => {
+ const webpSources = imgName
+ ? `/images/${imgName}-320.webp 320w, /images/${imgName}-640.webp 640w, /images/${imgName}-1024.webp 1024w`
+ : null;
+
+ const srcFallback = imgName ? `/images/${imgName}-640.webp` : imgSrc;
+
return (
-
- {link ? (
- {title}
- ) : (
- title
- )}
-
+ {link ? {title} : title}
{description}
- {imgSrc && (
-
+ {srcFallback && (
+
)}
{children}