simcity-demo-001 / index.html
MakiAi's picture
Add 2 files
c9583ac verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple City Simulation</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: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0,0,0,0.7);
color: white;
padding: 15px;
border-radius: 10px;
max-width: 300px;
}
#controls {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0,0,0,0.7);
color: white;
padding: 15px;
border-radius: 10px;
}
button {
background: #4f46e5;
color: white;
border: none;
padding: 8px 15px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
}
button:hover {
background: #6366f1;
}
.building {
transition: all 0.5s;
}
.building:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.3);
}
</style>
</head>
<body class="bg-gray-900">
<div id="info">
<h1 class="text-xl font-bold mb-2">Simple City Simulation</h1>
<p>Click and drag to rotate the view. Scroll to zoom in/out.</p>
<p class="mt-2 text-sm text-gray-300">Buildings: <span id="buildingCount">0</span></p>
</div>
<div id="controls">
<button id="addBuilding">Add Building</button>
<button id="removeBuilding">Remove Building</button>
<button id="toggleLights">Toggle Lights</button>
<button id="dayNight">Day/Night</button>
</div>
<script>
// Initialize Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x87ceeb); // Sky blue
document.body.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Grid helper
const gridHelper = new THREE.GridHelper(100, 100);
scene.add(gridHelper);
// City variables
let buildings = [];
let isNight = false;
let lightsOn = true;
// Create ground
const groundGeometry = new THREE.PlaneGeometry(100, 100);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x333333,
roughness: 0.8,
metalness: 0.2
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// Create roads
function createRoads() {
const roadMaterial = new THREE.MeshStandardMaterial({ color: 0x555555 });
// Main roads
for (let i = -40; i <= 40; i += 20) {
// Horizontal roads
const hRoadGeometry = new THREE.PlaneGeometry(90, 5);
const hRoad = new THREE.Mesh(hRoadGeometry, roadMaterial);
hRoad.position.set(0, 0.01, i);
hRoad.rotation.x = -Math.PI / 2;
scene.add(hRoad);
// Vertical roads
const vRoadGeometry = new THREE.PlaneGeometry(5, 90);
const vRoad = new THREE.Mesh(vRoadGeometry, roadMaterial);
vRoad.position.set(i, 0.01, 0);
vRoad.rotation.x = -Math.PI / 2;
scene.add(vRoad);
}
// Road markings
const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffff00 });
for (let i = -40; i <= 40; i += 20) {
// Horizontal lines
for (let j = -45; j <= 45; j += 5) {
const points = [];
points.push(new THREE.Vector3(j, 0.02, i - 2));
points.push(new THREE.Vector3(j, 0.02, i + 2));
const hLineGeometry = new THREE.BufferGeometry().setFromPoints(points);
const hLine = new THREE.Line(hLineGeometry, lineMaterial);
scene.add(hLine);
}
// Vertical lines
for (let j = -45; j <= 45; j += 5) {
const points = [];
points.push(new THREE.Vector3(i - 2, 0.02, j));
points.push(new THREE.Vector3(i + 2, 0.02, j));
const vLineGeometry = new THREE.BufferGeometry().setFromPoints(points);
const vLine = new THREE.Line(vLineGeometry, lineMaterial);
scene.add(vLine);
}
}
}
createRoads();
// Create random building
function createBuilding(x, z) {
const width = 3 + Math.random() * 4;
const depth = 3 + Math.random() * 4;
const height = 5 + Math.random() * 15;
// Random color
const colors = [0x8a2be2, 0x4682b4, 0x556b2f, 0xb8860b, 0xcd5c5c, 0x9370db];
const color = colors[Math.floor(Math.random() * colors.length)];
const geometry = new THREE.BoxGeometry(width, height, depth);
const material = new THREE.MeshStandardMaterial({
color: color,
roughness: 0.7,
metalness: 0.1
});
const building = new THREE.Mesh(geometry, material);
building.position.set(x, height / 2, z);
building.castShadow = true;
building.receiveShadow = true;
building.className = 'building';
// Add windows
if (lightsOn) {
const windowColor = isNight ? 0xffffaa : 0xadd8e6;
const windowMaterial = new THREE.MeshBasicMaterial({ color: windowColor });
const windowWidth = width * 0.8;
const windowHeight = height * 0.8;
const windowDepth = depth * 0.8;
const windowGeometry = new THREE.BoxGeometry(windowWidth, windowHeight, windowDepth);
const windowMesh = new THREE.Mesh(windowGeometry, windowMaterial);
windowMesh.position.set(0, 0, 0.1);
building.add(windowMesh);
}
scene.add(building);
buildings.push(building);
updateBuildingCount();
return building;
}
// Generate initial city
function generateCity() {
// Clear existing buildings
buildings.forEach(building => scene.remove(building));
buildings = [];
// Create buildings in blocks
for (let x = -35; x <= 35; x += 10) {
for (let z = -35; z <= 35; z += 10) {
// Skip center blocks to leave space for roads
if (Math.abs(x) < 10 && Math.abs(z) < 10) continue;
// Create 1-3 buildings per block
const buildingsInBlock = 1 + Math.floor(Math.random() * 3);
for (let i = 0; i < buildingsInBlock; i++) {
const offsetX = (Math.random() - 0.5) * 6;
const offsetZ = (Math.random() - 0.5) * 6;
createBuilding(x + offsetX, z + offsetZ);
}
}
}
}
generateCity();
// Update building count display
function updateBuildingCount() {
document.getElementById('buildingCount').textContent = buildings.length;
}
// Toggle day/night
function toggleDayNight() {
isNight = !isNight;
if (isNight) {
renderer.setClearColor(0x000033);
ambientLight.intensity = 0.2;
directionalLight.intensity = 0.3;
} else {
renderer.setClearColor(0x87ceeb);
ambientLight.intensity = 0.4;
directionalLight.intensity = 0.8;
}
// Update building windows
buildings.forEach(building => {
const windowMesh = building.children[0];
if (windowMesh) {
windowMesh.material.color.setHex(isNight ? 0xffffaa : 0xadd8e6);
}
});
}
// Toggle lights
function toggleLights() {
lightsOn = !lightsOn;
buildings.forEach(building => {
if (lightsOn) {
const windowColor = isNight ? 0xffffaa : 0xadd8e6;
const windowMaterial = new THREE.MeshBasicMaterial({ color: windowColor });
const width = building.geometry.parameters.width * 0.8;
const height = building.geometry.parameters.height * 0.8;
const depth = building.geometry.parameters.depth * 0.8;
const windowGeometry = new THREE.BoxGeometry(width, height, depth);
const windowMesh = new THREE.Mesh(windowGeometry, windowMaterial);
windowMesh.position.set(0, 0, 0.1);
building.add(windowMesh);
} else {
if (building.children.length > 0) {
building.remove(building.children[0]);
}
}
});
}
// Camera position
camera.position.set(40, 40, 40);
camera.lookAt(0, 0, 0);
// Orbit controls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Event listeners for buttons
document.getElementById('addBuilding').addEventListener('click', () => {
const x = (Math.random() - 0.5) * 80;
const z = (Math.random() - 0.5) * 80;
createBuilding(x, z);
});
document.getElementById('removeBuilding').addEventListener('click', () => {
if (buildings.length > 0) {
const building = buildings.pop();
scene.remove(building);
updateBuildingCount();
}
});
document.getElementById('toggleLights').addEventListener('click', toggleLights);
document.getElementById('dayNight').addEventListener('click', toggleDayNight);
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
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=MakiAi/simcity-demo-001" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>