[READ-ONLY] Mirror of https://github.com/flo-bit/flo-bit.github.io. my personal website, w/ astro, svelte, tailwind, typescript, threlte flo-bit.dev/
portfolio portfolio-website svelte sveltekit tailwind threejs threlte typescript
0

Configure Feed

Select the types of activity you want to include in your feed.

flo-bit.github.io / src / lib / 3D / Scene.svelte
3.8 kB 155 lines
1<script lang="ts"> 2 import { T, useTask, useThrelte } from '@threlte/core'; 3 import { interactivity, useCursor } from '@threlte/extras'; 4 import { Quaternion, Euler, Vector2, Group } from 'three'; 5 import { onMount } from 'svelte'; 6 import { spring } from './Utils'; 7 8 import Stars from './Stars.svelte'; 9 import Nebula from './Nebula.svelte'; 10 import PlanetModel from './PlanetModel.svelte'; 11 12 const { onPointerEnter, onPointerLeave } = useCursor(); 13 interactivity(); 14 15 let size = 2; 16 let sizeSpring = spring<number>(size, 0.1, 0.5); 17 18 let distance = 1; 19 const maxSpeed = 0.05; 20 const acceleration = 0.001; 21 const damping = 0.98; 22 23 let isDragging = false; 24 let previousPointerPosition = new Vector2(); 25 let velocity = new Vector2(); 26 27 let quaternion = new Quaternion(); 28 let planet: Group; 29 30 useTask((delta) => { 31 size = sizeSpring.update(delta); 32 33 velocity.multiplyScalar(damping); 34 35 let rotate = isDragging ? 0.0 : 0.001; 36 37 const deltaRotationQuaternion = new Quaternion().setFromEuler( 38 new Euler(velocity.y * delta * 120, (velocity.x + rotate) * delta * 120, 0, 'XYZ') 39 ); 40 quaternion.multiplyQuaternions(deltaRotationQuaternion, quaternion); 41 42 if (planet) { 43 planet.quaternion.copy(quaternion); 44 planet.position.set(pos * 4 - 2, 0.5, -distance); 45 } 46 }); 47 48 const onPointerMove = (event: PointerEvent | TouchEvent) => { 49 if (!isDragging) return; 50 event.preventDefault(); 51 52 let clientX, clientY; 53 if (event instanceof TouchEvent) { 54 clientX = event.touches[0].clientX; 55 clientY = event.touches[0].clientY; 56 } else { 57 clientX = event.clientX; 58 clientY = event.clientY; 59 } 60 61 const deltaMove = new Vector2( 62 clientX - previousPointerPosition.x, 63 clientY - previousPointerPosition.y 64 ); 65 66 velocity.x += deltaMove.x * acceleration; 67 velocity.y += deltaMove.y * acceleration; 68 69 // Limit the speed 70 if (velocity.length() > maxSpeed) { 71 velocity.normalize().multiplyScalar(maxSpeed); 72 } 73 74 previousPointerPosition.set(clientX, clientY); 75 }; 76 77 const onPointerDown = (event: PointerEvent | TouchEvent) => { 78 isDragging = true; 79 let clientX, clientY; 80 if (event instanceof TouchEvent) { 81 clientX = event.touches[0].clientX; 82 clientY = event.touches[0].clientY; 83 } else { 84 clientX = event.clientX; 85 clientY = event.clientY; 86 } 87 previousPointerPosition.set(clientX, clientY); 88 89 if (event instanceof TouchEvent) { 90 event.preventDefault(); // Prevent scrolling 91 } 92 }; 93 94 const onPointerUp = () => { 95 isDragging = false; 96 }; 97 98 const { renderer } = useThrelte(); 99 100 onMount(() => { 101 const canvas = renderer.domElement; 102 103 canvas.addEventListener('pointermove', onPointerMove, {passive: false}); 104 canvas.addEventListener('pointerup', onPointerUp, false); 105 canvas.addEventListener('touchmove', onPointerMove, {passive: false}); 106 canvas.addEventListener('touchend', onPointerUp, false); 107 108 return () => { 109 canvas.removeEventListener('pointermove', onPointerMove, false); 110 canvas.removeEventListener('pointerup', onPointerUp, false); 111 canvas.removeEventListener('touchmove', onPointerMove, false); 112 canvas.removeEventListener('touchend', onPointerUp, false); 113 }; 114 }); 115 116 export let pos = 0; 117</script> 118 119<T.PerspectiveCamera 120 makeDefault 121 position={[0, 0, 5]} 122 on:create={({ ref }) => { 123 ref.lookAt(0, 1, 0); 124 }} 125 far={100} 126/> 127 128<T.DirectionalLight intensity={3} position={[-pos * 10 + 5, 2 + pos * 3, 2]} /> 129 130<T.Group 131 bind:ref={planet} 132 on:pointerdown={(evt) => { 133 onPointerDown(evt.nativeEvent); 134 }} 135 on:pointerleave={() => { 136 sizeSpring.set(2); 137 onPointerLeave(); 138 }} 139 on:pointerenter={() => { 140 sizeSpring.set(2.1); 141 onPointerEnter(); 142 }} 143 on:touchstart={(evt) => { 144 onPointerDown(evt.nativeEvent); 145 }} 146 on:touchend={() => { 147 onPointerUp(); 148 }} 149 scale={size} 150> 151 <PlanetModel /> 152</T.Group> 153 154<Stars /> 155<Nebula />