mind_craft / index.html
broadfield-dev's picture
Update index.html
c3a874a verified
<!DOCTYPE html>
<html>
<head>
<title>Minecraft-like 3D Game</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { width: 100%; height: 100%; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script>
// Replace with your Hugging Face Space URL when deployed
const BASE_URL = window.location.hostname === "localhost" ? "http://localhost:7860" : "https://broadfield-dev-mind-craft.hf.space";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const chunkSize = 5;
let playerPos = [0, 0];
const chunks = new Map();
function createChunkMesh(chunkData, chunkX, chunkZ) {
const geometry = new THREE.BufferGeometry();
const vertices = [];
const indices = [];
for (let x = 0; x < chunkSize; x++) {
for (let z = 0; z < chunkSize; z++) {
const y = chunkData[x][z];
const baseX = chunkX * chunkSize + x;
const baseZ = chunkZ * chunkSize + z;
vertices.push(baseX, y, baseZ);
}
}
for (let x = 0; x < chunkSize - 1; x++) {
for (let z = 0; z < chunkSize - 1; z++) {
const a = x + z * chunkSize;
const b = (x + 1) + z * chunkSize;
const c = x + (z + 1) * chunkSize;
const d = (x + 1) + (z + 1) * chunkSize;
indices.push(a, b, d);
indices.push(a, d, c);
}
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
return mesh;
}
async function move(dx, dz) {
try {
// Gradio doesn’t expose /move, so we fetch the root and simulate
const response = await fetch(`${BASE_URL}/api/predict`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"fn_index": 0, // Index of move_player function in Blocks
"data": [dx, dz, null] // dx, dz, and null for state
})
});
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
const result = await response.json();
const data = JSON.parse(result.data[1]); // Parse the JSON string from output
playerPos = data.player_pos;
const key = `${data.chunk_coords[0]},${data.chunk_coords[1]}`;
if (!chunks.has(key)) {
const mesh = createChunkMesh(data.chunk, data.chunk_coords[0], data.chunk_coords[1]);
chunks.set(key, mesh);
}
updateCamera();
} catch (error) {
console.error('Fetch error:', error);
}
}
function updateCamera() {
camera.position.set(playerPos[0], 10, playerPos[1] + 10);
camera.lookAt(playerPos[0], 0, playerPos[1]);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
document.addEventListener('keydown', (event) => {
switch (event.key) {
case 'ArrowUp': move(0, -1); break;
case 'ArrowDown': move(0, 1); break;
case 'ArrowLeft': move(-1, 0); break;
case 'ArrowRight': move(1, 0); break;
}
});
move(0, 0); // Initial load
</script>
</body>
</html>