Skip to content

Instantly share code, notes, and snippets.

@cognominal
Created June 29, 2023 22:51
Show Gist options
  • Save cognominal/f62a2c532b437e60b7852f2d5f9be15d to your computer and use it in GitHub Desktop.
Save cognominal/f62a2c532b437e60b7852f2d5f9be15d to your computer and use it in GitHub Desktop.
Ferris wheel (CSS only)
<div class="scene">
<div class="ferriswheel">
<div class="stand">
<div class="side">
<div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="side">
<div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="base">
<div></div><div></div><div></div><div></div>
<div class="sideShadow">
<div></div><div></div><div></div><div></div>
</div>
<div class="cartShadow">
<div></div><div></div><div></div><div></div>
</div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
<div class="wing">
<div class="structure">
<div class="side"><i></i><i></i><i></i></div>
<div class="side"><i></i><i></i><i></i></div>
<i></i>
<div class="structure_center"></div>
</div>
<div class="cart">
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div><div></div>
<div class="cart_pole"></div>
<div class="cart_bottom"></div>
</div>
</div>
</div>
</div>
<script src="https://assets.codepen.io/1948355/twitterButton-2.1.0.js"></script>
*, *::before, *::after {
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
body {
background-image: linear-gradient(#024, #200 50%);
min-height: 100vh;
display: grid;
place-items: center;
font-size: 10px;
perspective: 80em;
overflow: hidden;
*:not(:empty) {
transform-style: preserve-3d;
}
}
$duration: 60s;
.scene {
position: relative;
animation: scene $duration -50s infinite linear;
@keyframes scene {
from { transform: translateY(-5em) rotateY(0deg); }
to { transform: translateY(-5em) rotateY(-360deg); }
}
}
.ferriswheel {
position: absolute;
@keyframes wheel {
from { transform: rotateZ(0deg); }
to { transform: rotateZ(360deg); }
}
}
.stand {
.side {
transform: rotateY(var(--ry, 0)) translateZ(6em);
&:nth-child(2) { --ry: 180deg; }
> div {
position: absolute;
&:nth-child(1) {
width: 25em; height: 25em;
transform: translateX(-50%) rotateX(4deg);
transform-origin: top;
background-image:
conic-gradient(from 140deg at top, #000 0, transparent 18.5deg, #000 37deg 43deg, transparent 61.5deg, #000 80deg),
linear-gradient(#000, #678 10%, #234);
clip-path: polygon(50% 0, 0 100%, 25% 100%, 50% 0, 100% 100%, 75% 100%);
}
&:nth-child(2) {
width: 25em; height: 25.55em;
transform: translateX(-50%) rotateX(12deg);
transform-origin: top;
background-image:
conic-gradient(from 140deg at top, #000 0, transparent 18.5deg, #000 37deg 43deg, transparent 61.5deg, #000 80deg),
linear-gradient(#000, #abc 10%, #234);
clip-path: polygon(50% 0, 0 100%, 25% 100%, 50% 0, 100% 100%, 75% 100%);
}
&:nth-child(3) {
width: 6em; height: 28em;
transform: rotateY(-90deg) rotateX(atan(0.5));
transform-origin: top left;
clip-path: polygon(0 0, 1.7em 100%, 5.4em 100%);
background-image:
conic-gradient(from 160deg at top left, #000 0, transparent 13deg, #000 30deg),
linear-gradient(#000, #abc 10%, #234);
}
&:nth-child(4) {
width: 6em; height: 25.7em;
transform: rotateY(-90deg) rotateX(atan(0.25));
transform-origin: top left;
clip-path: polygon(0 0, 1.7em 100%, 5.4em 100%);
background-image:
conic-gradient(from 160deg at top left, #000 0, transparent 13deg, #000 30deg),
linear-gradient(#000, #234 10%);
}
&:nth-child(5) {
width: 6em; height: 28em;
transform: rotateY(-90deg) rotateX(atan(-0.5));
transform-origin: top left;
clip-path: polygon(0 0, 1.7em 100%, 5.3em 100%);
background-image:
conic-gradient(from 160deg at top left, #000 0, transparent 13deg, #000 30deg),
linear-gradient(#000, #abc 10%, #234);
}
&:nth-child(6) {
width: 6em; height: 25.7em;
transform: rotateY(-90deg) rotateX(atan(-0.25));
transform-origin: top left;
clip-path: polygon(0 0, 1.7em 100%, 5.3em 100%);
background-image:
conic-gradient(from 160deg at top left, #000 0, transparent 13deg, #000 30deg),
linear-gradient(#000, #234 10%);
}
}
}
.base {
position: absolute;
inset: -20em;
background-color: #456;
transform: rotateX(-90deg) translateZ(25em);
box-shadow: 0 0 1em #000 inset;
> div:nth-child(-n + 4) {
position: absolute;
left: 0; top: 50%;
width: 100%; height: 2em;
background-color: #456;
transform-origin: top;
transform: rotateZ(var(--rz, 0)) rotateX(90deg) translateZ(20em);
box-shadow: 0 0 1em #000 inset;
&:nth-child(2) { --rz: 90deg; }
&:nth-child(3) { --rz: 180deg; }
&:nth-child(4) { --rz: 270deg; }
}
}
.sideShadow > div {
position: absolute;
left: 3em; top: 3em;
width: 6.2em; height: 3.4em;
background-color: #123;
filter: blur(0.5em);
&:nth-child(1) { left: 7.5em; top: 8.8em; }
&:nth-child(2) { left: 7.5em; top: 27.8em; }
&:nth-child(3) { left: 26.3em; top: 8.8em; }
&:nth-child(4) { left: 26.3em; top: 27.8em; }
}
.cartShadow {
position: absolute;
inset: 0;
div {
position: absolute;
inset: 10em;
background-image: radial-gradient(closest-side, #0007, transparent);
animation:
cartShadow $duration*0.5 var(--delay, 0s) infinite ease-in-out,
cartShadowOpacity $duration*0.5 var(--delay, 0s) infinite linear;
@keyframes cartShadow {
from { transform: translateX(70%); }
to { transform: translateX(-70%); }
}
@keyframes cartShadowOpacity {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
&:nth-child(2) { --delay: #{$duration*-0.125}; }
&:nth-child(3) { --delay: #{$duration*-0.25}; }
&:nth-child(4) { --delay: #{$duration*-0.375}; }
}
}
}
.wing {
position: absolute;
animation: wheel $duration var(--delay, 0s) infinite linear;
@for $i from 0 to 8 {
&:nth-child(#{$i + 2}) {
--delay: #{$duration * -0.125 * $i};
--hue: #{$i * 135};
}
}
}
.structure {
position: absolute;
width: 15em;
.side {
transform: translateZ(var(--tz, 5em));
&:nth-child(2) { --tz: -5em; }
i:nth-child(1) {
width: 11.5em;
transform-origin: left;
transform: translate(15em, -50%) rotateZ(112.5deg);
}
i:nth-child(2) {
width: 21.3em;
transform-origin: left;
transform: translate(15em, -50%) rotateZ(135deg);
}
i:nth-child(3) {
width: 14em;
transform: translate(1em, -50%);
}
}
i {
position: absolute;
left: 0; top: 0;
height: 0.25em;
background-image: linear-gradient(#aaa, #333, #aaa);
transform-style: preserve-3d;
border-radius: 0.25em;
&::after {
content: '';
position: absolute;
inset: 0;
transform: rotateX(var(--rx, 90deg));
background: inherit;
border-radius: inherit;
}
}
> i:nth-child(3) {
width: 10em;
background-color: #fff;
transform: translate(calc(15em - 50%), -50%) rotateY(90deg);
}
&_center {
position: absolute;
width: 14em; height: 1em;
background-image:
repeating-linear-gradient(90deg, #234 0 0.25em, #789 0 0.5em);
box-shadow: 0 0 0.5em #0005 inset;
transform: translate(-50%, -50%) rotateY(90deg) translateZ(calc(0.5em / tan(22.5deg)));
transform-style: preserve-3d;
&::before, &::after {
content: '';
position: absolute;
width: 1.4em; height: 1em;
background-image: repeating-radial-gradient(circle at right, #234 0 0.25em, #789 0 0.5em);
transform-origin: left;
transform: rotateY(120deg);
clip-path: polygon(0 0, 100% 50%, 0 100%);
}
&::after {
left: 100%;
transform: rotateY(60deg);
}
}
}
.cart {
position: absolute;
top: -0.4em; left: 15em;
// font-size: 20%;
transform-origin: 50% 0.4em;
animation: wheel $duration var(--delay, 0s) infinite linear reverse;
--color: hsl(var(--hue) 75% 75%);
> div {
position: absolute;
left: 0; top: 0;
&:nth-child(6n + 1) { --ry: 0deg; }
&:nth-child(6n + 2) { --ry: 60deg; }
&:nth-child(6n + 3) { --ry: 120deg; }
&:nth-child(6n + 4) { --ry: 180deg; }
&:nth-child(6n + 5) { --ry: 240deg; }
&:nth-child(6n + 6) { --ry: 300deg; }
&:nth-child(-n + 6) {
top: 1em;
width: 4em; height: 3.4em;
background-color: var(--color);
background-image:
conic-gradient(from 150deg at 50% -0.2em, #0001, 5deg, transparent, 55deg, #0002 60deg),
linear-gradient(#fff7, transparent);
transform-origin: top;
transform: translateX(-50%) rotateY(var(--ry)) translateZ(calc(0.1em * tan(60deg))) rotateX(75deg);
clip-path: polygon(1.9em 0, 2.1em 0, 100% 100%, 0 100%);
box-shadow: 0 0.1em 0.3em #0007 inset;
}
&:nth-child(n + 7):nth-child(-n + 12) {
top: 1.86em;
width: 4em; height: 0.6em;
background-color: var(--color);
transform: translateX(-50%) rotateY(var(--ry)) translateZ(calc(2em * tan(60deg)));
box-shadow: 0 0 0.4em #0004 inset;
}
&:nth-child(n + 13):nth-child(-n + 18) {
top: 9em;
width: 4em; height: 2em;
background-color: var(--color);
background-image: linear-gradient(#0007, #0000);
transform-origin: top;
transform: translateX(-50%) rotateY(var(--ry)) translateZ(calc(1.5em * tan(60deg))) rotateX(155deg);
clip-path: polygon(0.5em 0, 3.5em 0, 100% 100%, 0 100%);
box-shadow: 0 0.1em 0.6em #0007 inset;
}
&:nth-child(n + 19):nth-child(-n + 24) {
top: 6.6em;
width: 4em; height: 0.6em;
background-color: var(--color);
transform: translateX(-50%) rotateY(var(--ry)) translateZ(calc(2em * tan(60deg)));
box-shadow: 0 0 0.4em #0004 inset;
}
&.cart_pole {
width: 0.8em; height: 8.4em;
background-image:
radial-gradient(circle at 50% 0.4em, #fff, #aaa 0.4em, transparent 0.4em),
linear-gradient(90deg, transparent 0.3em, #777 0.3em, #fff, #777 0.5em, transparent 0.5em);
transform: translateX(-50%) rotateY(var(--ry)) translateZ(calc(0.1em * tan(60deg)));
transform-style: preserve-3d;
&::before, &::after {
content: '';
position: absolute;
inset: 0;
transform: rotateY(var(--rx, 60deg));
background: inherit;
border-radius: inherit;
}
&::after { --rx: 120deg; }
}
&.cart_bottom {
top: 9em;
width: 6em; height: calc(3em * tan(60deg));
background-color: var(--color);
background-image: radial-gradient(#000a, #0007);
transform: translate(-50%, -50%) rotateX(90deg);
clip-path: polygon(0 50%, 25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment