@@ -3,13 +3,21 @@ timport * as THREE from "three";
33const ZOOM_DIST = 5 ; // how close the camera gets (in planet radii + offset)
44const TWEEN_SPEED = 0.07 ; // lerp factor for camera movement
55
6- export function main ( canvas ) {
7-
6+ export function main ( canvas , onPlanetFocus ) {
7+ const loader = new THREE . TextureLoader ( ) ;
88 const renderer = new THREE . WebGLRenderer ( { antialias : true , canvas } ) ;
99 renderer . setPixelRatio ( window . devicePixelRatio ) ;
1010 renderer . toneMapping = THREE . ACESFilmicToneMapping ;
1111 renderer . toneMappingExposure = 2.0 ;
1212
13+ const createRepeatingTexture = ( path , repeatX = 2 , repeatY = 1 ) => {
14+ const tex = loader . load ( path ) ;
15+ tex . wrapS = THREE . RepeatWrapping ;
16+ tex . wrapT = THREE . RepeatWrapping ;
17+ tex . repeat . set ( repeatX , repeatY ) ;
18+ return tex ;
19+ } ;
20+
1321 const fov = 45 ;
1422 const aspect = canvas . clientWidth / canvas . clientHeight ;
1523 const near = 0.1 ;
@@ -37,20 +45,19 @@ export function main(canvas) {
3745 // Sun
3846 const sunGeo = new THREE . SphereGeometry ( 4.5 , 64 , 64 ) ;
3947 const sunMat = new THREE . MeshStandardMaterial ( {
40- color : 0xe8ffff ,
41- emissive : 0x88ffee ,
42- emissiveIntensity : 3.2 ,
43- roughness : 0.0 ,
44- metalness : 0.0
48+ map : createRepeatingTexture ( '/textures/glorptest.png' , 3 , 3 ) ,
49+ emissiveMap : loader . load ( '/textures/suntexture.webp' ) , // same tex drives the glow
50+ emissive : 0x91ffaf ,
51+ emissiveIntensity : 0.1 ,
4552 } ) ;
4653 const sun = new THREE . Mesh ( sunGeo , sunMat ) ;
4754 scene . add ( sun ) ;
4855
4956 // Planets
5057 const planetData = [
51- { radius : 1.1 , orbitR : 14 , speed : 0.8 , tilt : 0.2 , color : 0xff6644 , emissive : 0x441100 } ,
52- { radius : 1.5 , orbitR : 24 , speed : 0.45 , tilt : 0.35 , color : 0x44aaff , emissive : 0x001133 } ,
53- { radius : 1.2 , orbitR : 36 , speed : 0.25 , tilt : 0.15 , color : 0x88dd55 , emissive : 0x112200 } ,
58+ { radius : 1.1 , orbitR : 14 , speed : 0.8 , tilt : 0.2 , color : 0xff6644 , emissive : 0x441100 , texture : '/textures/texture1.webp' } ,
59+ { radius : 1.5 , orbitR : 24 , speed : 0.45 , tilt : 0.35 , color : 0x44aaff , emissive : 0x001133 , texture : '/textures/texture2.webp' } ,
60+ { radius : 1.2 , orbitR : 36 , speed : 0.25 , tilt : 0.15 , color : 0x88dd55 , emissive : 0x112200 , texture : '/textures/texture3.webp' } ,
5461 ] ;
5562
5663 const planets = planetData . flatMap ( d => {
@@ -74,9 +81,7 @@ export function main(canvas) {
7481 return [ 0 , 1 , 2 ] . map ( i => {
7582 const geo = new THREE . SphereGeometry ( d . radius , 36 , 36 ) ;
7683 const mat = new THREE . MeshStandardMaterial ( {
77- color : d . color ,
78- emissive : d . emissive ,
79- emissiveIntensity : 1.0 ,
84+ map : loader . load ( d . texture ) ,
8085 roughness : 0.65 ,
8186 metalness : 0.05
8287 } ) ;
@@ -128,11 +133,23 @@ export function main(canvas) {
128133 const raycaster = new THREE . Raycaster ( ) ;
129134 const pointer = new THREE . Vector2 ( ) ;
130135
131- let paused = false ; // are planets frozen?
132- let focusedPlanet = null ; // the planet object we zoomed into
133- let cameraTarget = null ; // THREE.Vector3 we're tweening toward
134- let lookAtTarget = null ; // THREE.Vector3 we're looking at
136+ let paused = false ;
137+ let focusedPlanet = null ;
138+ let cameraTarget = null ;
139+ let lookAtTarget = null ;
135140 let tweening = false ;
141+ let popupFired = false ;
142+
143+ // Zoom out — resets focus and starts the camera tween back to the initial position.
144+ // Called both by canvas clicks on empty space and externally (e.g. the ✕ button).
145+ function zoomOut ( ) {
146+ console . log ( "Hi" ) ;
147+ focusedPlanet = null ;
148+ paused = false ;
149+ tweening = true ;
150+ cameraTarget = initPos . clone ( ) ;
151+ lookAtTarget = new THREE . Vector3 ( 0 , 0 , 0 ) ;
152+ }
136153
137154 canvas . addEventListener ( 'click' , e => {
138155 const rect = canvas . getBoundingClientRect ( ) ;
@@ -144,20 +161,16 @@ export function main(canvas) {
144161 const hits = raycaster . intersectObjects ( meshes ) ;
145162
146163 if ( hits . length > 0 ) {
147- // Clicked a planet — focus it
148164 const hit = hits [ 0 ] ;
149165 focusedPlanet = planets . find ( p => p . mesh === hit . object ) ;
150- paused = true ;
151- tweening = true ;
166+ paused = true ;
167+ tweening = true ;
168+ popupFired = false ;
152169 } else {
153- // Clicked empty space — release
154- focusedPlanet = null ;
155- paused = false ;
156- tweening = true ;
157- cameraTarget = initPos . clone ( ) ;
158- lookAtTarget = new THREE . Vector3 ( 0 , 0 , 0 ) ;
170+ zoomOut ( ) ;
159171 }
160172 } ) ;
173+
161174 // ─────────────────────────────────────────────────────────────────────
162175
163176 function resizeRendererToDisplaySize ( renderer ) {
@@ -172,7 +185,6 @@ export function main(canvas) {
172185
173186 function render ( ) {
174187
175- // Advance planet orbits (only when not paused)
176188 planets . forEach ( p => {
177189 if ( ! paused ) {
178190 p . angle += p . speed * 0.008 ;
@@ -187,47 +199,30 @@ export function main(canvas) {
187199
188200 sun . rotation . y += 0.003 ;
189201
190-
191-
192-
193-
194-
195-
196- // Update the camera target each frame while focused
197- // (so the camera tracks the planet even mid-tween if it still moves slightly)
198202 if ( focusedPlanet ) {
199203 const pPos = focusedPlanet . mesh . position ;
200- // Position the camera slightly behind & above the planet relative to the origin
201204 const dir = pPos . clone ( ) . normalize ( ) ;
202205 cameraTarget = pPos . clone ( ) . add ( dir . multiplyScalar ( focusedPlanet . radius + ZOOM_DIST ) ) ;
203206 cameraTarget . y += focusedPlanet . radius * 0.8 ;
204207 lookAtTarget = pPos . clone ( ) ;
205208 }
206209
207- // Tween camera
208210 if ( tweening && cameraTarget && lookAtTarget ) {
209211 camera . position . lerp ( cameraTarget , TWEEN_SPEED ) ;
210212 currentLookAt . lerp ( lookAtTarget , TWEEN_SPEED ) ;
211213 camera . lookAt ( currentLookAt ) ;
212214
213- // Stop tweening once close enough
214215 if ( camera . position . distanceTo ( cameraTarget ) < 0.05 ) {
215216 tweening = false ;
216217
217-
218-
219-
220-
221- // POP UP HERE
222-
223-
224-
225-
226-
227-
218+ if ( focusedPlanet && ! popupFired ) {
219+ popupFired = true ;
220+ if ( typeof onPlanetFocus === 'function' ) {
221+ onPlanetFocus ( ) ;
222+ }
223+ }
228224 }
229225 } else if ( ! paused ) {
230- // Normal parallax behaviour
231226 currentOffset . x += ( targetOffset . x - currentOffset . x ) * 0.13 ;
232227 currentOffset . y += ( targetOffset . y - currentOffset . y ) * 0.13 ;
233228
@@ -240,11 +235,6 @@ export function main(canvas) {
240235 camera . lookAt ( currentLookAt ) ;
241236 }
242237
243-
244-
245-
246-
247-
248238 if ( resizeRendererToDisplaySize ( renderer ) ) {
249239 camera . aspect = canvas . clientWidth / canvas . clientHeight ;
250240 camera . updateProjectionMatrix ( ) ;
@@ -255,4 +245,6 @@ export function main(canvas) {
255245 }
256246
257247 requestAnimationFrame ( render ) ;
248+
249+ return { zoomOut } ;
258250}
0 commit comments