@@ -3,13 +3,21 @@ import * 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 => {
@@ -72,9 +79,7 @@ export function main(canvas) {
7279 return [ 0 , 1 , 2 ] . map ( i => {
7380 const geo = new THREE . SphereGeometry ( d . radius , 36 , 36 ) ;
7481 const mat = new THREE . MeshStandardMaterial ( {
75- color : d . color ,
76- emissive : d . emissive ,
77- emissiveIntensity : 1.0 ,
82+ map : loader . load ( d . texture ) ,
7883 roughness : 0.65 ,
7984 metalness : 0.05
8085 } ) ;
@@ -122,11 +127,23 @@ export function main(canvas) {
122127 const raycaster = new THREE . Raycaster ( ) ;
123128 const pointer = new THREE . Vector2 ( ) ;
124129
125- let paused = false ; // are planets frozen?
126- let focusedPlanet = null ; // the planet object we zoomed into
127- let cameraTarget = null ; // THREE.Vector3 we're tweening toward
128- let lookAtTarget = null ; // THREE.Vector3 we're looking at
130+ let paused = false ;
131+ let focusedPlanet = null ;
132+ let cameraTarget = null ;
133+ let lookAtTarget = null ;
129134 let tweening = false ;
135+ let popupFired = false ;
136+
137+ // Zoom out — resets focus and starts the camera tween back to the initial position.
138+ // Called both by canvas clicks on empty space and externally (e.g. the ✕ button).
139+ function zoomOut ( ) {
140+ console . log ( "Hi" ) ;
141+ focusedPlanet = null ;
142+ paused = false ;
143+ tweening = true ;
144+ cameraTarget = initPos . clone ( ) ;
145+ lookAtTarget = new THREE . Vector3 ( 0 , 0 , 0 ) ;
146+ }
130147
131148 canvas . addEventListener ( 'click' , e => {
132149 const rect = canvas . getBoundingClientRect ( ) ;
@@ -138,20 +155,16 @@ export function main(canvas) {
138155 const hits = raycaster . intersectObjects ( meshes ) ;
139156
140157 if ( hits . length > 0 ) {
141- // Clicked a planet — focus it
142158 const hit = hits [ 0 ] ;
143159 focusedPlanet = planets . find ( p => p . mesh === hit . object ) ;
144- paused = true ;
145- tweening = true ;
160+ paused = true ;
161+ tweening = true ;
162+ popupFired = false ;
146163 } else {
147- // Clicked empty space — release
148- focusedPlanet = null ;
149- paused = false ;
150- tweening = true ;
151- cameraTarget = initPos . clone ( ) ;
152- lookAtTarget = new THREE . Vector3 ( 0 , 0 , 0 ) ;
164+ zoomOut ( ) ;
153165 }
154166 } ) ;
167+
155168 // ─────────────────────────────────────────────────────────────────────
156169
157170 function resizeRendererToDisplaySize ( renderer ) {
@@ -166,7 +179,6 @@ export function main(canvas) {
166179
167180 function render ( ) {
168181
169- // Advance planet orbits (only when not paused)
170182 planets . forEach ( p => {
171183 if ( ! paused ) {
172184 p . angle += p . speed * 0.008 ;
@@ -181,47 +193,30 @@ export function main(canvas) {
181193
182194 sun . rotation . y += 0.003 ;
183195
184-
185-
186-
187-
188-
189-
190- // Update the camera target each frame while focused
191- // (so the camera tracks the planet even mid-tween if it still moves slightly)
192196 if ( focusedPlanet ) {
193197 const pPos = focusedPlanet . mesh . position ;
194- // Position the camera slightly behind & above the planet relative to the origin
195198 const dir = pPos . clone ( ) . normalize ( ) ;
196199 cameraTarget = pPos . clone ( ) . add ( dir . multiplyScalar ( focusedPlanet . radius + ZOOM_DIST ) ) ;
197200 cameraTarget . y += focusedPlanet . radius * 0.8 ;
198201 lookAtTarget = pPos . clone ( ) ;
199202 }
200203
201- // Tween camera
202204 if ( tweening && cameraTarget && lookAtTarget ) {
203205 camera . position . lerp ( cameraTarget , TWEEN_SPEED ) ;
204206 currentLookAt . lerp ( lookAtTarget , TWEEN_SPEED ) ;
205207 camera . lookAt ( currentLookAt ) ;
206208
207- // Stop tweening once close enough
208209 if ( camera . position . distanceTo ( cameraTarget ) < 0.05 ) {
209210 tweening = false ;
210211
211-
212-
213-
214-
215- // POP UP HERE
216-
217-
218-
219-
220-
221-
212+ if ( focusedPlanet && ! popupFired ) {
213+ popupFired = true ;
214+ if ( typeof onPlanetFocus === 'function' ) {
215+ onPlanetFocus ( ) ;
216+ }
217+ }
222218 }
223219 } else if ( ! paused ) {
224- // Normal parallax behaviour
225220 currentOffset . x += ( targetOffset . x - currentOffset . x ) * 0.13 ;
226221 currentOffset . y += ( targetOffset . y - currentOffset . y ) * 0.13 ;
227222
@@ -234,11 +229,6 @@ export function main(canvas) {
234229 camera . lookAt ( currentLookAt ) ;
235230 }
236231
237-
238-
239-
240-
241-
242232 if ( resizeRendererToDisplaySize ( renderer ) ) {
243233 camera . aspect = canvas . clientWidth / canvas . clientHeight ;
244234 camera . updateProjectionMatrix ( ) ;
@@ -249,4 +239,6 @@ export function main(canvas) {
249239 }
250240
251241 requestAnimationFrame ( render ) ;
242+
243+ return { zoomOut } ;
252244}
0 commit comments