An interactive 3D Rubik's Cube puzzle game built with vanilla JavaScript and WebGL. This project demonstrates advanced 3D graphics, animation engines, touch interactions, and state management. Players can solve the cube with different difficulty levels and themes.
The HTML creates the UI framework for the 3D cube game. It includes the game canvas container, text overlays for titles and stats, interactive controls for difficulty settings, timer display, and theme customization options. The structure uses semantic elements and data attributes for easy JavaScript targeting.
<div class="ui">
<!-- Background with gradient and particles -->
<div class="ui__background">
<div class="background__gradient"></div>
<div class="background__particles"></div>
</div>
<!-- 3D Game Canvas -->
<div class="ui__game"></div>
<!-- Text Overlays -->
<div class="ui__texts">
<h1 class="text text--title">
<span class="title__word">THE</span>
<span class="title__word">CUBE</span>
</h1>
<div class="text text--note">Double tap to start</div>
<div class="text text--timer">
<span class="timer__display">0:00</span>
<div class="timer__indicator"></div>
</div>
<div class="text text--complete">
<div class="complete__badge">
<span>Complete!</span>
<div class="badge__sparkles"></div>
</div>
</div>
</div>
<!-- Game Settings/Preferences -->
<div class="ui__prefs">
<range name="size" title="Cube Size" list="2,3,4,5"></range>
<range name="flip" title="Flip Type" list="Swift ,Smooth,Bounce"></range>
<range name="scramble" title="Scramble Length" list="20,25,30"></range>
<range name="fov" title="Camera Angle" list="Ortographic,Perspective"></range>
<range name="theme" title="Color Scheme" list="Cube,Erno,Dust,Camo,Rain"></range>
</div>
<!-- Statistics Display -->
<div class="ui__stats">
<div class="stats" name="cube-size">
<i>Cube:</i><b>3x3x3</b>
</div>
<div class="stats" name="total-solves">
<i>Total solves:</i><b>-</b>
</div>
<div class="stats" name="best-time">
<i>Best time:</i><b>-</b>
</div>
</div>
</div>
SASS provides advanced styling with variables, mixins, and nested selectors. Creates a responsive layout for the 3D game canvas, styles UI elements for settings and controls, and provides theme color schemes. Uses CSS Grid/Flexbox for positioning, animations for UI transitions, and media queries for mobile responsiveness.
$primary: #667eea
$secondary: #764ba2
$text-light: #fff
.ui
width: 100%
height: 100vh
overflow: hidden
position: relative
background: linear-gradient(135deg, $primary 0%, $secondary 100%)
.ui__background
position: absolute
top: 0
left: 0
width: 100%
height: 100%
.background__gradient
width: 100%
height: 100%
background: radial-gradient(circle at center, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.3))
.background__particles
position: absolute
top: 0
left: 0
width: 100%
height: 100%
animation: float 20s infinite
.ui__game
width: 100%
height: 100%
canvas
display: block
width: 100%
height: 100%
.ui__texts
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
text-align: center
color: $text-light
z-index: 10
.text--title
font-size: 4rem
font-weight: bold
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3)
letter-spacing: 2px
animation: slideDown 0.8s ease-out
.text--timer
font-size: 2rem
margin-top: 20px
font-family: 'Courier New', monospace
.ui__prefs
position: absolute
bottom: 20px
left: 50%
transform: translateX(-50%)
display: flex
gap: 15px
padding: 20px
background: rgba(0, 0, 0, 0.2)
border-radius: 10px
backdrop-filter: blur(10px)
z-index: 20
.ui__stats
position: absolute
top: 20px
right: 20px
padding: 20px
background: rgba(0, 0, 0, 0.2)
border-radius: 10px
color: $text-light
z-index: 15
font-size: 0.9rem
@keyframes slideDown
from
opacity: 0
transform: translateY(-20px)
to
opacity: 1
transform: translateY(0)
JavaScript handles all game logic: 3D cube rendering using WebGL, animation engine for smooth transitions, touch/mouse event handling for user input, cube state management, timer functionality, and theme switching. Uses request animation frame for 60fps rendering and complex matrix transformations for 3D rotations.
const animationEngine = (() => {
let uniqueID = 0;
class AnimationEngine {
constructor() {
this.ids = [];
this.animations = {};
this.update = this.update.bind(this);
this.raf = 0;
this.time = 0;
}
update() {
const now = performance.now();
const delta = now - this.time;
this.time = now;
let i = this.ids.length;
this.raf = i ? requestAnimationFrame(this.update) : 0;
while (i--)
this.animations[this.ids[i]] && this.animations[this.ids[i]].update(delta);
}
add(animation) {
animation.id = uniqueID++;
this.ids.push(animation.id);
this.animations[animation.id] = animation;
if (this.raf !== 0) return;
this.time = performance.now();
this.raf = requestAnimationFrame(this.update);
}
remove(animation) {
const index = this.ids.indexOf(animation.id);
if (index < 0) return; this.ids.splice(index, 1); delete this.animations[animation.id]; if
(this.ids.length===0) { cancelAnimationFrame(this.raf); this.raf=0; } } } return new AnimationEngine();
})(); // 3D Cube Renderer class CubeRenderer { constructor(canvas) { this.canvas=canvas;
this.gl=canvas.getContext('webgl2'); this.initShaders(); this.initCube(); } initShaders() { // Vertex and
fragment shaders for 3D rendering const vertexShader=` attribute vec3 position; attribute vec3 color;
uniform mat4 projection; uniform mat4 view; uniform mat4 model; varying vec3 fragColor; void main() {
gl_Position=projection * view * model * vec4(position, 1.0); fragColor=color; } `; const fragmentShader=`
precision mediump float; varying vec3 fragColor; void main() { gl_FragColor=vec4(fragColor, 1.0); } `;
this.program=this.createProgram(vertexShader, fragmentShader); } initCube() { // Create cube vertices and
faces this.vertices=this.generateCubeVertices(); this.faces=this.generateCubeFaces(); } rotateCube(axis,
angle) { // Apply rotation matrix to cube const matrix=this.getRotationMatrix(axis, angle);
this.applyTransformation(matrix); } render() { // Clear and render the cube
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); this.gl.useProgram(this.program);
this.drawCube(); } } // Game State Management class GameState { constructor() { this.cubeSize=3;
this.isSolved=false; this.moves=0; this.time=0; this.bestTime=localStorage.getItem('bestTime') || null; }
recordSolve(time) { if (!this.bestTime || time < this.bestTime) { this.bestTime=time;
localStorage.setItem('bestTime', time); } } } // Initialize game const
canvas=document.querySelector('.ui__game'); const renderer=new CubeRenderer(canvas); const gameState=new
GameState();
1. HTML Structure: Provides semantic layout for the game UI, canvas container for 3D rendering, control elements for game settings, and text overlays for information display.
2. SASS Styling: Creates responsive layout, styles interactive controls, applies theme colors and animations, positions UI elements using absolute positioning and flexbox.
3. JavaScript 3D Engine: Renders 3D cube using WebGL, handles matrix transformations for rotations, manages animation frames for smooth 60fps gameplay, processes touch and mouse events for player input.
4. Game Loop: Animation engine continuously updates cube state → Applies player rotations → Renders 3D graphics → Checks win condition → Updates timer and statistics → Records best times.
5. State Management: Tracks cube configuration, move count, timer, best times in localStorage for persistence across sessions.