this is a code for virtual visit using 3d model as environment ,improve it , suggest new features and add it 
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mleiha Virtual Visit</title>
<style>
    body { margin: 0; }
    canvas { display: block; }
    #loadingContainer {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0.9);
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        z-index: 1100;
    }
    .mlogo{
        width: auto;
        height: 15vh;
    }
    #loadingText {
        font-family: Arial, sans-serif;
        font-size: 1.2em;
        color: white;
        margin-bottom: 20px;
    }
    #loadingBar {
        width: 300px;
        height: 10px;
        background: rgba(255,255,255,0.1);
        border-radius: 5px;
        overflow: hidden;
    }
    #loadingProgress {
        width: 0%;
        height: 100%;
        background: #4CAF50;
        transition: width 0.3s ease-in-out;
    }
    #startButton {
        margin-top: 20px;
        padding: 10px 20px;
        font-size: 1.1em;
        background: #4CAF50;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        display: none;
    }
    #startButton:hover {
        background: #45a049;
    }
    #controls {
        position: fixed;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(0,0,0,0.7);
        padding: 10px;
        border-radius: 5px;
        color: white;
        font-family: Arial, sans-serif;
        display: none;
    }
    #mobileControls {
        position: fixed;
        bottom: 20px;
        left: 0;
        right: 0;
        display: none;
        justify-content: space-between;
        padding: 20px;
        z-index: 1000;
    }
    .joystick {
        width: 150px;
        height: 150px;
        background: rgba(255,255,255,0.2);
        border-radius: 75px;
        position: relative;
        touch-action: none;
    }
    .joystick-knob {
        width: 50px;
        height: 50px;
        background: rgba(255,255,255,0.5);
        border-radius: 25px;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
    #jumpButton {
        position: fixed;
        bottom: 20px;
        right: 40vw;
        background: rgba(255,255,255,0.2);
        border: none;
        color: white;
        padding: 15px 30px;
        border-radius: 25px;
        font-size: 18px;
        display: none;
    }
    @media (max-width: 768px) {
        #controls { display: none; }
        #mobileControls { display: flex; }
        #jumpButton { display: block; }
    }
    .hotspot {
        position: fixed;
        background: rgba(255, 255, 255, 0.9);
        padding: 10px;
        border-radius: 8px;
        max-width: 200px;
        font-family: Arial, sans-serif;
        font-size: 14px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
        display: none;
        z-index: 999;
    }
    .hotspot-content img {
        max-width: 100%;
        margin-bottom: 10px;
    }
    .hotspot-content a {
        color: #4CAF50;
        text-decoration: none;
    }
    .hotspot-content a:hover {
        text-decoration: underline;
    }
    .hotspot-marker {
        position: absolute;
        width: 15px;
        height: 15px;
        background: rgba(255, 255, 255, 0.8);
        border: 1px solid #4CAF50;
        border-radius: 50%;
        cursor: pointer;
        transform: translate(-50%, -50%);
        transition: all 0.3s ease;
    }
    .hotspot-marker:hover {
        background: #4CAF50;
        transform: translate(-50%, -50%) scale(1.1);
    }
    #settingsButton {
        position: fixed;
        top: 20px;
        right: 20px;
        background: rgba(0,0,0,0.7);
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
    }
    #settingsButton:hover {
        background: rgba(0,0,0,0.9);
    }
    #settingsMenu {
        position: fixed;
        top: 70px;
        right: 20px;
        background: rgba(0,0,0,0.7);
        padding: 20px;
        border-radius: 5px;
        color: white;
        font-family: Arial, sans-serif;
        display: none;
        z-index: 1000;
    }
    #settingsMenu label {
        display: block;
        margin-bottom: 10px;
    }
    #settingsMenu input[type="range"] {
        width: 100%;
        margin-bottom: 10px;
    }
    #mainMenu {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0.9);
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        z-index: 1200;
    }
    #mainMenu h1 {
        color: white;
        margin-bottom: 20px;
    }
    #modelSelection {
        list-style-type: none;
        padding: 0;
    }
    #modelSelection li {
        background: #4CAF50;
        color: white;
        padding: 10px 20px;
        margin: 5px 0;
        border-radius: 5px;
        cursor: pointer;
        text-align: center;
        display: flex;
        align-items: center;
    }
    #modelSelection li:hover {
        background: #45a049;
    }
    #modelSelection img {
        width: 100px;
        height: 100px;
        margin-right: 10px;
        cursor: pointer;
        border: 2px solid transparent;
        transition: border-color 0.3s;
    }
    #modelSelection img:hover {
        border-color: #4CAF50;
    }
    #backToMainMenuButton {
        position: fixed;
        top: 20px;
        left: 20px;
        background: rgba(0,0,0,0.7);
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
    }
    #backToMainMenuButton:hover {
        background: rgba(0,0,0,0.9);
    }
    #fullscreenButton {
        position: fixed;
        top: 20px;
        right: 100px;
        background: rgba(0,0,0,0.7);
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
    }
    #fullscreenButton:hover {
        background: rgba(0,0,0,0.9);
    }
    #resetCameraButton {
        position: fixed;
        top: 20px;
        right: 160px;
        background: rgba(0,0,0,0.7);
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
    }
    #resetCameraButton:hover {
        background: rgba(0,0,0,0.9);
    }
</style>
</head>
<body>
<div id="mainMenu">
    <img class="mlogo" src="https://saa.shj.ae/Extras/Assets/logos/Logo%20-v-w.svg">
    <br>
    <h1>Select a Place</h1>
    <ul id="modelSelection">
        <li data-model="mleiha.glb"><img src="https://via.placeholder.com/100" alt="Mleiha Horse">Mleiha Horse</li>
        <li data-model="khorfakan.glb"><img src="https://via.placeholder.com/100" alt="Khorfakan">Khorfakan</li>
        <li data-model="model3.glb"><img src="https://via.placeholder.com/100" alt="Model 3">Model 3</li>
    </ul>
</div>
<div id="loadingContainer">
    <div id="loadingText">Loading 3D Model...</div>
    <div id="loadingBar">
        <div id="loadingProgress"></div>
    </div>
    <button id="startButton">Start Experience</button>
</div>
<div id="controls">
    WASD or Arrow Keys to move | Space to jump | Shift to run | Mouse to look around | Press ESC to unlock mouse | Q/E to rotate | R/F to scale
</div>
<div id="mobileControls">
    <div id="moveJoystick" class="joystick">
        <div class="joystick-knob"></div>
    </div>
    <div id="lookJoystick" class="joystick">
        <div class="joystick-knob"></div>
    </div>
</div>
<button id="jumpButton">JUMP</button>
<button id="settingsButton">Settings</button>
<div id="settingsMenu">
    <label for="moveSpeedRange">Move Speed:</label>
    <input type="range" id="moveSpeedRange" min="0.01" max="0.1" step="0.01" value="0.05">
    <label for="lookSpeedRange">Look Speed:</label>
    <input type="range" id="lookSpeedRange" min="0.01" max="0.1" step="0.01" value="0.03">
    <label for="soundOption">Enable Sounds:</label>
    <input type="checkbox" id="soundOption" checked>
    <label for="hotspotsOption">Show Hotspots:</label>
    <input type="checkbox" id="hotspotsOption" checked>
</div>
<button id="backToMainMenuButton">Main Menu</button>
<button id="fullscreenButton">Fullscreen</button>
<button id="resetCameraButton">Reset Camera</button>
<audio id="jumpSound" src="https://www.soundjay.com/buttons/button-7.mp3"></audio>
<audio id="clickSound" src="https://www.soundjay.com/buttons/button-3.mp3"></audio>
<audio id="rotateSound" src="https://www.soundjay.com/button/beep-07.mp3"></audio>
<audio id="scaleSound" src="https://www.soundjay.com/button/beep-08.mp3"></audio>
<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/loaders/GLTFLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/PointerLockControls.js"></script>
<script>
let camera, scene, renderer, controls;
let model;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let isRunning = false;
let isJumping = false;
let isMobile = window.innerWidth <= 768;
let modelBoundary = null;
let collisionObjects = [];
let isModelLoaded = false;
let canMove = false;
let hotspots = [];
const HOTSPOT_ACTIVATION_DISTANCE = 5; // Distance in units to trigger hotspot

let moveSpeed = 0.05; // Default move speed
let runMoveSpeed = 0.1; // Running speed
let lookSpeed = 0.03; // Default look speed
let jumpForce = 0.5;
let gravity = 0.09;
let verticalVelocity = 0;
let isGrounded = true;

let prevTime = performance.now();
const raycaster = new THREE.Raycaster();
const groundRaycaster = new THREE.Raycaster();
const playerCollider = new THREE.Vector3();
const collisionDistance = 0.5;
let soundEnabled = true; // Default sound setting
let hotspotsEnabled = true; // Default hotspots setting

let rotationSpeed = 0.02;
let scaleFactor = 0.01;
let rotationDirection = 0;
let scaleDirection = 0;

class Hotspot {
    constructor(position, title, description, imageUrl, linkUrl) {
        this.position = position;
        this.title = title;
        this.description = description;
        this.imageUrl = imageUrl;
        this.linkUrl = linkUrl;
        this.visible = false;
        this.marker = null;
        this.infoElement = null;
        this.createElements();
    }

    createElements() {
        const markerGeometry = new THREE.SphereGeometry(0.05, 16, 16);
        const markerMaterial = new THREE.MeshBasicMaterial({ color: 0x4CAF50 });
        this.marker = new THREE.Mesh(markerGeometry, markerMaterial);
        this.marker.position.copy(this.position);
        scene.add(this.marker);

        this.infoElement = document.createElement('div');
        this.infoElement.className = 'hotspot';
        this.infoElement.innerHTML = `
            <div class="hotspot-content">
                <h3 style="margin: 0 0 10px 0">${this.title}</h3>
                ${this.imageUrl ? `<img src="${this.imageUrl}" alt="${this.title}">` : ''}
                <p style="margin: 0">${this.description}</p>
                ${this.linkUrl ? `<a href="${this.linkUrl}" target="_blank">Learn More</a>` : ''}
            </div>
        `;
        document.body.appendChild(this.infoElement);
    }

    update(camera) {
        if (!hotspotsEnabled) return; // Skip updating if hotspots are disabled

        const distance = camera.position.distanceTo(this.position);
        
        if (distance < HOTSPOT_ACTIVATION_DISTANCE) {
            if (!this.visible) {
                this.show();
            }
            const vector = this.position.clone().project(camera);
            const x = (vector.x * 0.5 + 0.5) * window.innerWidth;
            const y = (-vector.y * 0.5 + 0.5) * window.innerHeight;
            
            this.infoElement.style.left = `${x + 20}px`;
            this.infoElement.style.top = `${y - 20}px`;
        } else if (this.visible) {
            this.hide();
        }

        this.marker.lookAt(camera.position);
    }

    show() {
        this.visible = true;
        this.infoElement.style.display = 'block';
        this.marker.material.color.setHex(0xFF4444);
    }

    hide() {
        this.visible = false;
        this.infoElement.style.display = 'none';
        this.marker.material.color.setHex(0x4CAF50);
    }
}

const modelHotspots = {
    'mleiha.glb': [
        {
            position: new THREE.Vector3(3, .7, 17.3),
            title: "Welcome Area",
            description: "This is the main entrance to the archaeological site.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/welcome-area"
        },
        {
            position: new THREE.Vector3(4.2, .85, 3.2),
            title: "Ancient Structure",
            description: "Remains of a building dating back to the 3rd millennium BCE.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/ancient-structure"
        },
    ],
    'khorfakan.glb': [
        {
            position: new THREE.Vector3(10, 1.5, 20),
            title: "Historical Monument",
            description: "A significant historical monument in Khorfakan.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/historical-monument"
        },
        {
            position: new THREE.Vector3(5, 2, 10),
            title: "Local Market",
            description: "Visit the vibrant local market.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/local-market"
        },
    ],
    'model3.glb': [
        {
            position: new THREE.Vector3(15, 1, 25),
            title: "Modern Architecture",
            description: "Explore the modern architecture design.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/modern-architecture"
        },
        {
            position: new THREE.Vector3(20, 1.5, 15),
            title: "Innovative Technology",
            description: "Discover the latest technology advancements.",
            imageUrl: "https://via.placeholder.com/150",
            linkUrl: "https://example.com/innovative-technology"
        },
    ]
};

function setupHotspots(modelPath) {
    clearHotspots();
    if (modelHotspots[modelPath]) {
        modelHotspots[modelPath].forEach(data => {
            hotspots.push(new Hotspot(data.position, data.title, data.description, data.imageUrl, data.linkUrl));
        });
    }
}

function clearHotspots() {
    hotspots.forEach(hotspot => {
        hotspot.hide(); // Hide the hotspot first
        scene.remove(hotspot.marker); // Remove the 3D marker from the scene
        document.body.removeChild(hotspot.infoElement); // Remove the HTML element from the DOM
    });
    hotspots = []; // Clear the hotspots array
}

function init() {
    scene = new THREE.Scene();
    const textureLoader = new THREE.TextureLoader();
    textureLoader.load('https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/venice_sunset_1k.hdr', function(texture) {
        texture.mapping = THREE.EquirectangularReflectionMapping;
        texture.encoding = THREE.sRGBEncoding;
        scene.background = texture;
    }, undefined, function(error) {
        console.error('Failed to load sky texture:', error);
        scene.background = new THREE.Color(0x87CEEB);
    });

    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.y = 1.7;

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.0;
    document.body.appendChild(renderer.domElement);

    scene.add(new THREE.AmbientLight(0xffffff, 0.6));
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
    directionalLight.position.set(100, 100, 100);
    scene.add(directionalLight);

    controls = new THREE.PointerLockControls(camera, document.body);

    setupEventListeners();

    if (isMobile) {
        window.moveJoystick = new Joystick('moveJoystick');
        window.lookJoystick = new Joystick('lookJoystick');
        document.getElementById('jumpButton').addEventListener('click', jump);
    }

    window.addEventListener('resize', onWindowResize, false);

    const floorGeometry = new THREE.PlaneGeometry(100, 100);
    const floorMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0.0 });
    const floor = new THREE.Mesh(floorGeometry, floorMaterial);
    floor.rotation.x = -Math.PI / 2;
    floor.position.y = 0.1;
    scene.add(floor);
    collisionObjects.push(floor);
}

function setupEventListeners() {
    if (!isMobile) {
        document.addEventListener('contextmenu', (event) => {
            event.preventDefault();
            if (controls.isLocked) {
                controls.unlock();
            } else {
                controls.lock();
            }
        });
        controls.addEventListener('lock', () => document.getElementById('controls').style.display = 'none');
        controls.addEventListener('unlock', () => {
            if (canMove) document.getElementById('controls').style.display = 'block';
        });
    }

    document.getElementById('startButton').addEventListener('click', startExperience);

    const onKeyDown = (event) => {
        if (!canMove) return;
        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': jump(); break;
            case 'ShiftLeft':
            case 'ShiftRight': isRunning = true; moveSpeed = runMoveSpeed; break;
            case 'KeyQ': rotationDirection = -1; break;
            case 'KeyE': rotationDirection = 1; break;
            case 'KeyR': scaleDirection = 1; break;
            case 'KeyF': scaleDirection = -1; break;
        }
    };

    const onKeyUp = (event) => {
        if (!canMove) return;
        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;
            case 'ShiftLeft':
            case 'ShiftRight': isRunning = false; moveSpeed = 0.05; break;
            case 'KeyQ':
            case 'KeyE': rotationDirection = 0; break;
            case 'KeyR':
            case 'KeyF': scaleDirection = 0; break;
        }
    };

    document.addEventListener('keydown', onKeyDown);
    document.addEventListener('keyup', onKeyUp);

    renderer.domElement.addEventListener('click', onMouseClick);

    document.getElementById('settingsButton').addEventListener('click', () => {
        const settingsMenu = document.getElementById('settingsMenu');
        settingsMenu.style.display = settingsMenu.style.display === 'block' ? 'none' : 'block';
    });

    document.getElementById('moveSpeedRange').addEventListener('input', (event) => {
        moveSpeed = parseFloat(event.target.value);
        runMoveSpeed = moveSpeed * 2;
    });

    document.getElementById('lookSpeedRange').addEventListener('input', (event) => {
        lookSpeed = parseFloat(event.target.value);
    });

    document.getElementById('soundOption').addEventListener('change', (event) => {
        soundEnabled = event.target.checked;
    });

    document.getElementById('hotspotsOption').addEventListener('change', (event) => {
        hotspotsEnabled = event.target.checked;
        toggleHotspots(hotspotsEnabled);
    });

    document.getElementById('backToMainMenuButton').addEventListener('click', backToMainMenu);

    document.getElementById('fullscreenButton').addEventListener('click', toggleFullscreen);
    document.getElementById('resetCameraButton').addEventListener('click', resetCamera);
}

function onMouseClick(event) {
    if (!canMove) return;

    const mouse = new THREE.Vector2();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(collisionObjects, true);

    if (intersects.length > 0) {
        const targetPosition = intersects[0].point;
        moveCameraTo(targetPosition);
        if (soundEnabled) playSound('clickSound');
    }
}

function checkGroundCollision(position) {
    groundRaycaster.ray.origin.copy(position);
    groundRaycaster.ray.direction.set(0, -1, 0);
    const intersections = groundRaycaster.intersectObjects(collisionObjects, true);
    if (intersections.length > 0 && intersections[0].distance < 1.7) {
        return intersections[0].point.y + 1.7;
    }
    return null;
}

function moveCameraTo(targetPosition) {
    const duration = 1000;
    const startTime = performance.now();

    const startPosition = camera.position.clone();
    const direction = targetPosition.clone().sub(startPosition).normalize();
    const distance = startPosition.distanceTo(targetPosition);

    function animateMove(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);

        const newPosition = startPosition.clone().addScaledVector(direction, distance * progress);

        const groundY = checkGroundCollision(newPosition);
        if (groundY !== null) {
            newPosition.y = groundY;
        }

        camera.position.copy(newPosition);

        if (progress < 1) {
            requestAnimationFrame(animateMove);
        }
    }

    requestAnimationFrame(animateMove);
}

function setupModelLoader(modelPath) {
    if (!modelPath) {
        console.error('Model path is undefined or empty');
        return;
    }
    const loader = new THREE.GLTFLoader();
    const progressBar = document.getElementById('loadingProgress');
    const startButton = document.getElementById('startButton');
    
    loader.load(modelPath, 
        function (gltf) {
            if (model) {
                scene.remove(model);
                disposeObject(model);
            }
            model = gltf.scene;
            scene.add(model);
            
            modelBoundary = new THREE.Box3().setFromObject(model);
            
            model.traverse((child) => {
                if (child.isMesh) {
                    child.geometry.computeBoundingBox();
                    collisionObjects.push(child);
                }
            });

            const center = modelBoundary.getCenter(new THREE.Vector3());
            const size = modelBoundary.getSize(new THREE.Vector3());
            camera.position.set(center.x, center.y + 1.7, center.z + size.z/4);
            
            isModelLoaded = true;
            progressBar.style.width = '100%';
            startButton.style.display = 'block';
            setupHotspots(modelPath);
        },
        function (xhr) {
            const percentComplete = (xhr.loaded / xhr.total) * 100;
            progressBar.style.width = percentComplete + '%';
        },
        function (error) {
            console.error('An error occurred loading the model:', error);
            document.getElementById('loadingText').innerText = 'Failed to load model. Please try again later.';
            document.getElementById('startButton').innerText = 'Retry';
            document.getElementById('startButton').style.display = 'block';
        }
    );
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    isMobile = window.innerWidth <= 768;
}

function checkCollision(position) {
    if (modelBoundary) {
        const padding = 1;
        const min = modelBoundary.min.clone().add(new THREE.Vector3(padding, 0, padding));
        const max = modelBoundary.max.clone().sub(new THREE.Vector3(padding, 0, padding));
        
        if (position.x < min.x || position.x > max.x ||
            position.z < min.z || position.z > max.z) {
            return true;
        }
    }

    const directions = [
        new THREE.Vector3(1, 0, 0),
        new THREE.Vector3(-1, 0, 0),
        new THREE.Vector3(0, 0, 1),
        new THREE.Vector3(0, 0, -1)
    ];

    for (const direction of directions) {
        raycaster.set(position, direction);
        const intersects = raycaster.intersectObjects(collisionObjects, true);
        if (intersects.length > 0 && intersects[0].distance < collisionDistance) {
            return true;
        }
    }

    return false;
}

function updatePosition(delta) {
    if (!controls.isLocked && !isMobile) return;

    const currentMoveSpeed = isRunning ? runMoveSpeed : moveSpeed;
    const moveDistance = currentMoveSpeed * delta * 60;
    const currentPosition = camera.position.clone();
    let newPosition = currentPosition.clone();

    verticalVelocity -= gravity;
    newPosition.y += verticalVelocity;

    const groundY = checkGroundCollision(newPosition);
    if (groundY !== null) {
        newPosition.y = groundY;
        verticalVelocity = 0;
        isGrounded = true;
        isJumping = false;
    } else {
        isGrounded = false;
    }

    const moveVector = new THREE.Vector3();
    const forward = new THREE.Vector3(0, 0, -1);
    const right = new THREE.Vector3(1, 0, 0);
    
    forward.applyQuaternion(camera.quaternion);
    right.applyQuaternion(camera.quaternion);
    
    forward.y = 0;
    right.y = 0;
    forward.normalize();
    right.normalize();

    if (moveForward || (isMobile && window.moveJoystick.y < 0)) {
        moveVector.add(forward.multiplyScalar(moveDistance));
    }
    if (moveBackward || (isMobile && window.moveJoystick.y > 0)) {
        moveVector.add(forward.multiplyScalar(-moveDistance));
    }
    if (moveRight || (isMobile && window.moveJoystick.x > 0)) {
        moveVector.add(right.multiplyScalar(moveDistance));
    }
    if (moveLeft || (isMobile && window.moveJoystick.x < 0)) {
        moveVector.add(right.multiplyScalar(-moveDistance));
    }

    newPosition.add(moveVector);

    if (!checkCollision(newPosition)) {
        camera.position.copy(newPosition);
    } else {
        camera.position.copy(currentPosition);
    }

    updateRotationAndScale(delta);
}

function updateRotationAndScale(delta) {
    if (rotationDirection !== 0) {
        model.rotation.y += rotationDirection * rotationSpeed * delta * 60;
        if (soundEnabled) playSound('rotateSound');
    }
    if (scaleDirection !== 0) {
        const currentScale = model.scale.x;
        const newScale = currentScale + scaleDirection * scaleFactor;
        if (newScale > 0.1 && newScale < 2) { // Limit scale between 0.1 and 2
            model.scale.set(newScale, newScale, newScale);
            if (soundEnabled) playSound('scaleSound');
        }
    }
}

function animate() {
    requestAnimationFrame(animate);

    const time = performance.now();
    const delta = (time - prevTime) / 1000;

    updatePosition(delta);

    if (isMobile) {
        if (window.moveJoystick) {
            if (window.moveJoystick.x !== 0 || window.moveJoystick.y !== 0) {
                moveForward = window.moveJoystick.y < 0;
                moveBackward = window.moveJoystick.y > 0;
                moveRight = window.moveJoystick.x > 0;
                moveLeft = window.moveJoystick.x < 0;
            } else {
                moveForward = false;
                moveBackward = false;
                moveRight = false;
                moveLeft = false;
            }
        }
        if (window.lookJoystick) {
            if (window.lookJoystick.x !== 0) {
                camera.rotation.y -= window.lookJoystick.x * lookSpeed;
            }
        }
    }

    hotspots.forEach(hotspot => hotspot.update(camera));

    prevTime = time;
    renderer.render(scene, camera);
}

function playSound(soundId) {
    const sound = document.getElementById(soundId);
    if (sound && soundEnabled) {
        sound.currentTime = 0;
        sound.play().catch(error => {
            console.error('Error playing sound:', error);
        });
    }
}

function jump() {
    if (!canMove) return;
    if (isGrounded) {
        verticalVelocity = jumpForce;
        isGrounded = false;
        isJumping = true;
        if (soundEnabled) playSound('jumpSound');
    }
}

function startExperience() {
    canMove = true;
    document.getElementById('loadingContainer').style.display = 'none';
    document.getElementById('backToMainMenuButton').style.display = 'block';
    if (!isMobile) {
        document.getElementById('controls').style.display = 'block';
    }
    controls.lock();
}

function backToMainMenu() {
    canMove = false;
    document.getElementById('backToMainMenuButton').style.display = 'none';
    document.getElementById('controls').style.display = 'none';
    document.getElementById('mobileControls').style.display = 'none';
    document.getElementById('jumpButton').style.display = 'none';
    document.getElementById('settingsButton').style.display = 'block'; // Ensure settings button is visible
    document.getElementById('settingsMenu').style.display = 'none';

    while (scene.children.length > 0) {
        const object = scene.children[0];
        scene.remove(object);
        disposeObject(object);
    }

    model = null;
    modelBoundary = null;
    collisionObjects = [];
    hotspots = [];

    camera.position.set(0, 1.7, 0);
    camera.rotation.set(0, 0, 0);

    const textureLoader = new THREE.TextureLoader();
    textureLoader.load('https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/venice_sunset_1k.hdr', function(texture) {
        texture.mapping = THREE.EquirectangularReflectionMapping;
        texture.encoding = THREE.sRGBEncoding;
        scene.background = texture;
    }, undefined, function(error) {
        console.error('Failed to load sky texture:', error);
        scene.background = new THREE.Color(0x87CEEB);
    });

    scene.add(new THREE.AmbientLight(0xffffff, 0.6));
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
    directionalLight.position.set(100, 100, 100);
    scene.add(directionalLight);

    const floorGeometry = new THREE.PlaneGeometry(100, 100);
    const floorMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0.0 });
    const floor = new THREE.Mesh(floorGeometry, floorMaterial);
    floor.rotation.x = -Math.PI / 2;
    floor.position.y = 0.1;
    scene.add(floor);
    collisionObjects.push(floor);

    document.getElementById('mainMenu').style.display = 'flex';
}

function disposeObject(object) {
    if (object.isMesh) {
        if (object.geometry) object.geometry.dispose();
        if (object.material) {
            if (Array.isArray(object.material)) {
                object.material.forEach(material => material.dispose());
            } else {
                object.material.dispose();
            }
        }
    }
    if (object.children && object.children.length > 0) {
        object.children.forEach(child => disposeObject(child));
    }
}

class Joystick {
    constructor(elementId) {
        this.element = document.getElementById(elementId);
        this.knob = this.element.querySelector('.joystick-knob');
        this.bounds = this.element.getBoundingClientRect();
        this.center = {
            x: this.bounds.width / 2,
            y: this.bounds.height / 2
        };
        this.x = 0;
        this.y = 0;

        this.knob.addEventListener('touchstart', this.handleTouch.bind(this));
        this.knob.addEventListener('touchmove', this.handleTouch.bind(this));
        this.knob.addEventListener('touchend', this.reset.bind(this));
    }

    handleTouch(event) {
        if (!canMove) return;
        event.preventDefault();
        const touch = event.touches[0];
        const bounds = this.element.getBoundingClientRect();
        
        let x = touch.clientX - bounds.left - this.center.x;
        let y = touch.clientY - bounds.top - this.center.y;
        
        const distance = Math.sqrt(x * x + y * y);
        const maxDistance = this.bounds.width / 2 - this.knob.offsetWidth / 2;
        
        if (distance > maxDistance) {
            const angle = Math.atan2(y, x);
            x = Math.cos(angle) * maxDistance;
            y = Math.sin(angle) * maxDistance;
        }
        
        this.knob.style.transform = `translate(${x}px, ${y}px)`;
        
        this.x = x / maxDistance;
        this.y = y / maxDistance;
    }

    reset() {
        this.knob.style.transform = 'translate(-50%, -50%)';
        this.x = 0;
        this.y = 0;
    }
}

function toggleHotspots(enable) {
    hotspots.forEach(hotspot => {
        if (enable) {
            hotspot.show();
        } else {
            hotspot.hide();
        }
    });
}

function toggleFullscreen() {
    if (!document.fullscreenElement) {
        document.documentElement.requestFullscreen();
    } else {
        document.exitFullscreen();
    }
}

function resetCamera() {
    camera.position.set(0, 1.7, 0);
    camera.rotation.set(0, 0, 0);
}

document.getElementById('modelSelection').addEventListener('click', function(event) {
    const target = event.target;
    if (target.tagName.toLowerCase() === 'li') {
        const modelPath = target.getAttribute('data-model');
        if (modelPath) {
            document.getElementById('mainMenu').style.display = 'none';
            document.getElementById('loadingContainer').style.display = 'flex';
            clearHotspots(); // Clear hotspots immediately when changing models
            setupModelLoader(modelPath);
        } else {
            console.error('Model path is undefined or empty');
        }
    }
});

init();
animate();
</script>
</body>
</html>