Created
          July 30, 2025 16:50 
        
      - 
      
 - 
        
Save bgauryy/093f9125937f30b00eac03fba688c008 to your computer and use it in GitHub Desktop.  
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | <!-- | |
| This is an example for HTML generation using octocode-mcp with this prompt: | |
| https://github.com/bgauryy/octocode-mcp | |
| "use octocode | |
| Search for threejs examples | |
| get top examples from top repositories | |
| create a stunning, hyper-realistic video of a man walking through a futuristic city. be creative! blow my mind!" | |
| --> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Futuristic City Walker - Hyper-Realistic 3D Experience</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #0c0c0c 0%, #1a1a2e 50%, #16213e 100%); | |
| overflow: hidden; | |
| font-family: 'Orbitron', monospace; | |
| } | |
| #container { | |
| position: relative; | |
| width: 100vw; | |
| height: 100vh; | |
| } | |
| #loading { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| color: #00ffff; | |
| font-size: 24px; | |
| text-align: center; | |
| z-index: 1000; | |
| text-shadow: 0 0 20px #00ffff; | |
| } | |
| #info { | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| color: #00ffff; | |
| font-size: 16px; | |
| z-index: 100; | |
| text-shadow: 0 0 10px #00ffff; | |
| background: rgba(0, 0, 0, 0.7); | |
| padding: 15px; | |
| border-radius: 10px; | |
| border: 1px solid #00ffff; | |
| } | |
| #controls { | |
| position: absolute; | |
| bottom: 20px; | |
| left: 20px; | |
| color: #00ffff; | |
| font-size: 14px; | |
| z-index: 100; | |
| background: rgba(0, 0, 0, 0.8); | |
| padding: 15px; | |
| border-radius: 10px; | |
| border: 1px solid #00ffff; | |
| } | |
| .loading-spinner { | |
| border: 3px solid rgba(0, 255, 255, 0.3); | |
| border-radius: 50%; | |
| border-top: 3px solid #00ffff; | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 20px auto; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap'); | |
| </style> | |
| </head> | |
| <body> | |
| <div id="container"> | |
| <div id="loading"> | |
| <div class="loading-spinner"></div> | |
| <h2>INITIALIZING FUTURE CITY</h2> | |
| <p>Loading hyper-realistic 3D environment...</p> | |
| </div> | |
| <div id="info" style="display: none;"> | |
| <h3>🌆 NEO TOKYO 2087</h3> | |
| <p>👤 Character: Walking</p> | |
| <p>🌧️ Weather: Neon Rain</p> | |
| <p>🎥 Camera: Cinematic Mode</p> | |
| <p>⚡ FPS: <span id="fps">60</span></p> | |
| </div> | |
| <div id="controls" style="display: none;"> | |
| <h4>🎮 CONTROLS</h4> | |
| <p>🖱️ Mouse: Look Around</p> | |
| <p>⌨️ WASD: Move Camera</p> | |
| <p>🔄 Space: Switch View</p> | |
| <p>🌈 R: Toggle Rain</p> | |
| </div> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/postprocessing/Pass.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/shaders/CopyShader.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/shaders/LuminosityHighPassShader.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/postprocessing/ShaderPass.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/postprocessing/EffectComposer.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/postprocessing/RenderPass.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/postprocessing/UnrealBloomPass.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/20.0.0/tween.umd.js"></script> | |
| <script> | |
| // Global variables | |
| let scene, camera, renderer, composer; | |
| let character, city, rainSystem; | |
| let controls, clock; | |
| let walkingAnimation, cameraAnimation; | |
| let currentCameraMode = 0; | |
| let rainEnabled = true; | |
| let frameCount = 0; | |
| let lastTime = 0; | |
| // Initialize the experience | |
| async function init() { | |
| try { | |
| await createScene(); | |
| await createLighting(); | |
| await createCity(); | |
| await createCharacter(); | |
| await createWeatherEffects(); | |
| await createPostProcessing(); | |
| setupControls(); | |
| setupAnimation(); | |
| hideLoading(); | |
| animate(); | |
| } catch (error) { | |
| console.error('Failed to initialize:', error); | |
| document.getElementById('loading').innerHTML = '<h2>❌ SYSTEM ERROR</h2><p>Failed to load future city</p>'; | |
| } | |
| } | |
| // Create the main scene | |
| async function createScene() { | |
| scene = new THREE.Scene(); | |
| scene.fog = new THREE.Fog(0x0a0a0a, 50, 1000); | |
| // Camera setup | |
| camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000); | |
| camera.position.set(0, 15, 30); | |
| // Renderer setup | |
| renderer = new THREE.WebGLRenderer({ | |
| antialias: true, | |
| alpha: true, | |
| powerPreference: "high-performance" | |
| }); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); | |
| renderer.shadowMap.enabled = true; | |
| renderer.shadowMap.type = THREE.PCFSoftShadowMap; | |
| renderer.toneMapping = THREE.ACESFilmicToneMapping; | |
| renderer.toneMappingExposure = 1.2; | |
| renderer.outputEncoding = THREE.sRGBEncoding; | |
| document.getElementById('container').appendChild(renderer.domElement); | |
| clock = new THREE.Clock(); | |
| } | |
| // Create dramatic lighting | |
| async function createLighting() { | |
| // Ambient light for overall illumination | |
| const ambientLight = new THREE.AmbientLight(0x1a1a2e, 0.3); | |
| scene.add(ambientLight); | |
| // Main directional light (moonlight) | |
| const moonLight = new THREE.DirectionalLight(0x4169e1, 1.5); | |
| moonLight.position.set(-100, 200, 100); | |
| moonLight.castShadow = true; | |
| moonLight.shadow.mapSize.width = 4096; | |
| moonLight.shadow.mapSize.height = 4096; | |
| moonLight.shadow.camera.near = 0.1; | |
| moonLight.shadow.camera.far = 500; | |
| moonLight.shadow.camera.left = -100; | |
| moonLight.shadow.camera.right = 100; | |
| moonLight.shadow.camera.top = 100; | |
| moonLight.shadow.camera.bottom = -100; | |
| scene.add(moonLight); | |
| // Neon city lights | |
| for (let i = 0; i < 20; i++) { | |
| const neonLight = new THREE.PointLight( | |
| Math.random() > 0.5 ? 0x00ffff : 0xff0080, | |
| 2, | |
| 50 | |
| ); | |
| neonLight.position.set( | |
| (Math.random() - 0.5) * 200, | |
| Math.random() * 30 + 10, | |
| (Math.random() - 0.5) * 200 | |
| ); | |
| scene.add(neonLight); | |
| // Animate neon lights | |
| const flickerTween = new TWEEN.Tween(neonLight) | |
| .to({ intensity: Math.random() * 3 + 1 }, Math.random() * 2000 + 1000) | |
| .easing(TWEEN.Easing.Quadratic.InOut) | |
| .yoyo(true) | |
| .repeat(Infinity) | |
| .start(); | |
| } | |
| } | |
| // Create futuristic city | |
| async function createCity() { | |
| city = new THREE.Group(); | |
| // Ground plane with neon grid | |
| const groundGeometry = new THREE.PlaneGeometry(400, 400, 50, 50); | |
| const groundMaterial = new THREE.MeshLambertMaterial({ | |
| color: 0x0a0a0a, | |
| transparent: true, | |
| opacity: 0.8 | |
| }); | |
| const ground = new THREE.Mesh(groundGeometry, groundMaterial); | |
| ground.rotation.x = -Math.PI / 2; | |
| ground.receiveShadow = true; | |
| city.add(ground); | |
| // Create neon grid overlay | |
| const gridHelper = new THREE.GridHelper(400, 50, 0x00ffff, 0x00ffff); | |
| gridHelper.material.opacity = 0.3; | |
| gridHelper.material.transparent = true; | |
| city.add(gridHelper); | |
| // Generate futuristic buildings | |
| for (let i = 0; i < 50; i++) { | |
| const building = createFuturisticBuilding(); | |
| building.position.set( | |
| (Math.random() - 0.5) * 300, | |
| 0, | |
| (Math.random() - 0.5) * 300 | |
| ); | |
| city.add(building); | |
| } | |
| // Add floating platforms | |
| for (let i = 0; i < 10; i++) { | |
| const platform = createFloatingPlatform(); | |
| platform.position.set( | |
| (Math.random() - 0.5) * 200, | |
| Math.random() * 50 + 20, | |
| (Math.random() - 0.5) * 200 | |
| ); | |
| city.add(platform); | |
| } | |
| scene.add(city); | |
| } | |
| // Create individual futuristic building | |
| function createFuturisticBuilding() { | |
| const building = new THREE.Group(); | |
| const height = Math.random() * 80 + 20; | |
| const width = Math.random() * 8 + 4; | |
| const depth = Math.random() * 8 + 4; | |
| // Main building structure | |
| const buildingGeometry = new THREE.BoxGeometry(width, height, depth); | |
| const buildingMaterial = new THREE.MeshPhongMaterial({ | |
| color: new THREE.Color().setHSL(Math.random() * 0.1 + 0.5, 0.8, 0.3), | |
| transparent: true, | |
| opacity: 0.8, | |
| emissive: new THREE.Color().setHSL(Math.random() * 0.1 + 0.5, 0.5, 0.1) | |
| }); | |
| const buildingMesh = new THREE.Mesh(buildingGeometry, buildingMaterial); | |
| buildingMesh.position.y = height / 2; | |
| buildingMesh.castShadow = true; | |
| buildingMesh.receiveShadow = true; | |
| building.add(buildingMesh); | |
| // Add glowing windows | |
| for (let floor = 0; floor < Math.floor(height / 4); floor++) { | |
| for (let side = 0; side < 4; side++) { | |
| if (Math.random() > 0.3) { | |
| const window = createNeonWindow(); | |
| const angle = (side * Math.PI) / 2; | |
| const distance = Math.max(width, depth) / 2 + 0.1; | |
| window.position.set( | |
| Math.cos(angle) * distance, | |
| floor * 4 + 2, | |
| Math.sin(angle) * distance | |
| ); | |
| window.rotation.y = angle; | |
| building.add(window); | |
| } | |
| } | |
| } | |
| return building; | |
| } | |
| // Create glowing neon window | |
| function createNeonWindow() { | |
| const windowGeometry = new THREE.PlaneGeometry(1.5, 1.5); | |
| const windowMaterial = new THREE.MeshBasicMaterial({ | |
| color: Math.random() > 0.5 ? 0x00ffff : 0xff0080, | |
| transparent: true, | |
| opacity: 0.8, | |
| emissive: Math.random() > 0.5 ? 0x00ffff : 0xff0080, | |
| emissiveIntensity: 0.5 | |
| }); | |
| const window = new THREE.Mesh(windowGeometry, windowMaterial); | |
| // Animate window glow | |
| const glowTween = new TWEEN.Tween(windowMaterial) | |
| .to({ emissiveIntensity: Math.random() * 0.8 + 0.2 }, Math.random() * 3000 + 1000) | |
| .easing(TWEEN.Easing.Sinusoidal.InOut) | |
| .yoyo(true) | |
| .repeat(Infinity) | |
| .start(); | |
| return window; | |
| } | |
| // Create floating platform | |
| function createFloatingPlatform() { | |
| const platformGeometry = new THREE.CylinderGeometry(8, 8, 1, 8); | |
| const platformMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x4169e1, | |
| transparent: true, | |
| opacity: 0.7, | |
| emissive: 0x1a1a2e, | |
| emissiveIntensity: 0.3 | |
| }); | |
| const platform = new THREE.Mesh(platformGeometry, platformMaterial); | |
| platform.castShadow = true; | |
| platform.receiveShadow = true; | |
| // Floating animation | |
| const floatTween = new TWEEN.Tween(platform.position) | |
| .to({ y: platform.position.y + 5 }, 4000) | |
| .easing(TWEEN.Easing.Sinusoidal.InOut) | |
| .yoyo(true) | |
| .repeat(Infinity) | |
| .start(); | |
| return platform; | |
| } | |
| // Create walking character | |
| async function createCharacter() { | |
| character = new THREE.Group(); | |
| // Create a stylized humanoid character | |
| const bodyGeometry = new THREE.CylinderGeometry(1, 1, 3, 8); | |
| const bodyMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x2c3e50, | |
| shininess: 100 | |
| }); | |
| const body = new THREE.Mesh(bodyGeometry, bodyMaterial); | |
| body.position.y = 2; | |
| body.castShadow = true; | |
| character.add(body); | |
| // Head | |
| const headGeometry = new THREE.SphereGeometry(0.8, 16, 16); | |
| const headMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0xfdbcb4, | |
| shininess: 50 | |
| }); | |
| const head = new THREE.Mesh(headGeometry, headMaterial); | |
| head.position.y = 4.5; | |
| head.castShadow = true; | |
| character.add(head); | |
| // Glowing eyes | |
| const eyeGeometry = new THREE.SphereGeometry(0.1, 8, 8); | |
| const eyeMaterial = new THREE.MeshBasicMaterial({ | |
| color: 0x00ffff, | |
| emissive: 0x00ffff, | |
| emissiveIntensity: 1 | |
| }); | |
| const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
| leftEye.position.set(-0.3, 4.6, 0.7); | |
| character.add(leftEye); | |
| const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
| rightEye.position.set(0.3, 4.6, 0.7); | |
| character.add(rightEye); | |
| // Arms | |
| const armGeometry = new THREE.CylinderGeometry(0.3, 0.3, 2, 8); | |
| const armMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x34495e, | |
| shininess: 80 | |
| }); | |
| const leftArm = new THREE.Mesh(armGeometry, armMaterial); | |
| leftArm.position.set(-1.5, 2.5, 0); | |
| leftArm.castShadow = true; | |
| character.add(leftArm); | |
| const rightArm = new THREE.Mesh(armGeometry, armMaterial); | |
| rightArm.position.set(1.5, 2.5, 0); | |
| rightArm.castShadow = true; | |
| character.add(rightArm); | |
| // Legs | |
| const legGeometry = new THREE.CylinderGeometry(0.4, 0.4, 2.5, 8); | |
| const legMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x2c3e50, | |
| shininess: 100 | |
| }); | |
| const leftLeg = new THREE.Mesh(legGeometry, legMaterial); | |
| leftLeg.position.set(-0.6, 0, 0); | |
| leftLeg.castShadow = true; | |
| character.add(leftLeg); | |
| const rightLeg = new THREE.Mesh(legGeometry, legMaterial); | |
| rightLeg.position.set(0.6, 0, 0); | |
| rightLeg.castShadow = true; | |
| character.add(rightLeg); | |
| character.position.set(0, 0, 0); | |
| scene.add(character); | |
| // Store body parts for animation | |
| character.userData = { | |
| body, head, leftArm, rightArm, leftLeg, rightLeg, leftEye, rightEye | |
| }; | |
| } | |
| // Create weather effects | |
| async function createWeatherEffects() { | |
| rainSystem = new THREE.Group(); | |
| // Create rain particles | |
| const rainCount = 5000; | |
| const rainGeometry = new THREE.BufferGeometry(); | |
| const rainPositions = new Float32Array(rainCount * 3); | |
| const rainVelocities = new Float32Array(rainCount); | |
| for (let i = 0; i < rainCount; i++) { | |
| rainPositions[i * 3] = (Math.random() - 0.5) * 400; | |
| rainPositions[i * 3 + 1] = Math.random() * 200; | |
| rainPositions[i * 3 + 2] = (Math.random() - 0.5) * 400; | |
| rainVelocities[i] = Math.random() * 2 + 1; | |
| } | |
| rainGeometry.setAttribute('position', new THREE.BufferAttribute(rainPositions, 3)); | |
| rainGeometry.setAttribute('velocity', new THREE.BufferAttribute(rainVelocities, 1)); | |
| const rainMaterial = new THREE.PointsMaterial({ | |
| color: 0x00ffff, | |
| size: 0.5, | |
| transparent: true, | |
| opacity: 0.8, | |
| blending: THREE.AdditiveBlending | |
| }); | |
| const rain = new THREE.Points(rainGeometry, rainMaterial); | |
| rainSystem.add(rain); | |
| // Store for animation | |
| rainSystem.userData = { geometry: rainGeometry, velocities: rainVelocities }; | |
| scene.add(rainSystem); | |
| } | |
| // Create post-processing effects | |
| async function createPostProcessing() { | |
| try { | |
| composer = new THREE.EffectComposer(renderer); | |
| const renderPass = new THREE.RenderPass(scene, camera); | |
| composer.addPass(renderPass); | |
| const bloomPass = new THREE.UnrealBloomPass( | |
| new THREE.Vector2(window.innerWidth, window.innerHeight), | |
| 1.5, // strength | |
| 0.4, // radius | |
| 0.85 // threshold | |
| ); | |
| composer.addPass(bloomPass); | |
| } catch (error) { | |
| console.warn('Post-processing failed, using standard renderer:', error); | |
| composer = null; // Fall back to standard rendering | |
| } | |
| } | |
| // Setup controls | |
| function setupControls() { | |
| controls = new THREE.OrbitControls(camera, renderer.domElement); | |
| controls.enableDamping = true; | |
| controls.dampingFactor = 0.05; | |
| controls.maxDistance = 100; | |
| controls.minDistance = 5; | |
| // Keyboard controls | |
| document.addEventListener('keydown', (event) => { | |
| switch(event.code) { | |
| case 'Space': | |
| event.preventDefault(); | |
| switchCameraMode(); | |
| break; | |
| case 'KeyR': | |
| toggleRain(); | |
| break; | |
| } | |
| }); | |
| } | |
| // Setup animations | |
| function setupAnimation() { | |
| // Character walking animation | |
| walkingAnimation = { | |
| time: 0, | |
| speed: 0.5, | |
| path: { | |
| radius: 25, | |
| center: { x: 0, z: 0 } | |
| } | |
| }; | |
| // Camera cinematic movements | |
| setupCinematicCamera(); | |
| } | |
| // Setup cinematic camera | |
| function setupCinematicCamera() { | |
| const cameraPositions = [ | |
| { x: 30, y: 15, z: 30 }, // Following shot | |
| { x: 0, y: 50, z: 80 }, // Wide shot | |
| { x: -40, y: 10, z: 20 }, // Side tracking | |
| { x: 0, y: 5, z: 5 } // Close follow | |
| ]; | |
| cameraAnimation = { | |
| positions: cameraPositions, | |
| current: 0, | |
| transitionTime: 0 | |
| }; | |
| } | |
| // Switch camera mode | |
| function switchCameraMode() { | |
| currentCameraMode = (currentCameraMode + 1) % 4; | |
| const targetPos = cameraAnimation.positions[currentCameraMode]; | |
| new TWEEN.Tween(camera.position) | |
| .to(targetPos, 2000) | |
| .easing(TWEEN.Easing.Cubic.InOut) | |
| .start(); | |
| } | |
| // Toggle rain | |
| function toggleRain() { | |
| rainEnabled = !rainEnabled; | |
| rainSystem.visible = rainEnabled; | |
| const info = document.getElementById('info'); | |
| info.querySelector('p:nth-child(3)').textContent = | |
| `🌧️ Weather: ${rainEnabled ? 'Neon Rain' : 'Clear Night'}`; | |
| } | |
| // Hide loading screen | |
| function hideLoading() { | |
| document.getElementById('loading').style.display = 'none'; | |
| document.getElementById('info').style.display = 'block'; | |
| document.getElementById('controls').style.display = 'block'; | |
| } | |
| // Update character animation | |
| function updateCharacterAnimation(deltaTime) { | |
| if (!character) return; | |
| const { body, head, leftArm, rightArm, leftLeg, rightLeg } = character.userData; | |
| walkingAnimation.time += deltaTime * walkingAnimation.speed; | |
| // Move character in a path | |
| const angle = walkingAnimation.time * 0.5; | |
| const radius = walkingAnimation.path.radius; | |
| character.position.x = Math.cos(angle) * radius; | |
| character.position.z = Math.sin(angle) * radius; | |
| character.rotation.y = angle + Math.PI / 2; | |
| // Walking animation | |
| const walkCycle = walkingAnimation.time * 4; | |
| // Arms swinging | |
| leftArm.rotation.x = Math.sin(walkCycle) * 0.5; | |
| rightArm.rotation.x = Math.sin(walkCycle + Math.PI) * 0.5; | |
| // Legs walking | |
| leftLeg.rotation.x = Math.sin(walkCycle + Math.PI) * 0.3; | |
| rightLeg.rotation.x = Math.sin(walkCycle) * 0.3; | |
| // Body bobbing | |
| body.position.y = 2 + Math.sin(walkCycle * 2) * 0.1; | |
| head.position.y = 4.5 + Math.sin(walkCycle * 2) * 0.1; | |
| } | |
| // Update rain animation | |
| function updateRainAnimation() { | |
| if (!rainSystem.visible) return; | |
| const { geometry, velocities } = rainSystem.userData; | |
| const positions = geometry.attributes.position.array; | |
| for (let i = 0; i < positions.length; i += 3) { | |
| positions[i + 1] -= velocities[i / 3]; | |
| if (positions[i + 1] < 0) { | |
| positions[i + 1] = 200; | |
| positions[i] = (Math.random() - 0.5) * 400; | |
| positions[i + 2] = (Math.random() - 0.5) * 400; | |
| } | |
| } | |
| geometry.attributes.position.needsUpdate = true; | |
| } | |
| // Update camera to follow character | |
| function updateCameraFollow() { | |
| if (!character || currentCameraMode === 1) return; // Skip if wide shot | |
| const charPos = character.position; | |
| const offset = cameraAnimation.positions[currentCameraMode]; | |
| const targetPos = { | |
| x: charPos.x + offset.x, | |
| y: offset.y, | |
| z: charPos.z + offset.z | |
| }; | |
| // Smooth camera follow | |
| camera.position.lerp(new THREE.Vector3(targetPos.x, targetPos.y, targetPos.z), 0.02); | |
| if (currentCameraMode === 3) { // Close follow mode | |
| camera.lookAt(charPos.x, charPos.y + 3, charPos.z); | |
| } | |
| } | |
| // Update FPS counter | |
| function updateFPS() { | |
| frameCount++; | |
| const currentTime = performance.now(); | |
| if (currentTime - lastTime >= 1000) { | |
| const fps = Math.round((frameCount * 1000) / (currentTime - lastTime)); | |
| document.getElementById('fps').textContent = fps; | |
| frameCount = 0; | |
| lastTime = currentTime; | |
| } | |
| } | |
| // Main animation loop | |
| function animate() { | |
| requestAnimationFrame(animate); | |
| const deltaTime = clock.getDelta(); | |
| // Update animations | |
| updateCharacterAnimation(deltaTime); | |
| updateRainAnimation(); | |
| updateCameraFollow(); | |
| updateFPS(); | |
| // Update controls | |
| controls.update(); | |
| // Update tweens | |
| TWEEN.update(); | |
| // Render | |
| if (composer) { | |
| composer.render(); | |
| } else { | |
| renderer.render(scene, camera); | |
| } | |
| } | |
| // Handle window resize | |
| function onWindowResize() { | |
| camera.aspect = window.innerWidth / window.innerHeight; | |
| camera.updateProjectionMatrix(); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| if (composer) { | |
| composer.setSize(window.innerWidth, window.innerHeight); | |
| } | |
| } | |
| window.addEventListener('resize', onWindowResize); | |
| // Start the experience | |
| init(); | |
| </script> | |
| </body> | |
| </html> | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment