site: home + grid tiles use <Image> instead of raw <img>

Eliminates the byte-dedup hazard that just bit timelined and apex: every
image consumer now goes through Astro's image pipeline, so duplicate
bytes share their webp variants instead of one consumer's strategy
silently winning and dropping the original asset.

Side-benefit is significant: tiles and the home hero now ship responsive
webp variants via srcset/sizes instead of the original PNG/JPG. The
superkey hero alone drops from 192 KB to ~29 KB at the largest size.

Video branches stay raw — astro:assets is image-only and videos don't
have this bug.
This commit is contained in:
2026-05-04 20:58:18 -04:00
parent 55c778817a
commit ed1d484ccb
2 changed files with 15 additions and 13 deletions
+5 -4
View File
@@ -1,5 +1,6 @@
--- ---
import { getCollection } from 'astro:content'; import { getCollection } from 'astro:content';
import { Image } from 'astro:assets';
import BaseLayout from '../layouts/BaseLayout.astro'; import BaseLayout from '../layouts/BaseLayout.astro';
import Masonry from '../components/Masonry.astro'; import Masonry from '../components/Masonry.astro';
import { heroes } from '../lib/hero'; import { heroes } from '../lib/hero';
@@ -30,11 +31,11 @@ const lastUpdated = reviews[0]?.data.date;
<article> <article>
<a href={tile.href} class:list={['tile', { 'text-only': !tile.hero }]}> <a href={tile.href} class:list={['tile', { 'text-only': !tile.hero }]}>
{tile.hero?.kind === 'image' && ( {tile.hero?.kind === 'image' && (
<img <Image
class="media" class="media"
src={tile.hero.src.src} src={tile.hero.src}
width={tile.hero.src.width} widths={[320, 480, 640]}
height={tile.hero.src.height} sizes="(max-width: 520px) 92vw, (max-width: 880px) 45vw, 320px"
loading="lazy" loading="lazy"
decoding="async" decoding="async"
alt={tile.name} alt={tile.name}
+10 -9
View File
@@ -1,5 +1,6 @@
--- ---
import { getCollection } from 'astro:content'; import { getCollection } from 'astro:content';
import { Image } from 'astro:assets';
import BaseLayout from '../layouts/BaseLayout.astro'; import BaseLayout from '../layouts/BaseLayout.astro';
import Masonry from '../components/Masonry.astro'; import Masonry from '../components/Masonry.astro';
import { heroes } from '../lib/hero'; import { heroes } from '../lib/hero';
@@ -91,14 +92,14 @@ const itemList = buildItemList(
{hero && hero.kind === 'review' && ( {hero && hero.kind === 'review' && (
<a href={hero.href} class="hero"> <a href={hero.href} class="hero">
{hero.hero?.kind === 'image' && ( {hero.hero?.kind === 'image' && (
<img <Image
class="hero-media" class="hero-media"
src={hero.hero.src.src} src={hero.hero.src}
width={hero.hero.src.width} widths={[480, 720, 960, 1280]}
height={hero.hero.src.height} sizes="(max-width: 720px) 92vw, 720px"
fetchpriority="high"
loading="eager" loading="eager"
decoding="sync" decoding="sync"
fetchpriority="high"
alt={hero.name} alt={hero.name}
/> />
)} )}
@@ -131,11 +132,11 @@ const itemList = buildItemList(
<article> <article>
<a href={tile.href} class:list={['tile', { 'text-only': !visual, 'is-list': tile.kind === 'list' }]}> <a href={tile.href} class:list={['tile', { 'text-only': !visual, 'is-list': tile.kind === 'list' }]}>
{visual?.kind === 'image' && ( {visual?.kind === 'image' && (
<img <Image
class="media" class="media"
src={visual.src.src} src={visual.src}
width={visual.src.width} widths={[320, 480, 640]}
height={visual.src.height} sizes="(max-width: 520px) 92vw, (max-width: 880px) 45vw, 320px"
loading="lazy" loading="lazy"
decoding="async" decoding="async"
alt={tile.name} alt={tile.name}