JSFiddle - React, Tailwind, and code Playground
HTML
<div class="scene" style="perspective: 1000px; width: 100%; height: 100%">
<!-- Apply opacity to the whole car: -->
<div class="car" style="width: 300px; height: 200px; transform: translate3d(100px, 100px, 0px) rotateY(140deg) rotateZ(-20deg)">
<h2>Car!</h2>
<div class="render-to-texture" style="perspective: 1000px; opacity: 0.4; transform: rotateZ(20deg) rotateY(0deg) rotateZ(-20deg)">
<div class="wrap" style="transform: rotateZ(20deg) rotateY(0deg) rotateZ(-20deg)">
<div class="frame" style="border: none">
<div class="frontLeftFender camo" style="width: 80px; height: 40px; transform: translate3d(0px, 0px, 50px)"></div>
<div class="frontRightFender camo" style="width: 80px; height: 40px; transform: translate3d(0px, 0px, -50px)"></div>
<div class="hood camo" style="width: 80px; height: 100px; transform: rotateX(90deg) translate3d(0px, 0px, 50px)"></div>
<div class="bumper" style="width: 100px; height: 40px; transform: rotateY(90deg) translate3d(0px, 0px, -50px)"></div>
<div class="leftDoor camo" style="width: 130px; height: 80px; transform: translate3d(80px, -40px, 50px)"></div>
<div class="rightDoor camo" style="width: 130px; height: 80px; transform: translate3d(80px, -40px, -50px)"></div>
<div class="roof camo" style="width: 130px; height: 100px; transform: rotateX(90deg) translate3d(80px, 0px, 90px)"></div>
<div class="windshield" style="width: 100px; height: 40px; transform: rotateY(90deg) translate3d(0px, -40px, 30px)"></div>
<div class="hatch camo" style="width: 80px; height: 100px; transform: rotateX(90deg) rotateY(90deg) translate3d(-50px, 0px, 170px)"></div>
<div class="underside" style="width: 210px; height: 100px; transform: rotateX(90deg) translate3d(0px, 0px, 10px)"></div>
</div>
<div class="wheel" style="border: none; transform: translate3d(20px, 24px, -50px)">
<div class="wheelRotation"...
CSS
.car {
border: 5px solid red;
}
html, body, .scene {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
}
.scene {
position: relative;
}
.scene div {
position: absolute;
transform-style: preserve-3d;
transform-origin: center center;
/*default size*/
width: 10px;
height: 10px;
}
.wheelSide {
background-image: url("http://www.freeiconspng.com/uploads/car-tire-png-see-tire-details-add-to-my-car-8.png");
background-size: 28px;
}
.wheelOuter {
background-color: black;
}
.camo {
background-image: url("http://blog.spoongraphics.co.uk/wp-content/uploads/2010/camo-patterns/Urban-Camo.jpg");
background-size: 200px;
background-repeat: repeat;
}
.bumper {
background-image: url("http://www.wranglerforum.com/attachment.php?attachmentid=18928&d=1273472303");
background-size: 168px;
background-position: center center;
}
.underside {
background-image: url("http://media.caranddriver.com/images/11q2/398067/2012-honda-civic-hybrid-technical-illustration-for-aero-under-body-panels-photo-398255-s-1280x782.jpg");
background-size: 288px;
background-position: center center;
}
JavaScript
// rotate wheels
let wheels = document.querySelectorAll('.wheelRotation')
requestAnimationFrame(function loop() {
wheels.forEach(wheel => {
let zRot = getRotation(wheel, 'z')
setRotation(wheel, 'z', zRot-6)
})
requestAnimationFrame(loop)
})
// rotate car
let rtt = document.querySelector('.render-to-texture')
let rttWrap = document.querySelector('.render-to-texture > .wrap')
let car = document.querySelector('.car')
requestAnimationFrame(function loop() {
let yRot = getRotation(car, 'y')
setRotation(car, 'y', yRot+1)
setRotation(rtt, 'y', -(yRot+1))
setRotation(rttWrap, 'y', (yRot+1))
requestAnimationFrame(loop)
})
function getRotation(el, axis) {
axis = (axis).toUpperCase()
let transformProp = el.style.transform
let yRot = parseInt(transformProp.substr(transformProp.indexOf('rotate'+axis)).split('(')[1])
return (yRot).toString() == "NaN" ? 0 : yRot
}
// there's probably a better way.
function setRotation(el, axis, value) {
axis = axis.toUpperCase()
let transformProp = el.style.transform
let halves = transformProp.split('rotate'+axis)
let firstHalf = halves[0]
let secondHalf = halves[1]
if (halves.length == 1) {
el.style.transform += `rotate${axis}(${value}deg)`
return
}
let secondHalfParts = secondHalf.split(')')
secondHalfParts[0] = `(${value}deg`
secondHalf = secondHalfParts.join(')')
el.style.transform = `${firstHalf}rotate${axis}${secondHalf}`
}