Skip to content

Instantly share code, notes, and snippets.

@pierreburel
Created February 17, 2023 05:54
Show Gist options
  • Save pierreburel/f1b9a651694a1395a051e6f3cbbd1e53 to your computer and use it in GitHub Desktop.
Save pierreburel/f1b9a651694a1395a051e6f3cbbd1e53 to your computer and use it in GitHub Desktop.
Generated by SassMeister.com.
@use "sass:list";
@use "sass:map";
@use "sass:math";
@use "sass:string";
$mass: 1 !default;
$stiffness: 100 !default;
$damping: 15 !default;
$steps: 50 !default;
$preset-gentle: (
mass: 1,
stiffness: 100,
damping: 15,
);
$preset-quick: (
mass: 1,
stiffness: 300,
damping: 20,
);
$preset-bouncy: (
mass: 1,
stiffness: 600,
damping: 15,
);
$preset-slow: (
mass: 1,
stiffness: 80,
damping: 20,
);
@function spring($t, $mass: $mass, $stiffness: $stiffness, $damping: $damping) {
$w0: math.sqrt($stiffness / $mass);
$zeta: $damping / (2 * math.sqrt($stiffness * $mass));
$wd: if($zeta < 1, $w0 * math.sqrt(1 - $zeta * $zeta), 0);
$a: 1;
$b: if($zeta < 1, $zeta * $w0 / $wd, $w0);
@if $zeta < 1 {
@return 1 - math.pow(math.$e, -$t * $zeta * $w0) * ($a * math.cos($wd * $t) + $b * math.sin($wd * $t));
}
@return 1 - ($a + $b * $t) * math.pow(math.$e, -$t * $w0);
}
@function lerp($from, $to, $t) {
@return $from * (1 - $t) + $to * $t;
}
@function precision($float, $digits: 1) {
$pow: math.pow(10, $digits);
@return round($float * $pow) / $pow;
}
@function keyframes($properties, $steps: $steps, $args...) {
$keyframes: ();
@for $i from 0 through $steps {
$percentage: $i * 100 / $steps + '%';
$keyframe: ();
$transform: '';
@each $property, $values in $properties {
$from: list.nth($values, 1);
$to: list.nth($values, 2);
$value: if($i == 0, $from, if($i == $steps, $to, precision(lerp($from, $to, spring($i / $steps, $args...)))));
@if list.index($transforms, $property) {
$transform: "#{$transform} #{$property}(#{$value})";
} @else {
$keyframe: map.set($keyframe, $property, $value);
}
}
$keyframe: map.set($keyframe, transform, string.slice(string.unquote($transform), 2, -1));
$keyframes: map.set($keyframes, $percentage, $keyframe);
}
// Optimize by removing consecutive values
$last: ();
$before-last: ();
@each $keyframe, $properties in $keyframes {
@each $property, $value in $properties {
@if map.get($last, $property, value) == $value and map.get($before-last, $property, value) == $value {
$keyframes: map.deep-remove($keyframes, map.get($last, $property, keyframe), $property);
}
$before-last: map.set($before-last, $property, map.get($last, $property));
$last: map.set($last, $property, (keyframe: $keyframe, value: $value));
}
}
@return $keyframes;
};
$transforms: ('translateX', 'translateY', 'translateZ', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'perspective');
@mixin keyframes($name, $properties, $steps: $steps, $args...) {
$keyframes: keyframes($properties, $steps, $args...);
@keyframes #{$name} {
@each $keyframe, $properties in $keyframes {
#{$keyframe} {
@each $property, $value in $properties {
#{$property}: $value;
}
}
}
}
}
@include keyframes(red, (
opacity: (0, 1),
translateX: (0%, 100%),
rotate: (0deg, 1turn),
scale: (1, 1.5),
));
@include keyframes(blue, (
opacity: (0, 1),
--translate: (0%, 100%),
--rotate: (0deg, 1turn),
--scale: (1, 1.5),
), $preset-bouncy...);
@property --translate {
initial-value: 0%;
inherits: false;
syntax: '<percentage>';
}
@property --rotate {
initial-value: 0deg;
inherits: false;
syntax: '<angle>';
}
@property --scale {
initial-value: 1;
inherits: false;
syntax: '<number>';
}
div {
width: 100px;
height: 100px;
animation-timing-function: linear;
animation-duration: 1s;
animation-fill-mode: both;
&:first-child {
background: red;
:hover & {
animation-name: red;
}
}
&:last-child {
background: blue;
transform: translateX(var(--translate)) rotate(var(--rotate)) scale(var(--scale));
:hover & {
animation-name: blue;
}
}
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 100vh;
margin: 0;
}
<div></div>
<div></div>
@keyframes red {
0% {
opacity: 0;
transform: translateX(0%) rotate(0deg) scale(1);
}
2% {
opacity: 0;
transform: translateX(1.8%) rotate(6.5deg) scale(1);
}
4% {
opacity: 0.1;
transform: translateX(6.5%) rotate(23.5deg) scale(1);
}
6% {
opacity: 0.1;
transform: translateX(13.2%) rotate(47.7deg) scale(1.1);
}
8% {
opacity: 0.2;
transform: translateX(21.2%) rotate(76.4deg) scale(1.1);
}
10% {
opacity: 0.3;
transform: translateX(29.8%) rotate(107.4deg) scale(1.1);
}
12% {
opacity: 0.4;
transform: translateX(38.6%) rotate(139deg) scale(1.2);
}
14% {
opacity: 0.5;
transform: translateX(47.3%) rotate(170.1deg) scale(1.2);
}
16% {
opacity: 0.6;
transform: translateX(55.5%) rotate(199.7deg) scale(1.3);
}
18% {
opacity: 0.6;
transform: translateX(63.1%) rotate(227.1deg) scale(1.3);
}
20% {
opacity: 0.7;
transform: translateX(70%) rotate(252deg) scale(1.3);
}
22% {
opacity: 0.8;
transform: translateX(76.2%) rotate(274.2deg) scale(1.4);
}
24% {
opacity: 0.8;
transform: translateX(81.5%) rotate(293.5deg) scale(1.4);
}
26% {
opacity: 0.9;
transform: translateX(86.2%) rotate(310.2deg) scale(1.4);
}
28% {
transform: translateX(90.1%) rotate(324.2deg) scale(1.5);
}
30% {
opacity: 0.9;
transform: translateX(93.3%) rotate(335.8deg) scale(1.5);
}
32% {
opacity: 1;
transform: translateX(95.9%) rotate(345.3deg) scale(1.5);
}
34% {
transform: translateX(98%) rotate(352.8deg) scale(1.5);
}
36% {
transform: translateX(99.6%) rotate(358.6deg) scale(1.5);
}
38% {
transform: translateX(100.8%) rotate(363deg) scale(1.5);
}
40% {
transform: translateX(101.7%) rotate(366.1deg) scale(1.5);
}
42% {
transform: translateX(102.3%) rotate(368.2deg) scale(1.5);
}
44% {
transform: translateX(102.6%) rotate(369.5deg) scale(1.5);
}
46% {
transform: translateX(102.8%) rotate(370.1deg) scale(1.5);
}
48% {
transform: translateX(102.8%) rotate(370.2deg) scale(1.5);
}
50% {
transform: translateX(102.8%) rotate(369.9deg) scale(1.5);
}
52% {
transform: translateX(102.6%) rotate(369.4deg) scale(1.5);
}
54% {
transform: translateX(102.4%) rotate(368.7deg) scale(1.5);
}
56% {
transform: translateX(102.2%) rotate(367.8deg) scale(1.5);
}
58% {
transform: translateX(101.9%) rotate(366.9deg) scale(1.5);
}
60% {
transform: translateX(101.7%) rotate(366deg) scale(1.5);
}
62% {
transform: translateX(101.4%) rotate(365.2deg) scale(1.5);
}
64% {
transform: translateX(101.2%) rotate(364.3deg) scale(1.5);
}
66% {
transform: translateX(101%) rotate(363.6deg) scale(1.5);
}
68% {
transform: translateX(100.8%) rotate(362.9deg) scale(1.5);
}
70% {
transform: translateX(100.6%) rotate(362.3deg) scale(1.5);
}
72% {
transform: translateX(100.5%) rotate(361.8deg) scale(1.5);
}
74% {
transform: translateX(100.4%) rotate(361.3deg) scale(1.5);
}
76% {
transform: translateX(100.3%) rotate(360.9deg) scale(1.5);
}
78% {
transform: translateX(100.2%) rotate(360.6deg) scale(1.5);
}
80% {
transform: translateX(100.1%) rotate(360.4deg) scale(1.5);
}
82% {
transform: translateX(100%) rotate(360.2deg) scale(1.5);
}
84% {
transform: translateX(100%) rotate(360deg) scale(1.5);
}
86% {
transform: translateX(100%) rotate(359.9deg) scale(1.5);
}
88% {
transform: translateX(99.9%) rotate(359.8deg) scale(1.5);
}
90% {
transform: translateX(99.9%) rotate(359.8deg) scale(1.5);
}
92% {
transform: translateX(99.9%) rotate(359.7deg) scale(1.5);
}
98% {
transform: translateX(99.9%) rotate(359.7deg) scale(1.5);
}
100% {
opacity: 1;
transform: translateX(100%) rotate(1turn) scale(1.5);
}
}
@keyframes blue {
0% {
opacity: 0;
--translate: 0%;
--rotate: 0deg;
--scale: 1;
}
2% {
opacity: 0.1;
--translate: 10.7%;
--rotate: 38.4deg;
--scale: 1.1;
}
4% {
opacity: 0.4;
--translate: 36.7%;
--rotate: 132.2deg;
--scale: 1.2;
}
6% {
opacity: 0.7;
--translate: 68.9%;
--rotate: 248deg;
--scale: 1.3;
}
8% {
opacity: 1;
--translate: 99%;
--rotate: 356.6deg;
--scale: 1.5;
}
10% {
opacity: 1.2;
--translate: 121.6%;
--rotate: 437.7deg;
--scale: 1.6;
}
12% {
opacity: 1.3;
--translate: 133.9%;
--rotate: 482deg;
--scale: 1.7;
}
14% {
opacity: 1.4;
--translate: 136.1%;
--rotate: 490deg;
}
16% {
opacity: 1.3;
--translate: 130.4%;
--rotate: 469.5deg;
--scale: 1.7;
}
18% {
opacity: 1.2;
--translate: 120%;
--rotate: 432.1deg;
--scale: 1.6;
}
20% {
opacity: 1.1;
--translate: 108.3%;
--rotate: 389.7deg;
--scale: 1.5;
}
22% {
opacity: 1;
--translate: 97.9%;
--rotate: 352.3deg;
}
24% {
opacity: 0.9;
--translate: 90.6%;
--rotate: 326.1deg;
--scale: 1.5;
}
26% {
--translate: 87.1%;
--rotate: 313.6deg;
--scale: 1.4;
}
28% {
--translate: 87.2%;
--rotate: 313.8deg;
}
30% {
--translate: 89.8%;
--rotate: 323.3deg;
--scale: 1.4;
}
32% {
opacity: 0.9;
--translate: 93.8%;
--rotate: 337.8deg;
--scale: 1.5;
}
34% {
opacity: 1;
--translate: 98.1%;
--rotate: 353.1deg;
}
36% {
--translate: 101.6%;
--rotate: 365.8deg;
}
38% {
--translate: 103.9%;
--rotate: 374deg;
}
40% {
--translate: 104.8%;
--rotate: 377.3deg;
}
42% {
--translate: 104.5%;
--rotate: 376.2deg;
}
44% {
--translate: 103.4%;
--rotate: 372.1deg;
}
46% {
--translate: 101.8%;
--rotate: 366.6deg;
}
48% {
--translate: 100.3%;
--rotate: 361.2deg;
}
50% {
--translate: 99.1%;
--rotate: 356.9deg;
}
52% {
--translate: 98.4%;
--rotate: 354.4deg;
}
54% {
--translate: 98.2%;
--rotate: 353.7deg;
}
56% {
--translate: 98.5%;
--rotate: 354.4deg;
}
58% {
--translate: 98.9%;
--rotate: 356.1deg;
}
60% {
--translate: 99.5%;
--rotate: 358.1deg;
}
62% {
--translate: 100%;
--rotate: 360deg;
}
64% {
--translate: 100.4%;
--rotate: 361.4deg;
}
66% {
--translate: 100.6%;
--rotate: 362.2deg;
}
68% {
--translate: 100.6%;
--rotate: 362.3deg;
}
70% {
--translate: 100.5%;
--rotate: 361.9deg;
}
72% {
--translate: 100.3%;
--rotate: 361.2deg;
}
74% {
--translate: 100.1%;
--rotate: 360.5deg;
}
76% {
--translate: 100%;
--rotate: 359.8deg;
}
78% {
--translate: 99.8%;
--rotate: 359.4deg;
}
80% {
--rotate: 359.2deg;
}
82% {
--rotate: 359.2deg;
}
84% {
--translate: 99.8%;
--rotate: 359.4deg;
}
86% {
--translate: 99.9%;
--rotate: 359.6deg;
}
88% {
--translate: 100%;
--rotate: 359.9deg;
}
90% {
--translate: 100%;
--rotate: 360.1deg;
}
92% {
--translate: 100.1%;
--rotate: 360.3deg;
}
96% {
--rotate: 360.3deg;
}
98% {
--translate: 100.1%;
--rotate: 360.2deg;
}
100% {
opacity: 1;
--translate: 100%;
--rotate: 1turn;
--scale: 1.5;
}
}
@property --translate {
initial-value: 0%;
inherits: false;
syntax: "<percentage>";
}
@property --rotate {
initial-value: 0deg;
inherits: false;
syntax: "<angle>";
}
@property --scale {
initial-value: 1;
inherits: false;
syntax: "<number>";
}
div {
width: 100px;
height: 100px;
animation-timing-function: linear;
animation-duration: 1s;
animation-fill-mode: both;
}
div:first-child {
background: red;
}
:hover div:first-child {
animation-name: red;
}
div:last-child {
background: blue;
transform: translateX(var(--translate)) rotate(var(--rotate)) scale(var(--scale));
}
:hover div:last-child {
animation-name: blue;
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 100vh;
margin: 0;
}
{
"sass": {
"compiler": "dart-sass/1.32.12",
"extensions": {},
"syntax": "SCSS",
"outputStyle": "expanded"
},
"autoprefixer": false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment