Zutaten-Effekt überarbeitet: Essen bleibt frei, Streuung in Schüben, Karten sauber begrenzt

- Streuung kennt jetzt den Umriss des Essens: Teile davor berühren es höchstens am Rand, Teile dahinter schauen halb hervor
- Zutaten fliegen in 2–3 Schüben aus dem Essen statt gleichmäßig rundum; dicht am Rand, nach außen weniger
- Champion-Karten: Zutaten bleiben innerhalb der Karte und unter dem Titel, kleinere Explosion, damit nichts in die Nachbarkarte fliegt
- Hohe Teile (Salatblätter) werden bei den Grenzen mit ihrer Höhe berücksichtigt
- Eigene Streuung für Speisekarten-Kopf und Komm-vorbei

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 03:55:18 +00:00
1 parent e77f081b44
commit 002dfa21f1
2 files changed
+67 -38

No files matched your search

+66 -37
View File
@@ -197,37 +197,42 @@
Jede Zutat: [Datei, x %, y % (relativ zur Essens-Box), Größe % der Box, Drehung, Ebene, auch mobil, gespiegelt] 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 */
var BITS = 'assets/img/bits/'; var BITS = 'assets/img/bits/';
/* Statt fester Positionen: natürliche Streuung. Nah am Essen dicht, nach außen immer weniger, /* Natürliche Streuung statt fester Positionen (fester Seed, damit es bei jedem Laden gleich aussieht).
unregelmäßige Winkel, kein Kreis. 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)
items: [Datei, Grundgröße in % der Essensbreite, auch mobil] - Die Zutaten fliegen in 2–3 Schüben aus dem Essen heraus: dicht am Rand, nach außen immer weniger
edge = Rand des Essens (0,5 = Bildrand), reach = weitester Abstand, top/bottom = erlaubter Bereich in % der Höhe, - Teile vor dem Essen berühren es höchstens am Rand, Teile dahinter schauen nur halb hervor
behind = Anteil der nahen Teile hinter dem Essen, hw = Höhe/Breite der Essens-Box */ - 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 = { var SCATTER = {
burger: { seed: 11, edge: .4, reach: 1, top: -34, bottom: 112, behind: .5, hw: .72, items: [ burger: { seed: 4, food: [39, 49, 38, 47], hw: .72, reach: 34, bursts: 3, behind: .3, top: -26, bottom: 116, items: [
['lettuce-2', 20, 1], ['tomato', 16, 1], ['bacon', 22, 1], ['onion-1', 15, 1], ['jalapeno-1', 11, 1], ['lettuce-1', 22, 1], ['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', 10, 0], ['bacon', 17, 0], ['lettuce-3', 17, 0], ['pickle', 11, 1], ['tomato', 13, 0], ['onion-2', 12, 0], ['jalapeno-2', 11, 0], ['bacon', 18, 0], ['lettuce-3', 18, 0],
['sesame-1', 3.6, 1], ['sesame-2', 4, 0], ['sesame-1', 3, 0], ['sesame-1', 2.6, 0] ['sesame-1', 3.4, 1], ['sesame-2', 3.8, 0], ['sesame-1', 3, 0], ['sesame-1', 2.6, 0]
] }, ] },
'burger-visit': { seed: 11, edge: .4, reach: .95, top: -6, bottom: 112, left: -14, behind: .5, hw: .63, items: [ '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', 15, 1], ['jalapeno-1', 11, 1], ['lettuce-1', 22, 1], ['lettuce-2', 20, 1], ['tomato', 16, 1], ['bacon', 22, 1], ['onion-1', 14, 1], ['jalapeno-1', 11, 1], ['lettuce-1', 20, 0],
['pickle', 11, 0], ['tomato', 13, 0], ['jalapeno-2', 10, 0], ['sesame-1', 3.6, 0], ['sesame-2', 4, 0] ['pickle', 10, 0], ['tomato', 12, 0], ['sesame-1', 3.4, 0], ['sesame-2', 3.8, 0]
] }, ] },
'burger-sm': { seed: 5, edge: .42, reach: .72, top: -14, bottom: 88, behind: .5, hw: .72, items: [ 'burger-page': { seed: 6, food: [38, 49, 37, 47], hw: .63, reach: 30, bursts: 3, behind: .3, top: -34, bottom: 112, items: [
['lettuce-1', 18, 1], ['tomato', 14, 1], ['bacon', 18, 1], ['onion-2', 12, 1], ['pickle', 9, 0], ['sesame-1', 3, 0] ['lettuce-2', 21, 1], ['tomato', 16, 1], ['bacon', 22, 1], ['onion-1', 14, 1], ['jalapeno-1', 11, 1], ['lettuce-1', 22, 0],
['pickle', 10, 0], ['tomato', 12, 0], ['jalapeno-2', 10, 0], ['sesame-1', 3.4, 0], ['sesame-2', 3.8, 0], ['sesame-1', 3, 0]
] }, ] },
'chicken-sm': { seed: 7, edge: .42, reach: .72, top: -14, bottom: 88, behind: .5, hw: .72, items: [ 'burger-sm': { seed: 5, fly: .4, food: [39, 49, 38, 47], hw: .72, reach: 10, bursts: 2, behind: .5, top: 8, bottom: 96, left: 5, right: 95, items: [
['bacon', 18, 1], ['lettuce-2', 18, 1], ['tomato', 13, 1], ['crumb-1', 9, 1], ['crumb-2', 7, 0], ['crumb-3', 6, 0] ['lettuce-1', 17, 1], ['tomato', 13, 1], ['bacon', 17, 1], ['onion-2', 11, 0], ['sesame-1', 2.6, 0]
] }, ] },
'wrap-sm': { seed: 3, edge: .42, reach: .72, top: -14, bottom: 88, behind: .5, hw: .67, items: [ 'chicken-sm': { seed: 7, fly: .4, food: [41, 48, 40, 47], hw: .73, reach: 10, bursts: 2, behind: .5, top: 8, bottom: 96, left: 5, right: 95, items: [
['lettuce-3', 18, 1], ['tomato', 13, 1], ['jalapeno-2', 10, 1], ['onion-2', 12, 1], ['jalapeno-1', 8, 0] ['bacon', 17, 1], ['lettuce-2', 17, 1], ['tomato', 13, 1], ['crumb-1', 7, 0], ['crumb-3', 6, 0]
] }, ] },
wings: { seed: 21, edge: .4, reach: .95, top: 4, bottom: 114, behind: .45, hw: .71, items: [ 'wrap-sm': { seed: 3, fly: .4, food: [43, 48, 42, 47], hw: .67, reach: 10, bursts: 2, behind: .5, top: 8, bottom: 96, left: 5, right: 95, items: [
['crumb-1', 11, 1], ['chili', 18, 1], ['crumb-3', 10, 1], ['jalapeno-1', 11, 1], ['crumb-6', 10, 1], ['crumb-8', 10, 1], ['lettuce-3', 17, 1], ['tomato', 13, 1], ['jalapeno-2', 11, 1], ['onion-2', 11, 0]
['crumb-4', 9, 0], ['jalapeno-2', 10, 0], ['crumb-7', 8, 0], ['crumb-2', 7, 0], ['crumb-5', 7, 0], ['crumb-2', 5, 0]
] }, ] },
tenders: { seed: 9, edge: .4, reach: .92, top: -20, bottom: 116, left: 2, behind: .45, hw: .59, items: [ wings: { seed: 21, food: [50, 50, 49, 49], hw: .71, reach: 26, bursts: 3, behind: .3, top: 2, bottom: 116, items: [
['crumb-6', 10, 1], ['chili', 17, 1], ['crumb-1', 10, 1], ['jalapeno-1', 10, 1], ['crumb-3', 9, 1], ['crumb-1', 10, 1], ['chili', 17, 1], ['crumb-3', 9, 1], ['jalapeno-1', 10, 1], ['crumb-6', 9, 1], ['crumb-8', 9, 1],
['crumb-8', 9, 0], ['crumb-4', 8, 0], ['crumb-7', 7, 0], ['crumb-5', 6, 0] ['crumb-4', 8, 0], ['jalapeno-2', 9, 0], ['crumb-7', 7, 0], ['crumb-2', 6, 0], ['crumb-5', 6, 0], ['crumb-2', 4.5, 0]
] },
tenders: { seed: 12, food: [47, 42, 46, 41], hw: .59, reach: 26, bursts: 3, behind: .3, top: -34, bottom: 124, left: 0, items: [
['crumb-6', 9, 1], ['chili', 16, 1], ['crumb-1', 9, 1], ['jalapeno-1', 9, 1], ['crumb-3', 8, 1],
['crumb-8', 8, 0], ['crumb-4', 7, 0], ['crumb-7', 6, 0], ['crumb-5', 5, 0]
] } ] }
}; };
function seeded(a) { function seeded(a) {
@@ -240,22 +245,45 @@
} }
function scatter(spec) { function scatter(spec) {
var r = seeded(spec.seed), placed = [], out = []; var r = seeded(spec.seed), placed = [], out = [];
var gauss = function () { return (r() + r() + r() - 1.5) / 1.5; };
var f = spec.food, hw = spec.hw;
// Rechnen in "Box-Breite"-Einheiten, damit Abstände in x und y vergleichbar sind
var cx = f[0], cy = f[1] * hw, rx = f[2], ry = f[3] * hw;
var bursts = [];
for (var j = 0; j < spec.bursts; j++) bursts.push(r() * Math.PI * 2);
// Abstand Mitte -> Rand des Essens in Richtung a (abgerundetes Rechteck)
var edgeAt = function (a) {
var c = Math.abs(Math.cos(a)), sn = Math.abs(Math.sin(a));
var k = 1 / Math.pow(Math.pow(c, 3) + Math.pow(sn, 3), 1 / 3);
return { x: rx * k * Math.cos(a), y: ry * k * Math.sin(a) };
};
// Abstand eines Punktes zum Umriss (negativ = innen)
var outside = function (x, y) {
var dx = x - cx, dy = y - cy, a = Math.atan2(dy / ry, dx / rx);
var e = edgeAt(a), le = Math.sqrt(e.x * e.x + e.y * e.y), lp = Math.sqrt(dx * dx + dy * dy);
return lp - le;
};
spec.items.forEach(function (it) { spec.items.forEach(function (it) {
for (var k = 0; k < 80; k++) { for (var k = 0; k < 240; k++) {
var a = r() * Math.PI * 2; var a = r() < .75 ? bursts[Math.floor(r() * bursts.length)] + gauss() * .7 : r() * Math.PI * 2;
var d = spec.edge + Math.pow(r(), 2.4) * (spec.reach - spec.edge) + (r() - .5) * .06; var size = it[1] * (.75 + r() * .5);
var x = 50 + Math.cos(a) * d * 100, y = 50 + Math.sin(a) * d * 100; var behind = r() < spec.behind && size > 5;
if (y < spec.top || y > spec.bottom || x < (spec.left != null ? spec.left : -60) || x > (spec.right != null ? spec.right : 160)) continue; var e = edgeAt(a), le = Math.sqrt(e.x * e.x + e.y * e.y);
var size = it[1] * 1.35 * (.8 + r() * .4) * (1 - Math.max(0, d - spec.edge) * .45); // hinter dem Essen: halb versteckt; davor: frei, dicht am Rand häufiger als weit außen
var gap = behind ? size * (r() * .25 - .1) : size * .38 + Math.pow(r(), 1.7) * spec.reach;
var x = cx + e.x / le * (le + gap), y = cy + e.y / le * (le + gap);
var yp = y / hw;
// hohe Teile (Salatblatt) ragen weiter nach oben/unten: halbe Höhe großzügig mit 0,75 × Größe ansetzen
if ((y - size * .75) / hw < spec.top || (y + size * .75) / hw > spec.bottom || x - size / 2 < (spec.left != null ? spec.left : -70) || x + size / 2 > (spec.right != null ? spec.right : 170)) continue;
if (!behind && outside(x, y) < size * .3) continue;
var free = placed.every(function (p) { var free = placed.every(function (p) {
var dx = p.x - x, dy = (p.y - y) * spec.hw; var dx = p.x - x, dy = p.y - y;
return Math.sqrt(dx * dx + dy * dy) > (p.s + size) * .42; return Math.sqrt(dx * dx + dy * dy) > (p.s + size) * .48;
}); });
if (!free) continue; if (!free) continue;
var p = { x: x, y: y, s: size }; placed.push({ x: x, y: y, s: size });
placed.push(p); // weiter außen etwas kleiner
var near = d < spec.edge + .08; out.push([it[0], +x.toFixed(1), +yp.toFixed(1), +size.toFixed(1), Math.round(gauss() * 70), behind ? 'b' : 'f', it[2], r() < .5 ? 1 : 0]);
out.push([it[0], +x.toFixed(1), +y.toFixed(1), +size.toFixed(1), Math.round((r() - .5) * 140), near && r() < spec.behind ? 'b' : 'f', it[2], r() < .5 ? 1 : 0]);
return; return;
} }
}); });
@@ -299,7 +327,7 @@
bits.push({ el: el, inner: inner, fl: fl, x: b[1], y: b[2], layer: b[5] }); bits.push({ el: el, inner: inner, fl: fl, x: b[1], y: b[2], layer: b[5] });
}); });
box.appendChild(holder); box.appendChild(holder);
return { box: box, bits: bits, hero: !lazy }; return { box: box, bits: bits, hero: !lazy, fly: spec.fly || 1 };
}).filter(Boolean); }).filter(Boolean);
/* ---------- Flammen nur animieren, solange sie sichtbar sind ---------- */ /* ---------- Flammen nur animieren, solange sie sichtbar sind ---------- */
@@ -508,6 +536,7 @@
}; };
// Explosionsziel: kräftig nach außen, mit Drall zur Seite und nach oben // Explosionsziel: kräftig nach außen, mit Drall zur Seite und nach oben
var away = function (b, k) { var away = function (b, k) {
k *= bl.fly;
var v = vec(b), len = Math.sqrt(v.x * v.x + v.y * v.y) || 1; var v = vec(b), len = Math.sqrt(v.x * v.x + v.y * v.y) || 1;
var side = b.side; var side = b.side;
return { return {
+1 -1
View File
@@ -80,7 +80,7 @@
<h1 class="display x3d" id="page-title" data-hero-big>Die Karte</h1> <h1 class="display x3d" id="page-title" data-hero-big>Die Karte</h1>
<p class="lead">Wings, Tenders, Burger, Wraps und Sides – alles mild oder scharf, zum Mitnehmen, geliefert oder direkt bei uns.</p> <p class="lead">Wings, Tenders, Burger, Wraps und Sides – alles mild oder scharf, zum Mitnehmen, geliefert oder direkt bei uns.</p>
</div> </div>
<div class="page-hero__img blast" data-blast="burger" data-blast-mode="hero"><span class="hero__glow" aria-hidden="true"></span><img class="shot blast__food" src="assets/img/menu/steakhouse-burger.webp" width="834" height="526" alt="Steakhouse Burger mit Pepper-Jack-Käse und Bacon"></div> <div class="page-hero__img blast" data-blast="burger-page" data-blast-mode="hero"><span class="hero__glow" aria-hidden="true"></span><img class="shot blast__food" src="assets/img/menu/steakhouse-burger.webp" width="834" height="526" alt="Steakhouse Burger mit Pepper-Jack-Käse und Bacon"></div>
<span class="sticker sticker--ink page-hero__st" data-sticker>Mild oder<br>scharf?</span> <span class="sticker sticker--ink page-hero__st" data-sticker>Mild oder<br>scharf?</span>
<div class="flames flames--in" aria-hidden="true" style="--flame-front: var(--cream)"><i></i><i></i><i></i></div> <div class="flames flames--in" aria-hidden="true" style="--flame-front: var(--cream)"><i></i><i></i><i></i></div>
</section> </section>