Highscore-Hintergrund: größere, abwechslungsreichere und kräftigere Animationen; Mond zieht über die volle Breite
This commit is contained in:
parent
3922089eff
commit
aceb783584
|
|
@ -60,9 +60,14 @@
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
/* Karten sind bewusst deckend (dunkel, frosted): die Hintergrund-Animationen
|
||||||
|
laufen dahinter und können die Inhalte nie überdecken oder unleserlich machen. */
|
||||||
.slot {
|
.slot {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: rgba(255, 255, 255, 0.16);
|
background: rgba(16, 26, 54, 0.8);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -71,11 +76,11 @@
|
||||||
min-height: 56px;
|
min-height: 56px;
|
||||||
}
|
}
|
||||||
.slot.empty {
|
.slot.empty {
|
||||||
background: rgba(255, 255, 255, 0.06);
|
background: rgba(16, 26, 54, 0.45);
|
||||||
}
|
}
|
||||||
.slot.current {
|
.slot.current {
|
||||||
background: rgba(255, 229, 102, 0.3);
|
border-color: var(--c-rocket-window);
|
||||||
box-shadow: 0 0 0 3px var(--c-rocket-window);
|
box-shadow: 0 0 0 2px var(--c-rocket-window), 0 0 18px rgba(255, 229, 102, 0.5);
|
||||||
}
|
}
|
||||||
.crown {
|
.crown {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
|
|
@ -8,158 +8,155 @@
|
||||||
|
|
||||||
let { stage }: { stage: Stage } = $props();
|
let { stage }: { stage: Stage } = $props();
|
||||||
|
|
||||||
// Deko lebt ausschließlich in zwei Seiten-Zonen links und rechts der zentrierten
|
// Animationen füllen die ganze Fläche hinter den (deckenden) Karten. l/t/b in %,
|
||||||
// Highscore-Spalte. Die Zonen klammern die Spalte aus und sind geclippt, sodass
|
// s = Größe, d = Dauer (s), dl = Verzögerung (s), flip/rot = Variation, c/sc/cv = Symbol-Variante.
|
||||||
// keine Animation jemals über eine Karte läuft.
|
type Deco = {
|
||||||
// l = Position in % innerhalb der Zone, t/b = oben/unten in %, s = Größe,
|
l: number; t?: number; b?: number; s: number; d: number; dl: number;
|
||||||
// d = Dauer (s), dl = Verzögerung (s), side = Zone.
|
flip?: boolean; rot?: number; c?: number; sc?: number; cv?: number;
|
||||||
type Side = 'l' | 'r';
|
};
|
||||||
type Deco = { side: Side; l: number; t?: number; b?: number; s: number; d: number; dl: number };
|
|
||||||
|
// Ballon-Farbvarianten [Körper, Kontur].
|
||||||
|
const BALLOON_COLORS = [
|
||||||
|
['#ff8aa8', '#c25578'],
|
||||||
|
['#6cc2ff', '#3a82c2'],
|
||||||
|
['#7ad17a', '#3f8f3f'],
|
||||||
|
['#ffd24a', '#c79a2a'],
|
||||||
|
['#c79aff', '#8a5fd0'],
|
||||||
|
];
|
||||||
|
const STAR_COLORS = ['#ffe34a', '#ffffff', '#a8e8ff', '#ffd24a'];
|
||||||
|
|
||||||
const balloons: Deco[] = [
|
const balloons: Deco[] = [
|
||||||
{ side: 'l', l: 55, t: 58, s: 62, d: 4.5, dl: 0 },
|
{ l: 5, t: 52, s: 92, c: 0, rot: -5, d: 3.6, dl: 0 },
|
||||||
{ side: 'l', l: 25, t: 26, s: 44, d: 5.2, dl: 0.6 },
|
{ l: 17, t: 12, s: 62, c: 1, flip: true, rot: 7, d: 4.3, dl: 0.7 },
|
||||||
{ side: 'l', l: 70, t: 82, s: 38, d: 5.0, dl: 0.4 },
|
{ l: 31, t: 76, s: 76, c: 2, rot: 3, d: 3.9, dl: 0.3 },
|
||||||
{ side: 'r', l: 40, t: 54, s: 68, d: 4.0, dl: 0.3 },
|
{ l: 58, t: 28, s: 70, c: 3, flip: true, rot: -6, d: 4.6, dl: 1.0 },
|
||||||
{ side: 'r', l: 65, t: 22, s: 48, d: 5.6, dl: 0.9 },
|
{ l: 80, t: 60, s: 96, c: 4, rot: 4, d: 3.4, dl: 0.2 },
|
||||||
{ side: 'r', l: 20, t: 78, s: 40, d: 4.8, dl: 1.2 },
|
{ l: 91, t: 16, s: 58, c: 1, flip: true, rot: -3, d: 4.8, dl: 0.5 },
|
||||||
|
{ l: 69, t: 86, s: 60, c: 0, rot: 5, d: 4.0, dl: 0.9 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const clouds: Deco[] = [
|
const clouds: Deco[] = [
|
||||||
{ side: 'l', l: 18, t: 16, s: 88, d: 9, dl: 0 },
|
{ l: 3, t: 16, s: 124, cv: 0, d: 7.5, dl: 0 },
|
||||||
{ side: 'l', l: 42, t: 70, s: 78, d: 10, dl: 0.5 },
|
{ l: 24, t: 62, s: 102, cv: 1, flip: true, d: 9, dl: 0.6 },
|
||||||
{ side: 'l', l: 58, t: 44, s: 68, d: 9.5, dl: 0.8 },
|
{ l: 13, t: 82, s: 92, cv: 0, flip: true, d: 8.4, dl: 1.2 },
|
||||||
{ side: 'r', l: 22, t: 24, s: 100, d: 11, dl: 1 },
|
{ l: 57, t: 22, s: 146, cv: 1, d: 7, dl: 0.3 },
|
||||||
{ side: 'r', l: 40, t: 78, s: 92, d: 8.5, dl: 1.5 },
|
{ l: 79, t: 64, s: 112, cv: 0, flip: true, d: 9.4, dl: 0.9 },
|
||||||
];
|
{ l: 88, t: 38, s: 96, cv: 1, d: 8, dl: 1.5 },
|
||||||
|
|
||||||
const moonStars: Deco[] = [
|
|
||||||
{ side: 'l', l: 30, t: 24, s: 24, d: 2.2, dl: 0 },
|
|
||||||
{ side: 'l', l: 55, t: 58, s: 18, d: 2.8, dl: 0.5 },
|
|
||||||
{ side: 'l', l: 18, t: 76, s: 22, d: 2.4, dl: 0.9 },
|
|
||||||
{ side: 'r', l: 65, t: 62, s: 20, d: 2.6, dl: 0.3 },
|
|
||||||
{ side: 'r', l: 35, t: 44, s: 16, d: 3.0, dl: 1.1 },
|
|
||||||
{ side: 'r', l: 72, t: 32, s: 16, d: 2.5, dl: 0.7 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const stars: Deco[] = [
|
const stars: Deco[] = [
|
||||||
{ side: 'l', l: 25, t: 18, s: 28, d: 2.2, dl: 0 },
|
{ l: 7, t: 15, s: 42, sc: 0, rot: 0, d: 1.8, dl: 0 },
|
||||||
{ side: 'l', l: 55, t: 46, s: 20, d: 2.6, dl: 0.6 },
|
{ l: 19, t: 49, s: 28, sc: 1, rot: 18, d: 2.4, dl: 0.5 },
|
||||||
{ side: 'l', l: 18, t: 70, s: 24, d: 2.4, dl: 1.0 },
|
{ l: 11, t: 79, s: 36, sc: 2, rot: -12, d: 2.0, dl: 1.0 },
|
||||||
{ side: 'l', l: 65, t: 82, s: 16, d: 3.0, dl: 0.3 },
|
{ l: 34, t: 29, s: 24, sc: 0, rot: 8, d: 2.6, dl: 0.3 },
|
||||||
{ side: 'l', l: 40, t: 32, s: 14, d: 3.1, dl: 1.4 },
|
{ l: 29, t: 88, s: 32, sc: 3, rot: -8, d: 2.2, dl: 0.8 },
|
||||||
{ side: 'r', l: 60, t: 20, s: 26, d: 2.3, dl: 0.8 },
|
{ l: 61, t: 13, s: 34, sc: 0, rot: 14, d: 1.9, dl: 0.4 },
|
||||||
{ side: 'r', l: 35, t: 46, s: 18, d: 2.7, dl: 0.2 },
|
{ l: 73, t: 47, s: 48, sc: 1, rot: -10, d: 2.3, dl: 0.1 },
|
||||||
{ side: 'r', l: 70, t: 70, s: 22, d: 2.5, dl: 1.2 },
|
{ l: 66, t: 82, s: 26, sc: 2, rot: 6, d: 2.7, dl: 1.1 },
|
||||||
{ side: 'r', l: 30, t: 82, s: 16, d: 2.9, dl: 0.5 },
|
{ l: 87, t: 23, s: 40, sc: 0, rot: -16, d: 2.0, dl: 0.7 },
|
||||||
{ side: 'r', l: 55, t: 34, s: 14, d: 2.8, dl: 0.9 },
|
{ l: 93, t: 61, s: 30, sc: 3, rot: 10, d: 2.5, dl: 0.2 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const grass: Deco[] = [
|
const grass: Deco[] = [
|
||||||
{ side: 'l', l: 25, b: 2, s: 46, d: 3.0, dl: 0 },
|
{ l: 5, b: 1, s: 66, d: 2.4, dl: 0 },
|
||||||
{ side: 'l', l: 60, b: 2, s: 38, d: 3.4, dl: 0.4 },
|
{ l: 19, b: 2, s: 48, flip: true, d: 2.8, dl: 0.4 },
|
||||||
{ side: 'r', l: 30, b: 2, s: 44, d: 2.8, dl: 0.2 },
|
{ l: 33, b: 1, s: 56, d: 2.2, dl: 0.7 },
|
||||||
{ side: 'r', l: 65, b: 2, s: 36, d: 3.2, dl: 0.6 },
|
{ l: 63, b: 2, s: 50, flip: true, d: 2.6, dl: 0.2 },
|
||||||
|
{ l: 78, b: 1, s: 70, d: 2.3, dl: 0.9 },
|
||||||
|
{ l: 90, b: 2, s: 46, flip: true, d: 2.7, dl: 0.5 },
|
||||||
];
|
];
|
||||||
|
|
||||||
function pos(d: Deco): string {
|
function baseStyle(d: Deco): string {
|
||||||
const vert = d.b != null ? `bottom:${d.b}%` : `top:${d.t}%`;
|
const vert = d.b != null ? `bottom:${d.b}%` : `top:${d.t}%`;
|
||||||
return `left:${d.l}%; ${vert}; --dur:${d.d}s; animation-delay:${d.dl}s`;
|
return `left:${d.l}%; ${vert}; transform: scaleX(${d.flip ? -1 : 1}) rotate(${d.rot ?? 0}deg);`;
|
||||||
}
|
}
|
||||||
|
const fx = (d: Deco) => `--dur:${d.d}s; animation-delay:${d.dl}s`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet layer(side: Side)}
|
<div class="ambience" aria-hidden="true">
|
||||||
{#if stage === 1}
|
{#if stage === 1}
|
||||||
{#each balloons.filter((d) => d.side === side) as d, i (i)}
|
{#each balloons as d, i (i)}
|
||||||
<span class="deco bob" style={pos(d)}><Balloon size={d.s} /></span>
|
<span class="deco" style={baseStyle(d)}>
|
||||||
|
<span class="anim float" style={fx(d)}>
|
||||||
|
<Balloon size={d.s} color={BALLOON_COLORS[d.c ?? 0][0]} stroke={BALLOON_COLORS[d.c ?? 0][1]} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if stage === 2}
|
{:else if stage === 2}
|
||||||
{#each clouds.filter((d) => d.side === side) as d, i (i)}
|
{#each clouds as d, i (i)}
|
||||||
<span class="deco drift" style={pos(d)}><Cloud size={d.s} opacity={0.92} /></span>
|
<span class="deco" style={baseStyle(d)}>
|
||||||
|
<span class="anim drift" style={fx(d)}><Cloud size={d.s} variant={d.cv ?? 0} opacity={0.95} /></span>
|
||||||
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if stage === 3}
|
{:else if stage === 3}
|
||||||
{#if side === 'r'}
|
<!-- Mond zieht eine Bahn über die ganze Breite, keine Sterne (sonst Verwechslung mit dem Stern-Level). -->
|
||||||
<span class="deco glow" style="left:42%; top:14%; --dur:5s; animation-delay:0s"><Moon size={80} /></span>
|
<span class="moon"><Moon size={104} /></span>
|
||||||
{/if}
|
|
||||||
{#each moonStars.filter((d) => d.side === side) as d, i (i)}
|
|
||||||
<span class="deco twinkle" style={pos(d)}><Star size={d.s} color="#fff7c8" /></span>
|
|
||||||
{/each}
|
|
||||||
{:else if stage >= 4}
|
{:else if stage >= 4}
|
||||||
{#each stars.filter((d) => d.side === side) as d, i (i)}
|
{#each stars as d, i (i)}
|
||||||
<span class="deco twinkle" style={pos(d)}><Star size={d.s} /></span>
|
<span class="deco" style={baseStyle(d)}>
|
||||||
|
<span class="anim twinkle" style={fx(d)}><Star size={d.s} color={STAR_COLORS[d.sc ?? 0]} /></span>
|
||||||
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
{#each grass.filter((d) => d.side === side) as d, i (i)}
|
{#each grass as d, i (i)}
|
||||||
<span class="deco sway" style={pos(d)}><Ground size={d.s} /></span>
|
<span class="deco" style={baseStyle(d)}>
|
||||||
|
<span class="anim sway" style={fx(d)}><Ground size={d.s} /></span>
|
||||||
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
<div class="ambience" aria-hidden="true">
|
|
||||||
<div class="zone left">{@render layer('l')}</div>
|
|
||||||
<div class="zone right">{@render layer('r')}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* --reserve = halbe Kartenbreite (60px) + Abstand. So bleibt die zentrierte
|
|
||||||
Spalte garantiert frei und die Zonen clippen alles, was hineinragen würde. */
|
|
||||||
.ambience {
|
.ambience {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
--reserve: 80px;
|
|
||||||
}
|
|
||||||
.zone {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.zone.left {
|
|
||||||
left: 0;
|
|
||||||
right: calc(50% + var(--reserve));
|
|
||||||
}
|
|
||||||
.zone.right {
|
|
||||||
left: calc(50% + var(--reserve));
|
|
||||||
right: 0;
|
|
||||||
}
|
}
|
||||||
.deco {
|
.deco {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0.9;
|
}
|
||||||
|
.anim {
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bob { animation: bob var(--dur, 4s) ease-in-out infinite alternate; }
|
.float { animation: float var(--dur, 3.6s) ease-in-out infinite alternate; }
|
||||||
@keyframes bob {
|
@keyframes float {
|
||||||
from { transform: translateY(8px) rotate(-3deg); }
|
0% { transform: translateY(18px) rotate(-5deg); }
|
||||||
to { transform: translateY(-16px) rotate(3deg); }
|
100% { transform: translateY(-30px) rotate(5deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.drift { animation: drift var(--dur, 9s) ease-in-out infinite alternate; }
|
.drift { animation: drift var(--dur, 8s) ease-in-out infinite alternate; }
|
||||||
@keyframes drift {
|
@keyframes drift {
|
||||||
from { transform: translateX(-22px); }
|
from { transform: translateX(-55px); }
|
||||||
to { transform: translateX(22px); }
|
to { transform: translateX(55px); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.twinkle { animation: twinkle var(--dur, 2.4s) ease-in-out infinite; }
|
.twinkle { animation: twinkle var(--dur, 2.2s) ease-in-out infinite; }
|
||||||
@keyframes twinkle {
|
@keyframes twinkle {
|
||||||
0%, 100% { opacity: 0.3; transform: scale(0.75); }
|
0%, 100% { opacity: 0.25; transform: scale(0.5); }
|
||||||
50% { opacity: 1; transform: scale(1.15); }
|
50% { opacity: 1; transform: scale(1.35); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.glow { animation: glow var(--dur, 5s) ease-in-out infinite alternate; }
|
.sway { animation: sway var(--dur, 2.5s) ease-in-out infinite alternate; transform-origin: bottom center; }
|
||||||
@keyframes glow {
|
|
||||||
from { filter: drop-shadow(0 0 4px rgba(255, 233, 163, 0.4)); transform: translateY(0); }
|
|
||||||
to { filter: drop-shadow(0 0 16px rgba(255, 233, 163, 0.9)); transform: translateY(-8px); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.sway { animation: sway var(--dur, 3s) ease-in-out infinite alternate; transform-origin: bottom center; }
|
|
||||||
@keyframes sway {
|
@keyframes sway {
|
||||||
from { transform: rotate(-7deg); }
|
from { transform: rotate(-12deg); }
|
||||||
to { transform: rotate(7deg); }
|
to { transform: rotate(12deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.moon {
|
||||||
|
position: absolute;
|
||||||
|
filter: drop-shadow(0 0 18px rgba(255, 233, 163, 0.85));
|
||||||
|
animation: moonpath 12s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes moonpath {
|
||||||
|
0% { left: -16%; top: 36%; }
|
||||||
|
50% { top: 14%; }
|
||||||
|
100% { left: 112%; top: 36%; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.deco { animation: none; }
|
.anim, .moon { animation: none; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user