diff --git a/site/package.json b/site/package.json index 8798a4640..0b8955161 100644 --- a/site/package.json +++ b/site/package.json @@ -19,6 +19,7 @@ "astro": "^7.2.8", "motion": "^12.34.0", "reading-time": "^1.5.0", + "sharp": "0.35.5", "tailwindcss": "^4.1.10" } } diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml index f9067e35a..f33a40b65 100644 --- a/site/pnpm-lock.yaml +++ b/site/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: reading-time: specifier: ^1.5.0 version: 1.5.0 + sharp: + specifier: ^0.35.5 + version: 0.35.5(@types/node@24.13.5) tailwindcss: specifier: ^4.1.10 version: 4.3.0 @@ -2400,8 +2403,7 @@ snapshots: '@fontsource/inter@5.2.8': {} - '@img/colour@1.1.0': - optional: true + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.35.5': optionalDependencies: @@ -4210,7 +4212,6 @@ snapshots: '@img/sharp-win32-ia32': 0.35.5 '@img/sharp-win32-x64': 0.35.5 '@types/node': 24.13.5 - optional: true shiki@4.4.3: dependencies: diff --git a/site/public/_headers b/site/public/_headers index f2b459a65..42e3ffbfa 100644 --- a/site/public/_headers +++ b/site/public/_headers @@ -7,3 +7,8 @@ Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() Strict-Transport-Security: max-age=31536000; includeSubDomains + +# Built assets carry a content hash in their name, so a new build is a new +# URL and the old one can be cached for good. +/_astro/* + Cache-Control: public, max-age=31536000, immutable diff --git a/site/public/textures/frost-blue.webp b/site/public/textures/frost-blue.webp deleted file mode 100644 index f16f729c7..000000000 Binary files a/site/public/textures/frost-blue.webp and /dev/null differ diff --git a/site/public/textures/lake-mist.webp b/site/public/textures/lake-mist.webp deleted file mode 100644 index 43851bc16..000000000 Binary files a/site/public/textures/lake-mist.webp and /dev/null differ diff --git a/site/public/textures/lake-motion.webp b/site/public/textures/lake-motion.webp deleted file mode 100644 index 9f5bd7d9d..000000000 Binary files a/site/public/textures/lake-motion.webp and /dev/null differ diff --git a/site/public/textures/paint-aqua.webp b/site/public/textures/paint-aqua.webp deleted file mode 100644 index 8c53d2c30..000000000 Binary files a/site/public/textures/paint-aqua.webp and /dev/null differ diff --git a/site/public/textures/paint-blue.webp b/site/public/textures/paint-blue.webp deleted file mode 100644 index a79d96368..000000000 Binary files a/site/public/textures/paint-blue.webp and /dev/null differ diff --git a/site/public/textures/reeded-glass.webp b/site/public/textures/reeded-glass.webp deleted file mode 100644 index 5628cc4f7..000000000 Binary files a/site/public/textures/reeded-glass.webp and /dev/null differ diff --git a/site/public/textures/sheer-blue.webp b/site/public/textures/sheer-blue.webp deleted file mode 100644 index 65639d2e3..000000000 Binary files a/site/public/textures/sheer-blue.webp and /dev/null differ diff --git a/site/public/textures/sheer-cream.webp b/site/public/textures/sheer-cream.webp deleted file mode 100644 index 5526d1c6e..000000000 Binary files a/site/public/textures/sheer-cream.webp and /dev/null differ diff --git a/site/public/textures/sheer-lavender.webp b/site/public/textures/sheer-lavender.webp deleted file mode 100644 index aca669e3a..000000000 Binary files a/site/public/textures/sheer-lavender.webp and /dev/null differ diff --git a/site/src/assets/textures/frost-blue.webp b/site/src/assets/textures/frost-blue.webp new file mode 100644 index 000000000..7696e89b7 Binary files /dev/null and b/site/src/assets/textures/frost-blue.webp differ diff --git a/site/src/assets/textures/lake-mist.webp b/site/src/assets/textures/lake-mist.webp new file mode 100644 index 000000000..2cf7fa951 Binary files /dev/null and b/site/src/assets/textures/lake-mist.webp differ diff --git a/site/src/assets/textures/lake-motion.webp b/site/src/assets/textures/lake-motion.webp new file mode 100644 index 000000000..bc444e7f5 Binary files /dev/null and b/site/src/assets/textures/lake-motion.webp differ diff --git a/site/src/assets/textures/paint-aqua.webp b/site/src/assets/textures/paint-aqua.webp new file mode 100644 index 000000000..6d1eecb59 Binary files /dev/null and b/site/src/assets/textures/paint-aqua.webp differ diff --git a/site/src/assets/textures/paint-blue.webp b/site/src/assets/textures/paint-blue.webp new file mode 100644 index 000000000..153231007 Binary files /dev/null and b/site/src/assets/textures/paint-blue.webp differ diff --git a/site/src/assets/textures/paint-teal.webp b/site/src/assets/textures/paint-teal.webp new file mode 100644 index 000000000..a36f33086 Binary files /dev/null and b/site/src/assets/textures/paint-teal.webp differ diff --git a/site/src/assets/textures/reeded-glass.webp b/site/src/assets/textures/reeded-glass.webp new file mode 100644 index 000000000..a40d2ad71 Binary files /dev/null and b/site/src/assets/textures/reeded-glass.webp differ diff --git a/site/src/assets/textures/sheer-blue.webp b/site/src/assets/textures/sheer-blue.webp new file mode 100644 index 000000000..3b4c112f3 Binary files /dev/null and b/site/src/assets/textures/sheer-blue.webp differ diff --git a/site/src/assets/textures/sheer-cream.webp b/site/src/assets/textures/sheer-cream.webp new file mode 100644 index 000000000..2fe4ec51d Binary files /dev/null and b/site/src/assets/textures/sheer-cream.webp differ diff --git a/site/src/assets/textures/sheer-lavender.webp b/site/src/assets/textures/sheer-lavender.webp new file mode 100644 index 000000000..e939ee29f Binary files /dev/null and b/site/src/assets/textures/sheer-lavender.webp differ diff --git a/site/src/assets/textures/sheer-peach.webp b/site/src/assets/textures/sheer-peach.webp new file mode 100644 index 000000000..270251fcf Binary files /dev/null and b/site/src/assets/textures/sheer-peach.webp differ diff --git a/site/src/assets/textures/sheer-sky.webp b/site/src/assets/textures/sheer-sky.webp new file mode 100644 index 000000000..870e9cf7f Binary files /dev/null and b/site/src/assets/textures/sheer-sky.webp differ diff --git a/site/src/components/Photo.astro b/site/src/components/Photo.astro new file mode 100644 index 000000000..d733dcea9 --- /dev/null +++ b/site/src/components/Photo.astro @@ -0,0 +1,47 @@ +--- +/** + * A background photo from src/assets/textures, built into AVIF (WebP for the + * few browsers without it) at a few widths, so every screen downloads only + * what it draws. Quality 50 keeps the grain of these photos at a fraction of + * WebP's size. A ~300-byte blurred copy is inlined as the image's own + * background, so the frame is never empty while the real file arrives. + */ +import { Picture } from 'astro:assets'; +import sharp from 'sharp'; +import path from 'node:path'; + +interface Props { + name: string; + /** The rendered width at each breakpoint, as an list. */ + sizes: string; + /** Above the fold: load first instead of lazily. */ + priority?: boolean; + class?: string; +} +const { name, sizes, priority = false, class: className = '' } = Astro.props; + +const images = import.meta.glob<{ default: ImageMetadata }>('../assets/textures/*.webp', { eager: true }); +const image = images[`../assets/textures/${name}.webp`]?.default; +if (!image) throw new Error(`Photo: no texture named "${name}" in src/assets/textures`); + +const lqip = await sharp(path.join(process.cwd(), 'src/assets/textures', `${name}.webp`)) + .resize(24) + .webp({ quality: 50 }) + .toBuffer(); +const placeholder = `background-image:url(data:image/webp;base64,${lqip.toString('base64')});background-size:cover;background-position:center;`; +--- +