Redesign: new logo, fonts, toon-shaded 3D, scroll animations

Visual overhaul addressing render glitches and adding wow factor.

Type:
- Display: Fraunces -> Instrument Serif (more elegant, italic-forward)
- Body:    Inter    -> Geist (tighter, more contemporary)
- Mono:    JetBrains -> Geist Mono

Logo:
- New SVG mark — pairs a gabled vernacular silhouette with a glass-grid
  contemporary tower, divided by a ground line. Communicates "2D3D" through
  architectural language rather than typography.
- Component supports mark / full / inverse variants
- Favicon + apple-touch-icon updated to match
- OG image regenerated with new palette and 3 representative house silhouettes

3D models (houses.ts):
- Switched to MeshToonMaterial with a 3-step gradient LUT — flat designer-toy
  look that's forgiving of low-poly approximations
- Reworked geometry across all six typologies for consistent scale and clean
  composition (real arches via ExtrudeGeometry on cula loggia, proper sasesc
  roof shapes via extruded slope, contemporary slats sized to volume)
- Per-house camera framing
- 2D->3D intro animation when scene first becomes visible — house extrudes
  from a flat plane (on-brand for the 2d3d.ro concept)
- Subtle breathing y-translation while idle
- Hover speeds up the spin smoothly

Animations:
- Word-split + staggered reveal for hero headline
- IntersectionObserver-based reveal-on-scroll for [data-reveal]/[data-reveal-blur]
- Animated number counters (Romanian locale)
- Magnetic hover on CTAs and brand mark
- Cursor-tracking radial glow in hero
- Section dividers with blueprint dimension-line aesthetic
- Marquee strip listing typology names in intro
- Glow-ring (animated conic gradient) on primary CTAs

Palette refined — slightly less saturated terra/wood/sky-mist for a more
sophisticated tone.

All animations respect prefers-reduced-motion. Off-screen 3D scenes still
paused via the prior IntersectionObserver fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude (Beletage)
2026-04-20 10:54:31 +03:00
parent 5e47123446
commit c0bc2c2f04
16 changed files with 1130 additions and 459 deletions
+63 -39
View File
@@ -13,17 +13,17 @@ 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"/>
<stop offset="0" stop-color="#190b06"/>
<stop offset="1" stop-color="#2e160d"/>
</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 id="sun" cx="0.5" cy="0.35" r="0.7">
<stop offset="0" stop-color="#f0c39b" stop-opacity="0.45"/>
<stop offset="1" stop-color="#f0c39b" 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"/>
<stop offset="0" stop-color="#7d361c"/>
<stop offset="0.5" stop-color="#e69d6a"/>
<stop offset="1" stop-color="#7d361c"/>
</linearGradient>
</defs>
@@ -31,47 +31,61 @@ const svg = `
<rect width="${W}" height="${H}" fill="url(#sun)"/>
<!-- Subtle grid -->
<g stroke="#fdf6f1" stroke-opacity="0.04">
<g stroke="#fbf8f1" 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">
<!-- 3 stylized houses across the ground -->
<g>
<!-- 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 transform="translate(140, 460)">
<rect x="-55" y="-10" width="110" height="60" fill="#7a4a23"/>
<rect x="-55" y="50" width="110" height="6" fill="#1f150c"/>
<polygon points="-72,-10 0,-180 72,-10" fill="#2a160b"/>
<polygon points="-2,-200 2,-200 0,-180" fill="#2a160b"/>
<line x1="-1" y1="-200" x2="-1" y2="-218" stroke="#1f150c" stroke-width="2"/>
<line x1="-9" y1="-210" x2="9" y2="-210" stroke="#1f150c" stroke-width="2"/>
</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 transform="translate(420, 460)">
<rect x="-55" y="-10" width="110" height="60" fill="#c8b380"/>
<rect x="-60" y="-90" width="120" height="80" fill="#e7d6b3"/>
<polygon points="-66,-90 0,-150 66,-90" fill="#5a3220"/>
<g fill="#1a0d05">
<rect x="-44" y="-50" width="20" height="22"/>
<rect x="-10" y="-50" width="20" height="22"/>
<rect x="24" y="-50" width="20" height="22"/>
</g>
</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 transform="translate(720, 460)">
<rect x="-90" y="-10" width="180" height="60" fill="#a8a29a"/>
<rect x="-90" y="50" width="180" height="6" fill="#1f150c"/>
<rect x="-85" y="-70" width="115" height="60" fill="#f3ecdc"/>
<rect x="38" y="-50" width="50" height="40" fill="#b58f5d"/>
<rect x="-78" y="-58" width="100" height="40" fill="#9ec5d9" opacity="0.7"/>
<polygon points="-90,-70 30,-90 30,-70" fill="#2e160d"/>
<g fill="#0d0805" opacity="0.85">
<rect x="-78" y="-100" width="20" height="3" transform="rotate(-3, -78, -100)"/>
<rect x="-50" y="-101" width="20" height="3" transform="rotate(-3, -50, -101)"/>
<rect x="-22" y="-102" width="20" height="3" transform="rotate(-3, -22, -102)"/>
</g>
</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>
<!-- Title — Instrument Serif look (use serif fallback) -->
<g transform="translate(80, 130)">
<text font-family="'Instrument Serif', Georgia, serif" font-size="24" fill="#e69d6a" letter-spacing="6">PATRIMONIU CONSTRUIT · 2026</text>
<text y="100" font-family="'Instrument Serif', Georgia, serif" font-size="92" font-weight="400" fill="#fbf8f1">Arhitectura</text>
<text y="200" font-family="'Instrument Serif', Georgia, serif" font-size="92" font-weight="400" fill="url(#shimmer)" font-style="italic">României</text>
<text y="270" font-family="'Instrument Serif', Georgia, serif" font-size="36" fill="#fbf8f1" opacity="0.8" font-style="italic">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 transform="translate(80, ${H - 60})">
<text font-family="'Geist', system-ui, sans-serif" font-weight="500" font-size="20" fill="#f9e3d0" opacity="0.85">2d3d.ro</text>
<text x="${W - 200}" font-family="'Geist', system-ui, sans-serif" font-size="20" fill="#f9e3d0" opacity="0.7">un proiect Beletage</text>
</g>
</svg>
`;
@@ -79,13 +93,23 @@ const svg = `
await sharp(Buffer.from(svg)).png({ quality: 92 }).toFile(join(outDir, 'og.png'));
console.log('Generated og.png');
// Also apple-touch-icon
// Also apple-touch-icon — matches favicon design
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"/>
<rect width="180" height="180" rx="40" fill="#190b06"/>
<rect x="18" y="142" width="144" height="6" fill="#2e160d"/>
<path d="M28 142 L28 84 L62 50 L96 84 L96 142 Z" fill="#d97942"/>
<path d="M62 50 L62 110 L96 142 M62 110 L28 142" stroke="#2e160d" stroke-width="3" stroke-linejoin="round" stroke-linecap="round"/>
<rect x="50" y="110" width="24" height="32" fill="#2e160d"/>
<rect x="56" y="116" width="6" height="6" fill="#fae8da"/>
<rect x="64" y="116" width="6" height="6" fill="#fae8da"/>
<rect x="106" y="62" width="50" height="80" fill="#fae8da"/>
<path d="M106 62 L131 40 L156 62" fill="#2e160d"/>
<g fill="#2e160d">
<rect x="114" y="74" width="8" height="8"/><rect x="127" y="74" width="8" height="8"/><rect x="140" y="74" width="8" height="8"/>
<rect x="114" y="92" width="8" height="8"/><rect x="127" y="92" width="8" height="8"/><rect x="140" y="92" width="8" height="8"/>
<rect x="114" y="110" width="8" height="8"/><rect x="127" y="110" width="8" height="8"/><rect x="140" y="110" width="8" height="8"/>
</g>
</svg>
`;
await sharp(Buffer.from(ati)).resize(180, 180).png().toFile(join(outDir, 'apple-touch-icon.png'));