feat: portfolio-led redesign with Shootings umbrella, original logo and motion layer

This commit is contained in:
desfoto automation
2026-09-19 17:11:25 +02:00
parent 2ccb39a69b
commit 447b909d05
177 changed files with 1853 additions and 773 deletions

View File

@@ -69,20 +69,106 @@
});
}
/* Soft reveal on scroll, disabled for reduced motion */
/* Motion layer: reveals, scroll progress, parallax and pointer spotlights.
Everything degrades to a static page and is disabled for reduced motion. */
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* Anything inside [data-stagger] reveals one item after another. */
Array.prototype.forEach.call(document.querySelectorAll('[data-stagger]'), function (group) {
var step = parseFloat(group.getAttribute('data-stagger')) || 0.08;
Array.prototype.forEach.call(group.children, function (child, index) {
if (!child.classList.contains('reveal')) {
child.classList.add('reveal');
}
child.style.setProperty('--d', (index * step).toFixed(2) + 's');
});
});
var items = document.querySelectorAll('.reveal');
var revealAll = function () {
Array.prototype.forEach.call(items, function (item) { item.classList.add('is-in'); });
};
if (reduce || !('IntersectionObserver' in window)) {
items.forEach(function (item) { item.classList.add('is-in'); });
revealAll();
} else {
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('is-in');
observer.unobserve(entry.target);
try {
var fired = 0;
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
fired = 1;
entry.target.classList.add('is-in');
observer.unobserve(entry.target);
}
});
}, { rootMargin: '0px 0px -8% 0px', threshold: 0.06 });
Array.prototype.forEach.call(items, function (item) { observer.observe(item); });
/* Safety net: if the browser never reports a box that is on screen, drop the
effect entirely instead of leaving content hidden. */
window.setTimeout(function () {
if (fired) { return; }
var onScreen = false;
Array.prototype.forEach.call(items, function (item) {
var box = item.getBoundingClientRect();
if (box.top < window.innerHeight && box.bottom > 0) { onScreen = true; }
});
if (onScreen) {
observer.disconnect();
revealAll();
}
});
}, { rootMargin: '0px 0px -10% 0px', threshold: 0.05 });
items.forEach(function (item) { observer.observe(item); });
}, 1600);
} catch (error) {
revealAll();
}
}
if (reduce) {
return;
}
var progress = document.querySelector('[data-progress]');
var parallax = Array.prototype.slice.call(document.querySelectorAll('[data-parallax]'));
var ticking = false;
function onScroll() {
var doc = document.documentElement;
var max = doc.scrollHeight - window.innerHeight;
var ratio = max > 0 ? Math.min(1, Math.max(0, window.scrollY / max)) : 0;
if (progress) {
progress.style.setProperty('--scroll', ratio.toFixed(4));
}
if (parallax.length) {
var view = window.innerHeight;
parallax.forEach(function (element) {
var rect = element.getBoundingClientRect();
if (rect.bottom < -240 || rect.top > view + 240) {
return;
}
var speed = parseFloat(element.getAttribute('data-parallax')) || 0.12;
var offset = (rect.top + rect.height / 2 - view / 2) * speed;
element.style.setProperty('--py', offset.toFixed(1) + 'px');
});
}
ticking = false;
}
function requestScroll() {
if (!ticking) {
ticking = true;
window.requestAnimationFrame(onScroll);
}
}
window.addEventListener('scroll', requestScroll, { passive: true });
window.addEventListener('resize', requestScroll);
onScroll();
/* Pointer-following highlight on the media cards. */
Array.prototype.forEach.call(document.querySelectorAll('.spot'), function (card) {
card.addEventListener('pointermove', function (event) {
var rect = card.getBoundingClientRect();
card.style.setProperty('--mx', ((event.clientX - rect.left) / rect.width * 100).toFixed(1) + '%');
card.style.setProperty('--my', ((event.clientY - rect.top) / rect.height * 100).toFixed(1) + '%');
});
});
}());