diff --git a/Jellyfin.Plugin.Seasonals/Web/autumn.css b/Jellyfin.Plugin.Seasonals/Web/autumn.css index ae67665..9fc46a7 100644 --- a/Jellyfin.Plugin.Seasonals/Web/autumn.css +++ b/Jellyfin.Plugin.Seasonals/Web/autumn.css @@ -1,164 +1,139 @@ -.autumn-container { - display: block; - position: fixed; - overflow: hidden; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 10; - contain: layout paint; -} - -.leaf { - position: fixed; - z-index: 15; - top: 0; - will-change: transform; - translate: 0 -10vh; - font-size: 1em; - color: #fff; - font-family: Arial, sans-serif; - text-shadow: 0 0 5px #000; - user-select: none; - -webkit-user-select: none; - cursor: default; - -webkit-animation-name: leaf-fall, leaf-shake; - -webkit-animation-duration: 7s, 4s; - -webkit-animation-timing-function: linear, ease-in-out; - -webkit-animation-iteration-count: infinite, infinite; - -webkit-user-select: none; - animation-name: leaf-fall, leaf-shake; - animation-duration: 7s, 4s; - animation-timing-function: linear, ease-in-out; - animation-iteration-count: infinite, infinite; -} - -/* Class to disable rotation */ -.no-rotation { - --rotate-start: 0deg !important; - --rotate-end: 0deg !important; -} - -@-webkit-keyframes leaf-fall { - 0% { - translate: 0 -10vh; - } - - 100% { - translate: 0 100vh; - } -} - -@keyframes leaf-fall { - 0% { - translate: 0 -10vh; - } - - 100% { - translate: 0 100vh; - } -} - -@-webkit-keyframes leaf-shake { - 0%, 100% { - transform: translateX(0) rotate(var(--rotate-start, -20deg)); - } - 50% { - transform: translateX(80px) rotate(var(--rotate-end, 20deg)); - } -} - -@keyframes leaf-shake { - 0%, 100% { - transform: translateX(0) rotate(var(--rotate-start, -20deg)); - } - 50% { - transform: translateX(80px) rotate(var(--rotate-end, 20deg)); - } -} - -.leaf:nth-of-type(0) { - left: 0%; - animation-delay: 0s, 0s; - --rotate-start: -25deg; - --rotate-end: 22deg; -} - -.leaf:nth-of-type(1) { - left: 10%; - animation-delay: 1s, 0.5s; - --rotate-start: -32deg; - --rotate-end: 35deg; -} - -.leaf:nth-of-type(2) { - left: 20%; - animation-delay: 6s, 1s; - --rotate-start: -28deg; - --rotate-end: 28deg; -} - -.leaf:nth-of-type(3) { - left: 30%; - animation-delay: 4s, 1.5s; - --rotate-start: -38deg; - --rotate-end: 32deg; -} - -.leaf:nth-of-type(4) { - left: 40%; - animation-delay: 2s, 0.8s; - --rotate-start: -22deg; - --rotate-end: 38deg; -} - -.leaf:nth-of-type(5) { - left: 50%; - animation-delay: 8s, 2s; - --rotate-start: -35deg; - --rotate-end: 25deg; -} - -.leaf:nth-of-type(6) { - left: 60%; - animation-delay: 6s, 1.2s; - --rotate-start: -40deg; - --rotate-end: 40deg; -} - -.leaf:nth-of-type(7) { - left: 70%; - animation-delay: 2.5s, 0.3s; - --rotate-start: -30deg; - --rotate-end: 30deg; -} - -.leaf:nth-of-type(8) { - left: 80%; - animation-delay: 1s, 1.8s; - --rotate-start: -26deg; - --rotate-end: 36deg; -} - -.leaf:nth-of-type(9) { - left: 90%; - animation-delay: 3s, 0.7s; - --rotate-start: -34deg; - --rotate-end: 24deg; -} - -.leaf:nth-of-type(10) { - left: 25%; - animation-delay: 2s, 2.3s; - --rotate-start: -29deg; - --rotate-end: 33deg; -} - -.leaf:nth-of-type(11) { - left: 65%; - animation-delay: 4s, 1.4s; - --rotate-start: -37deg; - --rotate-end: 27deg; +.autumn-container { + display: block; + position: fixed; + overflow: hidden; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 10; + contain: layout paint; +} + +.leaf { + position: fixed; + z-index: 15; + top: 0; + will-change: transform; + translate: 0 -10vh; + font-size: 1em; + color: #fff; + font-family: Arial, sans-serif; + text-shadow: 0 0 5px #000; + user-select: none; cursor: default; animation-name: leaf-fall, leaf-shake; + animation-duration: 7s, 4s; + animation-timing-function: linear, ease-in-out; + animation-iteration-count: infinite, infinite; +} + +/* Class to disable rotation */ +.no-rotation { + --rotate-start: 0deg !important; + --rotate-end: 0deg !important; +} + + +@keyframes leaf-fall { + 0% { + translate: 0 -10vh; + } + + 100% { + translate: 0 100vh; + } +} + + +@keyframes leaf-shake { + 0%, 100% { + transform: translateX(0) rotate(var(--rotate-start, -20deg)); + } + 50% { + transform: translateX(80px) rotate(var(--rotate-end, 20deg)); + } +} + +.leaf:nth-of-type(0) { + left: 0%; + animation-delay: 0s, 0s; + --rotate-start: -25deg; + --rotate-end: 22deg; +} + +.leaf:nth-of-type(1) { + left: 10%; + animation-delay: 1s, 0.5s; + --rotate-start: -32deg; + --rotate-end: 35deg; +} + +.leaf:nth-of-type(2) { + left: 20%; + animation-delay: 6s, 1s; + --rotate-start: -28deg; + --rotate-end: 28deg; +} + +.leaf:nth-of-type(3) { + left: 30%; + animation-delay: 4s, 1.5s; + --rotate-start: -38deg; + --rotate-end: 32deg; +} + +.leaf:nth-of-type(4) { + left: 40%; + animation-delay: 2s, 0.8s; + --rotate-start: -22deg; + --rotate-end: 38deg; +} + +.leaf:nth-of-type(5) { + left: 50%; + animation-delay: 8s, 2s; + --rotate-start: -35deg; + --rotate-end: 25deg; +} + +.leaf:nth-of-type(6) { + left: 60%; + animation-delay: 6s, 1.2s; + --rotate-start: -40deg; + --rotate-end: 40deg; +} + +.leaf:nth-of-type(7) { + left: 70%; + animation-delay: 2.5s, 0.3s; + --rotate-start: -30deg; + --rotate-end: 30deg; +} + +.leaf:nth-of-type(8) { + left: 80%; + animation-delay: 1s, 1.8s; + --rotate-start: -26deg; + --rotate-end: 36deg; +} + +.leaf:nth-of-type(9) { + left: 90%; + animation-delay: 3s, 0.7s; + --rotate-start: -34deg; + --rotate-end: 24deg; +} + +.leaf:nth-of-type(10) { + left: 25%; + animation-delay: 2s, 2.3s; + --rotate-start: -29deg; + --rotate-end: 33deg; +} + +.leaf:nth-of-type(11) { + left: 65%; + animation-delay: 4s, 1.4s; + --rotate-start: -37deg; + --rotate-end: 27deg; } \ No newline at end of file diff --git a/Jellyfin.Plugin.Seasonals/Web/birthday.css b/Jellyfin.Plugin.Seasonals/Web/birthday.css index 564a05c..3c2a9e7 100644 --- a/Jellyfin.Plugin.Seasonals/Web/birthday.css +++ b/Jellyfin.Plugin.Seasonals/Web/birthday.css @@ -8,9 +8,11 @@ z-index: 9999; overflow: hidden; contain: strict; + contain: layout paint; } .birthday-symbol { + will-change: opacity; position: fixed; top: 0; left: 0; @@ -29,7 +31,7 @@ } .birthday-inner { - pointer-events: auto; /* Allow hover over the actual item */ + pointer-events: auto; cursor: crosshair; display: inline-block; } @@ -138,7 +140,7 @@ opacity: 1; } 100% { - transform: translateY(calc(var(--burst-y) + 150px)); /* Gravity pull downwards */ + transform: translateY(calc(var(--burst-y) + 150px)); opacity: 0; } } diff --git a/Jellyfin.Plugin.Seasonals/Web/birthday.js b/Jellyfin.Plugin.Seasonals/Web/birthday.js index 1713740..e8af398 100644 --- a/Jellyfin.Plugin.Seasonals/Web/birthday.js +++ b/Jellyfin.Plugin.Seasonals/Web/birthday.js @@ -228,7 +228,19 @@ function createBirthday() { // Ensure the burst container is appended to the main document body or the birthday container createBalloonPopConfetti(document.body, cx, cy, balloonColors[randomItem]); } - }, { once: true }); + }); + + // Reset the balloon when it reappears at the bottom of the screen + symbol.addEventListener('animationiteration', function(e) { + // Ignore bubbling events from the inner sway animation + if (e.animationName === 'birthday-rise' || e.target === symbol) { + if (innerDiv.classList.contains('popped')) { + innerDiv.classList.remove('popped'); + innerDiv.style.animation = ''; + innerDiv.style.pointerEvents = 'auto'; + } + } + }); } const startRot = (Math.random() * 20) - 10; // -10 to +10 spread diff --git a/Jellyfin.Plugin.Seasonals/Web/christmas.css b/Jellyfin.Plugin.Seasonals/Web/christmas.css index 33f283c..81ef3bf 100644 --- a/Jellyfin.Plugin.Seasonals/Web/christmas.css +++ b/Jellyfin.Plugin.Seasonals/Web/christmas.css @@ -1,138 +1,112 @@ -.christmas-container { - display: block; - position: fixed; - overflow: hidden; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 10; - contain: layout paint; -} - -.christmas { - position: fixed; - z-index: 15; - top: 0; - will-change: transform; - translate: 0 -10vh; - font-size: 1em; - color: #fff; - font-family: Arial, sans-serif; - text-shadow: 0 0 5px #000; - user-select: none; - cursor: default; - -webkit-user-select: none; - -webkit-animation-name: christmas-fall, christmas-shake; - -webkit-animation-duration: 10s, 3s; - -webkit-animation-timing-function: linear, ease-in-out; - -webkit-animation-iteration-count: infinite, infinite; - animation-name: christmas-fall, christmas-shake; - animation-duration: 10s, 3s; - animation-timing-function: linear, ease-in-out; - animation-iteration-count: infinite, infinite; -} - -@-webkit-keyframes christmas-fall { - 0% { - translate: 0 -10vh; - } - - 100% { - translate: 0 110vh; - } -} - -@-webkit-keyframes christmas-shake { - - 0%, - 100% { - transform: translateX(0); - } - - 50% { - transform: translateX(80px); - } -} - -@keyframes christmas-fall { - 0% { - translate: 0 -10vh; - } - - 100% { - translate: 0 110vh; - } -} - -@keyframes christmas-shake { - 0%, - 100% { - transform: translateX(0); - } - - 50% { - transform: translateX(80px); - } -} - -.christmas:nth-of-type(0) { - left: 0%; - animation-delay: 0s, 0s; -} - -.christmas:nth-of-type(1) { - left: 10%; - animation-delay: 1s, 1s; -} - -.christmas:nth-of-type(2) { - left: 20%; - animation-delay: 6s, 0.5s; -} - -.christmas:nth-of-type(3) { - left: 30%; - animation-delay: 4s, 2s; -} - -.christmas:nth-of-type(4) { - left: 40%; - animation-delay: 2s, 2s; -} - -.christmas:nth-of-type(5) { - left: 50%; - animation-delay: 8s, 3s; -} - -.christmas:nth-of-type(6) { - left: 60%; - animation-delay: 6s, 2s; -} - -.christmas:nth-of-type(7) { - left: 70%; - animation-delay: 2.5s, 1s; -} - -.christmas:nth-of-type(8) { - left: 80%; - animation-delay: 1s, 0s; -} - -.christmas:nth-of-type(9) { - left: 90%; - animation-delay: 3s, 1.5s; -} - -.christmas:nth-of-type(10) { - left: 25%; - animation-delay: 2s, 0s; -} - -.christmas:nth-of-type(11) { - left: 65%; - animation-delay: 4s, 2.5s; +.christmas-container { + display: block; + position: fixed; + overflow: hidden; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 10; + contain: layout paint; +} + +.christmas { + position: fixed; + z-index: 15; + top: 0; + will-change: transform; + translate: 0 -10vh; + font-size: 1em; + color: #fff; + font-family: Arial, sans-serif; + text-shadow: 0 0 5px #000; + user-select: none; + cursor: default; animation-name: christmas-fall, christmas-shake; + animation-duration: 10s, 3s; + animation-timing-function: linear, ease-in-out; + animation-iteration-count: infinite, infinite; +} + + + +@keyframes christmas-fall { + 0% { + translate: 0 -10vh; + } + + 100% { + translate: 0 110vh; + } +} + +@keyframes christmas-shake { + 0%, + 100% { + transform: translateX(0); + } + + 50% { + transform: translateX(80px); + } +} + +.christmas:nth-of-type(0) { + left: 0%; + animation-delay: 0s, 0s; +} + +.christmas:nth-of-type(1) { + left: 10%; + animation-delay: 1s, 1s; +} + +.christmas:nth-of-type(2) { + left: 20%; + animation-delay: 6s, 0.5s; +} + +.christmas:nth-of-type(3) { + left: 30%; + animation-delay: 4s, 2s; +} + +.christmas:nth-of-type(4) { + left: 40%; + animation-delay: 2s, 2s; +} + +.christmas:nth-of-type(5) { + left: 50%; + animation-delay: 8s, 3s; +} + +.christmas:nth-of-type(6) { + left: 60%; + animation-delay: 6s, 2s; +} + +.christmas:nth-of-type(7) { + left: 70%; + animation-delay: 2.5s, 1s; +} + +.christmas:nth-of-type(8) { + left: 80%; + animation-delay: 1s, 0s; +} + +.christmas:nth-of-type(9) { + left: 90%; + animation-delay: 3s, 1.5s; +} + +.christmas:nth-of-type(10) { + left: 25%; + animation-delay: 2s, 0s; +} + +.christmas:nth-of-type(11) { + left: 65%; + animation-delay: 4s, 2.5s; } \ No newline at end of file diff --git a/Jellyfin.Plugin.Seasonals/Web/earthday.css b/Jellyfin.Plugin.Seasonals/Web/earthday.css index 4a7d917..1453b56 100644 --- a/Jellyfin.Plugin.Seasonals/Web/earthday.css +++ b/Jellyfin.Plugin.Seasonals/Web/earthday.css @@ -7,9 +7,11 @@ pointer-events: none; z-index: 1000; overflow: hidden; + contain: layout paint; } .earthday-meadow { + will-change: transform; position: absolute; bottom: 0; left: 0; @@ -25,6 +27,7 @@ } .earthday-sway { + will-change: transform; transform-origin: bottom center; animation: sway-grass 4s ease-in-out infinite alternate; } diff --git a/Jellyfin.Plugin.Seasonals/Web/easter.css b/Jellyfin.Plugin.Seasonals/Web/easter.css index a0a606f..3a87ac1 100644 --- a/Jellyfin.Plugin.Seasonals/Web/easter.css +++ b/Jellyfin.Plugin.Seasonals/Web/easter.css @@ -9,6 +9,7 @@ z-index: 10000; contain: strict; overflow: hidden; + contain: layout paint; } .easter-grass-container { @@ -38,6 +39,7 @@ /* sway */ .easter-sway { + will-change: transform; transform-origin: bottom center; animation: easter-wind-sway 6s ease-in-out infinite alternate; } diff --git a/Jellyfin.Plugin.Seasonals/Web/eid.css b/Jellyfin.Plugin.Seasonals/Web/eid.css index 43cc54d..ca7fa4f 100644 --- a/Jellyfin.Plugin.Seasonals/Web/eid.css +++ b/Jellyfin.Plugin.Seasonals/Web/eid.css @@ -9,6 +9,7 @@ z-index: 10; contain: strict; overflow: hidden; + contain: layout paint; } .eid-symbol { @@ -18,12 +19,14 @@ } .eid-symbol.floating-star { + will-change: opacity; opacity: 0; animation: eid-twinkle 4s ease-in-out infinite; mix-blend-mode: screen; } .lantern-rope { + will-change: transform; position: absolute; top: 0; width: 2px; diff --git a/Jellyfin.Plugin.Seasonals/Web/filmnoir.css b/Jellyfin.Plugin.Seasonals/Web/filmnoir.css index 28d9dc1..fbd9f69 100644 --- a/Jellyfin.Plugin.Seasonals/Web/filmnoir.css +++ b/Jellyfin.Plugin.Seasonals/Web/filmnoir.css @@ -22,8 +22,9 @@ /* Film grain */ .filmnoir-grain { + will-change: transform, opacity; position: absolute; - top: -50%; + top: 0; left: -50%; width: 200%; height: 200%; @@ -32,6 +33,7 @@ pointer-events: none; mix-blend-mode: overlay; opacity: 0.3; + translate: 0 -50vh; } /* Vignette */ @@ -48,6 +50,7 @@ /* Occasional flicker and scratch */ .filmnoir-scratches { + will-change: opacity; position: absolute; top: 0; left: 0; diff --git a/Jellyfin.Plugin.Seasonals/Web/fireworks.css b/Jellyfin.Plugin.Seasonals/Web/fireworks.css index 1dc299b..af6d1da 100644 --- a/Jellyfin.Plugin.Seasonals/Web/fireworks.css +++ b/Jellyfin.Plugin.Seasonals/Web/fireworks.css @@ -11,9 +11,10 @@ } .rocket-trail { + will-change: transform; position: absolute; left: var(--trailX); - top: var(--trailStartY); + top: 0; width: 4px; /* activate the following for rocket trail */ @@ -28,6 +29,7 @@ box-shadow: 0 0 8px 2px white;*/ animation: rocket-trail-animation 1s linear forwards; + translate: 0 var(--trailStartY); } @keyframes rocket-trail-animation { @@ -56,6 +58,7 @@ } .firework { + will-change: transform; position: absolute; width: 5px; height: 5px; diff --git a/Jellyfin.Plugin.Seasonals/Web/frost.css b/Jellyfin.Plugin.Seasonals/Web/frost.css index eeb846c..e3cd503 100644 --- a/Jellyfin.Plugin.Seasonals/Web/frost.css +++ b/Jellyfin.Plugin.Seasonals/Web/frost.css @@ -9,16 +9,17 @@ z-index: 10; overflow: hidden; contain: strict; + contain: layout paint; } .frost-layer { + will-change: transform; position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; - /* A glowing white-blue gradient from edges */ background: radial-gradient(ellipse at center, transparent 60%, rgba(180, 220, 255, 0.4) 100%); box-shadow: inset 0 0 60px rgba(200, 230, 255, 0.5), inset 0 0 120px rgba(255, 255, 255, 0.3); @@ -27,14 +28,13 @@ animation: frost-creep 4s ease-out forwards; } -/* Subtle repeating star/crystal pattern */ .frost-crystals { + will-change: transform; position: absolute; - top: -5%; + top: 0; left: -5%; width: 110%; height: 110%; - /* Use multi-layered star patterns for a random, crystalline spread */ background-image: url('data:image/svg+xml;utf8,'), url('data:image/svg+xml;utf8,'), @@ -43,12 +43,9 @@ background-size: 110px 110px, 60px 60px, 30px 30px; background-position: 0 0, 15px 15px, 5px 10px; mix-blend-mode: overlay; - - /* Mask out the center so crystals only appear strongly on the edges */ - -webkit-mask-image: radial-gradient(ellipse at center, transparent 50%, black 100%); mask-image: radial-gradient(ellipse at center, transparent 50%, black 100%); - animation: frost-shimmer 6s infinite alternate ease-in-out; + translate: 0 -5vh; } @keyframes frost-creep { diff --git a/Jellyfin.Plugin.Seasonals/Web/halloween.css b/Jellyfin.Plugin.Seasonals/Web/halloween.css index 2cbce01..c88ed9e 100644 --- a/Jellyfin.Plugin.Seasonals/Web/halloween.css +++ b/Jellyfin.Plugin.Seasonals/Web/halloween.css @@ -12,20 +12,12 @@ } .halloween { + will-change: transform; position: fixed; bottom: -10%; z-index: 15; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; - -webkit-user-select: none; cursor: default; - -webkit-animation-name: halloween-fall, halloween-shake; - -webkit-animation-duration: 10s, 3s; - -webkit-animation-timing-function: linear, ease-in-out; - -webkit-animation-iteration-count: infinite, infinite; - -webkit-animation-play-state: running, running; animation-name: halloween-fall, halloween-shake; animation-duration: 10s, 3s; animation-timing-function: linear, ease-in-out; @@ -33,29 +25,7 @@ animation-play-state: running, running } -@-webkit-keyframes halloween-fall { - 0% { - bottom: -10%; - } - 100% { - bottom: 110%; - } -} - -@-webkit-keyframes halloween-shake { - - 0%, - 100% { - -webkit-transform: translateX(0); - transform: translateX(0) - } - - 50% { - -webkit-transform: translateX(80px); - transform: translateX(80px) - } -} @keyframes halloween-fall { 0% { @@ -81,73 +51,61 @@ .halloween:nth-of-type(0) { left: 1%; - -webkit-animation-delay: 0s, 0s; animation-delay: 0s, 0s; } .halloween:nth-of-type(1) { left: 10%; - -webkit-animation-delay: -1s, -1s; animation-delay: -1s, -1s; } .halloween:nth-of-type(2) { left: 20%; - -webkit-animation-delay: -2s, -2s; animation-delay: -2s, -2s; } .halloween:nth-of-type(3) { left: 30%; - -webkit-animation-delay: -3s, -3s; animation-delay: -3s, -3s; } .halloween:nth-of-type(4) { left: 40%; - -webkit-animation-delay: -4s, -4s; animation-delay: -4s, -4s; } .halloween:nth-of-type(5) { left: 50%; - -webkit-animation-delay: -5s, -5s; animation-delay: -5s, -5s; } .halloween:nth-of-type(6) { left: 60%; - -webkit-animation-delay: -6s, -6s; animation-delay: -6s, -6s; } .halloween:nth-of-type(7) { left: 70%; - -webkit-animation-delay: -7s, -7s; animation-delay: -7s, -7s; } .halloween:nth-of-type(8) { left: 80%; - -webkit-animation-delay: -8s, -8s; animation-delay: -8s, -8s; } .halloween:nth-of-type(9) { left: 90%; - -webkit-animation-delay: -9s, -9s; animation-delay: -9s, -9s; } .halloween:nth-of-type(10) { left: 25%; - -webkit-animation-delay: -10s, -10s; animation-delay: -10s, -10s; } .halloween:nth-of-type(11) { left: 65%; - -webkit-animation-delay: -11s, -11s; animation-delay: -11s, -11s; } @@ -162,7 +120,6 @@ z-index: 1000; overflow: hidden; mask-image: linear-gradient(to top, black, transparent); - -webkit-mask-image: linear-gradient(to top, black, transparent); } .halloween-fog-blob { position: absolute; @@ -174,10 +131,12 @@ filter: blur(15px); } .halloween-fog-blob:nth-child(1) { + will-change: transform; left: -20vw; animation: fog-float1 25s ease-in-out infinite alternate; } .halloween-fog-blob:nth-child(2) { + will-change: transform; left: -50vw; background: radial-gradient(ellipse at center, rgba(100, 110, 120, 0.3) 0%, transparent 65%); animation: fog-float2 35s ease-in-out infinite alternate; @@ -196,7 +155,7 @@ /* --- Spiders --- */ .halloween-spider-wrapper { position: absolute; - top: -50px; + top: 0; display: flex; flex-direction: column; align-items: center; @@ -204,8 +163,10 @@ transform-origin: top; will-change: transform; pointer-events: auto; - padding: 20px; /* Increase hit area safely */ + padding: 20px; /* Increase hit area */ + translate: 0 -50px; } + .halloween-thread { width: 30px; /* Wider hit area for mouse interaction */ height: 100vh; @@ -223,12 +184,12 @@ background: linear-gradient(to bottom, rgba(200, 200, 200, 0.1), rgba(200, 200, 200, 0.6)); } .halloween-spider { + will-change: transform; animation: spider-swing 3s ease-in-out infinite alternate; transform-origin: top center; } /* MARK: SPIDER SWAY CONFIGURATION */ -/* Adjust degrees in 'rotate(...)' to change how far spider and thread swing in wind. */ @keyframes wind-sway { 0% { transform: rotate(0deg); } 25% { transform: rotate(2deg); } diff --git a/Jellyfin.Plugin.Seasonals/Web/hearts.css b/Jellyfin.Plugin.Seasonals/Web/hearts.css index 5f61fda..e4fce52 100644 --- a/Jellyfin.Plugin.Seasonals/Web/hearts.css +++ b/Jellyfin.Plugin.Seasonals/Web/hearts.css @@ -12,48 +12,21 @@ } .heart { + will-change: transform; position: fixed; bottom: -10%; z-index: 15; - -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; - -webkit-user-select: none; cursor: default; - -webkit-animation-name: heart-fall, heart-shake; - -webkit-animation-duration: 14s, 5s; - -webkit-animation-timing-function: linear, ease-in-out; - -webkit-animation-iteration-count: infinite, infinite; animation-name: heart-fall, heart-shake; animation-duration: 14s, 5s; animation-timing-function: linear, ease-in-out; animation-iteration-count: infinite, infinite; } -@-webkit-keyframes heart-fall { - 0% { - bottom: -10%; - } - 100% { - bottom: 110%; - } -} - -@-webkit-keyframes heart-shake { - - 0%, - 100% { - -webkit-transform: translateX(0); - transform: translateX(0) - } - - 50% { - -webkit-transform: translateX(80px); - transform: translateX(80px) - } -} @keyframes heart-fall { 0% { @@ -79,72 +52,60 @@ .heart:nth-of-type(0) { left: 1%; - -webkit-animation-delay: 0s, 0s; animation-delay: 0s, 0s } .heart:nth-of-type(1) { left: 10%; - -webkit-animation-delay: 1s, 1s; animation-delay: 1s, 1s } .heart:nth-of-type(2) { left: 20%; - -webkit-animation-delay: 6s, .5s; animation-delay: 6s, .5s } .heart:nth-of-type(3) { left: 30%; - -webkit-animation-delay: 4s, 2s; animation-delay: 4s, 2s } .heart:nth-of-type(4) { left: 40%; - -webkit-animation-delay: 2s, 2s; animation-delay: 2s, 2s } .heart:nth-of-type(5) { left: 50%; - -webkit-animation-delay: 8s, 3s; animation-delay: 8s, 3s } .heart:nth-of-type(6) { left: 60%; - -webkit-animation-delay: 6s, 2s; animation-delay: 6s, 2s } .heart:nth-of-type(7) { left: 70%; - -webkit-animation-delay: 2.5s, 1s; animation-delay: 2.5s, 1s } .heart:nth-of-type(8) { left: 80%; - -webkit-animation-delay: 1s, 0s; animation-delay: 1s, 0s } .heart:nth-of-type(9) { left: 90%; - -webkit-animation-delay: 3s, 1.5s; animation-delay: 3s, 1.5s } .heart:nth-of-type(10) { left: 25%; - -webkit-animation-delay: 2s, 0s; animation-delay: 2s, 0s } .heart:nth-of-type(11) { left: 65%; - -webkit-animation-delay: 4s, 2.5s; animation-delay: 4s, 2.5s } \ No newline at end of file diff --git a/Jellyfin.Plugin.Seasonals/Web/marioday.css b/Jellyfin.Plugin.Seasonals/Web/marioday.css index 4254a12..3af7de2 100644 --- a/Jellyfin.Plugin.Seasonals/Web/marioday.css +++ b/Jellyfin.Plugin.Seasonals/Web/marioday.css @@ -29,11 +29,13 @@ } .mario-jump { + will-change: transform; animation: jump-arc 0.8s ease-in-out; } /* 8-bit coin styling */ .mario-coin { + will-change: transform; position: absolute; width: 32px; height: 32px; @@ -47,11 +49,12 @@ .mario-coin::after { content: ''; position: absolute; - top: 6px; + top: 0; left: 10px; width: 4px; height: 12px; background: #daa520; + translate: 0 6px; } @keyframes mario-run { diff --git a/Jellyfin.Plugin.Seasonals/Web/oktoberfest.css b/Jellyfin.Plugin.Seasonals/Web/oktoberfest.css index 3e7da8a..58a1ed1 100644 --- a/Jellyfin.Plugin.Seasonals/Web/oktoberfest.css +++ b/Jellyfin.Plugin.Seasonals/Web/oktoberfest.css @@ -12,13 +12,15 @@ } .oktoberfest-symbol { + will-change: transform; position: absolute; - top: -10%; + top: 0; font-size: 2.2em; user-select: none; animation-name: oktoberfest-fall, oktoberfest-sway; animation-timing-function: linear, ease-in-out; animation-iteration-count: infinite, infinite; + translate: 0 -10vh; } @keyframes oktoberfest-fall {