const cameraOffset=new THREE.Vector3(0,12,-15),cameraLerpFactor=1;let cameraRotation=new THREE.Euler(0,0,0,"YXZ");const mouseSensitivity=4e-4;let moveForward=!1,moveBackward=!1,moveLeft=!1,moveRight=!1;const PLAYER_SPEED=20,jumpForce=1750,turnSpeed=.2;let isJumping=!1,lastJumpTime=0;const jumpCooldown=250,listener=new THREE.AudioListener,audioLoader=new THREE.AudioLoader;let minimapElements,minimapScene,minimapCamera,minimapRenderer;async function init(){return new Promise(async(e,t)=>{try{console.log("Initializing the game..."),await initStats(),await initScene(),await initLighting(),await initBackground(),await initPhysics(),await initPlayer(),console.log("Loading audio..."),await loadAudio(),await initBackgroundAudio(),console.log("Creating obstacles + particles..."),await createGroundPiece(0,0,0,60,260),await initBackgroundParticleSystem(),await initGateObstacles(),await createGroundPiece(0,0,290,10,10),await createGroundPiece(-29,0,275,10,10),await createGroundPiece(29,0,275,10,10),await createGroundPiece(20,0,300,10,10),await createGroundPiece(-18,0,305,10,10),await createGroundPiece(27,0,350,10,10),await createGroundPiece(5,0,330,10,10),await createGroundPiece(-15,0,350,10,10),await createGroundPiece(25,0,380,10,10),await createGroundPiece(0,0,390,10,10),await createGroundPiece(-20,0,387,10,10),await createGroundPiece(-10,0,410,10,10),await createGroundPiece(10,0,430,10,10),await createGroundPiece(-29,0,450,10,10),await createGroundPiece(20,0,460,10,10),await initRodObstacles(),await createGroundPiece(0,0,490,60,260),await initFinishLine(),minimapElements=createMinimapScene(),console.log("Game initialized successfully!"),e()}catch(i){console.error("Error initializing the game:",i),t(i)}})}function createMinimapScene(){let e=new THREE.Scene;function t(t,i,n,a,o){let $=new THREE.PlaneGeometry(a,o),r=new THREE.MeshBasicMaterial({color:8421504}),s=new THREE.Mesh($,r);s.position.set(t,i,-(n+o/2)),s.rotation.x=-Math.PI/2,e.add(s)}return function i(){let n=new THREE.OrthographicCamera(-50,50,50,-50,1,1e3);n.position.set(0,200,0),n.lookAt(0,0,0),n.up.set(0,0,-1);let a=new THREE.WebGLRenderer({canvas:document.getElementById("minimap"),alpha:!0});a.setSize(150,150),t(0,0,0,60,260),t(0,0,490,60,260),[[0,0,290],[-29,0,275],[29,0,275],[20,0,300],[-18,0,305],[27,0,350],[5,0,330],[-15,0,350],[25,0,380],[0,0,390],[-20,0,387],[-10,0,410],[10,0,430],[-29,0,450],[20,0,460],].forEach(([e,i,n])=>{t(e,i,n,10,10)});let o=function t(){let i=new THREE.CircleGeometry(2,16),n=new THREE.MeshBasicMaterial({color:"#f874b4"}),a=new THREE.Mesh(i,n);return a.rotation.x=-Math.PI/2,a.position.y=.1,e.add(a),a}();return{scene:e,camera:n,renderer:a,playerDot:o}}()}function updateMinimap(e,t){if(!e)return;let{scene:i,camera:n,renderer:a,playerDot:o}=e;o.position.x=t.position.x,o.position.z=-t.position.z,n.position.x=t.position.x,n.position.z=-t.position.z,n.lookAt(t.position.x,0,-t.position.z),a.render(i,n)}async function loadAudio(){backGroundMusic=new THREE.Audio(listener),jumpSound=new THREE.Audio(listener),jumpland=new THREE.Audio(listener),hitsound=new THREE.Audio(listener),winsound=new THREE.Audio(listener),countdownOneSound=new THREE.Audio(listener),countdownTwoSound=new THREE.Audio(listener),countdownThreeSound=new THREE.Audio(listener),countdownGoSound=new THREE.Audio(listener);let e=[];function t(e,t,i=!1,n=gameVolume){return new Promise((a,o)=>{audioLoader.load(e,e=>{t.setBuffer(e),t.setLoop(i),t.setVolume(n),a()},void 0,o)})}e.push(t(PbackGroundMusic,backGroundMusic,!0,gameVolume/2)),e.push(t(PjumpSound,jumpSound)),e.push(t(Pjumpland,jumpland)),e.push(t(Phitsound,hitsound)),e.push(t(Pwinsound,winsound)),e.push(t(countdownOne,countdownOneSound)),e.push(t(countdownTwo,countdownTwoSound)),e.push(t(countdownThree,countdownThreeSound)),e.push(t(countdownGo,countdownGoSound)),await Promise.all(e),backGroundMusic.play()}async function initBackgroundAudio(){return new Promise(e=>{backGroundMusic.play(),e()})}function updateGameVolume(){backGroundMusic&&backGroundMusic.setVolume(gameVolume/2)}async function initFinishLine(){return new Promise((e,t)=>{let i=new THREE.TextureLoader;i.load(finish,t=>{let i=new THREE.BoxGeometry(6.5,.1,1),n=new THREE.MeshStandardMaterial({map:t}),a=new THREE.Mesh(i,n);a.position.set(0,.5,495),a.scale.x=10,a.scale.z=15,scene.add(a),e()},void 0,e=>{console.error("Error loading texture:",e),t(e)})})}let particles=[];const particleCountDie=100,particleGeometry=new THREE.SphereGeometry(.1,8,8),particleMaterial=new THREE.MeshBasicMaterial({color:"#8E1767",transparent:!0,opacity:.8});function createParticleExplosion(e){particles.forEach(e=>{scene.remove(e.mesh)}),particles=[];for(let t=0;t<particleCount;t++){let i=new THREE.Mesh(particleGeometry,particleMaterial.clone());i.position.copy(e);let n=Math.acos(2*t/particleCount-1),a=Math.sqrt(particleCount*Math.PI)*n,o=new THREE.Vector3(10*Math.sin(n)*Math.cos(a),10*Math.cos(n),10*Math.sin(n)*Math.sin(a));o.x+=(Math.random()-.5)*2,o.y+=(Math.random()-.5)*2,o.z+=(Math.random()-.5)*2,scene.add(i),particles.push({mesh:i,velocity:o,lifetime:1})}}function updateParticles(e){particles.forEach((t,i)=>{t.mesh.position.x+=t.velocity.x*e,t.mesh.position.y+=t.velocity.y*e,t.mesh.position.z+=t.velocity.z*e,t.velocity.y-=9.8*e,t.lifetime-=e,t.mesh.material.opacity=t.lifetime,t.lifetime<=0&&(scene.remove(t.mesh),particles.splice(i,1))})}async function die(){currentLives--,isPlayerDead=!0,createParticleExplosion(model.position),model.visible=!1;let e=playerBody.position.z<210?{x:0,y:10,z:10}:{x:0,y:10,z:230};if(hitsound.play(),await new Promise(e=>setTimeout(e,1e3)),currentLives<=0){playerBody.position.set(0,10,10),document.exitPointerLock(),removeEventListeners(),generateHearts(currentLives),timerRunning=!1,removeEventListeners(),toggleMenu(),document.getElementById("volume-control").style.display="none",moveForward=!1,moveBackward=!1,moveLeft=!1,moveRight=!1,document.getElementById("resumeButton").style.display="none";let t=document.createElement("h1");t.id="lostMessage",t.innerHTML="You lost!",document.getElementById("gameMenu").appendChild(t)}else playerBody.position.set(e.x,e.y,e.z),generateHearts(currentLives);model.visible=!0,isPlayerDead=!1}async function initBackgroundParticleSystem(){return new Promise(e=>{let t=new THREE.BufferGeometry;positions=new Float32Array(3*particleCount),velocities=new Float32Array(3*particleCount);for(let i=0;i<particleCount;i++)positions[3*i]=(Math.random()-.5)*particleSpreadX,positions[3*i+1]=(Math.random()-.5)*particleSpreadY,positions[3*i+2]=Math.random()*particleSpreadZ,velocities[3*i]=(Math.random()-.5)*.1,velocities[3*i+1]=(Math.random()-.5)*.05,velocities[3*i+2]=(Math.random()-.5)*.05;t.setAttribute("position",new THREE.BufferAttribute(positions,3));let n=new THREE.PointsMaterial({color:"white",size:.25,transparent:!0,opacity:.25,blending:THREE.AdditiveBlending,depthTest:!0,sizeAttenuation:!0,fog:!0});particleSystem=new THREE.Points(t,n),scene.add(particleSystem),e()})}async function initStats(){return new Promise(e=>{(stats=new Stats).showPanel(0),document.body.appendChild(stats.dom),e()})}async function initScene(){return new Promise(e=>{(scene=new THREE.Scene).fog=new THREE.Fog(2105376,100,500),(camera=new THREE.PerspectiveCamera(70,window.innerWidth/window.innerHeight,.1,1e3)).add(listener),camera.position.set(0,0,0),(renderer=new THREE.WebGLRenderer({antialias:!0})).setSize(window.innerWidth,window.innerHeight),renderer.shadowMap.enabled=!0,renderer.shadowMap.type=THREE.PCFSoftShadowMap,renderer.outputColorSpace=THREE.SRGBColorSpace,renderer.toneMapping=THREE.ACESFilmicToneMapping,renderer.toneMappingExposure=1,renderer.shadowMap.type=THREE.PCFSoftShadowMap,document.body.appendChild(renderer.domElement),new THREE.AxesHelper(1e3),clock=new THREE.Clock,setupControls(),e()})}function checkForWin(){playerBody.position.z>492&&playerBody.position.y>0&&!1==gameWon&&(gameWon=!0,moveForward=!1,moveBackward=!1,moveLeft=!1,moveRight=!1,timerRunning=!1,null===localStorage.getItem("level2Unlocked")&&localStorage.setItem("level2Unlocked","true"),winsound.play(),showWinScreen(elapsedTime))}function toggleView(){(isFirstPerson=!isFirstPerson)?(controls.connect(),model.visible=!1):(controls.disconnect(),model.visible=!0)}function setupControls(){controls=new PointerLockControls(camera,renderer.domElement),document.addEventListener("click",()=>{isGamePaused||controls.lock()}),controls.addEventListener("lock",()=>{console.log("PointerLock activated")}),controls.addEventListener("unlock",()=>{console.log("PointerLock deactivated")})}async function initLighting(){return new Promise(e=>{let t=new THREE.AmbientLight(4210752,1);scene.add(t);let i=new THREE.DirectionalLight(16777215,2.5);i.position.set(50,100,-50),i.castShadow=!0,i.shadow.mapSize.width=4096,i.shadow.mapSize.height=4096,i.shadow.camera.left=-300,i.shadow.camera.right=300,i.shadow.camera.top=300,i.shadow.camera.bottom=-300,i.shadow.camera.near=1,i.shadow.camera.far=5e3,scene.add(i);let n=new THREE.DirectionalLight(16777215,.3);n.position.set(-50,50,-50),scene.add(n),e()})}async function initBackground(){return new Promise(e=>{let t=new THREE.TextureLoader,i=t.load(basicBg,function(e){e.wrapS=THREE.ClampToEdgeWrapping,e.wrapT=THREE.ClampToEdgeWrapping,e.repeat.set(1,1),e.offset.set(0,-.3)}),n=new THREE.SphereGeometry(500,60,40),a=new THREE.MeshBasicMaterial({map:i,side:THREE.BackSide}),o=new THREE.Mesh(n,a);scene.add(o),e()})}async function initPhysics(){return new Promise(e=>{(world=new CANNON.World).gravity.set(0,-30,0),cannonDebugger=new CannonDebugger(scene,world,{color:16711680}),e()})}async function initPlayer(){return new Promise(e=>{let t=new URL("../assets/SmoothFatGuy.glb",import.meta.url),i=new GLTFLoader;i.load(t.href,t=>{(model=t.scene).position.set(0,2,10),model.scale.set(.4,.4,.4),model.traverse(e=>{e.isMesh&&(e.castShadow=!0,e.receiveShadow=!0)}),scene.add(model),(cameraGoal=new THREE.Object3D).position.copy(cameraOffset),model.add(cameraGoal),mixer=new THREE.AnimationMixer(model);let i=t.animations,n=THREE.AnimationClip.findByName(i,"Running");runningAction=mixer.clipAction(n);let a=THREE.AnimationClip.findByName(i,"Running");runningLeftAction=mixer.clipAction(a);let o=THREE.AnimationClip.findByName(i,"Running");runningRightAction=mixer.clipAction(o);let $=THREE.AnimationClip.findByName(i,"Running Backward");backRunningAction=mixer.clipAction($);let r=THREE.AnimationClip.findByName(i,"Jumping Land");jumpAction=mixer.clipAction(r),idleClip=THREE.AnimationClip.findByName(i,"Idle"),idleAction=mixer.clipAction(idleClip);let s=THREE.AnimationClip.findByName(i,"Falling");fallingAction=mixer.clipAction(s),idleAction.setLoop(THREE.LoopRepeat),idleAction.play(),currentAction=idleAction;let c=new THREE.Box3().setFromObject(model),l=c.getSize(new THREE.Vector3),d=c.getCenter(new THREE.Vector3);modelCenterOffset=new THREE.Vector3().subVectors(model.position,d);let p=new CANNON.Box(new CANNON.Vec3(l.x/2,l.y/2,l.z/2));(playerBody=new CANNON.Body({mass:70,linearDamping:.9,angularDamping:.99,fixedRotation:!0,position:new CANNON.Vec3(d.x,d.y,d.z)})).addShape(p),world.addBody(playerBody),playerHelper=new THREE.BoxHelper(model,"red"),e()},void 0,e=>console.error("Error loading player model:",e))})}async function initEventListeners(){return new Promise(e=>{window.addEventListener("keydown",handleKeyDown),window.addEventListener("keyup",handleKeyUp),document.addEventListener("mousemove",onMouseMove,!1),window.addEventListener("keydown",e=>{"v"===e.key&&toggleView()}),e()})}let targetRotationY=0;const rotationDamping=.2;function onMouseMove(e){controls.isLocked&&(targetRotationY-=4e-4*e.movementX,cameraRotation.y+=(targetRotationY-cameraRotation.y)*.2,playerBody&&playerBody.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),cameraRotation.y))}function handleKeyDown(e){switch(e.key){case"w":case"ArrowUp":moveForward=!0;break;case"s":case"ArrowDown":moveBackward=!0;break;case"a":case"ArrowLeft":moveLeft=!0;break;case"d":case"ArrowRight":moveRight=!0;break;case"p":toggleMenu();break;case" ":console.log("Jumping"),isJumping||jump()}}function handleKeyUp(e){switch(e.key){case"w":case"ArrowUp":moveForward=!1;break;case"s":case"ArrowDown":moveBackward=!1;break;case"a":case"ArrowLeft":moveLeft=!1;break;case"d":case"ArrowRight":moveRight=!1}}

I need to create a dynamic skybox for threejs, the current skybox is apprently not "dynamic", any ideas, id also appreciate some recommmendations for lighting