Skip to content

Instantly share code, notes, and snippets.

@liladas
Created November 29, 2021 23:45
Show Gist options
  • Save liladas/9f43665e03eb1593a358ee8ca599631d to your computer and use it in GitHub Desktop.
Save liladas/9f43665e03eb1593a358ee8ca599631d to your computer and use it in GitHub Desktop.
SVG animation with sliders
<main>
<small style="position: absolute; padding: .5rem;">For better experience please use Chrome</small>
<section id="artboard">
<svg class="figure" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<g class="figure-container">
<g class="figure-landscape"><!-- Background landscape -->
<g class="ground">
<path class="ground__shadow" shadow="1" d="M240 140 l-4000 0 l0 350 Z" />
</g>
<g class="tree" tree="1">
<circle class="tree__fooliage" cx="50" cy="50" r="50" />
<g>
<path class="tree__trunk" d="M50 125 l0 -95 l2 0 l0 95 Z" />
<path class="tree__branch" d="M50 80 l-8 -8 l-15 0 l0 -2 l13 0 l-5 -5 l1 -2 l16 16 Z" />
<path class="tree__branch" d="M50 44 l-12 -7 l0 -2 l3 2 l0 -20 l2 0 l0 21 l7 4 Z" />
<path class="tree__branch" d="M52 64 l25 -20 l1 1 l-8 7 l20 0 l0 2 l-22 0 l-16 13 Z" />
<path class="tree__branch" d="M52 86 l12 -10 l2 1 l-14 12 Z" />
</g>
</g>
<g class="tree" tree="2">
<circle class="tree__fooliage" cx="50" cy="50" r="50" />
<g>
<path class="tree__trunk" d="M50 125 l0 -95 l2 0 l0 95 Z" />
<path class="tree__branch" d="M50 80 l-8 -8 l-15 0 l0 -2 l13 0 l-5 -5 l1 -2 l16 16 Z" />
<path class="tree__branch" d="M50 44 l-12 -7 l0 -2 l3 2 l0 -20 l2 0 l0 21 l7 4 Z" />
<path class="tree__branch" d="M52 64 l25 -20 l1 1 l-8 7 l20 0 l0 2 l-22 0 l-16 13 Z" />
<path class="tree__branch" d="M52 86 l12 -10 l2 1 l-14 12 Z" />
</g>
</g>
<g class="shrub" shrub="3">
<path class="shrub__part" d="M21 125 a20 20 0 0 1 40 0 Z" />
<path class="shrub__part" d="M6 135 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M0 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M41 139 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M61 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M16 140 a25 25 0 0 1 50 0 Z" />
</g>
<g class="shrub" shrub="4">
<path class="shrub__part" d="M21 125 a20 20 0 0 1 40 0 Z" />
<path class="shrub__part" d="M41 139 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M61 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M16 140 a25 25 0 0 1 50 0 Z" />
</g>
<g class="shrub" shrub="5">
<path class="shrub__part" d="M21 125 a20 20 0 0 1 40 0 Z" />
<path class="shrub__part" d="M6 135 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M0 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M41 139 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M61 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M16 140 a25 25 0 0 1 50 0 Z" />
</g>
</g>
<g class="figure-house">
<g class="foundation">
<g class="foundation__pole" pole="1">
<rect class="foundation__pole--front" />
<rect class="foundation__pole--back" />
</g>
<g class="foundation__pole" pole="2">
<rect class="foundation__pole--front" />
<rect class="foundation__pole--back" />
</g>
<g class="foundation__pole" pole="3">
<rect class="foundation__pole--front" />
<rect class="foundation__pole--back" x="3" />
</g>
<g class="foundation__pole" pole="4">
<rect class="foundation__pole--front" />
<rect class="foundation__pole--back" x="3" />
</g>
<g class="foundation__floor">
<rect/>
<rect/>
</g>
</g>
<g class="house">
<g class="house__side">
<path class="house__side__wall" d="M0 100 l0 -86 l33 -26 l33 26 l0 86 Z" />
<circle class="house__side__topwindow" cx="33" cy="6" r="7" />
<rect class="house__side__window" />
</g>
<g class="house__entrance">
<rect class="house__entrance__wall" />
<g class="house__entrance__sliding-door">
<rect class="house__entrance__sliding-door__frame" />
<rect class="house__entrance__sliding-door__glass" glass="1" />
<rect class="house__entrance__sliding-door__glass" glass="2" />
<rect class="house__entrance__sliding-door__glass" glass="3" />
</g>
</g>
<g class="house__protruding-part">
<rect class="house__protruding-part__side-wall" />
<rect class="house__protruding-part__wall" />
<rect class="house__protruding-part__window" />
</g>
<g class="house__roof">
<rect class="house__roof__tiles"/>
<g class="house__roof__tower">
<path class="house__roof__tower__side-wall" d="M0 0 l6 0 l13 10 l6 0 l0 -13 l-13 -9 l-12 9 Z" />
<path class="house__roof__tower__front-wall" d="M25 -3 l0 13 l25 0 l0 -13 Z" />
<rect class="house__roof__tower__roof"/>
<circle class="house__roof__tower__topwindow" cx="12" cy="-5" r="2" />
<rect class="house__roof__tower__window" />
</g>
</g>
</g>
</g>
<g class="figure-landscape"><!-- Foreground landscape -->
<g class="shrub" shrub="1">
<path class="shrub__part" d="M21 125 a20 20 0 0 1 40 0 Z" />
<path class="shrub__part" d="M6 135 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M0 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M41 139 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M61 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M16 140 a25 25 0 0 1 50 0 Z" />
</g>
<g class="shrub" shrub="2">
<path class="shrub__part" d="M21 125 a20 20 0 0 1 40 0 Z" />
<path class="shrub__part" d="M6 135 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M0 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M41 139 a15 15 0 0 1 30 0 Z" />
<path class="shrub__part" d="M61 140 a10 10 0 0 1 20 0 Z" />
<path class="shrub__part" d="M16 140 a25 25 0 0 1 50 0 Z" />
</g>
</g>
</g>
</svg>
</section>
<section id="controls">
<div id="house-size-slider" class="controller"></div>
<div id="foundation-height-slider" class="controller"></div>
<div id="foundation-width-slider" class="controller"></div>
</section>
</main>
<footer>
<small>
I saw this fancy animation by <a href="https://www.instagram.com/p/BdsGs4DlqMV/?taken-by=ameenimagina" target="_blank">Ameen Shahid</a> - I wanted to recreate it with HTML and CSS - made by <a href="https://twitter.com/knekkii" target="_blank">Kenneth Aamås</a></small>
</footer>
const config = {
start: [ 1 ],
step: 1,
range: {
min: [ 1 ],
max: [ 150 ]
}
};
let houseSizeSlider = noUiSlider.create(document.getElementById('house-size-slider'), config),
foundationHeightSlider = noUiSlider.create(document.getElementById('foundation-height-slider'), config),
foundationWidthSlider = noUiSlider.create(document.getElementById('foundation-width-slider'), config);
houseSizeSlider.on('update', updateValue);
foundationHeightSlider.on('update', updateValue);
foundationWidthSlider.on('update', updateValue);
function updateValue() {
let value = parseInt(this.get()),
id = this.target.id;
switch (id) {
case 'house-size-slider':
document.documentElement.style.setProperty('--house--size', (63 + value) + 'px');
break;
case 'foundation-height-slider':
document.documentElement.style.setProperty('--foundation--height', (41 + (value >= 2? (value / 2) : value)) + 'px');
break;
case 'foundation-width-slider':
document.documentElement.style.setProperty('--foundation--width', (174 + value) + 'px');
break;
default:
}
}
function playIntroSequence() {
// Intro sequence
setTimeout(() => {
houseSizeSlider.set(100);
foundationHeightSlider.set(100);
foundationWidthSlider.set(100);
}, 500);
setTimeout(() => {
houseSizeSlider.set(0);
}, 1100);
setTimeout(() => {
houseSizeSlider.set(100);
}, 1700);
setTimeout(() => {
foundationWidthSlider.set(150);
}, 2300);
setTimeout(() => {
foundationWidthSlider.set(100);
}, 2900);
setTimeout(() => {
houseSizeSlider.set(150);
foundationWidthSlider.set(150);
}, 3700);
setTimeout(() => {
houseSizeSlider.set(1);
foundationWidthSlider.set(1);
}, 4500);
setTimeout(() => {
houseSizeSlider.set(100);
foundationWidthSlider.set(100);
}, 5100);
setTimeout(() => {
houseSizeSlider.set(1);
foundationHeightSlider.set(1);
foundationWidthSlider.set(1);
}, 6000);
}
setTimeout(() => {
document.body.classList.add('ready');
// Play intro sequence
setTimeout(() => {
playIntroSequence();
}, 1000);
}, 0);
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/11.1.0/nouislider.min.js"></script>
@import url('https://fonts.googleapis.com/css?family=Inconsolata');
// Base
$primary: #414061;
$primary--light: #b8b9ea;
$primary--lighter: #d5d3f7;
$primary--dark: #393853;
$secondary: #ff986d;
$base: #fcfbff;
$transition-easing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
// Figure
$ground-shadow: $primary--dark;
$tree-fooliage: $secondary;
$tree-branch: #552427;
$house: $primary--light;
$house--size: 64px;
$house-foundation: $house;
$house-foundation--light: $primary--lighter;
$house-foundation--lighter: $base;
$house-foundation--height: 42px;
$house-foundation--width: 175px;
$house-wall: $house-foundation--light;
$house-wall--light: $house-foundation--lighter;
$house-roof: $base;
$house-window: $primary;
:root {
--house--size: $house--size;
--foundation--height: $house-foundation--height;
--foundation--width: $house-foundation--width;
}
body {
background-color: $primary;
color: $base;
font-family: 'Inconsolata', monospace;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr minmax(min-content, 40px);
align-items: center;
justify-content: center;
text-align: center;
margin: 0;
min-height: 100vh;
}
main {
display: grid;
grid-template-rows: minmax(300px, 1fr) 10vh;
grid-gap: 3vh;
height: 100%;
#artboard {
@extend %flex-center;
align-items: flex-end;
.figure {
position: relative;
height: 100%;
width: 100%;
// Groups
&-container {
transform: translate(calc(calc(100vw - 50%) - 145px), 30vh);
}
// Elements
.ground {
&__shadow {
fill: $ground-shadow;
&[shadow="1"] {
transform: translate(calc(calc(#{$house-foundation--width} - var(--foundation--width)) * -1), 0);
.ready & {
transition: transform 250ms 50ms $transition-easing-function;
}
}
}
}
.tree {
&[tree="1"] {
transform: translate(calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2), 18px);
.ready & {
transition: transform 250ms 50ms $transition-easing-function;
}
}
&[tree="2"] {
transform: translate(calc(178px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 1.1)), 53px) scale(.7);
.ready & {
transition: transform 250ms 50ms $transition-easing-function;
}
}
&__fooliage {
fill: $tree-fooliage;
}
&__branch, &__trunk {
fill: $tree-branch;
}
}
.shrub {
&[shrub="1"] {
transform: translate(calc(49px + calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 68px) scale(.55);
.ready & {
transition: transform 250ms 75ms $transition-easing-function;
}
}
&[shrub="2"] {
transform: translate(calc(130px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 102px) scale(.3);
.ready & {
transition: transform 250ms 50ms $transition-easing-function;
}
}
&[shrub="3"] {
transform: translate(calc(180px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 83px) scale(.4);
.ready & {
transition: transform 250ms 125ms $transition-easing-function;
}
}
&[shrub="4"] {
transform: translate(calc(185px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 57px) scale(.6);
.ready & {
transition: transform 250ms 100ms $transition-easing-function;
}
}
&[shrub="5"] {
transform: translate(calc(235px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 99px) scale(.3);
.ready & {
transition: transform 250ms 75ms $transition-easing-function;
}
}
&__part {
fill: $tree-fooliage;
}
}
.foundation {
&__pole {
&--front {
fill: $house-foundation;
.ready & {
transition: height 250ms $transition-easing-function;
}
}
&--back {
fill: $house-foundation--lighter;
.ready & {
transition: height 250ms $transition-easing-function;
}
}
&[pole="1"] {
transform: translate(calc(75px + calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 143px) rotate(180deg);
.ready & {
transition: transform 250ms $transition-easing-function;
}
.foundation__pole--front {
width: 10px;
height: var(--foundation--height);
}
.foundation__pole--back {
width: 3px;
height: var(--foundation--height);
}
}
&[pole="2"] {
transform: translate(calc(120px + calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 143px) rotate(180deg);
.ready & {
transition: transform 250ms $transition-easing-function;
}
.foundation__pole--front {
width: 10px;
height: var(--foundation--height);
}
.foundation__pole--back {
width: 3px;
height: var(--foundation--height);
}
}
&[pole="3"] {
transform: translate(calc(154px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 143px) rotate(180deg);
.ready & {
transition: transform 250ms $transition-easing-function;
}
.foundation__pole--front {
width: 10px;
height: var(--foundation--height);
}
.foundation__pole--back {
width: 7px;
height: var(--foundation--height);
}
}
&[pole="4"] {
transform: translate(calc(206px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), 143px) rotate(180deg);
.ready & {
transition: transform 250ms $transition-easing-function;
}
.foundation__pole--front {
width: 10px;
height: var(--foundation--height);
}
.foundation__pole--back {
width: 7px;
height: var(--foundation--height);
}
}
}
&__floor {
fill: $house-foundation--light;
transform: translate(calc(47px + calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2)), calc(136px - var(--foundation--height)));
.ready & {
transition: transform 250ms $transition-easing-function;
}
rect {
height: 7px;
}
rect:nth-of-type(1) {
width: var(--foundation--width);
.ready & {
transition: width 250ms $transition-easing-function;
}
}
rect:nth-of-type(2) {
fill: $house-foundation--lighter;
width: 7px;
transform: translate(calc(53px - calc(calc(#{$house-foundation--width} - var(--foundation--width)) / 2.5)), 0);
.ready & {
transition: transform 250ms $transition-easing-function;
}
}
}
}
.house {
fill: $house;
transform: translate(calc(71px + calc(calc(#{$house--size} - var(--house--size)) / 2)), calc(37px - var(--foundation--height)));
.ready & {
transition: transform 250ms $transition-easing-function;
}
&__side {
&__topwindow {
fill: $house-window;
}
&__window {
fill: $house-window;
height: 40px;
width: 24px;
transform: translate(20px, 30px);
}
}
&__entrance {
transform: translate(65px, 14px);
&__wall {
fill: $house;
height: 86px;
width: var(--house--size);
.ready & {
transition: width 250ms $transition-easing-function;
}
}
&__sliding-door {
transform: translate(1px, 8px);
&__frame {
fill: $house-foundation--lighter;
height: 78px;
width: $house--size;
}
&__glass {
fill: $house-window;
height: 70px;
width: 16px;
&[glass="1"] {
transform: translate(4px, 4px);
}
&[glass="2"] {
transform: translate(24px, 4px);
}
&[glass="3"] {
transform: translate(44px, 4px);
}
}
}
}
&__protruding-part {
transform: translate(calc(66px - calc(#{$house--size} - var(--house--size))), 14px);
.ready & {
transition: transform 250ms $transition-easing-function;
}
&__side-wall {
fill: $house-wall;
height: 86px;
width: $house--size;
}
&__wall {
fill: $house-wall--light;
height: 86px;
width: $house--size / 2;
transform: translate($house--size / 2, 0);
}
&__window {
fill: $house-window;
height: 40px;
width: 24px;
transform: translate(calc(#{$house--size / 2} + 5px), 16px);
}
}
&__roof {
--roof--length: 64px;
fill: $house-roof;
transform: translate(33px, -12px);
&__tiles {
height: 26px;
width: calc(var(--roof--length) - calc(#{$house--size} - var(--house--size)));
transform: skew(52deg);
.ready & {
transition: width 250ms $transition-easing-function;
}
}
&__tower {
transform: translate(calc(20px - calc(calc(#{$house--size} - var(--house--size)) / 2.25)), 0);
.ready & {
transition: transform 250ms $transition-easing-function;
}
&__side-wall {
fill: $house;
}
&__front-wall {
fill: $house-wall;
}
&__roof {
height: 9px;
width: 25px;
transform: translate(12px, -12px) skew(55deg);
}
&__topwindow {
fill: $house-window;
}
&__window {
fill: $house-window;
height: 7px;
width: 17px;
transform: translate(30px, 0);
}
}
}
}
}
}
#controls {
@extend %flex-center;
flex-wrap: wrap;
padding-top: .5rem;
#house-size-slider {
background-color: $base;
.noUi-handle {
border-color: $base;
}
}
#foundation-height-slider {
background-color: $secondary;
.noUi-handle {
border-color: $secondary;
}
}
#foundation-width-slider {
background-color: $primary--light;
.noUi-handle {
border-color: $primary--light;
}
}
.controller {
flex: 1;
margin: 0 3vw;
min-width: 70px;
max-width: 120px;
border: unset;
box-shadow: unset;
height: 2px;
.noUi-handle {
background-color: $primary;
border-radius: 0;
border-width: 2px;
box-shadow: unset;
width: 10px;
height: 10px;
right: -8px;
top: -4px;
&::before, &::after {
content: unset;
}
}
}
}
}
footer {
padding: 0 1rem;
}
a {
color: $primary--light;
}
%flex-center {
display: flex;
justify-content: center;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/11.1.0/nouislider.min.css" rel="stylesheet" />

SVG animation with sliders

Beautiful SVG animation which can be controlled by sliders. I got the idea from a post made by Ameen Shahid on Instagram, so I decided to try to recreate the illustrasjon/animation by only using SVG and CSS animations.

A Pen by Kenneth Aamås on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment