Skip to content

Instantly share code, notes, and snippets.

@mateothegreat
Created January 17, 2018 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mateothegreat/55e18ffd8564c8d0bcca549cae0cc693 to your computer and use it in GitHub Desktop.
Save mateothegreat/55e18ffd8564c8d0bcca549cae0cc693 to your computer and use it in GitHub Desktop.
CSS 3D Bouncy Castle
<div class="scene">
<div class="bouncy-castle">
<div class="floor">
<div class="floor__section floor__section--1">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="floor__section floor__section--2 floor__section--teal">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="floor__section floor__section--3">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="floor__section floor__section--4 floor__section--teal">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="floor__section floor__section--5">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="floor__grass">
<div class="face face--top"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
</div>
<div class="rope rope--left">
<div class="face"></div>
</div>
<div class="rope rope--right">
<div class="face"></div>
</div>
<div class="wall wall--back">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="wall wall--left">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="wall wall--right">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="pillar pillar-top-left">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="pillar pillar-top-right">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="pillar pillar-bottom-left">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="pillar pillar-bottom-right">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve">
<div class="steve__head">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve__body">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve__arm steve__arm--left">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve__arm steve__arm--right">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve__leg steve__leg--left">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
<div class="steve__leg steve__leg--right">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
</div>
<div class="robot">
<div class="face face--top"></div>
<div class="face face--bottom"></div>
<div class="face face--front"></div>
<div class="face face--back"></div>
<div class="face face--left"></div>
<div class="face face--right"></div>
</div>
</div>
</div>
//Variables
$animation-speed: 800ms;
$animation-delay: 0.5s;
$castle-size: 400px;
$grass-size: $castle-size + 240px;
$grass-depth: 48px;
$floor-section-size: $castle-size / 5;
$floor-depth: 72px;
$pillar-depth: 128px;
$pillar-thickness: 64px;
$wall-depth: 116px;
$wall-height: 32px;
$wall-width: $castle-size - ($pillar-thickness * 2) + 24px;
$snap-edge: ($castle-size / 2) - ($pillar-thickness / 2);
//Pivot Mixin
@mixin pivot(){
position: absolute;
left: 50%;
top: 50%;
transform-origin: 50%;
transform-style: preserve-3d;
}
//Face Mixin
@mixin face(
$texture: 'face-placeholder.jpg',
$texture-size: 128px,
$texture-position: 'center',
$height: 128px,
$width: 128px
){
backface-visibility: hidden;
background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/1678849/' + $texture);
background-position: $texture-position;
background-size: $texture-size;
height: $height;
position: absolute;
transform-style: preserve-3d;
width: $width;
image-rendering: -webkit-optimize-contrast;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
}
//Box Mixin
@mixin box(
$pivot-position-x: "center",
$pivot-position-y: "center",
$pivot-position-z: "center",
$depth: 128px,
$height: 128px,
$width: 128px,
$shadow-bottom: true,
$texture: "box-placeholder.jpg",
$texture-top: $texture,
$texture-bottom: $texture,
$texture-left: $texture,
$texture-right: $texture,
$texture-front: $texture,
$texture-back: $texture,
$texture-size: 128px,
$top-x: 0,
$bottom-x: 0,
$sides-x: 0,
$top-y: 0,
$bottom-y: 0,
$sides-y: 0,
$top-z: 0,
$bottom-z: 0,
$sides-z: 0
){
@if($pivot-position-z == 'top'){
$top-z: 0;
$bottom-z: - $depth;
$sides-z: - $depth /2;
}@else if($pivot-position-z == 'center'){
$top-z: $depth / 2;
$bottom-z: - $depth / 2;
$sides-z: 0;
}@else{
$top-z: $depth;
$bottom-z: 0;
$sides-z: $depth /2;
}
@if($pivot-position-y == 'top'){
$top-y: 0;
$bottom-y: 0;
$sides-y: calc( -50% + #{$height / 2});
}@else if($pivot-position-y == 'center'){
$top-y: -50%;
$bottom-y: -50%;
$sides-y: -50%;
}@else{
$top-y: -$height;
$bottom-y: -$height;
$sides-y: calc( -50% - #{$height / 2});
}
@if($pivot-position-x == 'left'){
$top-x: 0;
$bottom-x: 0;
$sides-x: calc( -50% + #{$width / 2});
}@else if($pivot-position-x == 'center'){
$top-x: -50%;
$bottom-x: -50%;
$sides-x: -50%;
}@else{
$top-x: -$width;
$bottom-x: -$width;
$sides-x: calc( -50% - #{$width / 2});
}
@include pivot;
.face--top{
@include face($texture-top, $texture-size, center, $height, $width);
transform: translate3d($top-x, $top-y, $top-z);
}
.face--bottom{
@include face($texture-bottom, $texture-size, center, $height, $width);
transform: translate3d($bottom-x, $bottom-y, $bottom-z);
@if($shadow-bottom){
box-shadow: 0 0 10px rgba(0,0,0,0.8);
}
}
.face--front{
@include face($texture-front, $texture-size, top center, $depth, $width);
transform: translate3d($sides-x, $sides-y, $sides-z)
translateY( $height / 2 )
rotateX(270deg);
}
.face--back{
@include face($texture-back, $texture-size, top center, $depth, $width);
transform: translate3d($sides-x, $sides-y, $sides-z)
translateY( -$height / 2 )
rotateX(270deg)
rotateY(180deg);
}
.face--left {
@include face($texture-left, $texture-size, top center, $depth, $height);
transform: translate3d($sides-x, $sides-y, $sides-z)
translateX( $width / 2 )
rotateX(270deg)
rotateY(90deg);
}
.face--right{
@include face($texture-right, $texture-size, top center, $depth, $height);
transform: translate3d($sides-x, $sides-y, $sides-z)
translateX( -$width / 2 )
rotateX(270deg)
rotateY(270deg);
}
}
//HTML & BODY
html{
height: 100%;
}
body {
background-color: #252c36;
background-image: linear-gradient(rgba(0,0,0,0.4),rgba(0,0,0,0.4),rgba(0,0,0,0));
height: 100%;
overflow: hidden;
transform: scale(0.75);
}
//Scene
.scene{
@include pivot;
transform: rotateX(45deg) rotateZ(225deg);
animation: sceneSpin 30s infinite linear;
}
@keyframes sceneSpin{
0%{ transform: rotateX(45deg) rotateZ(225deg); }
50%{ transform: rotateX(45deg) rotateZ(135deg); }
100%{ transform: rotateX(45deg) rotateZ(225deg); }
}
//Bouncy Castle
.bouncy-castle{
@include pivot;
}
//Floor
.floor{
@include pivot;
transform: translateZ(-2px);
}
.floor__grass{
@include box(
$pivot-position-z: 'top',
$depth: $grass-depth,
$height: $grass-size,
$width: $grass-size,
$texture: "grass-side.png",
$texture-top: "grass.png",
$texture-size: cover
);
transform: translateZ(-$floor-depth - 40px);
}
.floor__section{
@include box(
$pivot-position-z: 'top',
$depth: $floor-depth,
$height: $castle-size,
$width: $castle-size / 5,
$texture: "bouncy-dark.png",
$texture-left: "bouncy-dark-side.png",
$texture-right: "bouncy-dark-side.png",
$texture-front: "bouncy-dark-cap.png",
$texture-back: "bouncy-dark-cap.png",
$texture-size: cover
);
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.floor__section--teal{
@include box(
$pivot-position-z: 'top',
$depth: $floor-depth,
$height: $castle-size,
$width: $castle-size / 5,
$texture: "bouncy-teal.png",
$texture-left: "bouncy-teal-side.png",
$texture-right: "bouncy-teal-side.png",
$texture-front: "bouncy-teal-cap.png",
$texture-back: "bouncy-teal-cap.png",
$texture-size: cover
);
}
.floor__section--1{
animation-name: floorSection1;
transform: translateX( ($castle-size / 2) - ($floor-section-size / 2)) translateZ(-8px);
}
.floor__section--2{
animation-name: floorSection2;
transform: translateX( ($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size) translateZ(-20px);
}
.floor__section--3{
animation-name: floorSection3;
transform: translateZ(-28px);
}
.floor__section--4{
animation-name: floorSection4;
transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size)) translateZ(-16px);
}
.floor__section--5{
animation-name: floorSection5;
transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2))) translateZ(-8px);
}
@keyframes floorSection1{
0%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2)) translateZ(-8px); }
50%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2)) translateZ(-0); }
100%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2)) translateZ(-8px); }
}
@keyframes floorSection2{
0%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size) translateZ(-20px); }
50%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size) translateZ(0); }
100%{ transform: translateX( ($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size) translateZ(-20px); }
}
@keyframes floorSection3{
0%{ transform: translateZ(-28px); }
50%{ transform: translateZ(0); }
100%{ transform: translateZ(-28px); }
}
@keyframes floorSection4{
0%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size)) translateZ(-16px); }
50%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size)) translateZ(0); }
100%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2) - $floor-section-size)) translateZ(-16px); }
}
@keyframes floorSection5{
0%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2))) translateZ(-8px); }
50%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2))) translateZ(0); }
100%{ transform: translateX( - (($castle-size / 2) - ($floor-section-size / 2))) translateZ(-8px); }
}
//Pillars
.pillar{
@include box(
$pivot-position-z: 'bottom',
$depth: $pillar-depth,
$height: $pillar-thickness,
$width: $pillar-thickness,
$texture: 'bouncy-pillar.png',
$texture-top: 'bouncy-pillar-cap.png',
$texture-size: cover
);
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.pillar-top-left{
animation-name: pillarTopLeft;
transform: translateY(-$snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0);
}
.pillar-top-right{
animation-name: pillarTopRight;
transform: translateY(-$snap-edge) translateX($snap-edge) rotateX(0) rotateY(0);
}
.pillar-bottom-left{
animation-name: pillarBottomLeft;
transform: translateY($snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0);
}
.pillar-bottom-right{
animation-name: pillarBottomRight;
transform: translateY($snap-edge) translateX($snap-edge) rotateX(0) rotateY(0);
}
@keyframes pillarTopLeft{
0%{ transform: translateY(-$snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0); }
50%{ transform: translateY(-$snap-edge) translateX(-$snap-edge) rotateX(6deg) rotateY(-6deg); }
100%{ transform: translateY(-$snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0); }
}
@keyframes pillarTopRight{
0%{ transform: translateY(-$snap-edge) translateX($snap-edge) rotateX(0) rotateY(0); }
50%{ transform: translateY(-$snap-edge) translateX($snap-edge) rotateX(6deg) rotateY(6deg); }
100%{ transform: translateY(-$snap-edge) translateX($snap-edge) rotateX(0) rotateY(0); }
}
@keyframes pillarBottomLeft{
0%{ transform: translateY($snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0); }
50%{ transform: translateY($snap-edge) translateX(-$snap-edge) rotateX(-6deg) rotateY(-6deg); }
100%{ transform: translateY($snap-edge) translateX(-$snap-edge) rotateX(0) rotateY(0); }
}
@keyframes pillarBottomRight{
0%{ transform: translateY($snap-edge) translateX($snap-edge) rotateX(0) rotateY(0); }
50%{ transform: translateY($snap-edge) translateX($snap-edge) rotateX(-6deg) rotateY(6deg); }
100%{ transform: translateY($snap-edge) translateX($snap-edge) rotateX(0) rotateY(0); }
}
//Walls
.wall{
@include box(
$pivot-position-z: 'bottom',
$depth: $wall-depth,
$height: $wall-height,
$width: $wall-width,
$texture: "bouncy-wall.png",
$texture-top: "bouncy-wall-top.png",
$texture-size: cover
);
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.wall--back{
animation-name: wallBack;
transform: translateY($snap-edge) rotateX(0deg);
}
.wall--left{
animation-name: wallLeft;
transform: translateX(-$snap-edge) rotateZ(90deg) rotateX(0);
}
.wall--right{
animation-name: wallRight;
transform: translateX($snap-edge) rotateZ(90deg) rotateX(0);
}
@keyframes wallBack{
0%{ transform: translateY($snap-edge) rotateX(0deg); }
50%{ transform: translateY($snap-edge) rotateX(-8deg); }
100%{ transform: translateY($snap-edge) rotateX(0deg); }
}
@keyframes wallRight{
0%{ transform: translateX($snap-edge) rotateZ(90deg) rotateX(0); }
50%{ transform: translateX($snap-edge) rotateZ(90deg) rotateX(8deg); }
100%{ transform: translateX($snap-edge) rotateZ(90deg) rotateX(0); }
}
@keyframes wallLeft{
0%{ transform: translateX(-$snap-edge) rotateZ(90deg) rotateX(0); }
50%{ transform: translateX(-$snap-edge) rotateZ(90deg) rotateX(-8deg); }
100%{ transform: translateX(-$snap-edge) rotateZ(90deg) rotateX(0); }
}
//Robot
.robot{
@include box(
$pivot-position-z: 'bottom',
$depth: 27px,
$height: 54px,
$width: 27px,
$shadow-bottom: false,
$texture: "face-placeholder.jpg",
$texture-bottom: "robot-bottom.gif",
$texture-top: "robot-top.png",
$texture-left: "robot-side.png",
$texture-right: "robot-side.png",
$texture-front: "robot-cap.png",
$texture-back: "robot-cap.png",
$texture-size: cover
);
animation: robot $animation-speed infinite ease-in-out $animation-delay;
transform: translateY(-100px) translateX(100px) translateZ(-20px) rotateZ(45deg);
.face--bottom{
height: 78px;
width: 51px;
transform: translate3d(-50%, -50%, 13px);
}
}
@keyframes robot{
0%{ transform: translateY(-100px) translateX(100px) translateZ(-20px) rotateZ(45deg); }
50%{ transform: translateY(-100px) translateX(100px) translateZ(0) rotateZ(45deg); }
100%{ transform: translateY(-100px) translateX(100px) translateZ(-20px) rotateZ(45deg); }
}
//Steve
.steve{
@include pivot;
animation: steve $animation-speed infinite ease-in-out $animation-delay;
transform: translateZ(18px);
}
.steve__head{
@include box(
$pivot-position-z: 'bottom',
$depth: 32px,
$height: 32px,
$width: 32px,
$shadow-bottom: false,
$texture: "steve-head-top.png",
$texture-back: "steve-face.png",
$texture-left: "steve-head-right.png",
$texture-right: "steve-head-left.png",
$texture-size: cover
);
animation: steveHead $animation-speed infinite ease-in-out $animation-delay;
transform: translateZ(54px);
}
.steve__body{
@include box(
$pivot-position-z: 'top',
$depth: 48px,
$height: 24px,
$width: 32px,
$shadow-bottom: false,
$texture: "steve-body.png",
$texture-back: "steve-body-front.png",
$texture-size: cover
);
transform: translateZ(52px);
}
.steve__leg{
@include box(
$pivot-position-z: 'top',
$depth: 52px,
$height: 16px,
$width: 16px,
$texture: "steve-leg.png",
$texture-size: cover
);
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.steve__arm{
@include box(
$pivot-position-z: 'top',
$depth: 52px,
$height: 16px,
$width: 16px,
$shadow-bottom: false,
$texture: "steve-arm.png",
$texture-size: cover
);
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.steve__arm--left{
animation-name: steveArmLeft;
transform: translateX(-24px) translateZ(48px);
}
.steve__arm--right{
animation-name: steveArmRight;
transform: translateX(24px) translateZ(48px);
}
.steve__leg--left{
animation-name: steveLegLeft;
transform: translateX(-8px);
}
.steve__leg--right{
animation-name: steveLegRight;
transform: translateX(8px);
}
@keyframes steve{
0%{ transform: translateZ(18px); }
50%{ transform: translateZ(128px); }
100%{ transform: translateZ(18px); }
}
@keyframes steveHead{
0%{ transform: translateZ(54px) rotateX(0); }
50%{ transform: translateZ(54px) rotateX(-8deg); }
100%{ transform: translateZ(54px) rotateX(0); }
}
@keyframes steveArmLeft{
0%{ transform: translateX(-24px) translateZ(48px) rotateY(0); }
50%{ transform: translateX(-24px) translateZ(48px) rotateY(40deg); }
100%{ transform: translateX(-24px) translateZ(48px) rotateY(0); }
}
@keyframes steveArmRight{
0%{ transform: translateX(24px) translateZ(48px) rotateY(0); }
50%{ transform: translateX(24px) translateZ(48px) rotateY(-40deg); }
100%{ transform: translateX(24px) translateZ(48px) rotateY(0); }
}
@keyframes steveLegLeft{
0%{ transform: translateX(-8px) rotateY(0); }
50%{ transform: translateX(-8px) rotateY(20deg); }
100%{ transform: translateX(-8px) rotateY(0); }
}
@keyframes steveLegRight{
0%{ transform: translateX(8px) rotateY(0); }
50%{ transform: translateX(8px) rotateY(-20deg); }
100%{ transform: translateX(8px) rotateY(0); }
}
//Rope
.rope{
@include pivot;
animation-duration: $animation-speed;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: $animation-delay;
}
.rope .face{
@include face('rope.png', cover, center, 124px, $castle-size);
transform: translate3d(-50%, -50%, 0);
}
.rope--left{
animation-name: ropeLeft;
transform: translateX(252px) translateZ(-74px) rotateY(30deg) rotateZ(-90deg);
}
.rope--right{
animation-name: ropeRight;
transform: translateX(-252px) translateZ(-74px) rotateY(-30deg) rotateZ(-270deg);
}
@keyframes ropeLeft{
0%{ transform: translateX(252px) translateZ(-74px) rotateY(30deg) rotateZ(-90deg); }
50%{ transform: translateX(252px) translateZ(-74px) rotateY(40deg) rotateZ(-90deg); }
100%{ transform: translateX(252px) translateZ(-74px) rotateY(30deg) rotateZ(-90deg); }
}
@keyframes ropeRight{
0%{ transform: translateX(-252px) translateZ(-74px) rotateY(-30deg) rotateZ(-270deg); }
50%{ transform: translateX(-252px) translateZ(-74px) rotateY(-40deg) rotateZ(-270deg); }
100%{ transform: translateX(-252px) translateZ(-74px) rotateY(-30deg) rotateZ(-270deg); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment