Hero: Zutaten als Fontäne von Hand komponiert statt zufällig gestreut

- Burger wurde von unten getroffen: Salat, Zwiebel, Tomate und Sesam schießen nach oben und fächern zur Seite auf, Bacon liegt waagerecht (sah senkrecht wie Chili aus), keine halb verdeckten unscharfen Teile mehr
- Größere Teile mit klarer Rangfolge, Burger, Schriftzeile, Sticker, Hahn und Text bleiben frei
- Intro: Teile schießen aus der Burger-Mitte hoch, über das Ziel hinaus und setzen sich; Scroll setzt die Bewegung nach oben fort und blendet früher aus
- Zutaten drehen und wachsen um ihre eigene Mitte (transform-origin), Burger wandert beim Scrollen wieder nach oben statt nach unten
- Ausgewählt aus vier Entwürfen (Fontäne, Schlag, Kampagne, Schockwelle)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 04:32:21 +00:00
1 parent 002dfa21f1
commit 706854a9a7
2 files changed
+53 -16

No files matched your search

+3 -1
View File
@@ -1095,12 +1095,14 @@ body.nav-visible .cat-nav.is-stuck ul { top: var(--nav-h); }
/* ============ Fliegende Zutaten ============ */
.blast__bits { position: absolute; inset: 0; pointer-events: none; }
.bit { position: absolute; z-index: 3; }
.bit { position: absolute; z-index: 3; transform-origin: 0 0; } /* Mittelpunkt der Zutat liegt auf left/top: so drehen und wachsen sie um sich selbst */
.bit__c { display: block; translate: -50% -50%; }
.bit__in, .bit__fl { display: block; }
.bit img { display: block; width: 100%; height: auto; filter: drop-shadow(0 12px 10px rgba(40, 0, 0, .35)); }
.bit--b { z-index: 1; }
.bit--b img { filter: blur(1.2px) brightness(.88) drop-shadow(0 8px 8px rgba(40, 0, 0, .3)); }
.bit--n { z-index: 5; }
.bit--n img { filter: blur(4px) drop-shadow(0 24px 22px rgba(40, 0, 0, .35)); }
.hero__burger .blast__bits, .visit__deco .blast__bits, .wings__hero .blast__bits { z-index: auto; }
.champ__food .bit--f { z-index: 3; }
@media (max-width: 820px) { .bit--b img { filter: brightness(.9) drop-shadow(0 6px 6px rgba(40, 0, 0, .3)); } }
+50 -15
View File
@@ -195,7 +195,7 @@
/* ---------- Zutaten rund ums Essen (Explosion beim Scrollen) ----------
Jede Zutat: [Datei, x %, y % (relativ zur Essens-Box), Größe % der Box, Drehung, Ebene, auch mobil, gespiegelt]
Ebenen: b = hinter dem Essen (leicht unscharf), f = davor */
Ebenen: b = hinter dem Essen (leicht unscharf), f = davor, n = ganz nah an der Kamera (groß, unscharf) */
var BITS = 'assets/img/bits/';
/* Natürliche Streuung statt fester Positionen (fester Seed, damit es bei jedem Laden gleich aussieht).
- food: Umriss des Essens im Bild [Mitte x, Mitte y, Halbbreite, Halbhöhe] in % der Box (abgerundetes Rechteck)
@@ -204,11 +204,25 @@
- left/right/top/bottom: erlaubter Bereich (% der Box), z. B. damit nichts über Text oder aus der Karte ragt
items: [Datei, Grundgröße in % der Box-Breite, auch mobil] */
var SCATTER = {
burger: { seed: 4, food: [39, 49, 38, 47], hw: .72, reach: 34, bursts: 3, behind: .3, top: -26, bottom: 116, items: [
['lettuce-2', 22, 1], ['tomato', 17, 1], ['bacon', 24, 1], ['onion-1', 15, 1], ['jalapeno-1', 12, 1], ['lettuce-1', 24, 1],
['pickle', 11, 1], ['tomato', 13, 0], ['onion-2', 12, 0], ['jalapeno-2', 11, 0], ['bacon', 18, 0], ['lettuce-3', 18, 0],
['sesame-1', 3.4, 1], ['sesame-2', 3.8, 0], ['sesame-1', 3, 0], ['sesame-1', 2.6, 0]
] },
burger: [
['lettuce-3', 70, -37, 21, 24, 'b', 0, 0],
['onion-2', 27, -43, 13, 30, 'b', 0, 0],
['lettuce-2', 47, -27, 26, 12, 'f', 1, 0],
['onion-1', 14, -21, 24, -15, 'f', 1, 0],
['tomato', 81, 6, 27, 20, 'f', 1, 0],
['lettuce-1', -9, 19, 25, -30, 'f', 1, 0],
['lettuce-1', 94, 38, 27, 42, 'f', 1, 1],
['tomato', -20, 50, 20, -34, 'f', 0, 1],
['onionring', 103, 62, 23, 15, 'f', 0, 0],
['bacon', -31, 68, 26, -12, 'f', 0, 1],
['bacon', 110, 84, 24, 12, 'f', 0, 0],
['jalapeno-1', 6, 107, 16, 20, 'f', 0, 0],
['pickle', 73, 101, 16, -14, 'f', 0, 0],
['sesame-1', 33, -6, 6.5, 25, 'f', 1, 0],
['sesame-1', 39, -15, 6, -35, 'f', 0, 1],
['sesame-2', 62, -17, 8, -20, 'f', 0, 0],
['sesame-1', 58, -5, 5.5, 10, 'f', 1, 1]
],
'burger-visit': { seed: 8, food: [38, 49, 37, 47], hw: .63, reach: 26, bursts: 2, behind: .3, top: 6, bottom: 112, left: -12, items: [
['lettuce-2', 20, 1], ['tomato', 16, 1], ['bacon', 22, 1], ['onion-1', 14, 1], ['jalapeno-1', 11, 1], ['lettuce-1', 20, 0],
['pickle', 10, 0], ['tomato', 12, 0], ['sesame-1', 3.4, 0], ['sesame-2', 3.8, 0]
@@ -294,7 +308,8 @@
var blasts = $$('[data-blast]').map(function (box) {
var spec = SCATTER[box.getAttribute('data-blast')];
if (!spec) return null;
var set = scatter(spec);
// Array = von Hand gesetzte Komposition, Objekt = berechnete Streuung
var set = Array.isArray(spec) ? spec : scatter(spec);
var lazy = box.getAttribute('data-blast-mode') !== 'hero';
var holder = document.createElement('span');
holder.className = 'blast__bits';
@@ -304,7 +319,8 @@
if (mobileBits && !b[6]) return;
// Verschachtelt, damit sich nichts in die Quere kommt:
// .bit (Scroll-Explosion) > .bit__c (CSS-Zentrierung) > .bit__in (Intro) > .bit__fl (Schweben) > img (feste Drehung)
var size = b[3] * bitScale;
// Hero: Handy etwas weniger vergrößert (1,2 statt 1,35), damit die Fontäne den Burger nur berührt und nicht überdeckt
var size = b[3] * (mobileBits && !lazy ? 1.2 : bitScale);
var el = document.createElement('span');
el.className = 'bit bit--' + b[5];
el.style.left = b[1] + '%'; el.style.top = b[2] + '%'; el.style.width = size + '%';
@@ -485,7 +501,8 @@
var parts = $$('[data-hero-big] .part', hero);
gsap.to(parts[0], { xPercent: -10, ease: 'none', scrollTrigger: { trigger: hero, start: 'top top', end: 'bottom top', scrub: true } });
gsap.to(parts[1], { xPercent: 12, ease: 'none', scrollTrigger: { trigger: hero, start: 'top top', end: 'bottom top', scrub: true } });
gsap.to('.hero__burger', { yPercent: -12, ease: 'none', scrollTrigger: { trigger: hero, start: 'top top', end: 'bottom top', scrub: true } });
// CSS zentriert mit translate(-50%, -50%), GSAP liest das als yPercent -50: also -62 = 12 % nach oben
gsap.to('.hero__burger', { yPercent: -62, ease: 'none', scrollTrigger: { trigger: hero, start: 'top top', end: 'bottom top', scrub: true } });
});
}
@@ -544,17 +561,35 @@
y: v.y * .3 + (v.y / len) * W() * k * .55 - W() * .45 * k
};
};
// Hero = Fontäne: Der Burger wurde von unten getroffen. Alles schießt aus der Burger-Mitte nach oben,
// fächert zur Seite auf (Spin dreht nach außen) und die Scroll-Explosion setzt diese Bewegung fort.
var FX = .39, FY = .45; // Ausbruchspunkt in Box-Anteilen (Mitte des Burgers)
var spread = function (b) { // Abstand Ausbruchspunkt -> Endposition in px
return { x: (b.x / 100 - FX) * W(), y: (b.y / 100 - FY) * bl.box.offsetHeight };
};
var launch = function (b, k) { // Scroll-Ziel: weiter nach oben + nach außen fächern
var d = spread(b), sp = b.layer === 'n' ? 1.5 : b.layer === 'b' ? .7 : 1;
return { x: d.x * 1.1 * sp * k, y: -(W() * .55 + Math.max(0, -d.y) * .4) * sp * k };
};
var floats = [];
var tl = gsap.timeline({ paused: true });
bl.bits.forEach(function (b, i) {
b.side = i % 2 ? 1 : -1;
b.side = bl.hero ? (b.x < FX * 100 ? -1 : 1) : (i % 2 ? 1 : -1);
floats.push(gsap.to(b.fl, { y: '+=' + rand(-16, -8), rotation: '+=' + rand(-8, 8), duration: rand(1.8, 3.2), yoyo: true, repeat: -1, ease: 'sine.inOut', delay: rand(0, 1.5), paused: true }));
var spin = rand(160, 340) * b.side;
var grow = b.layer === 'b' ? 1.15 : 1.9;
var spin = (bl.hero ? rand(70, 210) : rand(160, 340)) * b.side;
var grow = b.layer === 'b' ? 1.15 : b.layer === 'n' ? 2.6 : bl.hero ? 1.6 : 1.9;
if (bl.hero) {
gsap.from(b.inner, { x: function () { return -vec(b).x; }, y: function () { return -vec(b).y; }, scale: .2, opacity: 0, rotation: -spin / 3, duration: 1.2, ease: 'back.out(1.3)', delay: .55 + i * .035 });
tl.to(b.el, { x: function () { return away(b, 1).x; }, y: function () { return away(b, 1).y; }, rotation: spin, scale: grow, duration: 1, ease: 'power2.in' }, 0)
.to(b.el, { opacity: 0, duration: .25, ease: 'none' }, .75);
// Intro: aus der Burger-Mitte nach oben; x gleitet, y schießt über das Ziel hinaus und fällt zurück
var dist = Math.sqrt(Math.pow(b.x / 100 - FX, 2) + Math.pow((b.y / 100 - FY) * .72, 2));
var t0 = .5 + (i % 5) * .03, dur = .95 + dist * .8;
gsap.from(b.inner, { x: function () { return -spread(b).x; }, duration: dur, ease: 'power3.out', delay: t0 });
gsap.from(b.inner, { y: function () { return -spread(b).y; }, duration: dur + .35, ease: 'back.out(2.1)', delay: t0 });
gsap.from(b.inner, { scale: .2, opacity: 0, rotation: -spin / 2, duration: dur, ease: 'back.out(1.4)', delay: t0 });
// Scroll: Position schießt zuerst schnell hoch und läuft dann aus (Fontäne), Spin/Größe wachsen gleichmäßig mit
var st = b.layer === 'n' ? 0 : b.layer === 'f' ? .04 + (i % 4) * .02 : .12;
tl.to(b.el, { x: function () { return launch(b, 1).x; }, y: function () { return launch(b, 1).y; }, duration: 1 - st, ease: 'power1.out' }, st)
.to(b.el, { rotation: spin, scale: grow, duration: 1 - st, ease: 'none' }, st)
.to(b.el, { opacity: 0, duration: .3, ease: 'none' }, .6);
} else {
tl.fromTo(b.el, { x: function () { return -vec(b).x * .6; }, y: function () { return -vec(b).y * .6; }, scale: .4, opacity: 0, rotation: -spin / 3 },
{ x: 0, y: 0, scale: 1, opacity: 1, rotation: 0, duration: .4, ease: 'power2.out' }, 0)