Grasped logo
SandboxGames

© Copyright 2026 by Grasped

3D Cube

Medium
canvas
3d
geometry
transform

This game will help you to understand how the 3d visualization works. Let's draw a cube and transform it in 3d space.

Goal

Render a wireframe 3D cube in the center of the canvas and project its vertices onto the 2D screen. The cube should be rotated around the X and Y axes when the mouse is dragged, so the perspective changes smoothly in real time. Your task is to correctly implement the 3D rotation, perspective projection, and edge drawing logic.

JavaScript

Loading...

Preview • sandboxed

Console output

3D Shapes

In this game, we will try to understand how the simplest 3D graphics work, using a cube as an example. Modeling these shapes can be divided into 3 parts:
  • the mathematical description of the shape
  • transformation: rotation and translation
  • projection onto a 2D screen plane and rendering
Let's look at each of these parts.

Cube Description

Assume that the cube is positioned exactly at the point (0, 0, 0) and has an edge length of 2. Then each of its points can be described as follows: alt This gives us 8 vertices. The edges are the following segments:
(C1, C2)
(C2, C3)
(C3, C4)
(C4, C1)
(C5, C6)
(C6, C7)
(C7, C8)
(C8, C5)
(C1, C5)
(C2, C6)
(C3, C7)
(C4, C8)
If the cube edge has length hhh, then to calculate the coordinates of vertex iii, each coordinate should be multiplied by h2\frac{h}{2}2h​. For example, for vertex 111 with coordinates C1(−1,−1,−1)C_1(-1, -1, -1)C1​(−1,−1,−1), the corresponding vertex of a cube with edge length hhh will be C1(−h2,−h2,−h2)C_1(-\frac{h}{2},-\frac{h}{2},-\frac{h}{2})C1​(−2h​,−2h​,−2h​).

Transformation

First, let us consider cube rotation. A cube can rotate around each of its axes. Let us look at the case where the cube rotates around the yyy axis. It looks like this: alt In this illustration, you can see that when rotating around the yyy axis, the yyy coordinate of each vertex does not change. So we can project the cube onto the xzxzxz plane. alt Here, α\alphaα is the angle of rotation relative to the vertex's initial position, and γ\gammaγ is the initial angle of vertex CCC relative to the xxx axis. C′(x′,z′)C'(x',z')C′(x′,z′) is the new position of the vertex after rotation. Let OOO be the center of the square and also the origin. Then it is clear that OC=OC′=rOC=OC'=rOC=OC′=r. Hence:
x=r⋅cos(γ)x=r \cdot cos(\gamma)x=r⋅cos(γ) z=r⋅sin(γ)z=r \cdot sin(\gamma)z=r⋅sin(γ) x′=r⋅cos(γ+α)x'=r \cdot cos(\gamma+\alpha)x′=r⋅cos(γ+α) z′=r⋅sin(γ+α)z'=r \cdot sin(\gamma+\alpha)z′=r⋅sin(γ+α)
Using trigonometric formulas, we can rewrite x′x'x′ and z′z'z′ a little:
x′=r⋅(cos(γ)⋅cos(α)−sin(γ)⋅sin(α))x'=r \cdot (cos(\gamma) \cdot cos(\alpha) - sin(\gamma) \cdot sin(\alpha))x′=r⋅(cos(γ)⋅cos(α)−sin(γ)⋅sin(α)) z′=r⋅(sin(γ)⋅cos(α)+sin(α)⋅cos(γ))z'=r \cdot (sin(\gamma) \cdot cos(\alpha) + sin(\alpha) \cdot cos(\gamma))z′=r⋅(sin(γ)⋅cos(α)+sin(α)⋅cos(γ))
Expanding the parentheses:
x′=r⋅cos(γ)⋅cos(α)−r⋅sin(γ)⋅sin(α)x'=r \cdot cos(\gamma) \cdot cos(\alpha) - r \cdot sin(\gamma) \cdot sin(\alpha)x′=r⋅cos(γ)⋅cos(α)−r⋅sin(γ)⋅sin(α) z′=r⋅sin(γ)⋅cos(α)+r⋅sin(α)⋅cos(γ)z'=r \cdot sin(\gamma) \cdot cos(\alpha) + r \cdot sin(\alpha) \cdot cos(\gamma)z′=r⋅sin(γ)⋅cos(α)+r⋅sin(α)⋅cos(γ)
Knowing the formulas for the original coordinates, we substitute:
x′=x⋅cos(α)−z⋅sin(α)x'= x \cdot cos(\alpha) - z \cdot sin(\alpha)x′=x⋅cos(α)−z⋅sin(α) z′=x⋅sin(α)+z⋅cos(α)z'= x \cdot sin(\alpha) + z \cdot cos(\alpha)z′=x⋅sin(α)+z⋅cos(α)
Then, by changing the angle α\alphaα, for example with mouse movement, we can calculate the coordinates of every point of the square using this formula.
In the same way, we can calculate rotation around the xxx axis:
y′=y⋅cos(α)+z⋅sin(α)y'= y \cdot cos(\alpha) + z \cdot sin(\alpha)y′=y⋅cos(α)+z⋅sin(α) z′=−y⋅sin(α)+z⋅cos(α)z'= -y \cdot sin(\alpha) + z \cdot cos(\alpha)z′=−y⋅sin(α)+z⋅cos(α)
Here, α\alphaα is already the angle of rotation around the xxx axis.
Rotation around the zzz axis can be calculated in exactly the same way, but since on the screen the mouse can only move in two directions, we will not need it. You can do this calculation as homework 😊.
Next, to implement translation, it is enough to simply add the shift along each axis to each coordinate obtained after rotation. We will not go into detail here.

Projection Onto a Plane

To display a 3D cube on a 2D screen, we need to define 2 things: the position of the screen or projection plane in space, and the position of the camera, which is the point from which we look at the screen. Suppose we have a point P(xp,yp,zp)P(x_p,y_p,z_p)P(xp​,yp​,zp​) defined in space. We need to find the point (xs,ys)(x_s,y_s)(xs​,ys​) defined in screen coordinates. Let us look at the image below:
alt
Here, S2(xs,0)S_2(x_s, 0)S2​(xs​,0) is the projection of point PPP onto the screen's xxx axis. Consider the 2 triangles (CS1S2)(CS_1S_2)(CS1​S2​) and (CP1P2)(CP_1P_2)(CP1​P2​); they are similar. From triangle similarity:
(S1S2)(P1P2)=(CS1)(CP1)\frac{(S_1S_2)}{(P_1P_2)}=\frac{(CS_1)}{(CP_1)}(P1​P2​)(S1​S2​)​=(CP1​)(CS1​)​
P1(0,0,zp)P_1(0,0,z_p)P1​(0,0,zp​) is the projection of PPP onto the zzz axis, and (xp,0,0)(x_p,0,0)(xp​,0,0) is the projection of PPP onto the xxx axis. Point CCC (the camera) has coordinates (0,0,zc)(0, 0, z_c)(0,0,zc​). Therefore, (CP1)=zp−zc(CP_1)=z_p-z_c(CP1​)=zp​−zc​. The focal length of the camera is (CS1)=f(CS_1)=f(CS1​)=f. So the ratio above can be written as:
xsxp=fzp−zc\frac{x_s}{x_p}=\frac{f}{z_p-z_c}xp​xs​​=zp​−zc​f​
Hence:
xs=f⋅xpzp−zcx_s=\frac{f \cdot x_p}{z_p-z_c}xs​=zp​−zc​f⋅xp​​
Similarly, we obtain:
ys=f⋅ypzp−zcy_s=\frac{f \cdot y_p}{z_p-z_c}ys​=zp​−zc​f⋅yp​​
The values of zcz_czc​ (the camera position) and fff (the camera focal length) are chosen manually.

Summary

Now you know how to move and rotate a cube in space, how to project it, and how to render it. The next step is implementation. Take this challenge on yourself 💪. Good luck!