perf(theme): make landing animations fully composited
CI / check (push) Successful in 4m12s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m19s

Keep every animation transform/opacity-only so frames never repaint:
- hero ring and loading glow pulse via opacity instead of background-position / box-shadow
- button shine sweeps with transform, not left
- floating glass chips drop animated backdrop-filter (it re-samples every frame)
- promote continuously animated layers (particles, halo, float) with will-change
- drop the negligible blur on moving clouds and remove the unused gradient-shift
This commit is contained in:
openhands committed 2026-09-18 12:51:02 +02:00
1 parent 4acafcfef6
commit 4b5dda467c
1 file changed
+26 -30
+26 -30
View File
@@ -380,7 +380,6 @@ summary,
left: 0;
opacity: 0.7;
transform: scale(var(--cloud-scale, 1));
filter: blur(0.5px);
will-change: transform;
animation-name: cloud-drift;
animation-timing-function: linear;
@@ -688,6 +687,7 @@ html.dark .site-backdrop-blob {
opacity: 0;
animation: particle-rise var(--dot-duration, 12s) linear infinite;
animation-delay: var(--dot-delay, 0s);
will-change: transform;
}
@keyframes particle-rise {
0% {
@@ -2055,17 +2055,6 @@ details[open] > summary .details-open\:rotate-180 {
opacity: 0.4;
}
}
@keyframes gradient-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes fade-in-up {
from {
opacity: 0;
@@ -2089,25 +2078,20 @@ details[open] > summary .details-open\:rotate-180 {
@keyframes pulse-glow {
0%,
100% {
box-shadow: 0 0 8px
color-mix(in srgb, var(--color-primary) 25%, transparent);
opacity: 0.5;
}
50% {
box-shadow: 0 0 24px
color-mix(in srgb, var(--color-primary) 45%, transparent);
opacity: 1;
}
}
.animate-float {
animation: float 4s ease-in-out infinite;
will-change: transform;
}
.animate-shimmer {
animation: shimmer-glow 2.5s ease-in-out infinite;
}
.animate-gradient {
background-size: 200% 200%;
animation: gradient-shift 8s ease infinite;
}
.animate-fade-in-up {
animation: fade-in-up 0.6s ease-out both;
}
@@ -2256,12 +2240,13 @@ details[open] > summary .details-open\:rotate-180 {
transparent 65%,
transparent 100%
);
transform: rotate(25deg);
transition: all 0.5s ease;
transform: translateX(-60%) rotate(25deg);
transition: transform 0.6s cubic-bezier(0.33, 1, 0.68, 1);
pointer-events: none;
will-change: transform;
}
.btn-shine:hover::after {
left: 100%;
transform: translateX(30%) rotate(25deg);
}
/* Staggered children animation */
@@ -2406,6 +2391,7 @@ html {
/* Gentle breathing pulse for the brand glows behind Frank / the hero. */
.brand-halo {
animation: hero-halo-pulse 6s ease-in-out infinite;
will-change: transform;
}
@keyframes hero-halo-pulse {
0%,
@@ -2434,7 +2420,8 @@ html {
}
/* ── Hero pro touches ──────────────────────────────────────────────── */
/* Continuously shifting gradient hairline drawn on the hero border. */
/* Continuously shifting gradient hairline drawn on the hero border.
Animated with opacity only (fully composited — no per-frame repaint). */
.hero-ring {
position: absolute;
inset: 0;
@@ -2448,8 +2435,6 @@ html {
color-mix(in srgb, var(--color-accent) 60%, transparent) 65%,
color-mix(in srgb, var(--color-primary) 70%, transparent) 100%
);
background-size: 260% 260%;
animation: gradient-shift 14s ease-in-out infinite;
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
@@ -2459,23 +2444,34 @@ html {
linear-gradient(#fff 0 0);
mask-composite: exclude;
pointer-events: none;
animation: hero-ring-pulse 14s ease-in-out infinite;
}
@keyframes hero-ring-pulse {
0%,
100% {
opacity: 0.75;
}
50% {
opacity: 1;
}
}
/* Frosted floating stat chips that bob gently on the hero. */
/* Frosted floating stat chips that bob gently on the hero.
No backdrop-filter while animating: sampling the backdrop every frame is
expensive, so the chips use a higher-opacity fill instead. */
.glass-chip {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.45rem 0.85rem;
border-radius: 999px;
background: color-mix(in srgb, var(--color-surface) 38%, transparent);
background: color-mix(in srgb, var(--color-surface) 72%, transparent);
border: 1px solid color-mix(in srgb, var(--color-text-muted) 14%, transparent);
box-shadow:
0 10px 26px -10px color-mix(in srgb, #000 30%, transparent),
inset 0 1px 0 0 color-mix(in srgb, #fff 12%, transparent);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
animation: float 5s ease-in-out infinite;
will-change: transform;
}
.glass-chip:nth-child(2) {
animation-delay: -1.7s;