Skip to content

Instantly share code, notes, and snippets.

@jacketcoder
Created February 28, 2022 08:42
Show Gist options
  • Save jacketcoder/fa52755c8277b50bab241b540ed2ef7d to your computer and use it in GitHub Desktop.
Save jacketcoder/fa52755c8277b50bab241b540ed2ef7d to your computer and use it in GitHub Desktop.
CSS 3D Block Builder

CSS 3D Block Builder

Click on the floor to start building cubes, click on the faces of cubes to build out from each face. Delete a cube with right-click. Have fun, don't expect the best FPS :) ~ Known oddities in Firefox and Edge.

A Pen by Miguel Maldonado on CodePen.

License.

div.controls
p #[strong Add cube]: Left mouse click #[br] #[strong Delete cube]: Right mouse click #[br] #[strong Rotate]: Left and right arrow keys #[br] #[strong Ascend / Descend]: Up and down arrow keys
div.container
div.floor#floor
//FLOOR TILES
- var i = 11;
- for (var x=0; x<=i; x++) {
- for (var y=0; y<=i; y++) {
div(class="f x" + x + " y" + y)(data-x = x*50)(data-y = y*50)
- }
- }
(function() {
var c = document.getElementById('cursor');
var f = document.getElementById('floor');
f.addEventListener('mousedown', clickHandle, false);
window.addEventListener('keydown', keysdown, false);
window.addEventListener('keyup', keysup, false);
//DISABLE RIGHT CLICK MENUS
window.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, false);
function clickHandle(e) {
var sel = e.target;
var pCube = sel.parentElement;
//CLICK ON FLOOR TILE
if (e.buttons === 1) {
addCube();
}
if (e.buttons === 2) {
deleteCube();
}
function addCube() {
if (sel.classList.contains("f")) {
var sx = sel.dataset.x;
var sy = sel.dataset.y;
var sz = 0;
var newCube = {
obj: createCube(sx, sy, sz),
x: sx,
y: sy,
z: sz
};
}
//CLICK ON 'UP' WALL
if (sel.classList.contains("u")) {
var sx = pCube.dataset.x;
var sy = pCube.dataset.y;
var sz = parseInt(pCube.dataset.z, 10) + 50;
addNewCube(sx, sy, sz);
}
//CLICK ON 'NORTH' WALL
if (sel.classList.contains("n")) {
var sx = pCube.dataset.x;
var sy = parseInt(pCube.dataset.y, 10) - 50;
var sz = pCube.dataset.z;
addNewCube(sx, sy, sz);
}
//CLICK ON 'SOUTH' WALL
if (sel.classList.contains("s")) {
var sx = pCube.dataset.x;
var sy = parseInt(pCube.dataset.y, 10) + 50;
var sz = pCube.dataset.z;
addNewCube(sx, sy, sz);
}
//CLICK ON 'EAST' WALL
if (sel.classList.contains("e")) {
var sx = parseInt(pCube.dataset.x, 10) + 50;
var sy = pCube.dataset.y;
var sz = pCube.dataset.z;
addNewCube(sx, sy, sz);
}
//CLICK ON 'WEST' WALL
if (sel.classList.contains("w")) {
var sx = parseInt(pCube.dataset.x, 10) - 50;
var sy = pCube.dataset.y;
var sz = pCube.dataset.z;
addNewCube(sx, sy, sz);
}
function addNewCube(sx, sy, sz) {
var newCube = {
obj: createCube(sx, sy, sz),
x: sx,
y: sy,
z: sz
};
}
}
function deleteCube() {
if (pCube.parentNode === f) {
//remove the cube DOM element
pCube.parentNode.removeChild(pCube);
}
}
}
//Create a cube, add to DOM, return cube element
function createCube(x, y, z) {
var docFragment = document.createDocumentFragment();
var cube = document.createElement('div');
cube.setAttribute('class', 'cube');
var w = [],
i = 0;
var sides = ['d', 'n', 'e', 'w', 's', 'u'];
while (i < 6) {
w[i] = document.createElement('div');
w[i].setAttribute('class', 'w' + (i + 1) + ' ' + sides[i]);
cube.appendChild(w[i]);
i++;
}
cube.dataset.x = x;
cube.dataset.y = y;
cube.dataset.z = z;
f.appendChild(cube);
cube.style.left = x + 'px';
cube.style.top = y + 'px';
cube.style.transform = 'translateZ(' + z + 'px)';
return cube;
}
var floor = {
rotateZ: 0,
translateZ: 0
};
var keyManager = {
leftArrow: false,
rightArrow: false,
upArrow: false,
downArrow: false
}
function keysdown(e) {
if (e.which === 37) {
keyManager.leftArrow = true;
}
if (e.which === 39) {
keyManager.rightArrow = true;
}
if (e.which === 38) {
keyManager.upArrow = true;
}
if (e.which === 40) {
keyManager.downArrow = true;
}
}
function keysup(e) {
keyManager.leftArrow = false;
keyManager.rightArrow = false;
keyManager.upArrow = false;
keyManager.downArrow = false;
}
function render() {
requestAnimationFrame(render);
if (keyManager.leftArrow) {
floor.rotateZ--;
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)';
}
if (keyManager.rightArrow) {
floor.rotateZ++;
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)';
}
if (keyManager.upArrow) {
floor.translateZ -= 3;
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)';
}
if (keyManager.downArrow) {
floor.translateZ += 3;
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)';
}
};
render();
})();
html,
body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: linear-gradient(to bottom, rgba(31, 113, 168, 1) 0%, rgba(88, 186, 232, 1) 100%);
}
.controls{
font-family:sans-serif;
line-height:1.5;
position:absolute;
bottom:2em;
left:2em;
font-size:0.9em;
color:white;
background:rgba(0,0,0,0.5);
padding:1em;
z-index:1;
strong{
color:yellow;
}
p{
margin:0;
}
}
.container {
perspective: 800px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.floor {
width: 600px;
height: 600px;
transform: rotateX(70deg);
transform-style: preserve-3d;
}
@for $x from 0 through 11 {
@for $y from 0 through 11 {
.x#{$x}.y#{$y} {
left: $x * 50px;
top: $y * 50px;
}
}
}
.f {
width: 50px;
height: 50px;
background: #2f3658;
position: absolute;
&:hover {
background: orange;
}
}
.w {
width: 50px;
height: 50px;
position: absolute;
box-shadow: inset 0px 0px 24px rgba(0, 0, 0, 0.53);
background: white;
&:hover {
box-shadow: inset 0 0 0px 4px orange;
}
}
.cube {
position: absolute;
transform-style: preserve-3d;
.w1 {
@extend .w;
}
.w2 {
@extend .w;
background: darken(white, 60%);
transform: rotateX(90deg)translateY(25px)translateZ(25px);
}
.w3 {
@extend .w;
background: darken(white, 25%);
transform: rotateX(90deg)rotateY(90deg)translateY(25px)translateZ(25px);
}
.w4 {
@extend .w;
background: darken(white, 40%);
transform: rotateX(90deg)rotateY(90deg)translateY(25px)translateZ(-25px);
}
.w5 {
@extend .w;
background: darken(white, 15%);
transform: rotateX(90deg)translateY(25px)translateZ(-25px);
}
.w6 {
@extend .w;
transform: translateZ(50px);
}
}
.c1 {
top: 0;
left: 0;
}
.c2 {
top: 0;
left: 100px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment