openvibers/openvibe.live Commits

Nothing spins on Live: loaders pulse, the star ring shimmers, the old mark springs (#491)

OP OpenVibers committed 13 days ago · b0601f2a52 · 7 files, +26 −31

Changes

ddiff --git a/public/css/features/broadcast.css b/public/css/features/broadcast.css
iindex 511a6785..5ab3f18a 100644
---- a/public/css/features/broadcast.css
++++ b/public/css/features/broadcast.css
@@@ -2635,8 +2635,8 @@ body.bc-studio-on .toast-container { z-index: 1500; }
.bcs-state[hidden] { display: none; }
.bcs-state b { font-size: 0.98rem; }
.bcs-state small { font-size: 0.78rem; color: rgba(255, 255, 255, 0.75); }
--.bcs-state-spin { width: 26px; height: 26px; border-radius: 50%; border: 3px solid rgba(255, 255, 255, 0.25); border-top-color: #fff; animation: bcs-spin 0.9s linear infinite; }
--@keyframes bcs-spin { to { transform: rotate(360deg); } }
++.bcs-state-spin { width: 26px; height: 26px; border-radius: 50%; border: 3px solid #fff; animation: bcs-pulse 1.4s ease-out infinite; } /* a ring that pulses out: nothing spins */
++@keyframes bcs-pulse { from { box-shadow: 0 0 0 0 rgba(255,255,255,.5); } to { box-shadow: 0 0 0 10px rgba(255,255,255,0); } }
/* Flip with more than two cameras: a small "+" (hold it to choose). */
.bcs-btn[data-act="flip"] { position: relative; }
.bcs-more-cams {
ddiff --git a/public/css/features/channel.css b/public/css/features/channel.css
iindex ce2fc183..ae483f0a 100644
---- a/public/css/features/channel.css
++++ b/public/css/features/channel.css
@@@ -785,9 +785,8 @@ button.viewer-badge:focus-visible { outline: 2px solid #93c5fd; outline-offset:
.stream-switch-spinner::before {
inset: 18%;
-- border: 2px solid rgba(255,255,255,0.2);
-- border-top-color: rgba(255,255,255,0.9);
-- animation: spin 1s linear infinite reverse;
++ border: 2px solid rgba(255,255,255,0.9);
++ animation: spin 1.2s ease-in-out infinite; /* "spin" breathes now (style.css): nothing spins */
}
.stream-switch-spinner::after {
ddiff --git a/public/css/features/dashboard.css b/public/css/features/dashboard.css
iindex 5f3c5570..4f2b8892 100644
---- a/public/css/features/dashboard.css
++++ b/public/css/features/dashboard.css
@@@ -15,7 +15,7 @@
.pc-fade-in { animation: pcFadeIn .22s ease-out; }
.pc-card-in { animation: pcCardIn .4s cubic-bezier(.34,1.4,.64,1); }
#dash-powerchat-card.pc-busy { border-color: color-mix(in srgb, var(--accent) 50%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 25%, transparent), 0 6px 24px color-mix(in srgb, var(--accent) 12%, transparent); }
--.pc-spinner { width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; border: 2px solid color-mix(in srgb, var(--accent) 25%, transparent); border-top-color: var(--accent, var(--accent)); display: inline-block; animation: pcSpin .7s linear infinite; }
++.pc-spinner { width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; border: 2px solid var(--accent); display: inline-block; animation: pcSpin 1.2s ease-in-out infinite; }
.pc-ellipsis span { animation: pcBlink 1.2s infinite both; }
.pc-ellipsis span:nth-child(2) { animation-delay: .2s; }
.pc-ellipsis span:nth-child(3) { animation-delay: .4s; }
ddiff --git a/public/css/features/home.css b/public/css/features/home.css
iindex 9d1dd1f6..f1159594 100644
---- a/public/css/features/home.css
++++ b/public/css/features/home.css
@@@ -915,7 +915,7 @@ body.egg-rainbow { animation: eggRainbow 2.6s linear; }
.star-card.is-compact .star-avatar-ring {
inset: -3px; border-radius: 50%;
background: conic-gradient(from 0deg, var(--star-gold), #f472b6, var(--accent), var(--star-gold));
-- animation: starRingSpin 6s linear infinite;
++ animation: starRingSpin 6s ease-in-out infinite;
opacity: 0.9;
}
.star-card.is-compact:hover .star-avatar-ring { opacity: 1; }
ddiff --git a/public/css/i18n-star.css b/public/css/i18n-star.css
iindex 01ac3c3f..0ff31c59 100644
---- a/public/css/i18n-star.css
++++ b/public/css/i18n-star.css
@@@ -47,7 +47,7 @@
position: relative; border-radius: 22px; padding: 2px; overflow: hidden; isolation: isolate;
animation: starCardIn 0.8s cubic-bezier(.2,1.3,.3,1) both;
}
--@keyframes starSpin { to { transform: rotate(360deg); } }
++@keyframes starSpin { 50% { filter: hue-rotate(50deg) brightness(1.15); } } /* the ring shimmers in colour; it never turns */
@keyframes starCardIn { from { opacity: 0; transform: translateY(24px) scale(0.97); } to { opacity: 1; transform: none; } }
.star-card {
position: relative; border-radius: 20px; overflow: hidden;
@@@ -164,9 +164,9 @@
/* Expanded (non-compact) card: both blocks run the full width under the avatar and text. */
@keyframes starMoreIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
--/* The avatar ring: a slow conic sweep rather than a static rainbow, so the card has one moving
-- element instead of several competing ones. Paused off-screen by the viewport gate. */
--@keyframes starRingSpin { to { transform: rotate(360deg); } }
++/* The avatar ring: its colours shimmer slowly rather than a static rainbow, so the card has one moving
++ element instead of several competing ones; it never turns. Paused off-screen by the viewport gate. */
++@keyframes starRingSpin { 50% { filter: hue-rotate(50deg) brightness(1.15); } }
/* The gold border sweep is the card's one loud effect; calm it down when compact so it frames
the card instead of shouting over it. */
ddiff --git a/public/css/media-player.css b/public/css/media-player.css
iindex 80fab64b..70b3740a 100644
---- a/public/css/media-player.css
++++ b/public/css/media-player.css
@@@ -77,12 +77,11 @@ code { background: rgba(255,255,255,.08); padding: 2px 6px; border-radius: 6px;
.mp-spinner {
width: 40px; height: 40px;
-- border: 3px solid rgba(139,92,246, 0.2);
-- border-top-color: var(--mp-accent);
++ border: 3px solid var(--mp-accent);
border-radius: 50%;
-- animation: mp-spin 0.8s linear infinite;
++ animation: mp-pulse 1.4s ease-out infinite; /* a ring that pulses out: nothing spins */
}
--@keyframes mp-spin { to { transform: rotate(360deg); } }
++@keyframes mp-pulse { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mp-accent) 55%, transparent); } to { box-shadow: 0 0 0 12px transparent; } }
/* ── Custom player controls ──────────────────────────────── */
.mp-controls {
ddiff --git a/public/css/style.css b/public/css/style.css
iindex f8c7e36e..abe396a5 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -2022,11 +2022,6 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
color: rgba(191, 219, 254, 0.94);
}
--@keyframes playerLoaderDrift {
-- from { transform: rotate(0deg) translate3d(0, 0, 0); }
-- to { transform: rotate(360deg) translate3d(0, 0, 0); }
--}
--
@keyframes playerLoaderMorph {
0% { border-radius: 42% 58% 53% 47% / 45% 44% 56% 55%; transform: scale(0.96) rotate(0deg); }
50% { border-radius: 58% 42% 46% 54% / 40% 60% 40% 60%; transform: scale(1.04) rotate(8deg); }
@@@ -2038,8 +2033,9 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
50% { transform: translateY(-10px) translateX(6px); }
}
++/* The owner: nothing spins. The loader's arc breathes where it once turned. */
@keyframes playerLoaderRotate {
-- to { transform: rotate(360deg); }
++ 50% { opacity: 0.45; transform: scale(0.94); }
}
@keyframes playerLoaderPulse {
@@@ -3500,7 +3496,7 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
@keyframes pcDotPulse { 0%,100% { box-shadow: 0 0 5px rgba(83,252,24,0.5); } 50% { box-shadow: 0 0 11px rgba(83,252,24,0.9); } }
/* Connecting state */
--@keyframes pcSpin { to { transform: rotate(360deg); } }
++@keyframes pcSpin { 50% { opacity: 0.4; transform: scale(0.85); } }
.pc-connecting-text { color: var(--text-secondary); }
@keyframes pcBlink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }
@@@ -4469,9 +4465,10 @@ body :is(.modal-overlay, .bc-ws-confirm-overlay, .bc-modal, .bc-perm-overlay, .b
0 0 0 1px rgba(255,255,255,0.1),
0 18px 32px rgba(0,0,0,0.3),
inset 0 0 26px rgba(255,255,255,0.08);
-- animation: playerLoaderMorph 5.8s ease-in-out infinite alternate, spin 1.9s linear infinite;
++ animation: playerLoaderMorph 5.8s ease-in-out infinite alternate;
}
--@keyframes spin { to { transform: rotate(360deg); } }
++/* "spin" is kept as a name for older rules, but it breathes: nothing spins (design lint, plan L45). */
++@keyframes spin { 50% { opacity: 0.45; transform: scale(0.85); } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
/* ── Cumulative Viewers (below video info bar) ──────────── */
@@@ -9547,17 +9544,17 @@ label.staff-inline-toggle.aiv-field { flex-direction:row; align-items:center; }
.nav-brand:hover .ov-v, .hero h1:hover .ov-v { animation: ovDraw 0.7s cubic-bezier(.2,.8,.2,1) both; }
@keyframes ovFloat { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-1px) rotate(2deg); } }
@keyframes ovGlow { 0%, 100% { opacity: 0.08; transform: scale(0.92); } 50% { opacity: 0.2; transform: scale(1.06); } }
--@keyframes ovComet { to { transform: rotate(360deg); } }
++@keyframes ovComet { 50% { opacity: 0.35; } }
@keyframes ovDraw { from { stroke-dashoffset: 46; } to { stroke-dashoffset: 0; } }
@keyframes ovDot { 0%, 100% { transform: scale(1); opacity: 0.85; } 50% { transform: scale(1.5); opacity: 1; } }
--@keyframes ovSpin { from { transform: rotate(0deg) scale(1); } 40% { transform: rotate(200deg) scale(1.18); } to { transform: rotate(360deg) scale(1); } }
--/* One spin as the route lands, on a spring-ish curve that overshoots past 360 and eases back. */
++@keyframes ovSpin { 40% { transform: scale(1.18); } }
++/* One spring as the route lands: it grows past its size and settles (it no longer turns). */
.brand-mark.is-spin svg { animation: ovSpinIn 1.05s cubic-bezier(.16, 1.16, .3, 1) 1 both; animation-play-state: running; }
@keyframes ovSpinIn {
-- 0% { transform: rotate(0deg) scale(0.86); }
-- 45% { transform: rotate(228deg) scale(1.2); }
-- 72% { transform: rotate(348deg) scale(0.97); }
-- 100% { transform: rotate(360deg) scale(1); }
++ 0% { transform: scale(0.86); }
++ 45% { transform: scale(1.2); }
++ 72% { transform: scale(0.97); }
++ 100% { transform: scale(1); }
}
/* And a short overshoot as it comes to rest, so going still reads as deliberate. */
.brand-mark.is-settling svg { animation: ovSettle 0.68s cubic-bezier(.26, 1.32, .42, 1) 1 both; animation-play-state: running; }