Animating a 3D creeper's head in CSS and JS! 
Tags: javascript, css, webdev, animation
Published: 2018-04-19 23:30:08

---
title: Animating a 3D creeper's head in CSS and JS! 
published: true
description: An introduction to 3D in CSS
tags: js,CSS,webdev,animation
cover_image: https://thepracticaldev.s3.amazonaws.com/i/px6hz2x7wz8tugneybv4.jpg
---

I'm currently coding a web application based on the minecraft universe.
In my first article on dev.to (it's a honor), I share with you how I built this cool animation with a 3D creeper's head **with no libraries, only CSS and vanilla JS**.



This tutorial is divided in 2 parts:
 - Modeling the creeper head
 - Animating the model with javascript


For this tutorial, I use the [ES6 syntax](https://dev.to/srebalaji/es6-for-beginners-with-example-c7) and [CSS variables](https://dev.to/hybrid_alex/quick-intro-to-css-variables-and-how-i-am-using-them-today--26lb).

## Modeling the 3D creeper's head

The first step in this work is to model the creeper's head. In my case, it is pretty easy, similar to model a cube. I used these two assets:
 - the face of the creeper, `face.png`
 - the side of his head, `side.png`
 
![alt text](https://github.com/Mcdostone/mcdostone.github.io/blob/master/face.png?raw=true")
![alt text](https://github.com/Mcdostone/mcdostone.github.io/blob/master/side.png?raw=true")

Each side of the cube is represented by a `img` tag and is nested in a `div` element, here `#creeper`.
```html
<div id="creeper">
    <img src="face.png" class="side front" />
    <img src="side.png" class="side back" />
    <img src="side.png" class="side top" />
    <img src="side.png" class="side bottom" />
    <img src="side.png" class="side left" />
    <img src="side.png" class="side right" />
</div>
```


By default in CSS, you can position HTML nodes in a 2D space, based on the X and Y axis. So everything is flat.
![2d space](https://thepracticaldev.s3.amazonaws.com/i/3a9s7yic0nme8z365yvc.png
)

In my case, I want to model a 3D object in my web page. So we need to change the default behavior of CSS! To do that, just indicate in the CSS that you want to place your elements in a 3D space:
```css
:root {
    --size-creeper: 128px;
}
#creeper {
    width: var(--size-creeper);
    height: var(--size-creeper);
    /* the magic happens here */
    transform-style: preserve-3d;
}

```

So now, I can place precisely every child element of `#creeper` based on the X, Y and Z axis. Here an example to place the top side of the cube:
```css
.side {
    position: absolute;
    width: var(--size-creeper);
    height: var(--size-creeper);
}
.top { transform: rotateX(90deg) translateZ(calc(var(--size-creeper) / 2)); }
```

The following isometric view can help you understanding how the objects are located in the 3D space and how you can play with the rotation, the translation and the scale:
![3d space](https://thepracticaldev.s3.amazonaws.com/i/ojqiajllufzq1hibsdxt.png
)

I add an animation to the `#creeper` element to see if everything is correctly positioned! For more details, you can go through the code:
{% codepen https://codepen.io/Mcdostone/pen/pLGjmV %}



## Animating the creeper's head

You can find some awesome animations on codepen.io. One of the last creations I've seen is this one: https://codepen.io/jhojann/pen/weKBxV?page=3. I'm gonna take some inspiration from this creation to animate my creeper head based on the mouse's position. Let's write some javascript code! I imagine the signature of my function something like this:

```js
const animate = (element, options = {}) => {
    ...
}
```

- `element` is the HTML element you want to animate
- `options` will be useful if you want to change the parameters of the animation. 

Let's code this function. The first thing I want is the exact position of the centered origin point of my creeper head. To get theses values, I use `getBoundingClientRect` on `#creeper`:
```js
const characterRect = element.getBoundingClientRect()
const originX = elementRect.left + elementRect.width / 2
const originY = elementRect.top + elementRect.height / 2
```

Cool, so now, we have the exact origin point of the head. Next step is to bind the cursor's position with the rotation on X and Y axis. I assume that when the cursor is positioned exactly on the origin point, the rotation on the X and Y axis should be equal to `0deg`. For the listener, I have something like this:
```js
// define default params 
options = Object.assign({}, { maxAngleX: 30, maxAngleY: 30 }, options)
// Re-maps a number from one range to another.
const map = (value, low1, high1, low2, high2) => low2 + (high2 - low2) * (value - low1) / (high1 - low1)
const follow = e => {
  try {
    const width = document.body.clientWidth
    const height = document.body.clientHeight
    // Support of smartphone/tablet
    const clientX = e.clientX || e.touches[0].clientX
    const clientY = e.clientY || e.touches[0].clientY
    const decY = map(clientY - originY, -height / 2, height / 2 , -options.maxAngleY, options.maxAngleY)
    const decX = map(clientX - originX, -width / 2, width / 2 , -options.maxAngleX, options.maxAngleX)
    element.style.transform = `rotateX(${-decY}deg) rotateY(${decX}deg)`
  } catch(e) {}
}
```

So now, let's bind mouse and touch events with this the my function `handle`:
```js
document.body.addEventListener('mousemove', handle)
document.body.addEventListener("touchmove", handle, false)
```

Last step is to call our `animate` function when the page is loaded:

```js
document.addEventListener('DOMContentLoaded', _ => {
    followCursor(document.querySelector('#creeper'))
})
```
This is the final result (move the cursor the see the animation):

{% codepen https://codepen.io/Mcdostone/pen/dmaGER %}


I hope you enjoyed this article. I'm also open-minded any improvement. I'm not a designer, just a guy who likes coding and creating cool stuff!