delight: hero entrance, badge materialise, scroll reveal, parallax, image hover

This commit is contained in:
2026-08-08 20:46:19 +02:00
parent 94672dadf5
commit ca5b34db96
+88
View File
@@ -224,6 +224,58 @@
.project:nth-of-type(even) .project-image { order: initial; } .project:nth-of-type(even) .project-image { order: initial; }
.project-image { position: relative; top: auto; } .project-image { position: relative; top: auto; }
} }
/* ── Delight ─────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
/* Hero: eyebrow, title, and paragraph stagger in on load */
@keyframes archiveIn {
from { opacity: 0; transform: translateY(22px); }
to { opacity: 1; transform: translateY(0); }
}
.hero-copy .eyebrow { animation: archiveIn 0.7s cubic-bezier(0.22,1,.36,1) 0.08s both; }
.hero-copy h1 { animation: archiveIn 1.0s cubic-bezier(0.22,1,.36,1) 0.22s both; }
.hero-copy p { animation: archiveIn 0.7s cubic-bezier(0.22,1,.36,1) 0.48s both; }
/* Masthead badge: letter-spacing collapses as it materialises */
@keyframes badgeIn {
from { opacity: 0; letter-spacing: .32em; }
to { opacity: .72; letter-spacing: .18em; }
}
.masthead::after { animation: badgeIn 1.5s cubic-bezier(0.22,1,.36,1) 0.65s both; }
/* Scroll-reveal: sections fade and slide up as they enter the viewport */
[data-reveal] {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.7s cubic-bezier(0.22,1,.36,1),
transform 0.7s cubic-bezier(0.22,1,.36,1);
}
[data-reveal].visible { opacity: 1; transform: translateY(0); }
/* Subtle offset for even-numbered sections to break rhythm */
.project:nth-of-type(even)[data-reveal] {
transition-delay: 0.06s;
}
/* Project images: contained zoom on hover */
.project-image { overflow: hidden; }
.project-image img {
transition: transform 0.6s cubic-bezier(0.22,1,.36,1);
}
.project-image:hover img { transform: scale(1.04); }
/* Divider: fade in with slight width expansion */
img.divider[data-reveal] {
transform: none;
filter: opacity(0) blur(2px);
transition: filter 0.6s cubic-bezier(0.22,1,.36,1),
transform 0.6s cubic-bezier(0.22,1,.36,1);
}
img.divider[data-reveal].visible {
filter: opacity(0.9) blur(0px);
}
}
</style> </style>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -340,5 +392,41 @@
<p>You are not completing the colony's story.<br />You are creating the place where its next story can begin.</p> <p>You are not completing the colony's story.<br />You are creating the place where its next story can begin.</p>
</div> </div>
</footer> </footer>
<script>
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (!reducedMotion) {
// Scroll reveal ─ sections and dividers materialise as they enter view
const reveal = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('visible')
reveal.unobserve(e.target)
}
})
}, { threshold: 0.06, rootMargin: '0px 0px -40px 0px' })
document.querySelectorAll('.intro, .project, .document, img.divider').forEach(el => {
el.setAttribute('data-reveal', '')
reveal.observe(el)
})
// Masthead parallax ─ background drifts very slowly upward on scroll
const masthead = document.querySelector('.masthead')
if (masthead) {
let ticking = false
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
const y = Math.min(window.scrollY * 0.12, 80)
masthead.style.backgroundPositionY = `calc(30% + ${y}px)`
ticking = false
})
ticking = true
}
}, { passive: true })
}
}
</script>
</body> </body>
</html> </html>