Skip to content

Commit 2ff696a

Browse files
authored
perf(website): size the hero poster to the box it paints in (#1062)
Closes #876 ### What changed `website/site/public/media/hero-poster.webp` is encoded at **1440×810** instead of 1920×1080, and `scripts/build-media.mjs` resizes to 1440 so the next `pnpm run media` keeps the size instead of restoring 1920. 1440 covers the box the film actually paints in: `Hero.astro` caps it at `min(1180px, 80vw, film-h * 16/9)`, so at most 1180×664 CSS px — 1440 is **1.22×** that, enough for a 1.25× display, and no `devicePixelRatio` branch is needed. The 1359×764 in #876 was the layout before that cap landed in #899, two days after the audit; the issue's numbers describe a box the site no longer has. ### Before / after | | bytes | dimensions | |---|---|---| | before | 42,926 | 1920 × 1080 | | after | **30,878** | 1440 × 810 | **−12,048 B, −28.1%.** Both below the issue's ≤ 45 KB bound. Note the source file was already smaller than the 73,916 B the 2026-10-17 audit measured — it was re-encoded during the #858 rebrand — so the absolute saving is smaller than the audit's 36.9 KiB estimate, while the resolution waste it reported is removed. ### Visual check SSIM of the new file against the old one, both scaled with lanczos to the comparison size: | comparison size | SSIM | |---|---| | 1180 × 664 (the film's CSS cap today) | 0.9968 | | 1359 × 764 (the layout #876 measured) | 0.9964 | | 2718 × 1528 (2× device pixels) | 0.9932 | ### `og:image` was never this file The issue's second consumer no longer exists: `Base.astro` defaults `ogImage` to `/media/social-card.png`, generated at 1200×630 by `build-social-card.mjs` (#884). Nothing overrides it — `grep -rn "ogImage=" website/site/src` returns only the default and the prop declaration. So the "must stay 1920×1080" constraint does not apply, and no second 1920 file is kept. Built output confirms both: ``` dist/media/hero-poster.webp 30,878 B 1440,810 poster="/media/hero-poster.webp" property="og:image" content="https://nostream.dev/media/social-card.png" ``` ### Verification - `pnpm build` in `website/site` succeeds (prebuild's brand + hero-NIP checks included); the asset in `dist/media/` is the new one at 30,878 B. - CLS: the film keeps `aspect-ratio: 16/9` on the `<video>`, unchanged by this PR, so the poster's intrinsic size does not enter layout. ### Out of scope `admin-poster.webp` and `peering-poster.webp` are encoded by the same script at 1920 and have the same geometry mismatch. They are not measured by this issue's audit and are left alone; the fix is one `resize()` call each when someone measures them. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Performance** * Reduced the landing page hero image width from 1920 to 1440 pixels, lowering the image’s download size while preserving visual quality. * Social preview imagery remains unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents c6c95a4 + 9fbe32b commit 2ff696a

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
"nostream-website": patch
3+
---
4+
5+
perf(website): size the hero poster to the box it paints in
6+
7+
`hero-poster.webp` was encoded at 1920×1080 for a box `Hero.astro` caps at
8+
1180×664 CSS px (`min(1180px, 80vw, film-h * 16/9)`), which Lighthouse's
9+
`image-delivery-insight` reported as 36.9 KiB of waste on
10+
`ema.tnsor.network` ([#876](https://github.com/cameri/nostream/issues/876)).
11+
The poster now encodes at 1440×810 — 1.22× that box, enough for a 1.25×
12+
display, so it needs no `devicePixelRatio` branch — and drops from 42,926 B
13+
to 30,878 B, a 28% reduction. SSIM against the old file at the display size
14+
is 0.9968 at 1180×664 and 0.9964 at the larger 1359×764 layout #876 measured.
15+
16+
The social preview is unaffected: `og:image` defaults to the generated
17+
`social-card.png` at 1200×630 in `build-social-card.mjs`, and the hero poster
18+
has no second consumer. `scripts/build-media.mjs` resizes to 1440 so the next
19+
`pnpm run media` keeps the size instead of restoring 1920.
-11.8 KB
Loading

‎website/site/scripts/build-media.mjs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,15 @@ if (existsSync(planet)) {
3535
console.warn('skip planet: run `pnpm run assets` in website/hero-animation first')
3636
}
3737

38+
// Page-sized, not film-sized: Hero.astro caps the film at `min(1180px, 80vw,
39+
// film-h * 16/9)`, so the poster paints in at most 1180x664 CSS px and 1440x810
40+
// is 1.22x that box - enough for a 1.25x display, and no devicePixelRatio
41+
// branch. (#876 measured 1359x764, the layout before that cap landed in #899.)
42+
// The social preview is `social-card.png`, generated at 1200x630 by
43+
// build-social-card.mjs, and never this file.
3844
const landingPoster = path.join(LANDING, 'frames', LANDING_POSTER)
3945
if (existsSync(landingPoster)) {
40-
await sharp(landingPoster).resize(1920).webp({ quality: 90 }).toFile(path.join(MEDIA, 'hero-poster.webp'))
46+
await sharp(landingPoster).resize(1440).webp({ quality: 90 }).toFile(path.join(MEDIA, 'hero-poster.webp'))
4147
console.log('hero poster → public/media')
4248
} else {
4349
console.warn(`skip hero poster: run \`pnpm run frames\` in website/hero-animation (need frames/${LANDING_POSTER})`)

0 commit comments

Comments
 (0)