<!
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rubik's Cube 3D Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
color: white;
overflow: hidden;
height: 100vh;
display: flex;
flex-direction: column;
}
header {
background: rgba(0, 0, 0, 0.3);
padding: 1rem;
text-align: center;
backdrop-filter: blur(10px);
z-index: 100;
}
h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.game-container {
flex: 1;
display: flex;
position: relative;
}
#canvas-container {
flex: 1;
position: relative;
}
.controls {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 10px;
backdrop-filter: blur(10px);
max-width: 300px;
}
.control-group {
margin-bottom: 15px;
}
.control-group h3 {
margin-bottom: 10px;
color: #ffd700;
font-size: 1.1rem;
}
.control-row {
display: flex;
gap: 10px;
margin-bottom: 8px;
flex-wrap: wrap;
}
button {
background: linear-gradient(145deg, #4a90e2, #357abd);
color: white;
border: none;
padding: 10px 15px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.4);
background: linear-gradient(145deg, #5ba0f2, #4080cd);
}
button:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.action-buttons {
display: flex;
gap: 10px;
margin-top: 15px;
}
.action-buttons button {
flex: 1;
padding: 12px;
font-weight: bold;
}
.scramble-btn {
background: linear-gradient(145deg, #e74c3c, #c0392b) !important;
}
.reset-btn {
background: linear-gradient(145deg, #27ae60, #229954) !important;
}
.info {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 15px;
border-radius: 10px;
backdrop-filter: blur(10px);
max-width: 250px;
}
.info h3 {
color: #ffd700;
margin-bottom: 10px;
}
.info p {
font-size: 14px;
line-height: 1.5;
margin-bottom: 5px;
}
.win-message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
padding: 40px;
border-radius: 20px;
text-align: center;
display: none;
z-index: 1000;
animation: fadeIn 0.5s ease;
}
.win-message h2 {
font-size: 3rem;
color: #ffd700;
margin-bottom: 20px;
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.5);
}
.win-message button {
padding: 15px 30px;
font-size: 18px;
background: linear-gradient(145deg, #ffd700, #ffed4e);
color: #333;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
to {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
color: #ffd700;
}
</style>
</head>
<body>
<header>
<h1>🎲 Rubik's Cube 3D</h1>
<p>Solve the classic puzzle in 3D!</p>
</header>
<div class="game-container">
<div id="canvas-container">
<div class="loading">Loading 3D Environment...</div>
</div>
<div class="controls">
<div class="control-group">
<h3>🎮 Face Controls</h3>
<div class="control-row">
<button onclick="rotateFace('F')">F (Front)</button>
<button onclick="rotateFace('B')">B (Back)</button>
</div>
<div class="control-row">
<button onclick="rotateFace('U')">U (Up)</button>
<button onclick="rotateFace('D')">D (Down)</button>
</div>
<div class="control-row">
<button onclick="rotateFace('L')">L (Left)</button>
<button onclick="rotateFace('R')">R (Right)</button>
</div>
</div>
<div class="control-group">
<h3>⌨️ Keyboard Shortcuts</h3>
<p>F/B/U/D/L/R - Rotate faces</p>
<p>Shift + Key - Counter-clockwise</p>
<p>Mouse - Rotate view</p>
<p>Scroll - Zoom</p>
</div>
<div class="action-buttons">
<button class="scramble-btn" onclick="scrambleCube()">🔀
Scramble</button>
<button class="reset-btn" onclick="resetCube()">🔄 Reset</button>
</div>
</div>
<div class="info">
<h3>📊 Game Info</h3>
<p>Moves: <span id="move-count">0</span></p>
<p>Status: <span id="game-status">Ready</span></p>
</div>
</div>
<div class="win-message" id="win-message">
<h2>🎉 Congratulations!</h2>
<p>You solved the Rubik's Cube!</p>
<p>Total moves: <span id="final-moves">0</span></p>
<button onclick="hideWinMessage()">Play Again</button>
</div>
<script
src="[Link]
<script>
// Global variables
let scene, camera, renderer;
let cubeGroup;
let cubies = [];
let isRotating = false;
let moveCount = 0;
let mouse = { x: 0, y: 0 };
let mouseDown = false;
// Colors for each face
const colors = {
F: 0xff0000, // Red - Front
B: 0xff8c00, // Orange - Back
U: 0xffffff, // White - Up
D: 0xffff00, // Yellow - Down
L: 0x00ff00, // Green - Left
R: 0x0000ff // Blue - Right
};
// Initialize [Link] scene
function init() {
// Scene setup
scene = new [Link]();
[Link] = new [Link](0x1a1a2e);
// Camera setup
camera = new [Link](
75,
[Link] / [Link],
0.1,
1000
);
[Link](5, 5, 5);
[Link](0, 0, 0);
// Renderer setup
renderer = new [Link]({ antialias: true });
[Link]([Link], [Link]);
[Link] = true;
[Link] = [Link];
const container = [Link]('canvas-container');
[Link] = '';
[Link]([Link]);
// Lighting
const ambientLight = new [Link](0xffffff, 0.6);
[Link](ambientLight);
const directionalLight = new [Link](0xffffff, 0.8);
[Link](10, 10, 5);
[Link] = true;
[Link] = 0.1;
[Link] = 50;
[Link] = -10;
[Link] = 10;
[Link] = 10;
[Link] = -10;
[Link](directionalLight);
// Create cube
createCube();
// Event listeners
setupEventListeners();
// Start animation loop
animate();
}
// Create the Rubik's cube
function createCube() {
cubeGroup = new [Link]();
cubies = [];
const geometry = new [Link](0.95, 0.95, 0.95);
for (let x = -1; x <= 1; x++) {
for (let y = -1; y <= 1; y++) {
for (let z = -1; z <= 1; z++) {
if (x === 0 && y === 0 && z === 0) continue; // Skip center
const materials = [];
for (let i = 0; i < 6; i++) {
[Link](new [Link]({
color: 0x333333,
shininess: 100
}));
}
const cubie = new [Link](geometry, materials);
[Link](x, y, z);
[Link] = true;
[Link] = true;
// Store original position
[Link] = { x, y, z };
// Set face colors
updateCubieColors(cubie);
[Link](cubie);
[Link](cubie);
}
}
}
[Link](cubeGroup);
}
// Update cubie face colors based on position
function updateCubieColors(cubie) {
const { x, y, z } = [Link];
const materials = [Link];
// Front face (z = 1)
if (z === 1) materials[0].[Link](colors.F);
else materials[0].[Link](0x333333);
// Back face (z = -1)
if (z === -1) materials[1].[Link](colors.B);
else materials[1].[Link](0x333333);
// Top face (y = 1)
if (y === 1) materials[2].[Link](colors.U);
else materials[2].[Link](0x333333);
// Bottom face (y = -1)
if (y === -1) materials[3].[Link](colors.D);
else materials[3].[Link](0x333333);
// Right face (x = 1)
if (x === 1) materials[4].[Link](colors.R);
else materials[4].[Link](0x333333);
// Left face (x = -1)
if (x === -1) materials[5].[Link](colors.L);
else materials[5].[Link](0x333333);
}
// Rotate a face of the cube
function rotateFace(face, counterClockwise = false) {
if (isRotating) return;
isRotating = true;
moveCount++;
[Link]('move-count').textContent = moveCount;
const rotationGroup = new [Link]();
const affectedCubies = [];
// Determine which cubies to rotate
[Link](cubie => {
const { x, y, z } = [Link];
let shouldRotate = false;
switch (face) {
case 'F': shouldRotate = z === 1; break;
case 'B': shouldRotate = z === -1; break;
case 'U': shouldRotate = y === 1; break;
case 'D': shouldRotate = y === -1; break;
case 'L': shouldRotate = x === -1; break;
case 'R': shouldRotate = x === 1; break;
}
if (shouldRotate) {
[Link](cubie);
[Link](cubie);
}
});
[Link](rotationGroup);
// Perform rotation
const angle = counterClockwise ? [Link] / 2 : -[Link] / 2;
const duration = 300;
const startTime = [Link]();
function animateRotation() {
const elapsed = [Link]() - startTime;
const progress = [Link](elapsed / duration, 1);
const easeProgress = 1 - [Link](1 - progress, 3); // Ease out
cubic
let axis;
switch (face) {
case 'F':
case 'B':
axis = new THREE.Vector3(0, 0, face === 'F' ? 1 : -1);
break;
case 'U':
case 'D':
axis = new THREE.Vector3(0, face === 'U' ? 1 : -1, 0);
break;
case 'L':
case 'R':
axis = new THREE.Vector3(face === 'R' ? 1 : -1, 0, 0);
break;
}
[Link](
new [Link]().setFromAxisAngle(axis, angle *
easeProgress)
);
if (progress < 1) {
requestAnimationFrame(animateRotation);
} else {
// Update positions
[Link](cubie => {
const worldPos = new THREE.Vector3();
[Link](worldPos);
[Link](worldPos);
[Link](0, 0, 0);
// Update user data
[Link].x = [Link]([Link].x);
[Link].y = [Link]([Link].y);
[Link].z = [Link]([Link].z);
// Update colors
updateCubieColors(cubie);
});
[Link](rotationGroup);
[Link](...affectedCubies);
isRotating = false;
// Check win condition
if (checkWin()) {
showWinMessage();
}
}
}
animateRotation();
}
// Check if the cube is solved
function checkWin() {
// Check each face
const faces = ['F', 'B', 'U', 'D', 'L', 'R'];
for (let face of faces) {
let faceColor = null;
let faceCubies = [];
// Get cubies on this face
[Link](cubie => {
const { x, y, z } = [Link];
let onFace = false;
switch (face) {
case 'F': onFace = z === 1; break;
case 'B': onFace = z === -1; break;
case 'U': onFace = y === 1; break;
case 'D': onFace = y === -1; break;
case 'L': onFace = x === -1; break;
case 'R': onFace = x === 1; break;
}
if (onFace) {
[Link](cubie);
}
});
// Check if all cubies on this face have the same color
for (let cubie of faceCubies) {
const materialIndex = getMaterialIndexForFace(face);
const color = [Link][materialIndex].[Link]();
if (faceColor === null) {
faceColor = color;
} else if (faceColor !== color) {
return false;
}
}
}
return true;
}
// Get material index for a face
function getMaterialIndexForFace(face) {
switch (face) {
case 'F': return 0;
case 'B': return 1;
case 'U': return 2;
case 'D': return 3;
case 'L': return 5;
case 'R': return 4;
}
}
// Scramble the cube
function scrambleCube() {
if (isRotating) return;
[Link]('game-status').textContent = 'Scrambling...';
moveCount = 0;
[Link]('move-count').textContent = moveCount;
const faces = ['F', 'B', 'U', 'D', 'L', 'R'];
const moves = 20;
let currentMove = 0;
function performScrambleMove() {
if (currentMove >= moves) {
[Link]('game-status').textContent =
'Scrambled!';
return;
}
const randomFace = faces[[Link]([Link]() * [Link])];
const randomDirection = [Link]() < 0.5;
rotateFace(randomFace, randomDirection);
currentMove++;
setTimeout(performScrambleMove, 350);
}
performScrambleMove();
}
// Reset the cube
function resetCube() {
if (isRotating) return;
[Link](cubeGroup);
createCube();
moveCount = 0;
[Link]('move-count').textContent = moveCount;
[Link]('game-status').textContent = 'Ready';
}
// Show win message
function showWinMessage() {
[Link]('final-moves').textContent = moveCount;
[Link]('win-message').[Link] = 'block';
[Link]('game-status').textContent = 'Solved!';
}
// Hide win message
function hideWinMessage() {
[Link]('win-message').[Link] = 'none';
resetCube();
}
// Setup event listeners
function setupEventListeners() {
// Mouse controls
[Link]('mousedown', (e) => {
mouseDown = true;
mouse.x = [Link];
mouse.y = [Link];
});
[Link]('mousemove', (e) => {
if (!mouseDown) return;
const deltaX = [Link] - mouse.x;
const deltaY = [Link] - mouse.y;
[Link].y += deltaX * 0.01;
[Link].x += deltaY * 0.01;
mouse.x = [Link];
mouse.y = [Link];
});
[Link]('mouseup', () => {
mouseDown = false;
});
// Mouse wheel zoom
[Link]('wheel', (e) => {
[Link]();
[Link](1 + [Link] * 0.001);
});
// Keyboard controls
[Link]('keydown', (e) => {
const key = [Link]();
const counterClockwise = [Link];
switch (key) {
case 'F':
case 'B':
case 'U':
case 'D':
case 'L':
case 'R':
rotateFace(key, counterClockwise);
break;
}
});
// Window resize
[Link]('resize', () => {
[Link] = [Link] / [Link];
[Link]();
[Link]([Link], [Link]);
});
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
// Auto-rotate when not interacting
if (!mouseDown) {
[Link].y += 0.002;
}
[Link](scene, camera);
}
// Initialize the game
init();
</script>
</body>
</html>