suna/backend/agent/workspace/index.html

495 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minecraft Clone</title>
<style>
/* Previous CSS styles remain the same */
body { margin: 0; overflow: hidden; }
canvas { display: block; image-rendering: pixelated; }
.crosshair {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 24px;
pointer-events: none;
text-shadow: 2px 2px #000;
}
.inventory {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 5px;
background: rgba(0, 0, 0, 0.5);
padding: 10px;
border-radius: 5px;
}
.inventory-slot {
width: 50px;
height: 50px;
background: rgba(255, 255, 255, 0.2);
border: 2px solid #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
image-rendering: pixelated;
}
.inventory-slot.selected {
background: rgba(255, 255, 255, 0.4);
border-color: #ffff00;
}
.hud {
position: fixed;
top: 20px;
left: 20px;
color: white;
font-family: 'Minecraft', monospace;
text-shadow: 2px 2px #000;
}
</style>
</head>
<body>
<div class="crosshair">+</div>
<div class="hud">
<div id="coordinates"></div>
<div id="selected-block"></div>
</div>
<div class="inventory" id="inventory"></div>
<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/PointerLockControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>
<script>
// Initialize Three.js with Minecraft-style settings
const scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x8CB4DB, 30, 100); // Minecraft-style fog distance
scene.background = new THREE.Color(0x8CB4DB); // Minecraft sky blue
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({
antialias: false,
logarithmicDepthBuffer: true,
physicallyCorrectLights: true
});
const clock = new THREE.Clock(); // Disable antialiasing for pixelated look
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(1); // Force pixel ratio to 1 for sharp pixels
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Minecraft-style textures
const textureLoader = new THREE.TextureLoader();
const texturePaths = {
grass_top: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/grass_top.png',
grass_side: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/grass_side.png',
dirt: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/dirt.png',
stone: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/stone.png',
wood: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/wood.png',
wood_top: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/wood.png',
leaves: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/leaves.png',
bedrock: 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/minecraft/stone.png'
};
// Configure texture settings for pixelated look
function loadMinecraftTexture(path) {
const texture = textureLoader.load(path);
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
return texture;
}
// Load all textures with Minecraft settings
const blockTextures = {};
for (const [key, path] of Object.entries(texturePaths)) {
blockTextures[key] = loadMinecraftTexture(path);
}
// Create materials with Minecraft-style shading
const materialSettings = {
transparent: false,
side: THREE.FrontSide,
shadowSide: THREE.FrontSide,
depthWrite: true,
depthTest: true
};
const blockMaterials = {
grass: [
new THREE.MeshBasicMaterial({ map: blockTextures.grass_side }),
new THREE.MeshBasicMaterial({ map: blockTextures.grass_side }),
new THREE.MeshBasicMaterial({ map: blockTextures.grass_top }),
new THREE.MeshBasicMaterial({ map: blockTextures.dirt }),
new THREE.MeshBasicMaterial({ map: blockTextures.grass_side }),
new THREE.MeshBasicMaterial({ map: blockTextures.grass_side })
],
dirt: Array(6).fill(new THREE.MeshBasicMaterial({ map: blockTextures.dirt })),
stone: Array(6).fill(new THREE.MeshBasicMaterial({ map: blockTextures.stone })),
wood: [
new THREE.MeshBasicMaterial({ map: blockTextures.wood }),
new THREE.MeshBasicMaterial({ map: blockTextures.wood }),
new THREE.MeshBasicMaterial({ map: blockTextures.wood_top }),
new THREE.MeshBasicMaterial({ map: blockTextures.wood_top }),
new THREE.MeshBasicMaterial({ map: blockTextures.wood }),
new THREE.MeshBasicMaterial({ map: blockTextures.wood })
],
leaves: Array(6).fill(new THREE.MeshBasicMaterial({
map: blockTextures.leaves,
transparent: true,
alphaTest: 0.5
})),
bedrock: Array(6).fill(new THREE.MeshBasicMaterial({ map: blockTextures.bedrock }))
};
// Simple lighting for Minecraft-style rendering
const ambientLight = new THREE.AmbientLight(0xffffff, 1.0);
scene.add(ambientLight);
// Enhanced block creation with Minecraft materials
function createBlock(x, y, z, type = 'grass') {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = blockMaterials[type];
const cube = new THREE.Mesh(geometry, materials);
cube.position.set(x, y, z);
cube.castShadow = true;
cube.receiveShadow = true;
cube.userData.type = type;
scene.add(cube);
blocks.set(`${x},${y},${z}`, cube);
return cube;
}
// Improved terrain generation with more Minecraft-like features
const noise = new SimplexNoise();
const worldSize = 32;
const blocks = new Map();
function generateTerrain() {
// Generate bedrock layer
for (let x = -worldSize/2; x < worldSize/2; x++) {
for (let z = -worldSize/2; z < worldSize/2; z++) {
createBlock(x, 0, z, 'bedrock');
}
}
// Generate terrain
for (let x = -worldSize/2; x < worldSize/2; x++) {
for (let z = -worldSize/2; z < worldSize/2; z++) {
const height = Math.floor(
(noise.noise2D(x * 0.1, z * 0.1) + 1) * 5 + 5
);
// Generate layers
for (let y = 1; y < height; y++) {
const blockType = y === height - 1 ? 'grass' :
y > height - 4 ? 'dirt' : 'stone';
createBlock(x, y, z, blockType);
}
// Generate trees with better distribution
if (Math.random() < 0.02 && height > 3) {
const treeHeight = 4 + Math.floor(Math.random() * 3);
// Tree trunk
for (let y = height; y < height + treeHeight; y++) {
createBlock(x, y, z, 'wood');
}
// Tree leaves
for (let lx = -2; lx <= 2; lx++) {
for (let ly = -2; ly <= 2; ly++) {
for (let lz = -2; lz <= 2; lz++) {
if (Math.abs(lx) + Math.abs(ly) + Math.abs(lz) <= 4 && Math.random() < 0.7) {
createBlock(
x + lx,
height + treeHeight + ly,
z + lz,
'leaves'
);
}
}
}
}
}
}
}
}
// Player Controls and Physics
const controls = new THREE.PointerLockControls(camera, document.body);
let canJump = false;
let velocity = new THREE.Vector3();
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let playerHeight = 1.6;
camera.position.set(0, playerHeight + 20, 20); // Move camera back for better initial view
// Click to start
document.addEventListener('click', () => {
controls.lock();
});
controls.addEventListener('lock', () => {
document.getElementById('inventory').style.display = 'flex';
});
controls.addEventListener('unlock', () => {
document.getElementById('inventory').style.display = 'none';
});
// Keyboard controls
const onKeyDown = function(event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = true;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = true;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = true;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = true;
break;
case 'Space':
if (canJump) {
velocity.y = 8;
canJump = false;
}
break;
}
};
const onKeyUp = function(event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = false;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = false;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = false;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = false;
break;
}
};
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
// Inventory system
const inventory = {
selectedSlot: 0,
slots: [
{ type: 'grass', count: Infinity },
{ type: 'dirt', count: Infinity },
{ type: 'stone', count: Infinity },
{ type: 'wood', count: Infinity },
{ type: 'leaves', count: Infinity },
{ type: 'bedrock', count: Infinity }
]
};
function updateInventoryUI() {
const inventoryEl = document.getElementById('inventory');
inventoryEl.innerHTML = '';
inventory.slots.forEach((slot, index) => {
const slotEl = document.createElement('div');
slotEl.className = `inventory-slot ${index === inventory.selectedSlot ? 'selected' : ''}`;
slotEl.textContent = slot.type;
slotEl.onclick = () => {
inventory.selectedSlot = index;
updateInventoryUI();
};
inventoryEl.appendChild(slotEl);
});
}
// Mouse wheel to change selected slot
document.addEventListener('wheel', (event) => {
if (controls.isLocked) {
inventory.selectedSlot = (inventory.selectedSlot + (event.deltaY > 0 ? 1 : -1) + inventory.slots.length) % inventory.slots.length;
updateInventoryUI();
}
});
// Block interaction
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// Place block
document.addEventListener('contextmenu', (event) => {
event.preventDefault();
if (controls.isLocked) {
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const intersect = intersects[0];
const position = intersect.point.add(intersect.face.normal);
const roundedPos = position.round();
// Check if block placement is not too close to player
const playerPos = camera.position.clone();
if (playerPos.distanceTo(roundedPos) > 2) {
const selectedType = inventory.slots[inventory.selectedSlot].type;
createBlock(
roundedPos.x,
roundedPos.y,
roundedPos.z,
selectedType
);
}
}
}
});
// Break block
document.addEventListener('click', (event) => {
if (controls.isLocked) {
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const intersect = intersects[0];
const block = intersect.object;
// Prevent breaking bedrock
if (block.userData.type !== 'bedrock') {
scene.remove(block);
blocks.delete(`${block.position.x},${block.position.y},${block.position.z}`);
}
}
}
});
// Player physics and movement
function movePlayer(delta) {
if (controls.isLocked) {
// Gravity
velocity.y -= 20 * delta; // Minecraft-like gravity
// Forward/backward movement
const direction = new THREE.Vector3();
direction.z = Number(moveForward) - Number(moveBackward);
direction.x = Number(moveRight) - Number(moveLeft);
direction.normalize();
// Apply movement based on camera direction
if (moveForward || moveBackward) {
velocity.z -= direction.z * 20 * delta;
}
if (moveLeft || moveRight) {
velocity.x -= direction.x * 20 * delta;
}
// Apply friction
velocity.x *= 0.9;
velocity.z *= 0.9;
// Collision detection
const futurePosition = camera.position.clone();
futurePosition.x += velocity.x * delta;
futurePosition.y += velocity.y * delta;
futurePosition.z += velocity.z * delta;
// Check for collisions with blocks
const playerRadius = 0.3;
const checkPositions = [
[0, 0, 0], // Center
[playerRadius, 0, playerRadius], // Corners
[-playerRadius, 0, playerRadius],
[playerRadius, 0, -playerRadius],
[-playerRadius, 0, -playerRadius]
];
let collision = false;
for (const [offsetX, offsetY, offsetZ] of checkPositions) {
const checkPos = futurePosition.clone().add(new THREE.Vector3(offsetX, offsetY, offsetZ));
const blockPos = checkPos.clone().floor();
if (blocks.has(`${blockPos.x},${blockPos.y},${blockPos.z}`)) {
collision = true;
break;
}
}
// Update position if no collision
if (!collision) {
controls.moveRight(-velocity.x * delta);
controls.moveForward(-velocity.z * delta);
camera.position.y += velocity.y * delta;
} else {
velocity.setX(0);
velocity.setZ(0);
if (velocity.y < 0) {
velocity.setY(0);
canJump = true;
}
}
// Prevent falling through ground
if (camera.position.y < playerHeight) {
camera.position.y = playerHeight;
velocity.y = 0;
canJump = true;
}
// Update HUD
document.getElementById('coordinates').textContent =
`Position: ${Math.round(camera.position.x)}, ${Math.round(camera.position.y)}, ${Math.round(camera.position.z)}`;
document.getElementById('selected-block').textContent =
`Selected: ${inventory.slots[inventory.selectedSlot].type}`;
}
}
// ... (previous code for controls, movement, and interaction remains unchanged)
// Update animation loop with fog
function animate() {
requestAnimationFrame(animate);
const delta = Math.min(0.1, clock.getDelta());
movePlayer(delta);
// Update fog based on time of day (simplified)
const time = Date.now() * 0.001;
const fogColor = new THREE.Color(0x8CB4DB);
scene.fog.color = fogColor;
scene.background = fogColor;
renderer.render(scene, camera);
}
// Initialize the game
generateTerrain();
animate();
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>