Усі нотатки

Обкладинка показує
справжній проєкт

Як наші картки проєктів пройшли шлях від AI-концептів до справжніх перших екранів мовою читача — без жодної бібліотеки для картинок. І що показувати, коли в проєкту ще немає сайту.

Одразу до коду

Концепти пішли, коли прийшла справжня робота

У ранніх версіях головної були картки-концепти з AI-обкладинками й позначкою «Концепт · не опубліковано». За тиждень усі три місця зайняли опубліковані проєкти, і кожна картка показала ілюстрацію з власного сайту проєкту: кота з майстерні Piaskot, курсор PPC4.biz і Арчі з KotoHosting.

Згенерована сцена, подана як справжній проєкт, обіцяла б те, чого ніколи не було. Згенеровані картинки тут однаково мають місце: спільний портрет на сторінці «Про нас» — AI-сцена, і підпис про це каже.

Обкладинка говорить мовою читача

Кілька днів по тому сторінка робіт стала однією сіткою однакових карток, а кожна обкладинка — знімком першого екрана живого сайту. Багато з цих сайтів мають кілька мов, тож читач бачить версію, найближчу до своєї: англійську на англійській сторінці, польську, а як її немає — англійську на польській, українську на українській. Російську — ніколи, навіть якщо вона на сайті ще є.

На картці для цього вистачає двох атрибутів. data-src-uk чи data-src-pl називає інший знімок, data-href-uk чи data-href-pl — іншу адресу. Збирач сайту вписує їх у готовий HTML кожної мови. У вихідних файлах і в офлайн-копії те саме роблять кілька рядків JavaScript.

HTML · projects.html

<img src="assets/img/work-kotohosting-en.webp" data-src-uk="assets/img/work-kotohosting.webp" …>
<a class="text-link" href="https://kotohosting.com/en/" data-href-uk="https://kotohosting.com/" …>

Сайтові з однією мовою нічого додавати не треба: один знімок і одна адреса служать усім трьом версіям нашої сторінки.

Знімок одним викликом DevTools

Для цього ми нічого не встановлюємо. Edge чи Chrome працює без вікна, а tools/shoot-cover.cjs говорить із ним через протокол DevTools зі звичайного Node.js: починаючи з версії 22, у Node вбудовані fetch і WebSocket.

Сторінка відкривається у вікні 1440 × 960 — ті самі пропорції 3:2, що й у наших карток. Далі браузер зберігає екран одразу у WebP і тим самим викликом зменшує його на третину, тож обкладинка 960 × 640 виходить без жодної бібліотеки для картинок.

JavaScript · tools/shoot-cover.cjs

await send('Emulation.setDeviceMetricsOverride', { width: 1440, height: 960, deviceScaleFactor: 1, mobile: false });
// Entrance animations settle into their final state instead of being caught halfway.
await send('Emulation.setEmulatedMedia', { features: [{ name: 'prefers-reduced-motion', value: 'reduce' }] });
await send('Page.navigate', { url });
await loaded();
const shot = await send('Page.captureScreenshot', {
  format: 'webp', quality,
  clip: { x: 0, y: 0, width: 1440, height: 960, scale: 2 / 3 },
});

Terminal · Kotka.dev

node tools/shoot-cover.cjs "https://koto-e.com/?nocache=1" assets/img/work-kotoecom.webp
  • Додавайте одноразовий параметр на кшталт ?nocache=1: кеш на сервері чи в CDN може віддати стару версію сторінки, і застарілий знімок легко проґавити.
  • Стежте за вагою. Наші обкладинки важать приблизно 40–47 КБ. Фотографічний перший екран за якості 82 вийшов на 70 КБ, тож якість знизили до 74, і вийшло 56 КБ.
  • Замінена обкладинка отримує нове ім’я файлу. Картинки кешуються на 30 днів, і збирач їх не перейменовує.

Коли сайту ще немає

Наш плагін для WooCommerce, Koto Shop, публічної сторінки поки не має. Тож його картка отримала складену обкладинку: два телефони зі справжніми екранами замовлень плагіна, знятими на локальному тестовому стенді з вигаданими замовленнями, і Котка, яка наглядає праворуч.

Чесність тут тримається на двох деталях. Екрани — плагіна; сховано лише плашку WordPress про оновлення, бо вона не частина плагіна. І картка не вдає, що кудись веде: замість посилання вона каже, що публічна версія вже готується.

Постановка, але без удавання

Обкладинка — маленька обіцянка про те, що за карткою. Знімок тримає її сам собою; композиція — коли слова довкола кажуть правду. Котка наглядає за обома.

Усі нотаткиТакож: що їде на сервер