1import * as THREE from 'https://cdn.skypack.dev/[email protected]'; 2import { GLTFLoader } from 'https://cdn.skypack.dev/[email protected]/examples/jsm/loaders/GLTFLoader.js'; 3import lottieWeb from 'https://cdn.skypack.dev/lottie-web'; 4// import { RectAreaLightHelper } from 'https://cdn.skypack.dev/[email protected]/examples/jsm/helpers/RectAreaLightHelper.js'; 5 6let scene, renderer, camera; 7let loader, clock, secondsElapsed; 8let island, sittingDude, walkingDude, campfire, flower1, flower2, entry1, entry2, cloud, cloud2; 9let dudeMixer, fireMixer, walkingClip, idleClip, fireClip; 10 11const raycaster = new THREE.Raycaster(); 12const pointer = new THREE.Vector2(); 13 14var walkSpeed = 3; 15var walkDirection = 1; 16var isWalking = true; 17var hover1 = false; 18var hover2 = false; 19var selectedObject = ""; 20var clickedDownload = false; 21var initialCameraHeight = 5; 22var targetCameraHeight = 30; 23 24 25loadObjects(); 26 27function loadObjects(){ 28 var body = document.getElementById('body') 29 var progress = document.getElementById('progress'); 30 var title = document.getElementById('title'); 31 var subtitle = document.getElementById('subtitle'); 32 var animation = document.getElementById('animation'); 33 var qrcode = document.getElementById('qrcode'); 34 var wrapper = document.getElementById('wrapper'); 35 var install = document.getElementById('install') 36 var progressBar = document.createElement('div'); 37 var info = document.getElementById('info') 38 39 lottieWeb.loadAnimation({ 40 container: animation, // the dom element that will contain the animation 41 renderer: 'svg', 42 loop: true, 43 autoplay: true, 44 path: 'loading.json' // the path to the animation json 45 }); 46 47 title.addEventListener('click', function(){ 48 if(camera.position.y !== initialCameraHeight) { 49 camera.position.y = 5; 50 } 51 clickedDownload = false; 52 qrcode.classList.remove('play') 53 qrcode.style.opacity = '0'; 54 install.style.opacity = '1'; 55 56 }) 57 58 install.addEventListener('click', function(){ 59 //detect if on mobile 60 var onMobile = getComputedStyle(title).top == "140px" ? true : false; 61 if( onMobile ) { 62 window.open('https://testflight.apple.com/join/63hZF0lB', '_blank').focus(); 63 } else { 64 clickedDownload = true; 65 qrcode.classList.add('play') 66 qrcode.style.opacity = '1'; 67 install.style.opacity = '0'; 68 } 69 }) 70 71 progress.appendChild(progressBar); 72 73 document.body.appendChild(progress); 74 75 //Load scene 76 scene = new THREE.Scene(); 77 78 const manager = new THREE.LoadingManager(); 79 manager.onStart = function ( url, itemsLoaded, itemsTotal ) { 80 81 console.log( 'Started loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' ); 82 83 }; 84 85 manager.onLoad = function ( ) { 86 87 console.log( 'Loading complete!'); 88 89 lottieWeb.stop(); 90 animation.style.opacity = "0"; 91 progress.style.opacity = "0"; 92 title.style.opacity = "1"; 93 subtitle.style.opacity = "1"; 94 wrapper.style.opacity = "1"; 95 info.style.opacity = "1"; 96 init(); 97 98 }; 99 100 101 manager.onProgress = function ( url, itemsLoaded, itemsTotal ) { 102 103 console.log( 'Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' ); 104 progressBar.style.width = (itemsLoaded / itemsTotal * 100) + '%'; 105 106 }; 107 108 manager.onError = function ( url ) { 109 110 console.log( 'There was an error loading ' + url ); 111 112 }; 113 114 loader = new GLTFLoader( manager ); 115 loadIsland(); 116 loadSittingDude(); 117 loadWalkingDude(); 118 loadFlowers(); 119 loadCampfire(); 120 loadEntries(); 121 loadClouds(); 122} 123 124function init(){ 125 126 camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight); 127 128 camera.far = 200; 129 camera.updateProjectionMatrix(); 130 camera.position.set(0,initialCameraHeight,58); // y:5 z=55 131 132 clock = new THREE.Clock(); 133 134 renderer = new THREE.WebGLRenderer({powerPreference: "high-performance"}); 135 renderer.setSize( window.innerWidth, window.innerHeight ); 136 renderer.setClearColor(0x3084B3, 1); 137 renderer.setPixelRatio(1.5); 138 renderer.outputEncoding = THREE.sRGBEncoding; 139 document.body.appendChild( renderer.domElement ); 140 141 142 const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x080820, 0.7 ); 143 hemiLight.position.set( 0, 30, 0 ); 144 scene.add( hemiLight ); 145 146 const dirLight = new THREE.DirectionalLight( 0xffffff, 0.6 ); 147 dirLight.color.setHSL( 0.1, 1, 0.95 ); 148 dirLight.position.set( 1, 1.75, 1 ); 149 dirLight.position.multiplyScalar(30); 150 scene.add( dirLight ); 151 152 //Entry spotlight 153 const rectLight = new THREE.RectAreaLight( 0xffffff, 1.2, 5, 9 ); 154 rectLight.position.set( 10, 7, 43 ); 155 rectLight.lookAt( 12, 7, 40 ); 156 scene.add(rectLight); 157 158 // const rectLightHelper = new RectAreaLightHelper( rectLight ); 159 // rectLight.add( rectLightHelper ); 160 161 //Entry 2 spotlight 162 const rectLight2 = new THREE.RectAreaLight( 0xffffff, 1, 5, 9 ); 163 rectLight2.position.set( -13, 7, 38 ); 164 rectLight2.lookAt( -15, 7, 35 ); 165 scene.add(rectLight2); 166 167 window.addEventListener( 'resize', onWindowResize ); 168 document.addEventListener('mousemove', onMouseMove, false); 169 170 animate(); 171} 172 173function loadIsland() { 174 loader.load('assets/island/island.gltf', function (gltf) { 175 island = gltf.scene; 176 island.position.set(0,0,0) 177 island.matrixAutoUpdate = false;
178 scene.add(island); 179 180 }, undefined, function ( error ) { 181 console.log('error loading island') 182 console.error( error ); 183 }); 184} 185 186function loadSittingDude(){ 187 loader.load('assets/dude/dude.gltf', function (gltf) { 188 sittingDude = gltf.scene 189 sittingDude.children[0].children[12].children[0].material.color.set( 0x52AAD1 ); 190 sittingDude.position.set(0,0,5); 191 192 scene.add(sittingDude); 193 }, undefined, function ( error ) { 194 console.log('error loading dude') 195 console.error( error ); 196 }); 197} 198 199function loadWalkingDude(){ 200 201 loader.load('assets/dude_walk/Dude_test.gltf', function (gltf) { 202 walkingDude = gltf.scene; 203 walkingDude.position.z = -5; 204 walkingDude.position.x = -20; 205 dudeMixer = new THREE.AnimationMixer(walkingDude); 206 dudeMixer.addEventListener( 'loop', loopedAnimation ); // properties of e: type, action, loopDelta 207 idleClip = gltf.animations[0] 208 walkingClip = gltf.animations[1] 209 dudeMixer.clipAction( walkingClip ).play(); 210 scene.add(walkingDude); 211 }, undefined, function ( error ) { 212 console.log('hi') 213 console.error( error ); 214 }); 215} 216 217function loadFlowers() { 218 loader.load('assets/flower/flower.gltf', function (gltf) { 219 flower1 = gltf.scene 220 flower1.position.set(-15,0,35); 221 flower1.rotation.y = Math.PI / 2; 222 scene.add(flower1); 223 }, undefined, function ( error ) { 224 console.log('error loading flower 1') 225 console.error( error ); 226 }); 227 228 loader.load('assets/flower/flower.gltf', function (gltf) { 229 flower2 = gltf.scene 230 flower2.position.set(12,0,40); 231 flower2.rotation.y = 11 * Math.PI / 6; 232 scene.add(flower2); 233 }, undefined, function ( error ) { 234 console.log('error loading flower 2') 235 console.error( error ); 236 }); 237} 238 239function loadCampfire(){ 240 loader.load('assets/campfire/scene.gltf', function (gltf) { 241 campfire = gltf.scene 242 campfire.scale.set(3,3,3); 243 campfire.position.set(2.5,0,32); 244 245 fireMixer = new THREE.AnimationMixer(campfire); 246 fireClip = gltf.animations[0] 247 fireMixer.clipAction( fireClip ).play(); 248 249 scene.add(campfire); 250 }, undefined, function ( error ) { 251 console.log('error loading campfire') 252 console.error( error ); 253 }); 254} 255 256 257function loadEntries(){ 258 loader.load('assets/entries/entry.gltf', function (gltf) { 259 entry1 = gltf.scene 260 entry1.position.set(12,4.8,40); 261 entry1.rotation.y = 5 * Math.PI / 4; 262 scene.add(entry1); 263 }, undefined, function ( error ) { 264 console.log('error loading entry 1') 265 console.error( error ); 266 }); 267 loader.load('assets/entries/entry2.gltf', function (gltf) { 268 entry2 = gltf.scene 269 entry2.position.set(-15,4.8,35); 270 entry2.rotation.y = 5 * Math.PI / 4; 271 scene.add(entry2); 272 }, undefined, function ( error ) { 273 console.log('error loading entry 2') 274 console.error( error ); 275 }); 276} 277 278 279function loadClouds(){ 280 loader.load('assets/cloud/scene.gltf', function (gltf) { 281 cloud = gltf.scene; 282 cloud.scale.set(5,5,5); 283 cloud.position.set(25,35,0); 284 285 cloud2 = cloud.clone(); 286 cloud2.position.set(-25,30,0); 287 288 scene.add(cloud); 289 scene.add(cloud2) 290 }, undefined, function ( error ) { 291 console.log('error loading cloud') 292 console.error( error ); 293 }); 294} 295 296function onMouseMove( event ) { 297 298 pointer.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1; 299 pointer.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1; 300 raycaster.setFromCamera( pointer, camera ); 301 302 // See if the ray from the camera into the world hits one of our meshes 303 const mesh = [entry1, entry2] 304 305 const intersects = raycaster.intersectObjects( mesh, true ); 306 307 if ( intersects.length > 0) { 308 var object = intersects[0].object.name; 309 if (selectedObject == object) return; 310 selectedObject = object; 311 if(object == "Entry1") { 312 entry1.scale.set(2,2,2); 313 entry1.position.set(12,7.5,40); 314 hover1 = true; 315 } else { 316 entry2.scale.set(2,2,2); 317 entry2.position.set(-15,7.5,35); 318 hover2 = true; 319 } 320 } else if(selectedObject.length > 0){ 321 if(selectedObject == "Entry1") { 322 entry1.scale.set(1,1,1); 323 entry1.position.set(12,4.8,40); 324 hover1 = false;
325 } else { 326 entry2.scale.set(1,1,1); 327 entry2.position.set(-15,4.8,35); 328 hover2 = false; 329 } 330 selectedObject = ""; 331 } 332 333} 334 335 336function onWindowResize() { 337 338 camera.aspect = window.innerWidth / window.innerHeight; 339 camera.updateProjectionMatrix(); 340 341 renderer.setSize( window.innerWidth, window.innerHeight ); 342 343} 344 345 346 347function animate() { 348 requestAnimationFrame( animate ); 349 350 // if(camera.position.y > targetCameraHeight){ 351 // camera.position.y -= 0.1; 352 // } 353 354 if(clickedDownload){ 355 if(camera.position.y < targetCameraHeight){ 356 camera.position.y += 0.15; 357 } 358 } 359 360 var delta = clock.getDelta(); 361 secondsElapsed = clock.getElapsedTime(); 362 363 moveObjects(delta); 364 365 renderer.render( scene, camera ); 366} 367 368function moveObjects(delta){ 369 370 // Basic movement 371 cloud.position.x += 0.005; 372 cloud2.position.x -= 0.007; 373 374 entry1.rotation.y += hover1 ? 0.005 : 0.012; 375 entry1.position.y += Math.sin(secondsElapsed)/200 376 entry2.rotation.y += hover2 ? 0.005 : 0.012; 377 entry2.position.y += Math.sin(secondsElapsed)/200 378 379 // Update animation frames 380 dudeMixer.update(delta) ; 381 fireMixer.update(delta); 382 383 // Blend animation frames for walking and idle 384 if(isWalking){ 385 if(walkingDude.position.z < 20 && walkingDude.position.z > -5){ 386 walkingDude.position.z += (delta)*(walkDirection)*(walkSpeed); 387 } else { 388 walkDirection *= -1; 389 walkingDude.position.z += (delta)*(walkDirection)*(walkSpeed)*(2); 390 walkingDude.rotation.y = walkDirection == -1 ? Math.PI : 0; 391 } 392 } 393} 394 395function loopedAnimation(e){ 396 var roundedSeconds = Math.round(secondsElapsed) 397 if(roundedSeconds % 12 == 0){ 398 dudeMixer.clipAction( walkingClip ).fadeOut(0.5) 399 400 dudeMixer.clipAction( idleClip ) 401 .reset() 402 .setEffectiveTimeScale( 1 ) 403 .setEffectiveWeight( 1 ) 404 .fadeIn( 0.5 ) 405 .play(); 406 407 isWalking = false; 408 } else if (roundedSeconds % 5 == 0){ 409 dudeMixer.clipAction( idleClip ).fadeOut(0.2) 410 411 dudeMixer.clipAction( walkingClip ) 412 .reset() 413 .setEffectiveTimeScale( 1 ) 414 .setEffectiveWeight( 1 ) 415 .fadeIn( 0.5 ) 416 .play(); 417 418 isWalking = true; 419 } 420}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.