larpaso-website/scripts/icons-bauen.mjs
Lara 3ae5f815e8 Brand favicon, link preview image, and zoomable portfolio devices
Replace the Astro placeholder favicon (white L on indigo) with the larpaso
"la" mark from the prototype, in SVG/ICO/PNG sizes plus an Apple touch
icon, and add Open Graph tags with a 1200x630 preview image so shared links
show the logo. Icons are rebuilt with scripts/icons-bauen.mjs.

Clicking or tapping the laptop or phone in the hero and the portfolio now
opens a full-page capture of the example site in a dialog, scrollable and
switchable between desktop and mobile. The scroll videos stay as they were.
New content fields mappe.items[].fullImage / fullMobileImage, also in the
admin schema.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:44:09 +02:00

56 lines
2.3 KiB
JavaScript

// Baut Favicon, App-Icons und das Vorschaubild für geteilte Links aus den
// Marken-SVGs in public/. Aufruf: node scripts/icons-bauen.mjs
// Quelle des Favicons: das "la" auf Petrol aus dem Prototyp lara-webdesign.html.
import sharp from 'sharp';
import { readFileSync, writeFileSync } from 'node:fs';
const pub = (f) => new URL(`../public/${f}`, import.meta.url);
const papier = { r: 252, g: 250, b: 246, alpha: 1 };
const favicon = readFileSync(pub('favicon.svg'));
const logo = readFileSync(pub('logo.svg'));
const png = (svg, size) =>
sharp(svg, { density: 72 * Math.ceil(size / 100) * 4 }).resize(size, size).png().toBuffer();
// Transparente Icons
for (const size of [48, 96, 192, 512]) {
writeFileSync(pub(`icon-${size}.png`), await png(favicon, size));
}
// Apple-Icon braucht deckenden Grund (iOS füllt Transparenz schwarz)
const appleInner = await png(favicon, 148);
await sharp({ create: { width: 180, height: 180, channels: 4, background: papier } })
.composite([{ input: appleInner, gravity: 'center' }])
.png()
.toFile(new URL('../public/apple-touch-icon.png', import.meta.url).pathname.replace(/^\/(\w:)/, '$1'));
// favicon.ico mit 16/32/48 als PNG-Einträge
const sizes = [16, 32, 48];
const bufs = await Promise.all(sizes.map((s) => png(favicon, s)));
const header = Buffer.alloc(6 + 16 * sizes.length);
header.writeUInt16LE(0, 0);
header.writeUInt16LE(1, 2);
header.writeUInt16LE(sizes.length, 4);
let offset = header.length;
sizes.forEach((s, i) => {
const e = 6 + 16 * i;
header.writeUInt8(s, e);
header.writeUInt8(s, e + 1);
header.writeUInt16LE(1, e + 4);
header.writeUInt16LE(32, e + 6);
header.writeUInt32LE(bufs[i].length, e + 8);
header.writeUInt32LE(offset, e + 12);
offset += bufs[i].length;
});
writeFileSync(pub('favicon.ico'), Buffer.concat([header, ...bufs]));
// Vorschaubild für WhatsApp, Signal, Facebook, LinkedIn & Co. (1200 x 630)
const logoPng = await sharp(logo, { density: 300 }).resize({ width: 860 }).png().toBuffer();
await sharp({ create: { width: 1200, height: 630, channels: 4, background: papier } })
.composite([{ input: logoPng, gravity: 'center' }])
.flatten({ background: papier })
.jpeg({ quality: 88 })
.toFile(new URL('../public/og-image.jpg', import.meta.url).pathname.replace(/^\/(\w:)/, '$1'));
console.log('Icons gebaut.');