Spaces:
Sleeping
Sleeping
<html> | |
<head> | |
<title>Infinite World Builder</title> | |
<style> | |
body { margin: 0; overflow: hidden; } | |
canvas { display: block; } | |
</style> | |
</head> | |
<body> | |
<script type="module"> | |
import * as THREE from 'https://unpkg.com/[email protected]/build/three.module.js'; | |
let scene, camera, renderer; | |
let newObjects = []; // Array to store objects added during this session | |
init(); | |
function init() { | |
scene = new THREE.Scene(); | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); | |
camera.position.set(0, 2, 10); | |
renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
document.body.appendChild(renderer.domElement); | |
// Add ambient light. | |
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); | |
scene.add(ambientLight); | |
// Load objects from injected global state. | |
if(window.GLOBAL_STATE && window.GLOBAL_STATE.game_state) { | |
window.GLOBAL_STATE.game_state.forEach(obj => { | |
addObjectToScene(obj); | |
}); | |
} | |
// When the canvas is clicked, add a new cube at a random position. | |
window.addEventListener('click', (event) => { | |
// Create a new cube with random color. | |
const geometry = new THREE.BoxGeometry(); | |
const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff }); | |
const cube = new THREE.Mesh(geometry, material); | |
cube.position.x = (Math.random() - 0.5) * 10; | |
cube.position.y = (Math.random() - 0.5) * 10; | |
cube.position.z = (Math.random() - 0.5) * 10; | |
scene.add(cube); | |
// Record this object's details. | |
const objRecord = { | |
obj_id: THREE.MathUtils.generateUUID(), | |
type: "Cube", | |
x: cube.position.x, | |
y: cube.position.y, | |
z: cube.position.z, | |
timestamp: new Date().toISOString() | |
}; | |
newObjects.push(objRecord); | |
}); | |
animate(); | |
} | |
// Add an object (assumed to be a cube) to the scene from a record. | |
function addObjectToScene(obj) { | |
const geometry = new THREE.BoxGeometry(); | |
// Use a default color (green) for objects loaded from state. | |
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); | |
const cube = new THREE.Mesh(geometry, material); | |
cube.position.set(obj.x || 0, obj.y || 0, obj.z || 0); | |
scene.add(cube); | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
renderer.render(scene, camera); | |
} | |
// This function is called from Streamlit (via streamlit_js_eval) to send new objects and player position. | |
window.getSaveDataAndPosition = function() { | |
// For simplicity, use the camera position as the player's position. | |
const playerPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z }; | |
const payload = { | |
playerPosition: playerPosition, | |
objectsToSave: newObjects | |
}; | |
// Clear the newObjects array after packaging the payload. | |
newObjects = []; | |
return JSON.stringify(payload); | |
} | |
// This function can be called from Streamlit to reset any client-side new object records. | |
window.resetNewlyPlacedObjects = function() { | |
newObjects = []; | |
} | |
</script> | |
</body> | |
</html> | |