1- import { useState , useEffect } from 'react' ;
2- import { PlanetScene } from './planet-scene' ;
3- import { PlanetControls } from './planet-controls' ;
4- import { PlanetImportExport } from './planet-import-export' ;
5- import { calculatePlanetStats } from '@/utils/planet-physics' ;
6- import { useSession , useSupabaseClient } from '@supabase/auth-helpers-react' ;
7- import type { PlanetStats } from '@/utils/planet-physics' ;
1+ "use client"
82
9- const TERRESTRIAL_THRESHOLD = 7.5 ; // Earth masses
10- const GASEOUS_THRESHOLD = 2.0 ; // Earth radii
3+ import { useState , useEffect } from "react"
4+ import { Canvas } from "@react-three/fiber"
5+ import { OrbitControls , Stars , Environment } from "@react-three/drei"
6+ import { PlanetShader } from "./PlanetShader"
7+ import { SettingsPanel } from "./SettingsPanel" ;
8+ import { Cog } from "lucide-react"
9+ import { Button } from "@/components/ui/button"
10+ import { type PlanetStats , calculateDensity , defaultPlanetStats } from "@/lib/planet-physics"
1111
1212export interface PlanetGeneratorProps {
13- classificationConfig ?: any ;
14- content ?: string ;
15- classificationId : string ;
16- author : string ;
17- type ?: string ;
18- biome ?: string ;
19- } ;
20-
21- export default function PlanetGenerator ( { classificationConfig, author, classificationId } : PlanetGeneratorProps ) {
22- const supabase = useSupabaseClient ( ) ;
23- const session = useSession ( ) ;
24-
25- const initialMass = classificationConfig ?. exportedValue ?. mass ?? 1 ;
26- const initialRadius = classificationConfig ?. exportedValue ?. radius ?? 1 ;
27-
28- const [ mass , setMass ] = useState ( initialMass ) ;
29- const [ radius , setRadius ] = useState ( initialRadius ) ;
30- const [ typeOverride , setTypeOverride ] = useState < 'terrestrial' | 'gaseous' | null > ( null ) ;
31-
32- const stats = calculatePlanetStats ( mass , radius , undefined , undefined , typeOverride ) ;
33-
34- const handleMassChange = ( newMass : number ) => {
35- if ( typeOverride === 'terrestrial' && newMass > TERRESTRIAL_THRESHOLD ) {
36- setMass ( TERRESTRIAL_THRESHOLD ) ;
37- } else if ( typeOverride === 'gaseous' && newMass <= TERRESTRIAL_THRESHOLD ) {
38- setMass ( TERRESTRIAL_THRESHOLD + 0.1 ) ;
39- } else {
40- setMass ( newMass ) ;
41- }
42- } ;
43-
44- const handleRadiusChange = ( newRadius : number ) => {
45- if ( typeOverride === 'terrestrial' && newRadius > GASEOUS_THRESHOLD ) {
46- setRadius ( GASEOUS_THRESHOLD ) ;
47- } else if ( typeOverride === 'gaseous' && newRadius <= GASEOUS_THRESHOLD ) {
48- setRadius ( GASEOUS_THRESHOLD + 0.1 ) ;
49- } else {
50- setRadius ( newRadius ) ;
51- }
52- } ;
53-
54- const handleTypeOverride = ( type : 'terrestrial' | 'gaseous' | null ) => {
55- setTypeOverride ( type ) ;
56- if ( type === 'terrestrial' ) {
57- if ( mass > TERRESTRIAL_THRESHOLD ) setMass ( TERRESTRIAL_THRESHOLD ) ;
58- if ( radius > GASEOUS_THRESHOLD ) setRadius ( GASEOUS_THRESHOLD ) ;
59- } else if ( type === 'gaseous' ) {
60- if ( mass <= TERRESTRIAL_THRESHOLD ) setMass ( TERRESTRIAL_THRESHOLD + 0.1 ) ;
61- if ( radius <= GASEOUS_THRESHOLD ) setRadius ( GASEOUS_THRESHOLD + 0.1 ) ;
62- } ;
63- } ;
64-
65- const handleImport = ( importedStats : Partial < PlanetStats > ) => {
66- if ( importedStats . mass !== undefined ) {
67- setMass ( importedStats . mass ) ;
68- } ;
69- if ( importedStats . radius !== undefined ) {
70- setRadius ( importedStats . radius ) ;
71- } ;
72-
73- setTypeOverride ( null ) ;
74- } ;
75-
76- const handleSave = async ( ) => {
77- if ( ! classificationId ) {
78- console . error ( 'Classification ID is missing.' ) ;
79- return ;
80- } ;
81-
82- const idToQuery = typeof classificationId === 'string' ? classificationId : String ( classificationId ) ;
83-
84- try {
85- const { data, error } = await supabase
86- . from ( 'classifications' )
87- . select ( 'classificationConfiguration' )
88- . eq ( 'id' , idToQuery )
89- . single ( ) ;
90-
91- if ( error ) throw error ;
92-
93- const currentConfig = data ?. classificationConfiguration || { } ;
94- const newConfig = {
95- ...currentConfig ,
96- exportedValue : { mass, radius } ,
97- } ;
98-
99- const { error : updateError } = await supabase
100- . from ( 'classifications' )
101- . update ( { classificationConfiguration : newConfig } )
102- . eq ( 'id' , idToQuery ) ;
103-
104- if ( updateError ) throw updateError ;
105-
106- alert ( 'Planet configuration saved successfully!' ) ;
107- } catch ( err ) {
108- console . error ( 'Error saving planet configuration:' , err ) ;
109- alert ( 'Failed to save planet configuration.' ) ;
110- } ;
111- } ;
13+ classificationId ?: string ;
14+ author ?: string ;
15+ classificationConfig ?: JSON ;
16+ } ;
17+
18+ export function PlanetGenerator ( ) {
19+ const [ showSettings , setShowSettings ] = useState ( false )
20+ const [ planetStats , setPlanetStats ] = useState < PlanetStats > ( defaultPlanetStats )
21+
22+ // Update density when mass or radius changes
23+ useEffect ( ( ) => {
24+ setPlanetStats ( ( prev ) => ( {
25+ ...prev ,
26+ density : calculateDensity ( prev . mass , prev . radius ) ,
27+ } ) )
28+ } , [ planetStats . mass , planetStats . radius ] )
11229
11330 return (
114- < div className = "bg-black p-6" >
115- < div className = "max-w-5xl mx-auto" >
116- < h1 className = "text-3xl font-bold text-white mb-6" > Procedural Planet Generator</ h1 >
117- < div className = "flex flex-row gap-6 items-start" >
118- < PlanetScene stats = { stats } />
119- < div className = "flex flex-col gap-4 w-full" >
120- < PlanetControls
121- stats = { stats }
122- onMassChange = { handleMassChange }
123- onRadiusChange = { handleRadiusChange }
124- onTypeOverride = { handleTypeOverride }
125- />
126- < PlanetImportExport stats = { stats } onImport = { handleImport } onSave = { handleSave } />
127- </ div >
128- </ div >
129- </ div >
31+ < div className = "w-full h-screen relative" >
32+ < Canvas camera = { { position : [ 0 , 0 , 10 ] , fov : 45 } } >
33+ { /* <color attach="background" args={["#020209"]} /> */ }
34+ < ambientLight intensity = { 0.4 } />
35+ < pointLight position = { [ 10 , 10 , 10 ] } intensity = { 2 } />
36+ < pointLight position = { [ - 10 , - 10 , - 10 ] } intensity = { 0.5 } color = "#b0c4de" />
37+ < directionalLight position = { [ 5 , 5 , 5 ] } intensity = { 1.5 } castShadow />
38+ < Environment preset = "sunset" />
39+ < PlanetShader planetStats = { planetStats } />
40+ < Stars radius = { 100 } depth = { 50 } count = { 5000 } factor = { 4 } saturation = { 0 } fade speed = { 1 } />
41+ < OrbitControls enableZoom = { true } enablePan = { true } enableRotate = { true } />
42+ < mesh position = { [ 0 , 0 , - 15 ] } >
43+ < sphereGeometry args = { [ 5 , 32 , 32 ] } />
44+ < meshBasicMaterial color = "#4060ff" transparent opacity = { 0.03 } />
45+ </ mesh >
46+ </ Canvas >
47+
48+ < Button
49+ variant = "outline"
50+ size = "icon"
51+ className = "absolute top-4 right-4 bg-black/50 hover:bg-black/70 text-white"
52+ onClick = { ( ) => setShowSettings ( ! showSettings ) }
53+ >
54+ < Cog className = "h-4 w-4" />
55+ </ Button >
56+
57+ { showSettings && < SettingsPanel planetStats = { planetStats } setPlanetStats = { setPlanetStats } /> }
13058 </ div >
131- ) ;
132- } ;
59+ )
60+ }
0 commit comments