diff --git a/nextjs-app/components/Illustration.tsx b/nextjs-app/components/Illustration.tsx index cc3963c..2f85d6a 100644 --- a/nextjs-app/components/Illustration.tsx +++ b/nextjs-app/components/Illustration.tsx @@ -60,6 +60,18 @@ export function HeroIllustration() { srcSet="/brand/hero-band-500.webp 500w, /brand/hero-band-700.webp 700w, /brand/hero-band-972.webp 972w" sizes={SIZES} /> + {/* + The band's JPEG, and the reason it exists. + + cannot vary by viewport, so it is always the wide crop. A + browser that takes neither AVIF nor WebP would therefore fall through + to the desktop frame on a phone and lose the schoolhouse — the exact + failure this whole component is arranged to prevent, surviving in the + one path nobody looks at. No `type` here, so it matches anywhere the + media query does, and it sits after the modern formats so they still + win where supported. + */} + =18" } @@ -4160,8 +4161,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -8584,9 +8585,9 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", - "optional": true, "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", @@ -8629,8 +8630,8 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "devOptional": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver.js" }, diff --git a/nextjs-app/package.json b/nextjs-app/package.json index 45a2434..c2ff2ea 100644 --- a/nextjs-app/package.json +++ b/nextjs-app/package.json @@ -36,6 +36,7 @@ "@types/jest": "^30.0.0", "@types/leaflet": "^1.9.21", "jest": "^30.2.0", - "jest-environment-jsdom": "^30.2.0" + "jest-environment-jsdom": "^30.2.0", + "sharp": "^0.34.5" } } diff --git a/nextjs-app/scripts/build-hero-images.js b/nextjs-app/scripts/build-hero-images.js index 91b7043..a87f458 100644 --- a/nextjs-app/scripts/build-hero-images.js +++ b/nextjs-app/scripts/build-hero-images.js @@ -25,8 +25,16 @@ * squeezing further toward 4.9:1 crops the empty sides, not the subject. * * AVIF and WebP are both emitted. This is flat-shaded vector-style artwork, so - * AVIF lands roughly an order of magnitude under the source PNG; the JPEG is - * only the fallback and is never served to a current browser. + * AVIF lands roughly an order of magnitude under the source PNG. Both crops + * also get a JPEG: the wide one backs the , and the band one backs a + * — without it a browser taking neither modern format would + * fall through to the desktop frame on a phone, since cannot vary by + * viewport. + * + * sharp is declared in devDependencies rather than leaned on as a transitive + * dependency of next. It does currently arrive that way, but relying on that + * means a Next upgrade can silently break this script — the same reasoning as + * the outputFileTracingIncludes note in next.config.js. */ const path = require('path');