Build: Arhitectura României — interactive 3D scrollytelling
Astro 6 + Tailwind 4 + Three.js + GSAP/Lenis stack. - Hero with animated procedural 3D Maramures house silhouette - Six typology sections (Maramures, cula, sasesc, interbelic, comunist, contemporan), each with a low-poly Three.js model and interactive drag-to-rotate - 5-question quiz that recommends a typology, with native + social share - Beletage backlinks throughout: footer, header CTA, dedicated section, quiz result, share strip - Full SEO: dynamic OG image, JSON-LD WebSite/Organization/Article, sitemap (i18n), robots, canonical, hreflang - RO primary, EN landing variant - Romanian-warm palette (terra/wood/sky-mist/bone), Fraunces + Inter fonts - Lazy-init Three scenes via IntersectionObserver, prefers-reduced-motion respected Static output, ready for Cloudflare Pages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import sharp from 'sharp';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const outDir = join(__dirname, '..', 'public');
|
||||
await mkdir(outDir, { recursive: true });
|
||||
|
||||
const W = 1200, H = 630;
|
||||
|
||||
const svg = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#1f0e08"/>
|
||||
<stop offset="1" stop-color="#3a1c10"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="sun" cx="0.5" cy="0.35" r="0.6">
|
||||
<stop offset="0" stop-color="#f4cfb1" stop-opacity="0.55"/>
|
||||
<stop offset="1" stop-color="#f4cfb1" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="shimmer" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0" stop-color="#b35831"/>
|
||||
<stop offset="0.5" stop-color="#ecae82"/>
|
||||
<stop offset="1" stop-color="#b35831"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<rect width="${W}" height="${H}" fill="url(#bg)"/>
|
||||
<rect width="${W}" height="${H}" fill="url(#sun)"/>
|
||||
|
||||
<!-- Subtle grid -->
|
||||
<g stroke="#fdf6f1" stroke-opacity="0.04">
|
||||
${Array.from({ length: 20 }).map((_, i) => `<line x1="${i * 60}" y1="0" x2="${i * 60}" y2="${H}"/>`).join('')}
|
||||
${Array.from({ length: 11 }).map((_, i) => `<line x1="0" y1="${i * 60}" x2="${W}" y2="${i * 60}"/>`).join('')}
|
||||
</g>
|
||||
|
||||
<!-- Stylized house silhouettes (3 of them) -->
|
||||
<g opacity="0.95">
|
||||
<!-- Maramures -->
|
||||
<g transform="translate(150, 380)">
|
||||
<rect x="-50" y="-10" width="100" height="80" fill="#5e3a1a"/>
|
||||
<polygon points="-65,-10 0,-160 65,-10" fill="#2d1810"/>
|
||||
<polygon points="0,-160 0,-185 -7,-160" fill="#2d1810"/>
|
||||
</g>
|
||||
<!-- Cula -->
|
||||
<g transform="translate(420, 380)">
|
||||
<rect x="-50" y="40" width="100" height="40" fill="#cfbf94"/>
|
||||
<rect x="-55" y="-30" width="110" height="70" fill="#e2d8be"/>
|
||||
<rect x="-55" y="-100" width="110" height="70" fill="#e2d8be"/>
|
||||
<polygon points="-65,-100 0,-160 65,-100" fill="#7e5d36"/>
|
||||
</g>
|
||||
<!-- Contemporary -->
|
||||
<g transform="translate(700, 380)">
|
||||
<rect x="-70" y="-20" width="140" height="100" fill="#f1ecdf"/>
|
||||
<rect x="40" y="-10" width="60" height="90" fill="#bf9b6f"/>
|
||||
<rect x="-65" y="-10" width="80" height="50" fill="#84b6cd" opacity="0.6"/>
|
||||
<polygon points="-75,-20 75,-50 75,-20" fill="#3a1c10"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Title -->
|
||||
<g transform="translate(80, 110)">
|
||||
<text font-family="Georgia, serif" font-size="22" fill="#ecae82" letter-spacing="6">PATRIMONIU CONSTRUIT · 2026</text>
|
||||
<text y="92" font-family="Georgia, serif" font-size="80" font-weight="500" fill="#faf8f3">Arhitectura</text>
|
||||
<text y="172" font-family="Georgia, serif" font-size="80" font-weight="500" fill="url(#shimmer)" font-style="italic">României</text>
|
||||
<text y="240" font-family="Georgia, serif" font-size="44" fill="#faf8f3">de la cula la zgârie-nori</text>
|
||||
</g>
|
||||
|
||||
<!-- Bottom strip -->
|
||||
<g transform="translate(80, ${H - 70})">
|
||||
<text font-family="system-ui, sans-serif" font-size="22" fill="#fae8da" opacity="0.8">2d3d.ro</text>
|
||||
<text x="${W - 160}" font-family="system-ui, sans-serif" font-size="22" fill="#fae8da" opacity="0.8">de Beletage</text>
|
||||
</g>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
await sharp(Buffer.from(svg)).png({ quality: 92 }).toFile(join(outDir, 'og.png'));
|
||||
console.log('Generated og.png');
|
||||
|
||||
// Also apple-touch-icon
|
||||
const ati = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180">
|
||||
<rect width="180" height="180" rx="36" fill="#3a1c10"/>
|
||||
<path d="M30 122 L90 30 L150 122 Z" fill="#d4703f"/>
|
||||
<rect x="36" y="122" width="108" height="22" fill="#5e2d1a"/>
|
||||
<circle cx="90" cy="92" r="9" fill="#fae8da"/>
|
||||
</svg>
|
||||
`;
|
||||
await sharp(Buffer.from(ati)).resize(180, 180).png().toFile(join(outDir, 'apple-touch-icon.png'));
|
||||
console.log('Generated apple-touch-icon.png');
|
||||
Reference in New Issue
Block a user