Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active April 10, 2024 20:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomasdarimont/8c694b4522c6cb10d85c to your computer and use it in GitHub Desktop.
Save thomasdarimont/8c694b4522c6cb10d85c to your computer and use it in GitHub Desktop.
Spinning Cube with HTML5, Canvas, JS
<!doctype html>
<html>
<head>
<title>Spinning Cube</title>
<script type="text/javascript">
function Point3D(x,y,z) {
this.x = x;
this.y = y;
this.z = z;
this.rotateX = function(currentAngle) {
var rad = currentAngle * Math.PI / 180;
var cosa = Math.cos(rad);
var sina = Math.sin(rad);
var y = this.y * cosa - this.z * sina;
var z = this.y * sina + this.z * cosa;
return new Point3D(this.x, y, z);
};
this.rotateY = function(currentAngle) {
var rad = currentAngle * Math.PI / 180;
var cosa = Math.cos(rad);
var sina = Math.sin(rad);
var z = this.z * cosa - this.x * sina;
var x = this.z * sina + this.x * cosa;
return new Point3D(x,this.y, z);
};
this.rotateZ = function(currentAngle) {
var rad = currentAngle * Math.PI / 180;
var cosa = Math.cos(rad);
var sina = Math.sin(rad);
var x = this.x * cosa - this.y * sina;
var y = this.x * sina + this.y * cosa;
return new Point3D(x, y, this.z);
};
this.project = function(viewWidth, viewHeight, fieldOfView, viewDistance) {
var factor = fieldOfView / (viewDistance + this.z);
var x = this.x * factor + viewWidth / 2;
var y = this.y * factor + viewHeight / 2;
return new Point3D(x, y, this.z);
};
}
var vertices = [
new Point3D(-1,1,-1),
new Point3D(1,1,-1),
new Point3D(1,-1,-1),
new Point3D(-1,-1,-1),
new Point3D(-1,1,1),
new Point3D(1,1,1),
new Point3D(1,-1,1),
new Point3D(-1,-1,1)
];
var cubeFaces = [[0,1,2,3],[1,5,6,2],[5,4,7,6],[4,0,3,7],[0,4,5,1],[3,2,6,7]]
var currentAngle = 0;
var screen = {
w : 64,
h: 64
};
function startRendering() {
var canvas = document.getElementById("renderScreen");
if (canvas && canvas.getContext) {
canvas.width = screen.w;
canvas.height = screen.h;
ctx = canvas.getContext("2d");
ctx.strokeStyle = "rgb(255,15,155)"
requestAnimationFrame(renderLoop);
}
}
function renderLoop() {
var points = new Array();
ctx.fillRect(0,0, screen.h, screen.w);
vertices.map(function(vertex){
points.push(vertex.rotateX(currentAngle).rotateY(currentAngle).rotateZ(currentAngle).project(screen.h, screen.w,128,7));
});
cubeFaces.map(function(cubeFace){
ctx.beginPath();
ctx.moveTo(points[cubeFace[0]].x,points[cubeFace[0]].y);
ctx.lineTo(points[cubeFace[1]].x,points[cubeFace[1]].y);
ctx.lineTo(points[cubeFace[2]].x,points[cubeFace[2]].y);
ctx.lineTo(points[cubeFace[3]].x,points[cubeFace[3]].y);
ctx.closePath();
ctx.stroke();
});
currentAngle += 2;
requestAnimationFrame(renderLoop);
}
window.onload = startRendering;
</script>
<style>
body {
background-color: rgb(0, 0, 0);
}
#renderScreen {
transform: translate(200px, 120px) scale(5, 5);
image-rendering: optimizeQuality;
/* image-rendering: optimizeSpeed; */
}
</style>
</head>
<body>
<canvas id="renderScreen"/>
</body>
</html>
@ungoldman
Copy link

Hi @thomasdarimont 👋

Thanks for sharing this!

I adapted this code a bit for a small silly side project:

https://github.com/ungoldman/shape-rotator

@thomasdarimont
Copy link
Author

thomasdarimont commented Apr 16, 2022

Thanks! I just updated the example to use requestAnimationFrame instead of setInterval.

Your examples look really nice, thanks for sharing as well :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment