Shumiland/scripts/compress-images.mjs
Vadym Samoilenko dc726c5135
Some checks are pending
CI / Type Check (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Unit Tests (push) Waiting to run
Deploy / Build & Push Image (push) Waiting to run
Deploy / Deploy to VPS (push) Blocked by required conditions
feat: hero dino overlay, WhyParents auto-cycle, YouTube video support
- Hero: T-Rex (hero-bg1) and family moved to z-[20/30], rendered after
  text so dinosaur visually overlaps the title text on desktop
- WhyParents: auto-cycle accordion items every 4s; manual click resets timer
- VideoSection: detect YouTube URLs → render iframe; mp4 uses video tag
- Webp filename cleanup across section components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 23:29:16 +01:00

78 lines
2.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sharp from 'sharp'
import { readdir, stat } from 'fs/promises'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const imgDir = path.resolve(__dirname, '../public/images/figma')
const SKIP = /\.(svg|webp|gif)$/i
const SIZE_LIMITS = {
// hero / footer / video-preview — full bleed, keep wide
'hero-bg1.png': { width: 1920 },
'hero-bg2.png': { width: 1920 },
'hero-bg-family.png': { width: 1920 },
'footer-bg.png': { width: 1920 },
'video-preview.png': { width: 1920 },
// location cards — displayed at ~560px, 2× retina = 1120
'loc-dinopark.jpg': { width: 1200 },
'loc-divo-lis.png': { width: 1200 },
// gallery tiles — displayed at ~380px, 2× = 760
'gallery-1.png': { width: 800 },
'gallery-2.png': { width: 800 },
'gallery-3.png': { width: 800 },
'gallery-4.png': { width: 800 },
'gallery-6.png': { width: 800 },
'gallery-7.png': { width: 800 },
'gallery-8.png': { width: 800 },
// why-parents side tiles
'why-parents-1.png': { width: 800 },
'why-parents-2.png': { width: 800 },
'why-parents-3.png': { width: 800 },
'why-parents-4.png': { width: 800 },
// news / blog thumbnails
'news-bg1.jpg': { width: 800 },
'news-bg2.png': { width: 800 },
'news-bg3.jpg': { width: 800 },
// misc
'review-avatar-bg.jpg': { width: 160 },
'check-mark.png': { width: 48 },
}
const files = await readdir(imgDir)
let totalBefore = 0
let totalAfter = 0
for (const file of files) {
if (SKIP.test(file)) continue
if (file.endsWith('.webp')) continue
const src = path.join(imgDir, file)
const dst = path.join(imgDir, file.replace(/\.(png|jpg|jpeg)$/i, '.webp'))
const srcStat = await stat(src)
totalBefore += srcStat.size
const limit = SIZE_LIMITS[file] ?? { width: 1920 }
try {
const info = await sharp(src)
.resize({ width: limit.width, withoutEnlargement: true })
.webp({ quality: 82, effort: 4 })
.toFile(dst)
totalAfter += info.size
const pct = ((1 - info.size / srcStat.size) * 100).toFixed(1)
console.log(
`${file}${file.replace(/\.(png|jpg|jpeg)$/i, '.webp')} ${(srcStat.size / 1e6).toFixed(1)}MB → ${(info.size / 1e6).toFixed(1)}MB (${pct}% smaller)`
)
} catch (err) {
console.error(`${file}: ${err.message}`)
}
}
console.log(
`\nTotal: ${(totalBefore / 1e6).toFixed(1)}MB → ${(totalAfter / 1e6).toFixed(1)}MB (${((1 - totalAfter / totalBefore) * 100).toFixed(1)}% reduction)`
)