У меня есть этот код. Как его запустить через блокнот на пк?

import * as THREE from 'three';
import {
    OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import {
    EffectComposer
} from 'three/addons/postprocessing/EffectComposer.js';
import {
    RenderPass
} from 'three/addons/postprocessing/RenderPass.js';
import {
    UnrealBloomPass
} from 'three/addons/postprocessing/UnrealBloomPass.js';
import {
    SMAAPass
} from 'three/addons/postprocessing/SMAAPass.js';

// Initialize loading manager
const loadingManager = new THREE.LoadingManager();
const textureLoader = new THREE.TextureLoader(loadingManager);
let assetsLoaded = false;
let playerRubles = 1000; // Initialize player's starting rubles

const parentDiv = document.getElementById('renderDiv');
let canvas = document.getElementById('threeRenderCanvas');
if (!canvas) {
    canvas = document.createElement('canvas');
    canvas.id = 'threeRenderCanvas';
    parentDiv.appendChild(canvas);
}

// Create loading screen
const loadingScreen = document.createElement('div');
loadingScreen.style.position = 'absolute';
loadingScreen.style.top = '0';
loadingScreen.style.left = '0';
loadingScreen.style.width = '100%';
loadingScreen.style.height = '100%';
loadingScreen.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
loadingScreen.style.color = 'white';
loadingScreen.style.display = 'flex';
loadingScreen.style.justifyContent = 'center';
loadingScreen.style.alignItems = 'center';
loadingScreen.style.fontSize = '24px';
loadingScreen.innerHTML = 'Loading... 0%';
parentDiv.appendChild(loadingScreen);

// Initialize background music variable
let backgroundMusic;

// Loading manager events
loadingManager.onProgress = function(url, itemsLoaded, itemsTotal) {
    const progress = ((itemsLoaded / itemsTotal) * 100).toFixed(0);
    loadingScreen.innerHTML = `Loading... ${progress}%`;
};

loadingManager.onLoad = function() {
    assetsLoaded = true;
    loadingScreen.style.display = 'none';

    // Initialize and play background music
    backgroundMusic = new Audio('https://play.rosebud.ai/assets/rosebud_official_theme_02.mp3?hJzg');
    backgroundMusic.loop = true;
    backgroundMusic.volume = 0.04; // Adjust volume as needed (0.0 to 1.0)
    backgroundMusic.play().catch((error) => {
        console.warn('Autoplay was prevented. User interaction is required to play the background music.');
    });
};

// Initialize the scene
const scene = new THREE.Scene();

// Clock for animation
const clock = new THREE.Clock();

// Initialize the camera
const camera = new THREE.PerspectiveCamera(
    75,
    canvas.offsetWidth / canvas.offsetHeight,
    0.1,
    1000
);
camera.position.set(0, 50, 100);
camera.lookAt(0, 0, 0);

// Initialize the renderer with HDR
const renderer = new THREE.WebGLRenderer({
    antialias: true,
    canvas: canvas,
    powerPreference: 'high-performance',
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;

// Initialize post-processing
const composer = new EffectComposer(renderer);

// Regular scene render pass
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);

// Add subtle bloom effect
const bloomPass = new UnrealBloomPass(
    new THREE.Vector2(window.innerWidth, window.innerHeight),
    0.2, // bloom strength
    0.4, // radius
    0.9 // threshold
);
composer.addPass(bloomPass);

// Add anti-aliasing
const smaaPass = new SMAAPass(
    window.innerWidth * renderer.getPixelRatio(),
    window.innerHeight * renderer.getPixelRatio()
);
composer.addPass(smaaPass);

// Initialize composer size
composer.setSize(parentDiv.clientWidth, parentDiv.clientHeight);

// Define sky colors for environmental lighting
const skyColor = new THREE.Color(0x87ceeb); // Bright sky blue
const groundColor = new THREE.Color(0xffffff); // White ground reflection

// Create sky dome with improved colors
const vertexShader = `
varying vec3 vWorldPosition;
void main() {
    vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
    vWorldPosition = worldPosition.xyz;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`;
const fragmentShader = `
uniform vec3 topColor;
uniform vec3 bottomColor;
uniform float offset;
uniform float exponent;
varying vec3 vWorldPosition;
void main() {
    float h = normalize( vWorldPosition + offset ).y;
    gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h, 0.0 ), exponent ), 0.0 ) ), 1.0 );
}`;
const uniforms = {
    topColor: {
        value: skyColor
    },
    bottomColor: {
        value: groundColor
    },
    offset: {
        value: 33
    },
    exponent: {
        value: 0.6
    },
};
const skyGeo = new THREE.SphereGeometry(500, 32, 15);
const skyMat = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.BackSide,
});
const sky = new THREE.Mesh(skyGeo, skyMat);
scene.add(sky);

// Modify OrbitControls setup
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25; // Adjusted damping factor
controls.screenSpacePanning = false;
controls.maxPolarAngle = Math.PI / 2;

// Create flat terrain
function createTerrain() {
    const size = 200;

    // Create simple flat plane for visuals
    const geometry = new THREE.PlaneGeometry(size, size);
    const texture = textureLoader.load('https://develop.play.rosebud.ai/assets/Grass_04.png?MBRT');
    const normalMap = textureLoader.load('https://develop.play.rosebud.ai/assets/Grass_04_Nrm.png?BQVT');

    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(20, 20);
    texture.encoding = THREE.sRGBEncoding;

    normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
    normalMap.repeat.set(20, 20);

    const material = new THREE.MeshStandardMaterial({
        map: texture,
        normalMap: normalMap,
        normalScale: new THREE.Vector2(2, 2),
        roughness: 0.8,
        metalness: 0.1,
        envMapIntensity: 1.0,
    });

    const terrain = new THREE.Mesh(geometry, material);
    terrain.rotation.x = -Math.PI / 2;
    terrain.receiveShadow = true;
    scene.add(terrain);

    return terrain;
}

// Setup improved lighting system
const sunLight = new THREE.DirectionalLight(skyColor, 2.0);
sunLight.position.set(-50, 100, -50);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 2048;
sunLight.shadow.mapSize.height = 2048;
sunLight.shadow.camera.near = 10;
sunLight.shadow.camera.far = 400;
sunLight.shadow.camera.left = -100;
sunLight.shadow.camera.right = 100;
sunLight.shadow.camera.top = 100;
sunLight.shadow.camera.bottom = -100;
sunLight.shadow.bias = -0.001;
scene.add(sunLight);

// Add hemisphere light to simulate sky and ground bounce light
const hemiLight = new THREE.HemisphereLight(skyColor, groundColor, 0.6);
scene.add(hemiLight);

// Create initial scene
const terrain = createTerrain();
// VegetableBed class to manage individual beds
class VegetableBed {
    constructor(position) {
        this.selected = false;
        this.outline = null;
        this.isMoving = false;
        this.isColliding = false;
        // Create the soil bed
        const bedGeometry = new THREE.BoxGeometry(4, 0.5, 4);

        // Create a canvas for the soil texture
        const soilCanvas = document.createElement('canvas');
        soilCanvas.width = 256;
        soilCanvas.height = 256;
        const ctx = soilCanvas.getContext('2d');
        // Fill with lighter brown base
        ctx.fillStyle = '#b5783c'; // New lighter brown base
        ctx.fillRect(0, 0, 256, 256);
        // Add darker and lighter variations for texture
        for (let i = 0; i < 8; i++) {
            // Slightly darker brown stripes
            ctx.fillStyle = '#a66a35'; // Darker variation
            ctx.fillRect(0, i * 32, 256, 8);
            // Slightly lighter brown stripes
            ctx.fillStyle = '#c48643'; // Lighter variation
            ctx.fillRect(0, (i * 32) + 16, 256, 8);
        }
        const soilTexture = new THREE.CanvasTexture(soilCanvas);
        soilTexture.wrapS = THREE.RepeatWrapping;
        soilTexture.wrapT = THREE.RepeatWrapping;
        soilTexture.repeat.set(2, 2);
        soilTexture.needsUpdate = true;
        const soilMaterial = new THREE.MeshStandardMaterial({
            map: soilTexture,
            roughness: 0.8,
            metalness: 0.05,
            color: 0xb5783c, // New lighter brown color
            side: THREE.DoubleSide,
            emissive: 0x3a2815,
            emissiveIntensity: 0.05
        });
        this.mesh = new THREE.Mesh(bedGeometry, soilMaterial);
        this.mesh.position.copy(position);
        this.mesh.position.y = 0.25; // Raise slightly above ground
        this.mesh.castShadow = true;
        this.mesh.receiveShadow = true;
        // Add raised edges
        const edgeGeometry = new THREE.BoxGeometry(4.4, 0.7, 0.2);
        const edgeMaterial = new THREE.MeshStandardMaterial({
            color: 0x228B22, // Forest Green color for the edges
            roughness: 0.8,
            metalness: 0.1
        });

        // Create edges
        const edges = [{
            position: [0, 0, 2.1],
            rotation: [0, 0, 0]
        }, {
            position: [0, 0, -2.1],
            rotation: [0, 0, 0]
        }, {
            position: [2.1, 0, 0],
            rotation: [0, Math.PI / 2, 0]
        }, {
            position: [-2.1, 0, 0],
            rotation: [0, Math.PI / 2, 0]
        }];

        edges.forEach(edge => {
            const edgeMesh = new THREE.Mesh(edgeGeometry, edgeMaterial);
            edgeMesh.position.set(
                edge.position[0],
                edge.position[1],
                edge.position[2]
            );
            edgeMesh.rotation.set(edge.rotation[0], edge.rotation[1], edge.rotation[2]);
            edgeMesh.castShadow = true;
            edgeMesh.receiveShadow = true;
            this.mesh.add(edgeMesh);
        });

        // Properties for farming mechanics
        this.isPlanted = false;
        this.growthStage = 0;
        this.needsWater = false;
        this.plantType = null; // Store the type of plant
        this.plantedTime = null; // Store when the plant was planted
        this.isReadyToHarvest = false;
        this.growthTimer = null;
        this.carrotModel = null; // Store the carrot model
    }
    getMesh() {
        return this.mesh;
    }
    select() {
        if (!this.selected) {
            this.selected = true;
            // Create outline
            const outlineGeometry = new THREE.BoxGeometry(4.2, 0.6, 4.2);
            const outlineMaterial = new THREE.MeshBasicMaterial({
                color: 0xffff00,
                side: THREE.BackSide
            });
            this.outline = new THREE.Mesh(outlineGeometry, outlineMaterial);
            this.outline.position.y = 0;
            this.mesh.add(this.outline);
            showContextMenu(this);
        }
    }
    deselect() {
        if (this.selected) {
            this.selected = false;
            if (this.outline) {
                this.mesh.remove(this.outline);
                this.outline.geometry.dispose();
                this.outline.material.dispose();
                this.outline = null;
            }
            hideContextMenu();
        }
    }
}
// Initialize empty vegetable beds array
function createVegetableBeds() {
    return [];
}
// Create vegetable beds array
const vegetableBeds = createVegetableBeds();
// Create context menu
const contextMenu = document.createElement('div');
contextMenu.style.cssText = `
    position: fixed;
    background: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 10px;
    border-radius: 5px;
    display: none;
    z-index: 1001;
    font-family: Arial, sans-serif;
`;
document.body.appendChild(contextMenu);
// Create currency display
const currencyDisplay = document.createElement('div');
currencyDisplay.style.cssText = `
    position: fixed;
    top: 20px;
    left: 20px;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    padding: 10px 20px;
    border-radius: 5px;
    font-family: Arial, sans-serif;
    font-size: 18px;
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 5px;
`;
// Create buy button
const buyButton = document.createElement('button');
buyButton.style.cssText = `
    position: fixed;
    top: 70px;
    left: 20px;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    padding: 10px 20px;
    border-radius: 5px;
    font-family: Arial, sans-serif;
    font-size: 16px;
    border: 1px solid #fff;
    cursor: pointer;
    z-index: 1000;
    transition: background-color 0.3s;
`;
buyButton.innerHTML = 'Buy New Seedbed (₽100)';
buyButton.addEventListener('click', () => {
    if (playerRubles >= 100) {
        playerRubles -= 100;
        updateCurrencyDisplay();

        // Create new bed at center of view
        const newPosition = new THREE.Vector3(0, 0, 0);
        const newBed = new VegetableBed(newPosition);
        scene.add(newBed.getMesh());
        vegetableBeds.push(newBed);

        // Immediately enter move mode for the new bed
        vegetableBeds.forEach(bed => bed.deselect()); // Deselect all other beds
        newBed.isMoving = true; // Enter move mode
        canvas.style.cursor = 'move';
    } else {
        alert('Not enough rubles!');
    }
});
document.body.appendChild(buyButton);
// Update currency display
function updateCurrencyDisplay() {
    currencyDisplay.innerHTML = `
        <span style="color: #ffd700;">₽</span> ${playerRubles.toLocaleString()}
    `;
}
document.body.appendChild(currencyDisplay);
updateCurrencyDisplay(); // Initial display update
// Show context menu
function showContextMenu(bed) {
    const vector = new THREE.Vector3();
    bed.mesh.getWorldPosition(vector);
    vector.project(camera);
    const x = (vector.x * 0.5 + 0.5) * canvas.clientWidth;
    const y = (-vector.y * 0.5 + 0.5) * canvas.clientHeight;
    contextMenu.style.left = `${x}px`;
    contextMenu.style.top = `${y}px`;
    contextMenu.innerHTML = `
        <div style="margin-bottom: 8px;">Seedbed</div>
        <button id="moveBtn" style="margin-right: 5px; padding: 5px;">Move</button>
        <button id="plantBtn" style="margin-right: 5px; padding: 5px;">Plant</button>
        <button id="deselectBtn" style="padding: 5px;">Deselect</button>
        ${bed.isPlanted ? 
            `<div style="margin-top: 8px;">
                Growing: ${bed.plantType}
                ${bed.isReadyToHarvest ? 
                    `<button id="harvestBtn" style="margin-left: 10px; padding: 5px;">Harvest (₽20)</button>` : 
                    `<br>Time remaining: <span id="timeRemaining"></span>`
                }
            </div>` 
            : ''}
    `;
    contextMenu.style.display = 'block';
    // Add button listeners
    document.getElementById('deselectBtn').onclick = () => bed.deselect();
    document.getElementById('moveBtn').onclick = () => {
        bed.isMoving = true;
        bed.deselect(); // This will also hide the context menu
        canvas.style.cursor = 'move';
    };

    // Add plant button listener
    document.getElementById('plantBtn').onclick = () => {
        if (!bed.isPlanted) {
            showPlantingMenu(bed);
        } else {
            alert('This bed is already planted!');
        }
    };
    // Add harvest button listener if bed is ready to harvest
    if (bed.isReadyToHarvest) {
        document.getElementById('harvestBtn').onclick = () => {
            playerRubles += 20; // Add 20 rubles for harvesting
            updateCurrencyDisplay();

            // Reset the bed
            bed.isPlanted = false;
            bed.isReadyToHarvest = false;
            bed.plantType = null;
            bed.plantedTime = null;
            if (bed.growthTimer) {
                clearInterval(bed.growthTimer);
                bed.growthTimer = null;
            }
            // Remove carrot models if they exist
            if (bed.carrotModels) {
                bed.mesh.remove(bed.carrotModels);
                // Clean up each carrot instance
                bed.carrotModels.children.forEach(carrot => {
                    carrot.traverse(child => {
                        if (child instanceof THREE.Mesh) {
                            if (child.geometry) {
                                child.geometry.dispose();
                            }
                            if (child.material) {
                                if (Array.isArray(child.material)) {
                                    child.material.forEach(mat => mat.dispose());
                                } else {
                                    child.material.dispose();
                                }
                            }
                        }
                    });
                });
                bed.carrotModels = null;
            }
            if (bed.carrotModel) {
                bed.carrotModel = null;
            }

            // Refresh the context menu
            showContextMenu(bed);
        };
    }
    // Update time remaining if plant is growing
    if (bed.isPlanted && !bed.isReadyToHarvest) {
        const timeRemainingElement = document.getElementById('timeRemaining');
        const updateTimeRemaining = () => {
            const now = Date.now();
            const timeElapsed = now - bed.plantedTime;
            const totalGrowthTime = 60000; // 1 minute in milliseconds
            const timeRemaining = Math.max(totalGrowthTime - timeElapsed, 0);
            const growthPercentage = ((totalGrowthTime - timeRemaining) / totalGrowthTime) * 100;
            // Update carrot model based on growth stage
            updateCarrotGrowth(bed, growthPercentage);
            if (timeRemaining > 0) {
                const seconds = Math.ceil(timeRemaining / 1000);
                timeRemainingElement.textContent = `${seconds}s`;
            } else {
                bed.isReadyToHarvest = true;
                // Only update if this is the currently selected bed
                if (bed.selected && contextMenu.style.display !== 'none') {
                    showContextMenu(bed);
                }
            }
        };

        updateTimeRemaining(); // Initial update

        // Clear any existing interval
        if (bed.growthTimer) {
            clearInterval(bed.growthTimer);
        }

        // Set new interval
        bed.growthTimer = setInterval(updateTimeRemaining, 1000);
    }
}
// Hide context menu
function hideContextMenu() {
    contextMenu.style.display = 'none';
    if (plantingMenu) {
        plantingMenu.style.display = 'none';
    }
}
// Create planting menu
let plantingMenu = document.createElement('div');
plantingMenu.style.cssText = `
    position: fixed;
    background: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 10px;
    border-radius: 5px;
    display: none;
    z-index: 1002;
    font-family: Arial, sans-serif;
`;
document.body.appendChild(plantingMenu);

function showPlantingMenu(bed) {
    const rect = contextMenu.getBoundingClientRect();
    plantingMenu.style.left = `${rect.right + 10}px`;
    plantingMenu.style.top = `${rect.top}px`;

    plantingMenu.innerHTML = `
        <div style="margin-bottom: 8px;">Select Crop:</div>
        <button id="carrotsBtn" style="padding: 5px; width: 100%;">Carrots (₽5)</button>
    `;
    plantingMenu.style.display = 'block';

    document.getElementById('carrotsBtn').onclick = () => {
        if (playerRubles >= 5) {
            playerRubles -= 5;
            updateCurrencyDisplay();

            bed.plantType = 'Carrots';
            bed.isPlanted = true;
            bed.isReadyToHarvest = false;
            bed.plantedTime = Date.now();
            bed.growthStage = 0;

            // Create carrot model
            createCarrotModel(bed);

            // Set up growth timer
            if (bed.growthTimer) {
                clearInterval(bed.growthTimer);
            }
            hideContextMenu(); // Hide both menus
            showContextMenu(bed); // Refresh the main context menu to show planted status
        } else {
            alert('Not enough rubles to plant carrots!');
            hideContextMenu();
        }
    };
}
// Add mouse interaction
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// Add a flag to track if we just finished moving
let justFinishedMoving = false;
canvas.addEventListener('click', (event) => {
    // If we just finished moving, ignore this click
    if (justFinishedMoving) {
        justFinishedMoving = false;
        return;
    }
    // Calculate mouse position in normalized device coordinates (-1 to +1)
    const rect = canvas.getBoundingClientRect();
    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    // Check for intersections with vegetable beds
    const intersects = [];
    vegetableBeds.forEach(bed => {
        const result = raycaster.intersectObject(bed.getMesh(), true);
        if (result.length > 0) {
            intersects.push({
                bed,
                distance: result[0].distance
            });
        }
    });
    // Sort by distance and select the closest one
    if (intersects.length > 0) {
        // Deselect all beds first
        vegetableBeds.forEach(bed => bed.deselect());
        // Select the closest bed
        intersects.sort((a, b) => a.distance - b.distance);
        intersects[0].bed.select();
    } else {
        // Clicked empty space, deselect all
        vegetableBeds.forEach(bed => bed.deselect());
    }
});
// Add mouse move and up handlers for moving beds
let movePlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
let moveIntersection = new THREE.Vector3();
canvas.addEventListener('mousemove', (event) => {
    const rect = canvas.getBoundingClientRect();
    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
    // Find the currently moving bed
    const movingBed = vegetableBeds.find(bed => bed.isMoving);
    if (movingBed) {
        raycaster.setFromCamera(mouse, camera);
        raycaster.ray.intersectPlane(movePlane, moveIntersection);
        // Round the position to the nearest grid position
        const gridSize = 6; // Same as spacing in createVegetableBeds
        const x = Math.round(moveIntersection.x / gridSize) * gridSize;
        const z = Math.round(moveIntersection.z / gridSize) * gridSize;
        // Update bed position
        movingBed.mesh.position.set(x, movingBed.mesh.position.y, z);
        // Check for collisions
        let collision = false;

        // Check collisions for all beds
        vegetableBeds.forEach(otherBed => {
            if (otherBed === movingBed) return;
            const otherPos = otherBed.mesh.position;
            const distance = movingBed.mesh.position.distanceTo(otherPos);

            if (distance < 5) { // Minimum distance between beds
                collision = true;
                // Update colors for both the moving bed and the colliding bed
                otherBed.isColliding = true;
                otherBed.mesh.children.forEach(child => {
                    if (child.isMesh) {
                        child.material.color.setHex(0xff0000);
                    }
                });
                otherBed.mesh.material.color.setHex(0xff0000);
            }
        });
        // Update material color based on collision for moving bed
        if (collision !== movingBed.isColliding) {
            movingBed.isColliding = collision;
            movingBed.mesh.children.forEach(child => {
                if (child.isMesh) {
                    child.material.color.setHex(collision ? 0xff0000 : 0x228B22);
                }
            });
            movingBed.mesh.material.color.setHex(collision ? 0xff0000 : 0xb5783c);
        }
        // Reset colors for beds that are no longer colliding
        vegetableBeds.forEach(otherBed => {
            if (otherBed === movingBed) return;
            const distance = movingBed.mesh.position.distanceTo(otherBed.mesh.position);
            if (distance >= 5 && otherBed.isColliding) {
                otherBed.isColliding = false;
                otherBed.mesh.children.forEach(child => {
                    if (child.isMesh) {
                        child.material.color.setHex(0x228B22);
                    }
                });
                otherBed.mesh.material.color.setHex(0xb5783c);
            }
        });
    }
});
canvas.addEventListener('mouseup', (event) => {
    const movingBed = vegetableBeds.find(bed => bed.isMoving);
    if (movingBed) {
        const currentPos = movingBed.mesh.position;
        let collision = false;

        // Check collisions with all other beds
        vegetableBeds.forEach(otherBed => {
            if (otherBed === movingBed) return;
            const otherPos = otherBed.mesh.position;
            const distance = currentPos.distanceTo(otherPos);

            if (distance < 5) { // Minimum distance between beds
                collision = true;
                // Update colors for both beds
                otherBed.mesh.children.forEach(child => {
                    if (child.isMesh) {
                        child.material.color.setHex(0xff0000);
                    }
                });
                otherBed.mesh.material.color.setHex(0xff0000);
                otherBed.isColliding = true;
            }
        });
        if (collision) {
            // Return bed to previous valid position or starting position
            movingBed.mesh.position.set(
                movingBed.lastValidPosition?.x || 0,
                movingBed.mesh.position.y,
                movingBed.lastValidPosition?.z || 0
            );
        } else {
            // Store the valid position
            movingBed.lastValidPosition = {
                x: movingBed.mesh.position.x,
                z: movingBed.mesh.position.z
            };
        }
        // Reset all beds' colors
        vegetableBeds.forEach(bed => {
            bed.isColliding = false;
            bed.mesh.children.forEach(child => {
                if (child.isMesh) {
                    child.material.color.setHex(0x228B22);
                }
            });
            bed.mesh.material.color.setHex(0xb5783c);
        });
        movingBed.isMoving = false;
        canvas.style.cursor = 'default';

        // Set the flag to prevent immediate selection
        justFinishedMoving = true;

        // Use setTimeout to reset the flag after a short delay
        setTimeout(() => {
            justFinishedMoving = false;
        }, 100);

        // Prevent the click event from triggering bed selection
        event.stopPropagation();
    }
});
// Animation loop
function animate() {
    requestAnimationFrame(animate);
    if (assetsLoaded) {
        applyControls(); // Apply camera controls
        controls.update();
        // Update context menu position if a bed is selected
        const selectedBed = vegetableBeds.find(bed => bed.selected);
        if (selectedBed && contextMenu.style.display !== 'none') {
            const vector = new THREE.Vector3();
            selectedBed.mesh.getWorldPosition(vector);
            vector.project(camera);
            const x = (vector.x * 0.5 + 0.5) * canvas.clientWidth;
            const y = (-vector.y * 0.5 + 0.5) * canvas.clientHeight;
            contextMenu.style.left = `${x}px`;
            contextMenu.style.top = `${y}px`;
        }
    }
    composer.render();
}

// Handle window resize
function onWindowResize() {
    const width = parentDiv.clientWidth;
    const height = parentDiv.clientHeight;

    // Update camera
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // Update renderer and composer
    renderer.setSize(width, height);
    composer.setSize(width, height);

    // Update post-processing passes
    bloomPass.resolution.set(width, height);
    smaaPass.setSize(width, height);
}

// Add event listeners
window.addEventListener('resize', onWindowResize);
const resizeObserver = new ResizeObserver(onWindowResize);
resizeObserver.observe(parentDiv);

// Start animation
animate();

// =========================
// Mobile Controls Integration
// =========================

// Create a container for the D-pad
const dpadContainer = document.createElement('div');
dpadContainer.id = 'dpadContainer';
document.body.appendChild(dpadContainer);

// Create directional buttons
const directions = ['up', 'down', 'left', 'right'];
directions.forEach(direction => {
    const button = document.createElement('button');
    button.id = `${direction}Button`;
    button.classList.add('dpad-button');
    // Set the appropriate icon based on direction
    let iconUrl = '';
    switch (direction) {
        case 'up':
            iconUrl = 'https://play.rosebud.ai/assets/up_chevron.png?YWEq';
            break;
        case 'down':
            iconUrl = 'https://play.rosebud.ai/assets/down_chevron.png?yojk';
            break;
        case 'left':
            iconUrl = 'https://play.rosebud.ai/assets/left_chevron.png?C3aB';
            break;
        case 'right':
            iconUrl = 'https://play.rosebud.ai/assets/right_chevron.png?mSRu';
            break;
    }
    button.style.backgroundImage = `url('${iconUrl}')`;
    dpadContainer.appendChild(button);
});

// Create a container for the Jump button
const jumpContainer = document.createElement('div');
jumpContainer.id = 'jumpContainer';
document.body.appendChild(jumpContainer);

// Create Jump button
const jumpButton = document.createElement('button');
jumpButton.id = 'jumpButton';
jumpButton.classList.add('jump-button');
jumpButton.style.backgroundImage = `url('https://play.rosebud.ai/assets/Up-Arrow.png?64aM')`;
jumpContainer.appendChild(jumpButton);

// Inject CSS styles dynamically
const styles = `
/* D-Pad Container */
#dpadContainer {
    position: fixed;
    bottom: 150px; /* Moved up further */
    left: 30px; /* Moved inward */
    width: 150px; /* Increased size */
    height: 150px; /* Increased size */
    display: grid;
    grid-template-areas:
        ".   up   ."
        "left  . right"
        ".  down  .";
    grid-gap: 10px; /* Spacing between buttons */
    z-index: 1000;
}

/* Positioning each button in the grid */
#upButton {
    grid-area: up;
}

#downButton {
    grid-area: down;
}

#leftButton {
    grid-area: left;
}

#rightButton {
    grid-area: right;
}

/* D-Pad Buttons */
.dpad-button {
    width: 50px; /* Consistent size */
    height: 50px; /* Consistent size */
    margin: 0; /* Remove margin as grid-gap handles spacing */
    background-color: rgba(0, 0, 0, 0.5); /* Dark semi-transparent background */
    background-size: 60%; /* Uniform icon size */
    background-repeat: no-repeat;
    background-position: center;
    border: none;
    border-radius: 12px; /* Rounded corners */
    opacity: 0.9; /* Higher opacity */
    transition: 
        opacity 0.2s, 
        transform 0.1s, 
        box-shadow 0.2s, 
        filter 0.2s; /* Smooth transitions */
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); /* Initial shadow */
}

/* Active State for D-Pad Buttons */
.dpad-button:active {
    opacity: 1;
    transform: scale(0.95);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); /* Shadow becomes more pronounced */
    filter: brightness(1.1); /* Slight brightness increase */
}

/* Jump Button Container */
#jumpContainer {
    position: fixed;
    bottom: 150px; /* Moved up further */
    right: 30px; /* Moved inward */
    width: 80px; /* Maintained size */
    height: 80px; /* Maintained size */
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

/* Jump Button */
.jump-button {
    width: 70px; /* Increased size */
    height: 70px; /* Increased size */
    background-color: rgba(0, 0, 0, 0.5); /* Dark semi-transparent background */
    background-size: 60%; /* Uniform icon size */
    background-repeat: no-repeat;
    background-position: center;
    border: none;
    border-radius: 35px; /* Fully rounded */
    opacity: 0.9; /* Higher opacity */
    transition: 
        opacity 0.2s, 
        transform 0.1s, 
        box-shadow 0.2s, 
        filter 0.2s; /* Smooth transitions */
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); /* Initial shadow */
    background-image: url('https://play.rosebud.ai/assets/Up-Arrow.png?64aM'); /* Jump button icon */
}

/* Active State for Jump Button */
.jump-button:active {
    opacity: 1;
    transform: scale(0.95);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); /* Shadow becomes more pronounced */
    filter: brightness(1.1); /* Slight brightness increase */
}

/* Responsive Adjustments */
@media (max-width: 600px) {
    /* D-Pad Container */
    #dpadContainer {
        bottom: 120px; /* Increased from 80px to move up on smaller screens */
        left: 25px;
        width: 120px;
        height: 120px;
    }

    /* D-Pad Buttons */
    .dpad-button {
        width: 40px;
        height: 40px;
        background-size: 60%; /* Ensure uniform size */
    }

    /* Jump Button Container */
    #jumpContainer {
        bottom: 120px; /* Increased from 80px */
        right: 25px;
        width: 60px;
        height: 60px;
    }

    /* Jump Button */
    .jump-button {
        width: 60px;
        height: 60px;
        background-size: 60%; /* Ensure uniform size */
    }
}
`;

// Append the styles to the head
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);

// Define keysPressed object with standardized key names
const keysPressed = {
    up: false,
    down: false,
    left: false,
    right: false,
    jump: false,
};

// Helper functions to handle button presses
function addButtonListeners(buttonId, key) {
    const button = document.getElementById(buttonId);
    if (!button) return;

    // Prevent default to avoid unwanted scrolling or other behaviors
    button.addEventListener('touchstart', (event) => {
        event.preventDefault();
        keysPressed[key] = true;
    }, {
        passive: false
    });

    button.addEventListener('touchend', (event) => {
        event.preventDefault();
        keysPressed[key] = false;
    }, {
        passive: false
    });

    // Also handle mouse events for desktop compatibility
    button.addEventListener('mousedown', (event) => {
        event.preventDefault();
        keysPressed[key] = true;
    });

    button.addEventListener('mouseup', (event) => {
        event.preventDefault();
        keysPressed[key] = false;
    });

    button.addEventListener('mouseleave', (event) => {
        event.preventDefault();
        keysPressed[key] = false;
    });
}

// Map buttons to standardized keys
addButtonListeners('upButton', 'up');
addButtonListeners('downButton', 'down');
addButtonListeners('leftButton', 'left');
addButtonListeners('rightButton', 'right');
addButtonListeners('jumpButton', 'jump');

// =========================
// Keyboard Controls Integration
// =========================

// Add event listeners for keyboard controls
window.addEventListener('keydown', (event) => {
    switch (event.code) {
        case 'ArrowUp':
        case 'KeyW':
            keysPressed.up = true;
            break;
        case 'ArrowDown':
        case 'KeyS':
            keysPressed.down = true;
            break;
        case 'ArrowLeft':
        case 'KeyA':
            keysPressed.left = true;
            break;
        case 'ArrowRight':
        case 'KeyD':
            keysPressed.right = true;
            break;
        case 'Space':
            keysPressed.jump = true;
            break;
        default:
            break;
    }
});

window.addEventListener('keyup', (event) => {
    switch (event.code) {
        case 'ArrowUp':
        case 'KeyW':
            keysPressed.up = false;
            break;
        case 'ArrowDown':
        case 'KeyS':
            keysPressed.down = false;
            break;
        case 'ArrowLeft':
        case 'KeyA':
            keysPressed.left = false;
            break;
        case 'ArrowRight':
        case 'KeyD':
            keysPressed.right = false;
            break;
        case 'Space':
            keysPressed.jump = false;
            break;
        default:
            break;
    }
});

// =========================
// End of Mobile and Keyboard Controls Integration
// =========================

// Function to apply controls based on keysPressed
function applyControls() {
    const moveSpeed = 1.0; // Adjust as needed
    const verticalSpeed = 1.0; // Speed for moving up/down

    if (keysPressed.up) {
        camera.position.z -= moveSpeed;
    }
    if (keysPressed.down) {
        camera.position.z += moveSpeed;
    }
    if (keysPressed.left) {
        camera.position.x -= moveSpeed;
    }
    if (keysPressed.right) {
        camera.position.x += moveSpeed;
    }
    if (keysPressed.jump) {
        camera.position.y += verticalSpeed;
    }
}
// Function to create a carrot model
function createCarrotModel(bed) {
    // Remove existing carrot model if it exists
    if (bed.carrotModel) {
        bed.mesh.remove(bed.carrotModels);
        // Properly dispose of all geometries and materials
        bed.carrotModels.children.forEach(carrot => {
            carrot.traverse(child => {
                if (child.geometry) child.geometry.dispose();
                if (child.material) child.material.dispose();
            });
        });
        bed.carrotModels = null;
    }
}
// Function to update carrot growth
function updateCarrotGrowth(bed, growthPercentage) {
    let scale;

    if (growthPercentage < 33) {
        // Remove any existing model (0-32%)
        if (bed.carrotModels) {
            bed.mesh.remove(bed.carrotModels);
            bed.carrotModels.children.forEach(carrot => {
                carrot.traverse(child => {
                    if (child.geometry) child.geometry.dispose();
                    if (child.material) child.material.dispose();
                });
            });
            bed.carrotModels = null;
        }
        return;
    }

    // Create or update carrot model
    if (!bed.carrotModel) {
        // Create carrot body (cone)
        const carrotGeometry = new THREE.ConeGeometry(0.2, 1, 8);
        const carrotMaterial = new THREE.MeshStandardMaterial({
            color: 0xff6b1a
        }); // Orange color
        bed.carrotModel = new THREE.Group();
        const carrotBody = new THREE.Mesh(carrotGeometry, carrotMaterial);

        // Create a group for the carrot body
        const carrotBodyGroup = new THREE.Group();
        carrotBodyGroup.add(carrotBody);
        carrotBodyGroup.rotation.x = Math.PI; // Rotate the body to point downward
        bed.carrotModel.add(carrotBodyGroup);

        // Create carrot leaves
        const leavesGroup = new THREE.Group();

        // Create a single leaf shape
        const leafShape = new THREE.Shape();
        leafShape.moveTo(0, 0);
        leafShape.bezierCurveTo(0.1, 0.3, 0.2, 0.6, 0.1, 1.0); // Right curve, made longer
        leafShape.bezierCurveTo(0, 1.2, -0.2, 0.6, -0.1, 1.0); // Left curve, made longer
        leafShape.bezierCurveTo(-0.2, 0.6, -0.1, 0.3, 0, 0); // Bottom curve, adjusted for longer shape

        const leafGeometry = new THREE.ShapeGeometry(leafShape);
        const leafMaterial = new THREE.MeshStandardMaterial({
            color: 0x228B22,
            side: THREE.DoubleSide,
            roughness: 0.7,
            metalness: 0.1
        });

        // Create two leaves
        for (let i = 0; i < 2; i++) {
            const leaf = new THREE.Mesh(leafGeometry, leafMaterial);
            leaf.position.y = 0.5;
            leaf.scale.set(0.2, 0.8, 0.2); // Thinner and longer leaves

            // Position leaves on opposite sides
            leaf.rotation.z = (i === 0 ? -0.2 : 0.2); // Slight angle outward
            leaf.rotation.x = Math.PI / 8; // Less tilt for more upright position

            // Add subtle random variation
            leaf.rotation.z += (Math.random() - 0.5) * 0.1;
            leaf.rotation.x += (Math.random() - 0.5) * 0.1;

            leavesGroup.add(leaf);
        }

        bed.carrotModel.add(leavesGroup);

        // Create a group for all 9 carrot models
        const carrotsGroup = new THREE.Group();

        // Create 3x3 grid of carrots
        for (let row = -1; row <= 1; row++) {
            for (let col = -1; col <= 1; col++) {
                const carrotInstance = bed.carrotModel.clone();
                // Position each carrot in the grid
                carrotInstance.position.set(
                    col * 1.0, // Spread on X axis
                    0.25, // Height above bed
                    row * 1.0 // Spread on Z axis
                );
                // Add slight random rotation variation for natural look
                carrotInstance.rotation.y = (Math.random() - 0.5) * 0.2;
                carrotsGroup.add(carrotInstance);
            }
        }

        bed.carrotModels = carrotsGroup; // Store the group of carrots
        bed.mesh.add(carrotsGroup);
    }

    // Scale based on growth percentage
    if (growthPercentage >= 33 && growthPercentage < 66) {
        scale = 0.3; // Small model
    } else if (growthPercentage >= 66 && growthPercentage < 100) {
        scale = 0.6; // Medium model
    } else {
        scale = 1.0; // Large model (100%)
    }

    if (bed.carrotModels) {
        bed.carrotModels.children.forEach(carrot => {
            carrot.scale.set(scale, scale, scale);
        });
    }
}