fix hero anim.

This commit is contained in:
Arlind Ukshini 2026-04-23 13:40:26 +02:00
parent 8bd0fda910
commit ecf83137c9
2 changed files with 19 additions and 43 deletions

View file

@ -71,6 +71,11 @@
el.style.opacity = '1'; el.style.opacity = '1';
el.style.transform = 'none'; el.style.transform = 'none';
}); });
// The hero-wrap is hidden by CSS (`.js .hero-wrap { opacity: 0 }`)
// to prevent a flash during page activation — unhide it here since
// we're skipping the fade-in tween.
const heroWrap = document.querySelector('.hero-wrap');
if (heroWrap) heroWrap.style.opacity = '1';
// Still fade the Europe map fully in — it's the scene background. // Still fade the Europe map fully in — it's the scene background.
const mapEl = document.getElementById('overview-globe'); const mapEl = document.getElementById('overview-globe');
if (mapEl) mapEl.style.opacity = '1'; if (mapEl) mapEl.style.opacity = '1';
@ -360,50 +365,17 @@
// Script 1 body — HERO + SCENE 2 (architecture stack) + SCENE 3 (words) + SCENE 4 (bifrost arc) // Script 1 body — HERO + SCENE 2 (architecture stack) + SCENE 3 (words) + SCENE 4 (bifrost arc)
/* ------------------------------------------------------------- /* -------------------------------------------------------------
HERO staggered intro on load HERO single overall fade-in. The wrap is hidden via CSS
(`.js .hero-wrap { opacity: 0 }`) so the hero stays invisible
during the page-activation transition, then fades in once
Bifrost has booted.
------------------------------------------------------------- */ ------------------------------------------------------------- */
const heroTl = gsap.timeline({ defaults: { ease: 'power3.out' } }); gsap.to('.hero-wrap', {
opacity: 1,
// Split the hero title into lines-ish spans for a nicer reveal duration: 1.0,
const heroTitle = document.querySelector('.hero-title'); ease: 'power2.out',
if (heroTitle) { delay: 0.1,
// preserve <br>, wrap visible text chunks in spans
const walk = (node) => {
const kids = [...node.childNodes];
kids.forEach(k => {
if (k.nodeType === Node.TEXT_NODE && k.textContent.trim()) {
const frag = document.createDocumentFragment();
k.textContent.split(/(\s+)/).forEach(tok => {
if (tok.trim()) {
const w = document.createElement('span');
w.className = 'htw';
w.style.display = 'inline-block';
w.style.overflow = 'hidden';
const inner = document.createElement('span');
inner.style.display = 'inline-block';
inner.style.transform = 'translateY(110%)';
inner.style.willChange = 'transform';
inner.textContent = tok;
w.appendChild(inner);
frag.appendChild(w);
} else {
frag.appendChild(document.createTextNode(tok));
}
}); });
node.replaceChild(frag, k);
} else if (k.nodeType === Node.ELEMENT_NODE && k.tagName !== 'BR') {
walk(k);
}
});
};
walk(heroTitle);
}
heroTl
.from('.eyebrow', { opacity: 0, y: 14, duration: 0.7 }, 0.15)
.to('.hero-title .htw > span', { y: '0%', duration: 1.05, stagger: 0.045, ease: 'power4.out' }, 0.2)
.from('.hero-lede', { opacity: 0, y: 20, duration: 0.9 }, 0.7)
.from('.hero-foot', { opacity: 0, y: 14, duration: 0.8 }, 0.9);
/* ------------------------------------------------------------- /* -------------------------------------------------------------
ARCHITECTURE two-phase scrubbed sequence ARCHITECTURE two-phase scrubbed sequence

View file

@ -790,6 +790,10 @@ html {
margin-inline: auto; margin-inline: auto;
padding-top: clamp(2rem, 6vh, 4rem); padding-top: clamp(2rem, 6vh, 4rem);
} }
/* Hide the hero on first paint while JS is booting so it doesn't
flash in raw form during the page-activation transition. The
Bifrost init fades it in once ScrollTriggers are wired up. */
.js .hero-wrap { opacity: 0; }
.eyebrow { .eyebrow {
font-size: var(--step-sm); font-size: var(--step-sm);