diff --git a/index.html b/index.html index 781b0ba3..5b684594 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,6 @@ Akkoma - diff --git a/src/components/status_content/mfm.scss b/src/components/status_content/mfm.scss index 45d32d4e..f5d77938 100644 --- a/src/components/status_content/mfm.scss +++ b/src/components/status_content/mfm.scss @@ -1,5 +1,331 @@ -/* Some MFM CSS is also defined in ./static/mfm.css */ -.StatusContent { +/** + * "FEP-c16b: Formatting MFM functions" attributes that Akkoma supports + */ + +.StatusContent:not(.mfm-disabled) { + /* The following are the non-animated MFM */ + .mfm-center { + display: block; + text-align: center; + } + + .mfm-flip { + display: inline-block; + transform: scaleX(-1); + } + + .mfm-flip[data-mfm-v] { + transform: scaleY(-1); + } + + .mfm-flip[data-mfm-v][data-mfm-h] { + transform: scale(-1, -1); + } + + .mfm-font[data-mfm-serif] { + font-family: serif; + } + + .mfm-font[data-mfm-monospace] { + font-family: monospace; + } + + .mfm-font[data-mfm-cursive] { + font-family: cursive; + } + + .mfm-font[data-mfm-fantasy] { + font-family: fantasy; + } + + .mfm-font[data-mfm-emoji] { + font-family: emoji; + } + + .mfm-font[data-mfm-math] { + font-family: math; + } + + .mfm-blur { + filter: blur(6px); + transition: filter 0.3s; + + &:hover { + filter: blur(0); + } + } + + .mfm-rotate { + display: inline-block; + transform: rotate(calc(var(--mfm-deg, 90) * 1deg)); + transform-origin: center center; + } + + .mfm-x2 { + --mfm-zoom-size: 200%; + } + + .mfm-x3 { + --mfm-zoom-size: 400%; + } + + .mfm-x4 { + --mfm-zoom-size: 600%; + } + + .mfm-x2, + .mfm-x3, + .mfm-x4, + .mfm-tada { + font-size: var(--mfm-zoom-size); + + .mfm-x2, + .mfm-x3, + .mfm-x4, + .mfm-tada { + /* only half effective */ + font-size: calc(var(--mfm-zoom-size) / 2 + 50%); + + .mfm-x2, + .mfm-x3, + .mfm-x4, + .mfm-tada { + /* disabled */ + font-size: 100%; + } + } + } + + .mfm-position { + transform: translate(calc(var(--mfm-x, 0) * 1em), calc(var(--mfm-y, 0) * 1em)); + } + + .mfm-scale { + transform: scale(var(--mfm-x, 1), var(--mfm-y, 1)); + } + + .mfm-fg { + color: var(--mfm-color, #f00); + } + + .mfm-bg { + background-color: var(--mfm-color, #0f0); + } + + /* The following are the animated MFM */ + + /* .mfm-hover means that we should only play animation when hovering over the StatusContent + * So either StatusContent does not have this class, + * or it has the class and we are hovering over StatusContent + */ + &:not(.mfm-hover:not(:hover)) { + .mfm-jelly { + display: inline-block; + animation: mfm-rubberBand var(--mfm-speed, 1s) linear infinite both; + } + + .mfm-twitch { + display: inline-block; + animation: mfm-twitch var(--mfm-speed, 0.5s) ease infinite; + } + + .mfm-shake { + display: inline-block; + animation: mfm-shake var(--mfm-speed, 0.5s) ease infinite; + } + + .mfm-spin { + display: inline-block; + animation: mfm-spin var(--mfm-speed, 1.5s) linear infinite; + } + + .mfm-spin[data-mfm-y] { + animation-name: mfm-spinY; + } + + .mfm-spin[data-mfm-x] { + animation-name: mfm-spinX; + } + + .mfm-spin[data-mfm-alternate] { + animation-direction: alternate; + } + + .mfm-spin[data-mfm-left] { + animation-direction: reverse; + } + + .mfm-jump { + display: inline-block; + animation: mfm-jump var(--mfm-speed, 0.75s) linear infinite; + } + + .mfm-bounce { + display: inline-block; + animation: mfm-bounce var(--mfm-speed, 0.75s) linear infinite; + transform-origin: center bottom; + } + + .mfm-rainbow { + animation: mfm-rainbow var(--mfm-speed, 1s) linear infinite; + } + + .mfm-tada { + display: inline-block; + animation: mfm-tada var(--mfm-speed, 1s) linear infinite both; + + --mfm-zoom-size: 150%; + } + } + + /* animation keyframes */ + + @keyframes mfm-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + @keyframes mfm-spinX { + 0% { transform: perspective(128px) rotateX(0deg); } + 100% { transform: perspective(128px) rotateX(360deg); } + } + + @keyframes mfm-spinY { + 0% { transform: perspective(128px) rotateY(0deg); } + 100% { transform: perspective(128px) rotateY(360deg); } + } + + @keyframes mfm-jump { + 0% { transform: translateY(0); } + 25% { transform: translateY(-16px); } + 50% { transform: translateY(0); } + 75% { transform: translateY(-8px); } + 100% { transform: translateY(0); } + } + + @keyframes mfm-bounce { + 0% { transform: translateY(0) scale(1, 1); } + 25% { transform: translateY(-16px) scale(1, 1); } + 50% { transform: translateY(0) scale(1, 1); } + 75% { transform: translateY(0) scale(1.5, 0.75); } + 100% { transform: translateY(0) scale(1, 1); } + } + + @keyframes mfm-twitch { + 0% { transform: translate(7px, -2px); } + 5% { transform: translate(-3px, 1px); } + 10% { transform: translate(-7px, -1px); } + 15% { transform: translate(0, -1px); } + 20% { transform: translate(-8px, 6px); } + 25% { transform: translate(-4px, -3px); } + 30% { transform: translate(-4px, -6px); } + 35% { transform: translate(-8px, -8px); } + 40% { transform: translate(4px, 6px); } + 45% { transform: translate(-3px, 1px); } + 50% { transform: translate(2px, -10px); } + 55% { transform: translate(-7px, 0); } + 60% { transform: translate(-2px, 4px); } + 65% { transform: translate(3px, -8px); } + 70% { transform: translate(6px, 7px); } + 75% { transform: translate(-7px, -2px); } + 80% { transform: translate(-7px, -8px); } + 85% { transform: translate(9px, 3px); } + 90% { transform: translate(-3px, -2px); } + 95% { transform: translate(-10px, 2px); } + 100% { transform: translate(-2px, -6px); } + } + + @keyframes mfm-shake { + 0% { transform: translate(-3px, -1px) rotate(-8deg); } + 5% { transform: translate(0, -1px) rotate(-10deg); } + 10% { transform: translate(1px, -3px) rotate(0deg); } + 15% { transform: translate(1px, 1px) rotate(11deg); } + 20% { transform: translate(-2px, 1px) rotate(1deg); } + 25% { transform: translate(-1px, -2px) rotate(-2deg); } + 30% { transform: translate(-1px, 2px) rotate(-3deg); } + 35% { transform: translate(2px, 1px) rotate(6deg); } + 40% { transform: translate(-2px, -3px) rotate(-9deg); } + 45% { transform: translate(0, -1px) rotate(-12deg); } + 50% { transform: translate(1px, 2px) rotate(10deg); } + 55% { transform: translate(0, -3px) rotate(8deg); } + 60% { transform: translate(1px, -1px) rotate(8deg); } + 65% { transform: translate(0, -1px) rotate(-7deg); } + 70% { transform: translate(-1px, -3px) rotate(6deg); } + 75% { transform: translate(0, -2px) rotate(4deg); } + 80% { transform: translate(-2px, -1px) rotate(3deg); } + 85% { transform: translate(1px, -3px) rotate(-10deg); } + 90% { transform: translate(1px, 0) rotate(3deg); } + 95% { transform: translate(-2px, 0) rotate(-3deg); } + 100% { transform: translate(2px, 1px) rotate(2deg); } + } + + @keyframes mfm-rubberBand { + 0% { transform: scale3d(1, 1, 1); } + 30% { transform: scale3d(1.25, 0.75, 1); } + 40% { transform: scale3d(0.75, 1.25, 1); } + 50% { transform: scale3d(1.15, 0.85, 1); } + 65% { transform: scale3d(0.95, 1.05, 1); } + 75% { transform: scale3d(1.05, 0.95, 1); } + 100% { transform: scale3d(1, 1, 1); } + } + + @keyframes mfm-rainbow { + 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } + 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } + } + + @keyframes mfm-tada { + 0%, + 100% { transform: scale3d(1, 1, 1); } + + 10%, + 20% { transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); } + + 30%, + 50%, + 70%, + 90% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); } + + 40%, + 60%, + 80% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); } + } + + /** + * Legacy MFM + * This is for backwards compatibility with posts formatted on Akkoma before support for FEP-c16b + * Note that it uses the keyframes as defined above for the FEP-c16b compatible MFM representation + */ + + .mfm { + display: inline-block; + } + + /* The following are the legacy non-animated MFM */ + ._mfm_flip_[data-h][data-v] { + transform: scale(-1, -1); + } + + ._mfm_flip_[data-v] { + transform: scaleY(-1); + } + + ._mfm_flip_:not([data-v]) { + transform: scaleX(-1); + } + + ._mfm_x2_ { + font-size: 200%; + } + + ._mfm_x3_ { + font-size: 400%; + } + + ._mfm_x4_ { + font-size: 600%; + } + ._mfm_x2_ { .emoji { height: 100px; @@ -18,20 +344,75 @@ } } - &.mfm-hover:not(:hover) { - .mfm { - animation: none !important; - } + ._mfm_blur_ { + filter: blur(6px); + transition: filter 0.3s; } - &.mfm-disabled { - span { - font-size: 100% !important; + + ._mfm_blur_:hover { + filter: blur(0); + } + + ._mfm_rotate_ { + transform: rotate(90deg); + transform-origin: center center; + } + + /* The following are the legacy animated MFM */ + + /* .mfm-hover means that we should only play animation when hovering over the StatusContent + * So either StatusContent does not have this class, + * or it has the class and we are hovering over StatusContent + */ + &:not(.mfm-hover:not(:hover)) { + ._mfm_tada_ { + font-size: 150%; + animation: mfm-tada 1s linear infinite both; } - .mfm { - animation: none !important; + + ._mfm_jelly_ { + animation: mfm-rubberBand 1s linear infinite both; } - .emoji { - height: 32px !important; + + ._mfm_twitch_ { + animation: mfm-twitch 0.5s ease infinite; + } + + ._mfm_shake_ { + animation: mfm-shake 0.5s ease infinite; + } + + ._mfm_spin_ { + animation: mfm-spin 0.5s linear infinite; + } + + ._mfm_spin_[data-x] { + animation-name: mfm-spinX; + } + + ._mfm_spin_[data-y] { + animation-name: mfm-spinY; + } + + ._mfm_spin_[left] { + animation-direction: reverse; + } + + ._mfm_spin_[alternate] { + animation-direction: alternate; + } + + ._mfm_jump_ { + animation: mfm-jump 0.75s linear infinite; + } + + ._mfm_bounce_ { + animation: mfm-bounce 0.75s linear infinite; + transform-origin: center bottom; + } + + ._mfm_rainbow_ { + animation: mfm-rainbow 1s linear infinite; } } } diff --git a/src/components/status_content/mfm_foundkey.scss b/src/components/status_content/mfm_foundkey.scss deleted file mode 100644 index 6932b98a..00000000 --- a/src/components/status_content/mfm_foundkey.scss +++ /dev/null @@ -1,274 +0,0 @@ -.mfm-center { - display: block; - text-align: center; -} - -.mfm-flip { - display: inline-block; - transform: scaleX(-1); -} -.mfm-flip[data-mfm-v] { - transform: scaleY(-1); -} -.mfm-flip[data-mfm-v][data-mfm-h] { - transform: scale(-1, -1); -} - -.mfm-font[data-mfm-serif] { - font-family: serif; -} -.mfm-font[data-mfm-monospace] { - font-family: monospace; -} -.mfm-font[data-mfm-cursive] { - font-family: cursive; -} -.mfm-font[data-mfm-fantasy] { - font-family: fantasy; -} -.mfm-font[data-mfm-emoji] { - font-family: emoji; -} -.mfm-font[data-mfm-math] { - font-family: math; -} - -.mfm-blur { - filter: blur(6px); - transition: filter 0.3s; - - &:hover { - filter: blur(0px); - } -} - -.mfm-rotate { - display: inline-block; - transform: rotate(calc(var(--mfm-deg, 90) * 1deg)); - transform-origin: center center; -} - -.mfm-x2 { - --mfm-zoom-size: 200%; -} -.mfm-x3 { - --mfm-zoom-size: 400%; -} -.mfm-x4 { - --mfm-zoom-size: 600%; -} -.mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada { - font-size: var(--mfm-zoom-size); - - .mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada { - /* only half effective */ - font-size: calc(var(--mfm-zoom-size) / 2 + 50%); - - .mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada { - /* disabled */ - font-size: 100%; - } - } -} - -.mfm-position { - transform: translate(calc(var(--mfm-x, 0) * 1em), calc(var(--mfm-y, 0) * 1em)); -} - -.mfm-scale { - transform: scale(var(--mfm-x, 1), var(--mfm-y, 1)); -} - -.mfm-fg { - color: var(--mfm-color, #f00); -} - -.mfm-bg { - background-color: var(--mfm-color, #0f0); -} - -.markdown-container { - blockquote { - display: block; - margin: 8px; - padding: 6px 0 6px 12px; - color: var(--fg); - border-left: solid 3px var(--fg); - opacity: 0.7; - } - - blockquote blockquote blockquote { - opacity: 1; - } - - blockquote > p:first-child { - margin-top: 0; - } - blockquote > p:last-child { - margin-bottom: 0; - } -} - -.animated-mfm { - .mfm-jelly { - display: inline-block; - animation: mfm-rubberBand var(--mfm-speed, 1s) linear infinite both; - } - - .mfm-twitch { - display: inline-block; - animation: mfm-twitch var(--mfm-speed, .5s) ease infinite; - } - - .mfm-shake { - display: inline-block; - animation: mfm-shake var(--mfm-speed, .5s) ease infinite; - } - - .mfm-spin { - display: inline-block; - animation: mfm-spin var(--mfm-speed, 1.5s) linear infinite; - } - .mfm-spin[data-mfm-y] { - animation-name: mfm-spinY; - } - .mfm-spin[data-mfm-x] { - animation-name: mfm-spinX; - } - .mfm-spin[data-mfm-alternate] { - animation-direction: alternate; - } - .mfm-spin[data-mfm-left] { - animation-direction: reverse; - } - - .mfm-jump { - display: inline-block; - animation: mfm-jump var(--mfm-speed, .75s) linear infinite; - } - - .mfm-bounce { - display: inline-block; - animation: mfm-bounce var(--mfm-speed, .75s) linear infinite; - transform-origin: center bottom; - } - - .mfm-rainbow { - animation: mfm-rainbow var(--mfm-speed, 1s) linear infinite; - } - - .mfm-tada { - display: inline-block; - animation: mfm-tada var(--mfm-speed, 1s) linear infinite both; - --mfm-zoom-size: 150%; - } -} - -/* animation keyframes */ - -@keyframes mfm-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -@keyframes mfm-spinX { - 0% { transform: perspective(128px) rotateX(0deg); } - 100% { transform: perspective(128px) rotateX(360deg); } -} - -@keyframes mfm-spinY { - 0% { transform: perspective(128px) rotateY(0deg); } - 100% { transform: perspective(128px) rotateY(360deg); } -} - -@keyframes mfm-jump { - 0% { transform: translateY(0); } - 25% { transform: translateY(-16px); } - 50% { transform: translateY(0); } - 75% { transform: translateY(-8px); } - 100% { transform: translateY(0); } -} - -@keyframes mfm-bounce { - 0% { transform: translateY(0) scale(1, 1); } - 25% { transform: translateY(-16px) scale(1, 1); } - 50% { transform: translateY(0) scale(1, 1); } - 75% { transform: translateY(0) scale(1.5, 0.75); } - 100% { transform: translateY(0) scale(1, 1); } -} - -// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes mfm-twitch { - 0% { transform: translate(7px, -2px) } - 5% { transform: translate(-3px, 1px) } - 10% { transform: translate(-7px, -1px) } - 15% { transform: translate(0px, -1px) } - 20% { transform: translate(-8px, 6px) } - 25% { transform: translate(-4px, -3px) } - 30% { transform: translate(-4px, -6px) } - 35% { transform: translate(-8px, -8px) } - 40% { transform: translate(4px, 6px) } - 45% { transform: translate(-3px, 1px) } - 50% { transform: translate(2px, -10px) } - 55% { transform: translate(-7px, 0px) } - 60% { transform: translate(-2px, 4px) } - 65% { transform: translate(3px, -8px) } - 70% { transform: translate(6px, 7px) } - 75% { transform: translate(-7px, -2px) } - 80% { transform: translate(-7px, -8px) } - 85% { transform: translate(9px, 3px) } - 90% { transform: translate(-3px, -2px) } - 95% { transform: translate(-10px, 2px) } - 100% { transform: translate(-2px, -6px) } -} - -// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes mfm-shake { - 0% { transform: translate(-3px, -1px) rotate(-8deg) } - 5% { transform: translate(0px, -1px) rotate(-10deg) } - 10% { transform: translate(1px, -3px) rotate(0deg) } - 15% { transform: translate(1px, 1px) rotate(11deg) } - 20% { transform: translate(-2px, 1px) rotate(1deg) } - 25% { transform: translate(-1px, -2px) rotate(-2deg) } - 30% { transform: translate(-1px, 2px) rotate(-3deg) } - 35% { transform: translate(2px, 1px) rotate(6deg) } - 40% { transform: translate(-2px, -3px) rotate(-9deg) } - 45% { transform: translate(0px, -1px) rotate(-12deg) } - 50% { transform: translate(1px, 2px) rotate(10deg) } - 55% { transform: translate(0px, -3px) rotate(8deg) } - 60% { transform: translate(1px, -1px) rotate(8deg) } - 65% { transform: translate(0px, -1px) rotate(-7deg) } - 70% { transform: translate(-1px, -3px) rotate(6deg) } - 75% { transform: translate(0px, -2px) rotate(4deg) } - 80% { transform: translate(-2px, -1px) rotate(3deg) } - 85% { transform: translate(1px, -3px) rotate(-10deg) } - 90% { transform: translate(1px, 0px) rotate(3deg) } - 95% { transform: translate(-2px, 0px) rotate(-3deg) } - 100% { transform: translate(2px, 1px) rotate(2deg) } -} - -@keyframes mfm-rubberBand { - from { transform: scale3d(1, 1, 1); } - 30% { transform: scale3d(1.25, 0.75, 1); } - 40% { transform: scale3d(0.75, 1.25, 1); } - 50% { transform: scale3d(1.15, 0.85, 1); } - 65% { transform: scale3d(0.95, 1.05, 1); } - 75% { transform: scale3d(1.05, 0.95, 1); } - to { transform: scale3d(1, 1, 1); } -} - -@keyframes mfm-rainbow { - 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } - 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } -} - -@keyframes mfm-tada { - 0%, 100% { transform: scale3d(1, 1, 1); } - 10%, 20% { transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); } - 30%, 50%, 70%, 90% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); } - 40%, 60%, 80% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); } -} diff --git a/static/mfm.css b/static/mfm.css deleted file mode 100644 index a386ad3c..00000000 --- a/static/mfm.css +++ /dev/null @@ -1,228 +0,0 @@ -/* Some MFM CSS is also defined in ./src/components/status_content/mfm.scss */ -.mfm { - display: inline-block; -} - -._mfm_tada_ { - font-size: 150%; - animation: mfm-tada 1s linear infinite both; -} - -._mfm_jelly_ { - animation: mfm-jelly 1s linear infinite both; -} - -._mfm_twitch_ { - animation: mfm-twitch 0.5s ease infinite; -} - -._mfm_shake_ { - animation: mfm-shake 0.5s ease infinite; -} - -._mfm_spin_ { - animation: mfm-spin 0.5s linear infinite; -} - -._mfm_spin_[data-x] { - animation-name: mfm-spinX; -} -._mfm_spin_[data-y] { - animation-name: mfm-spinY; -} -._mfm_spin_[left] { - animation-direction: reverse; -} -._mfm_spin_[alternate] { - animation-direction: alternate; -} - -._mfm_jump_ { - animation: mfm-jump 0.75s linear infinite; -} - -._mfm_bounce_ { - animation: mfm-bounce 0.75s linear infinite; - transform-origin: center bottom; -} - -._mfm_flip_[data-h][data-v] { - transform: scale(-1, -1); -} -._mfm_flip_[data-v] { - transform: scaleY(-1); -} -._mfm_flip_:not([data-v]) { - transform: scaleX(-1); -} - -._mfm_x2_ { - font-size: 200%; -} - -._mfm_x3_ { - font-size: 400%; -} - -._mfm_x4_ { - font-size: 600%; -} - -._mfm_blur_ { - filter: blur(6px); - transition: filter 0.3s -} -._mfm_blur_:hover { - filter: blur(0px); -} - -._mfm_rainbow_ { - animation: mfm-rainbow 1s linear infinite; -} - -._mfm_rotate_ { - transform: rotate(90deg); - transform-origin: center center; -} - -/* sparkle */ - -@keyframes mfm-tada { - from { - transform: scale3d(1, 1, 1); - } - - 10%, - 20% { - transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); - } - - 30%, - 50%, - 70%, - 90% { - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, - 60%, - 80% { - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - transform: scale3d(1, 1, 1); - } -} - -@keyframes bounce { - 0% { - transform: scaleX(0.9) scaleY(0.9); - } - - 19% { - transform: scaleX(1.1) scaleY(1.1); - } - - 48% { - transform: scaleX(0.95) scaleY(0.95); - } - - 100% { - transform: scaleX(1) scaleY(1); - } -} - -@keyframes mfm-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -@keyframes mfm-spinX { - 0% { transform: perspective(128px) rotateX(0deg); } - 100% { transform: perspective(128px) rotateX(360deg); } -} - -@keyframes mfm-spinY { - 0% { transform: perspective(128px) rotateY(0deg); } - 100% { transform: perspective(128px) rotateY(360deg); } -} - -@keyframes mfm-jump { - 0% { transform: translateY(0); } - 25% { transform: translateY(-16px); } - 50% { transform: translateY(0); } - 75% { transform: translateY(-8px); } - 100% { transform: translateY(0); } -} - -@keyframes mfm-bounce { - 0% { transform: translateY(0) scale(1, 1); } - 25% { transform: translateY(-16px) scale(1, 1); } - 50% { transform: translateY(0) scale(1, 1); } - 75% { transform: translateY(0) scale(1.5, 0.75); } - 100% { transform: translateY(0) scale(1, 1); } -} - -@keyframes mfm-twitch { - 0% { transform: translate(7px, -2px); } - 5% { transform: translate(-3px, 1px); } - 10% { transform: translate(-7px, -1px); } - 15% { transform: translate(0, -1px); } - 20% { transform: translate(-8px, 6px); } - 25% { transform: translate(-4px, -3px); } - 30% { transform: translate(-4px, -6px); } - 35% { transform: translate(-8px, -8px); } - 40% { transform: translate(4px, 6px); } - 45% { transform: translate(-3px, 1px); } - 50% { transform: translate(2px, -10px); } - 55% { transform: translate(-7px, 0); } - 60% { transform: translate(-2px, 4px); } - 65% { transform: translate(3px, -8px); } - 70% { transform: translate(6px, 7px); } - 75% { transform: translate(-7px, -2px); } - 80% { transform: translate(-7px, -8px); } - 85% { transform: translate(9px, 3px); } - 90% { transform: translate(-3px, -2px); } - 95% { transform: translate(-10px, 2px); } - 100% { transform: translate(-2px, -6px); } -} - -@keyframes mfm-shake { - 0% { transform: translate(-3px, -1px) rotate(-8deg); } - 5% { transform: translate(0, -1px) rotate(-10deg); } - 10% { transform: translate(1px, -3px) rotate(0deg); } - 15% { transform: translate(1px, 1px) rotate(11deg); } - 20% { transform: translate(-2px, 1px) rotate(1deg); } - 25% { transform: translate(-1px, -2px) rotate(-2deg); } - 30% { transform: translate(-1px, 2px) rotate(-3deg); } - 35% { transform: translate(2px, 1px) rotate(6deg); } - 40% { transform: translate(-2px, -3px) rotate(-9deg); } - 45% { transform: translate(0, -1px) rotate(-12deg); } - 50% { transform: translate(1px, 2px) rotate(10deg); } - 55% { transform: translate(0, -3px) rotate(8deg); } - 60% { transform: translate(1px, -1px) rotate(8deg); } - 65% { transform: translate(0, -1px) rotate(-7deg); } - 70% { transform: translate(-1px, -3px) rotate(6deg); } - 75% { transform: translate(0, -2px) rotate(4deg); } - 80% { transform: translate(-2px, -1px) rotate(3deg); } - 85% { transform: translate(1px, -3px) rotate(-10deg); } - 90% { transform: translate(1px, 0) rotate(3deg); } - 95% { transform: translate(-2px, 0) rotate(-3deg); } - 100% { transform: translate(2px, 1px) rotate(2deg); } -} - -@keyframes mfm-jelly { - from { transform: scale3d(1, 1, 1); } - 30% { transform: scale3d(1.25, 0.75, 1); } - 40% { transform: scale3d(0.75, 1.25, 1); } - 50% { transform: scale3d(1.15, 0.85, 1); } - 65% { transform: scale3d(0.95, 1.05, 1); } - 75% { transform: scale3d(1.05, 0.95, 1); } - to { transform: scale3d(1, 1, 1); } -} - -@keyframes mfm-rainbow { - 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } - 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } -}