Skip to content

Instantly share code, notes, and snippets.

@MikletNg
Created January 10, 2023 16:40
Show Gist options
  • Save MikletNg/e0d130d2fa308694ea87971eb9ed95d4 to your computer and use it in GitHub Desktop.
Save MikletNg/e0d130d2fa308694ea87971eb9ed95d4 to your computer and use it in GitHub Desktop.
Minecraft Wolf - 3D CSS
// Lil minecraft wolf
// source:
// https://minecraft.fandom.com/wiki/Wolf
// Inspired by the works of Grant Jenkins:
// https://codepen.io/grantjenkins/pen/ZExEOex?editors=0100
mixin box(name)
.box(class=name)
.lt
.rt
.tp
.bt
.ft
.bk
.scene
+box('mud')
+box('grass')
.shadow
.wolf
.legs
+box('leg lt bk')
+box('leg lt ft')
+box('leg rt bk')
+box('leg rt ft')
.tails
+box('tail')
.bodys
+box('body ft')
+box('body bk')
.heads
+box('head')
+box('snout')
.mouths
+box('mouth')
+box('ear lt')
+box('ear rt')

Minecraft Wolf - 3D CSS

A quick play with some 3D CSS and animation.

Will add some more animation to this when I have more time

A Pen by Peter Norton on CodePen.

License.

// Enable scene interaction
const scene = document.querySelector('.scene');
const rotation = [];
const startPos = [];
let scale = 1;
const start = event => {
// get the rx and ry of scene
let style = window.getComputedStyle(scene);
rotation[0] = parseInt(style.getPropertyValue('--rx'));
rotation[1] = parseInt(style.getPropertyValue('--ry'));
// mouse starting position
startPos[0] = event.clientX || event.touches[0].clientX;
startPos[1] = event.clientY || event.touches[0].clientY;
};
const update = event => {
if (startPos.length > 0) {
// track changes to the x and y
let x = (event.clientX || event.touches[0].clientX) - startPos[0];
let y = (event.clientY || event.touches[0].clientY) - startPos[1];
// update the scene
scene.style.setProperty('--rx', rotation[0] - y + 'deg');
scene.style.setProperty('--ry', rotation[1] + x + 'deg');
// log output
console.table({
rx: `${rotation[0] - y}deg`,
ry: `${rotation[1] - x}deg`
});
}
};
const end = event => {
startPos.length = 0;
};
scene.addEventListener('touchstart', start, false);
scene.addEventListener('mousedown', start, false);
document.addEventListener('touchmove', update, false);
document.addEventListener('mousemove', update, false);
document.addEventListener('touchend', end, false);
document.addEventListener('mouseup', end, false);
// zoom in out on mouse wheel
scene.addEventListener('wheel', event => {
event.preventDefault();
scale += event.deltaY * -0.01;
scale = scale > 3 ? 3 : scale < 0.25 ? 0.25 : scale;
scene.style.setProperty('--scene-scale', scale);
}, { passive: false });
// Cube
// Sizing: --w: width, --h: height, --d: depth
// Position: --x: x-axis translation, --y: y-axis translation, --z: z-axis translation
.box {
--x: 0; // default
--y: 0; // default
--z: 0; // default
--d2: calc(var(--d) / 2);
position: absolute;
width: var(--w);
height: var(--h);
transform: translate3d(var(--x), var(--y), var(--z));
div {
position: absolute;
// outline: 1px solid rgba(grey, .25);
}
.lt {
width: var(--d);
height: var(--h);
left: 0;
transform: rotateY(-90deg) translatez(var(--d2));
}
.rt {
width: var(--d);
height: var(--h);
right: 0;
transform: rotateY(90deg) translatez(var(--d2));
}
.tp {
width: var(--w);
height: var(--d);
top: 0;
transform: rotateX(90deg) translateZ(var(--d2));
}
.bt {
width: var(--w);
height: var(--d);
bottom: 0;
transform: rotateX(-90deg) translateZ(var(--d2));
}
.ft {
width: var(--w);
height: var(--h);
transform: translateZ(var(--d2));
}
.bk {
width: var(--w);
height: var(--h);
transform: rotateY(180deg) translateZ(var(--d2));
}
}
@mixin color($col) {
// lit from front-left
.ft { background: $col }
.tp { background: lighten($col, 8%) }
.lt { background: lighten($col, 4%) }
.bk { background: darken($col, 8%) }
.rt { background: darken($col, 4%) }
.bt { background: darken($col, 20%) }
}
@mixin vars($w: 0, $h: 0, $d: 0, $x: 0, $y: 0, $z: 0) {
--w: calc(#{$w} * 1vmin); // width
--h: calc(#{$h} * 1vmin); // height
--d: calc(#{$d} * 1vmin); // depth
--x: calc(#{$x} * 1vmin); // translate-x
--y: calc(#{$y} * 1vmin); // translate-y
--z: calc(#{$z} * 1vmin); // translate-z
}
// Setting up the scene
:root {
--scene-width: 60vmin;
--scene-height: 20vmin;
--scene-depth: 60vmin;
--scene-scale: 1;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
overflow: hidden;
perspective: 1000px;
background-image: radial-gradient(#c9d8f7, #3874f5);
}
.scene {
--rx: -15deg;
--ry: -55deg;
position: relative;
transform-style: preserve-3d;
width: var(--scene-width);
height: var(--scene-height);
cursor: grab;
transform:
rotateX(var(--rx))
rotateY(var(--ry))
scale3d(var(--scene-scale), var(--scene-scale), var(--scene-scale));
* {
box-sizing: border-box;
transform-style: preserve-3d;
}
&:active {
cursor: grabbing;
}
}
// Ground
.grass {
--w: var(--scene-width);
--d: var(--scene-depth);
--h: 1vmin;
--y: var(--scene-height);
@include color(#659a42);
}
.mud {
--w: var(--scene-width);
--d: var(--scene-depth);
--h: 4vmin;
--y: calc(var(--scene-height) + 1vmin);
@include color(#6a5040);
}
.shadow {
width: 12vmin;
height: 25vmin;
position: absolute;
background: rgba(black, .1);
left: 24vmin;
transform: rotatex(90deg) translatez(-7.5vmin);
filter: blur(4px);
}
// Wolf
.wolf {
transform: translateX(25vmin) translateY(2vmin);
@include color(#999797);
.tail {
// vars= (w, h, d, x, y, x)
@include vars(3, 3, 10, 3.5, 2, -12);
}
.leg {
@include vars(3, 8, 3, 1, 10, 7);
&.rt {
--x: 6vmin;
}
&.bk {
--z: -7vmin;
}
}
.body {
&.ft {
@include vars(11, 10, 8, -0.5, 0, 6);
@include color(#8f8689);
.ft {
background: #a71c14;
}
}
&.bk {
@include vars(8, 8, 12, 1, 2, -4);
}
}
.head {
@include vars(9, 8, 4, 0.5, 1, 12);
.ft::before, .ft::after {
content: '';
position: absolute;
background: black;
width: 1.5vmin;
height: 2vmin;
left: 2vmin;
top: 2vmin;
}
.ft::after {
left: 5.5vmin;
}
}
.snout {
@include color(#b8aaa8);
@include vars(4, 2.5, 4, 3, 5, 16);
.ft::before,
.tp::before {
content: '';
position: absolute;
background: #32312d;
width: 2vmin;
height: 1vmin;
left: 1vmin;
top: 0;
}
.tp:before {
top: unset;
bottom: 0;
height: 1.5vmin;
}
}
.mouth {
@include color(#32312d);
@include vars(4, 1.5, 4, 3, 7.5, 16);
}
.ear {
@include vars(3, 3, 1, 0.5, -2, 11);
&.rt {
--x: 6.5vmin;
}
> div:not(.ft) {
background: #32312d;
}
}
}
// Animation
.tails {
transform-origin: 3.5vmin 2vmin -9vmin;
animation: wag .5s ease-in-out infinite alternate;
}
.mouths {
transform-origin: 3vmin 7.5vmin 14vmin;
animation: bark 4s ease-in-out infinite alternate;
}
@keyframes wag {
from {
transform: rotateX(-20deg) rotateY(-25deg);
}
to {
transform: rotateX(-20deg) rotateY(25deg);
}
}
@keyframes bark {
0%, 20% {
transform: rotateX(0deg);
}
10% {
transform: rotateX(-20deg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment