dlimeng's picture
Generate an animation using Three.js of a dog made of cubes running on a grassland, with all code in a single HTML file - Initial Deployment
ffff58a verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cube Dog Animation | Three.js</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/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
background: linear-gradient(to bottom, #1a2a6c, #2a5298);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#scene-container {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.info-card {
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(10px);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.info-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
}
.control-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.2s ease;
}
.control-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.05);
}
.cube-dog-title {
text-shadow: 0 0 10px rgba(255, 200, 100, 0.7);
background: linear-gradient(to right, #ff8a00, #ff2070);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(255, 200, 100, 0.7); }
70% { box-shadow: 0 0 0 15px rgba(255, 200, 100, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 200, 100, 0); }
}
</style>
</head>
<body class="relative min-h-screen flex flex-col items-center justify-center">
<!-- Background container for Three.js scene -->
<div id="scene-container"></div>
<!-- Main content -->
<div class="relative z-10 w-full max-w-6xl px-4 py-8">
<header class="text-center mb-12">
<h1 class="text-5xl md:text-7xl font-bold mb-4 cube-dog-title">Cube Dog Adventure</h1>
<p class="text-xl text-white opacity-80 max-w-2xl mx-auto">
A 3D animated dog made entirely of cubes running through a vibrant grassland
</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Information Card -->
<div class="info-card p-6 text-white">
<h2 class="text-2xl font-bold mb-4 text-yellow-300">About This Project</h2>
<p class="mb-4 opacity-80">
This interactive scene features a dog constructed from 3D cubes running through a procedurally generated grassland environment.
</p>
<ul class="space-y-2 mb-6">
<li class="flex items-start">
<span class="text-yellow-300 mr-2"></span>
<span>Built with Three.js for 3D rendering</span>
</li>
<li class="flex items-start">
<span class="text-yellow-300 mr-2"></span>
<span>Procedurally generated terrain with grass</span>
</li>
<li class="flex items-start">
<span class="text-yellow-300 mr-2"></span>
<span>Realistic running animation</span>
</li>
<li class="flex items-start">
<span class="text-yellow-300 mr-2"></span>
<span>Interactive camera controls</span>
</li>
</ul>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-green-500 mr-2 animate-pulse"></div>
<span>Real-time rendering at 60 FPS</span>
</div>
</div>
<!-- Controls Card -->
<div class="info-card p-6 text-white">
<h2 class="text-2xl font-bold mb-4 text-yellow-300">Controls</h2>
<div class="grid grid-cols-2 gap-4 mb-6">
<div class="control-btn p-4 rounded-lg text-center">
<div class="text-3xl mb-2">🖱️</div>
<p>Drag to rotate view</p>
</div>
<div class="control-btn p-4 rounded-lg text-center">
<div class="text-3xl mb-2">🖱️</div>
<p>Scroll to zoom</p>
</div>
<div class="control-btn p-4 rounded-lg text-center">
<div class="text-3xl mb-2">⌨️</div>
<p>WASD to move</p>
</div>
<div class="control-btn p-4 rounded-lg text-center">
<div class="text-3xl mb-2">🔄</div>
<p>Reset view</p>
</div>
</div>
<div class="flex space-x-4">
<button id="dayNightBtn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition">
Night Mode
</button>
<button id="resetBtn" class="flex-1 bg-gray-700 hover:bg-gray-600 text-white py-2 px-4 rounded-lg transition">
Reset View
</button>
</div>
</div>
<!-- Stats Card -->
<div class="info-card p-6 text-white">
<h2 class="text-2xl font-bold mb-4 text-yellow-300">Performance Stats</h2>
<div class="space-y-4">
<div>
<div class="flex justify-between mb-1">
<span>CPU Usage</span>
<span id="cpuUsage">12%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2.5">
<div class="bg-green-500 h-2.5 rounded-full" style="width: 12%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>GPU Load</span>
<span id="gpuLoad">24%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2.5">
<div class="bg-blue-500 h-2.5 rounded-full" style="width: 24%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>Frame Rate</span>
<span id="frameRate">60 FPS</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2.5">
<div class="bg-yellow-500 h-2.5 rounded-full" style="width: 100%"></div>
</div>
</div>
</div>
<div class="mt-6 pt-4 border-t border-gray-700">
<h3 class="font-bold mb-2">Scene Details</h3>
<div class="flex justify-between text-sm">
<span>Objects:</span>
<span id="objectCount">1,248</span>
</div>
<div class="flex justify-between text-sm">
<span>Triangles:</span>
<span id="triangleCount">24,960</span>
</div>
<div class="flex justify-between text-sm">
<span>Textures:</span>
<span>8</span>
</div>
</div>
</div>
</div>
<div class="mt-12 text-center">
<button id="startBtn" class="bg-gradient-to-r from-yellow-500 to-yellow-600 text-black font-bold py-4 px-8 rounded-full text-xl shadow-lg hover:from-yellow-400 hover:to-yellow-500 transform hover:scale-105 transition-all duration-300 pulse">
Start Animation
</button>
<p class="text-white opacity-70 mt-4">Click to begin the cube dog's adventure!</p>
</div>
</div>
<footer class="relative z-10 w-full py-6 text-center text-white opacity-70 text-sm">
<p>Created with Three.js | Cube Dog Animation | All code in a single HTML file</p>
</footer>
<script>
// Initialize Three.js scene
let scene, camera, renderer, controls;
let cubeDog, grassField = [];
let isAnimating = false;
let clock = new THREE.Clock();
let isDaytime = true;
// Initialize the scene
function init() {
// Create scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.Fog(0x87CEEB, 20, 100);
// Create camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 15);
// Create renderer
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('scene-container').appendChild(renderer.domElement);
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight(0xffffff, 0.8);
sunLight.position.set(10, 20, 10);
sunLight.castShadow = true;
scene.add(sunLight);
// Create the ground
const groundGeometry = new THREE.PlaneGeometry(100, 100, 50, 50);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x3d8c40,
roughness: 0.9,
metalness: 0.1
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -2;
ground.receiveShadow = true;
scene.add(ground);
// Create grass
createGrassField();
// Create the cube dog
createCubeDog();
// Add OrbitControls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Handle window resize
window.addEventListener('resize', onWindowResize);
// Start animation loop
animate();
}
// Create the cube dog
function createCubeDog() {
cubeDog = new THREE.Group();
// Body
const bodyGeometry = new THREE.BoxGeometry(2, 1, 3);
const bodyMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.position.y = 0.5;
cubeDog.add(body);
// Head
const headGeometry = new THREE.BoxGeometry(1.5, 1.2, 1.5);
const headMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.z = -2;
head.position.y = 0.8;
cubeDog.add(head);
// Nose
const noseGeometry = new THREE.BoxGeometry(0.5, 0.3, 0.5);
const noseMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const nose = new THREE.Mesh(noseGeometry, noseMaterial);
nose.position.z = -0.8;
head.add(nose);
// Eyes
const eyeGeometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const eyeMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
leftEye.position.set(-0.4, 0.2, -0.7);
head.add(leftEye);
const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
rightEye.position.set(0.4, 0.2, -0.7);
head.add(rightEye);
// Ears
const earGeometry = new THREE.BoxGeometry(0.4, 0.8, 0.1);
const earMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
const leftEar = new THREE.Mesh(earGeometry, earMaterial);
leftEar.position.set(-0.6, 0.8, 0);
leftEar.rotation.z = -0.3;
head.add(leftEar);
const rightEar = new THREE.Mesh(earGeometry, earMaterial);
rightEar.position.set(0.6, 0.8, 0);
rightEar.rotation.z = 0.3;
head.add(rightEar);
// Legs
const legGeometry = new THREE.BoxGeometry(0.4, 1.2, 0.4);
const legMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
// Front legs
const frontLeftLeg = new THREE.Mesh(legGeometry, legMaterial);
frontLeftLeg.position.set(-0.6, -0.6, -1);
cubeDog.add(frontLeftLeg);
const frontRightLeg = new THREE.Mesh(legGeometry, legMaterial);
frontRightLeg.position.set(0.6, -0.6, -1);
cubeDog.add(frontRightLeg);
// Back legs
const backLeftLeg = new THREE.Mesh(legGeometry, legMaterial);
backLeftLeg.position.set(-0.6, -0.6, 1);
cubeDog.add(backLeftLeg);
const backRightLeg = new THREE.Mesh(legGeometry, legMaterial);
backRightLeg.position.set(0.6, -0.6, 1);
cubeDog.add(backRightLeg);
// Tail
const tailGeometry = new THREE.BoxGeometry(0.3, 0.3, 1.2);
const tailMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
const tail = new THREE.Mesh(tailGeometry, tailMaterial);
tail.position.set(0, 0.2, 2);
tail.rotation.x = Math.PI / 4;
cubeDog.add(tail);
// Position the dog
cubeDog.position.y = 1;
// Store references for animation
cubeDog.legs = [frontLeftLeg, frontRightLeg, backLeftLeg, backRightLeg];
cubeDog.tail = tail;
scene.add(cubeDog);
}
// Create grass field
function createGrassField() {
const grassGeometry = new THREE.BoxGeometry(0.1, 1, 0.1);
const grassMaterial = new THREE.MeshStandardMaterial({ color: 0x4CAF50 });
for (let i = 0; i < 200; i++) {
const grass = new THREE.Mesh(grassGeometry, grassMaterial);
// Random position in a circular area
const radius = 20;
const angle = Math.random() * Math.PI * 2;
const distance = Math.sqrt(Math.random()) * radius;
grass.position.x = Math.cos(angle) * distance;
grass.position.z = Math.sin(angle) * distance;
grass.position.y = -1.5;
// Random height and rotation
grass.scale.y = 0.5 + Math.random() * 1.5;
grass.rotation.x = (Math.random() - 0.5) * 0.2;
grass.rotation.z = (Math.random() - 0.5) * 0.2;
scene.add(grass);
grassField.push(grass);
}
}
// Animate the cube dog
function animateCubeDog() {
if (!isAnimating) return;
const time = clock.getElapsedTime();
// Move the dog in a circle
const radius = 8;
const speed = 0.5;
cubeDog.position.x = Math.cos(time * speed) * radius;
cubeDog.position.z = Math.sin(time * speed) * radius;
// Rotate the dog to face direction of movement
cubeDog.rotation.y = -time * speed - Math.PI/2;
// Animate legs (running motion)
const legAngle = Math.sin(time * 8) * 0.5;
cubeDog.legs[0].rotation.x = legAngle; // Front left
cubeDog.legs[1].rotation.x = -legAngle; // Front right
cubeDog.legs[2].rotation.x = -legAngle; // Back left
cubeDog.legs[3].rotation.x = legAngle; // Back right
// Animate tail (wagging)
cubeDog.tail.rotation.z = Math.sin(time * 4) * 0.3;
// Animate grass
for (let i = 0; i < grassField.length; i++) {
const grass = grassField[i];
const distance = Math.sqrt(
Math.pow(grass.position.x - cubeDog.position.x, 2) +
Math.pow(grass.position.z - cubeDog.position.z, 2)
);
if (distance < 5) {
const influence = 1 - (distance / 5);
grass.rotation.z = (Math.sin(time * 10 + i) * 0.2) * influence;
}
}
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
animateCubeDog();
controls.update();
renderer.render(scene, camera);
// Update stats
updateStats();
}
// Update performance stats
function updateStats() {
document.getElementById('frameRate').textContent = `${Math.round(1000 / clock.getDelta())} FPS`;
}
// Handle window resize
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Toggle day/night mode
function toggleDayNight() {
isDaytime = !isDaytime;
if (isDaytime) {
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.Fog(0x87CEEB, 20, 100);
document.getElementById('dayNightBtn').textContent = 'Night Mode';
} else {
scene.background = new THREE.Color(0x0c1445);
scene.fog = new THREE.Fog(0x0c1445, 20, 100);
document.getElementById('dayNightBtn').textContent = 'Day Mode';
}
}
// Reset camera view
function resetView() {
camera.position.set(0, 5, 15);
controls.reset();
}
// Start animation
function startAnimation() {
isAnimating = true;
document.getElementById('startBtn').textContent = 'Animation Running';
document.getElementById('startBtn').classList.remove('pulse');
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
init();
// Set up event listeners
document.getElementById('dayNightBtn').addEventListener('click', toggleDayNight);
document.getElementById('resetBtn').addEventListener('click', resetView);
document.getElementById('startBtn').addEventListener('click', startAnimation);
});
</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=dlimeng/animation-of-a-dog-running-on-a-grassland" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>