Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Three.js 3D Cube Demo</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.min.js"></script> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
font-family: 'Inter', sans-serif; | |
} | |
#info { | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
color: white; | |
background: rgba(0,0,0,0.7); | |
padding: 15px; | |
border-radius: 10px; | |
z-index: 100; | |
pointer-events: none; | |
} | |
#loading { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: #000; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1000; | |
color: white; | |
font-size: 24px; | |
} | |
canvas { | |
display: block; | |
} | |
.control-panel { | |
position: absolute; | |
bottom: 20px; | |
left: 20px; | |
background: rgba(0,0,0,0.7); | |
padding: 15px; | |
border-radius: 10px; | |
color: white; | |
z-index: 100; | |
} | |
.control-panel label { | |
display: block; | |
margin-bottom: 5px; | |
} | |
.control-panel input { | |
width: 100%; | |
margin-bottom: 10px; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-900"> | |
<div id="loading">Loading Three.js scene...</div> | |
<div id="info"> | |
<h1 class="text-xl font-bold mb-2">Three.js 3D Cube Demo</h1> | |
<p>Drag to rotate the view</p> | |
<p>Scroll to zoom in/out</p> | |
</div> | |
<div class="control-panel"> | |
<label for="rotationSpeed">Rotation Speed</label> | |
<input type="range" id="rotationSpeed" min="0" max="0.1" step="0.001" value="0.01"> | |
<label for="cubeColor">Cube Color</label> | |
<input type="color" id="cubeColor" value="#ff6347"> | |
<button id="addCube" class="mt-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-3 rounded"> | |
Add Random Cube | |
</button> | |
</div> | |
<script> | |
// Wait for everything to load | |
window.addEventListener('load', init); | |
function init() { | |
// Hide loading screen | |
document.getElementById('loading').style.display = 'none'; | |
// Create scene | |
const scene = new THREE.Scene(); | |
scene.background = new THREE.Color(0x111122); | |
// Create camera | |
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.z = 5; | |
// Create renderer | |
const renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.shadowMap.enabled = true; | |
renderer.shadowMap.type = THREE.PCFSoftShadowMap; | |
document.body.appendChild(renderer.domElement); | |
// Add orbit controls | |
const controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.enableDamping = true; | |
controls.dampingFactor = 0.05; | |
// Add lights | |
const ambientLight = new THREE.AmbientLight(0x404040); | |
scene.add(ambientLight); | |
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); | |
directionalLight.position.set(5, 10, 7); | |
directionalLight.castShadow = true; | |
directionalLight.shadow.mapSize.width = 2048; | |
directionalLight.shadow.mapSize.height = 2048; | |
scene.add(directionalLight); | |
// Add hemisphere light for more natural lighting | |
const hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 0.5); | |
scene.add(hemisphereLight); | |
// Create floor | |
const floorGeometry = new THREE.PlaneGeometry(20, 20); | |
const floorMaterial = new THREE.MeshStandardMaterial({ | |
color: 0x333333, | |
roughness: 0.8, | |
metalness: 0.2 | |
}); | |
const floor = new THREE.Mesh(floorGeometry, floorMaterial); | |
floor.rotation.x = -Math.PI / 2; | |
floor.receiveShadow = true; | |
scene.add(floor); | |
// Create initial cube | |
let cubeColor = 0xff6347; | |
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); | |
const cubeMaterial = new THREE.MeshStandardMaterial({ | |
color: cubeColor, | |
roughness: 0.4, | |
metalness: 0.6 | |
}); | |
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); | |
cube.castShadow = true; | |
cube.position.y = 0.5; | |
scene.add(cube); | |
// Array to store additional cubes | |
const cubes = [cube]; | |
// Handle window resize | |
window.addEventListener('resize', () => { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
}); | |
// UI controls | |
const rotationSpeedControl = document.getElementById('rotationSpeed'); | |
const cubeColorControl = document.getElementById('cubeColor'); | |
const addCubeButton = document.getElementById('addCube'); | |
let rotationSpeed = parseFloat(rotationSpeedControl.value); | |
rotationSpeedControl.addEventListener('input', (e) => { | |
rotationSpeed = parseFloat(e.target.value); | |
}); | |
cubeColorControl.addEventListener('input', (e) => { | |
cubeColor = new THREE.Color(e.target.value); | |
cube.material.color = cubeColor; | |
}); | |
addCubeButton.addEventListener('click', () => { | |
const size = Math.random() * 0.5 + 0.3; | |
const geometry = new THREE.BoxGeometry(size, size, size); | |
const material = new THREE.MeshStandardMaterial({ | |
color: Math.random() * 0xffffff, | |
roughness: Math.random(), | |
metalness: Math.random() | |
}); | |
const newCube = new THREE.Mesh(geometry, material); | |
newCube.castShadow = true; | |
// Random position above floor | |
newCube.position.x = (Math.random() - 0.5) * 10; | |
newCube.position.z = (Math.random() - 0.5) * 10; | |
newCube.position.y = size / 2; | |
// Random rotation | |
newCube.rotation.x = Math.random() * Math.PI; | |
newCube.rotation.y = Math.random() * Math.PI; | |
scene.add(newCube); | |
cubes.push(newCube); | |
}); | |
// Animation loop | |
function animate() { | |
requestAnimationFrame(animate); | |
// Rotate cubes | |
cubes.forEach((c, i) => { | |
if (i === 0) { | |
// Main cube rotates on all axes | |
c.rotation.x += rotationSpeed; | |
c.rotation.y += rotationSpeed * 0.7; | |
c.rotation.z += rotationSpeed * 0.3; | |
} else { | |
// Other cubes rotate more slowly | |
c.rotation.y += rotationSpeed * 0.3; | |
} | |
}); | |
// Required if controls.enableDamping or controls.autoRotate are set to true | |
controls.update(); | |
renderer.render(scene, camera); | |
} | |
animate(); | |
} | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=wenju/rotate-cube" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
</html> |