Initial Commit

Commit pertama, memindahkan repository dari github ke gitea.
This commit is contained in:
dicky arya pratama committed 2026-11-04 17:18:53 +07:00
commit 13a47fbebf
41 files changed
+12327

No files matched your search

+385
View File
@@ -0,0 +1,385 @@
"use client";
import React, { useRef, useMemo, useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import * as THREE from "three";
// 1. Central Star (Helios / Core Sun) with radiant corona
function CentralStar() {
const sunRef = useRef<THREE.Mesh>(null!);
const coronaRef = useRef<THREE.Mesh>(null!);
const flareRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
const t = state.clock.getElapsedTime();
if (sunRef.current) {
sunRef.current.rotation.y += delta * 0.2;
const pulse = 1 + Math.sin(t * 2.5) * 0.03;
sunRef.current.scale.set(pulse, pulse, pulse);
}
if (coronaRef.current) {
coronaRef.current.rotation.y -= delta * 0.15;
coronaRef.current.rotation.z += delta * 0.08;
const pulse2 = 1.2 + Math.cos(t * 1.8) * 0.05;
coronaRef.current.scale.set(pulse2, pulse2, pulse2);
}
if (flareRef.current) {
flareRef.current.rotation.z -= delta * 0.2;
}
});
return (
<group>
{/* Intense Core Sun */}
<mesh ref={sunRef}>
<sphereGeometry args={[0.75, 32, 32]} />
<meshStandardMaterial
color="#38bdf8"
emissive="#60a5fa"
emissiveIntensity={2.5}
roughness={0.2}
/>
</mesh>
{/* Atmospheric Corona Layer */}
<mesh ref={coronaRef}>
<sphereGeometry args={[0.95, 24, 24]} />
<meshBasicMaterial
color="#818cf8"
transparent
opacity={0.3}
wireframe
/>
</mesh>
{/* Solar Flare Halo Disk */}
<mesh ref={flareRef} rotation={[Math.PI / 2, 0, 0]}>
<ringGeometry args={[0.9, 1.45, 32]} />
<meshBasicMaterial
color="#38bdf8"
transparent
opacity={0.2}
side={THREE.DoubleSide}
/>
</mesh>
{/* Radiant Solar Lights */}
<pointLight color="#67e8f9" intensity={4} distance={20} decay={2} />
<pointLight color="#c084fc" intensity={2.5} distance={15} position={[0, 1, 0]} decay={2} />
</group>
);
}
// 2. Orbital Path Ring (crisp, faint geometric trajectory)
function OrbitTrack({ radius, color = "#475569" }: { radius: number; color?: string }) {
const lineGeometry = useMemo(() => {
const points: THREE.Vector3[] = [];
const segments = 120;
for (let i = 0; i <= segments; i++) {
const theta = (i / segments) * Math.PI * 2;
points.push(new THREE.Vector3(Math.cos(theta) * radius, 0, Math.sin(theta) * radius));
}
return new THREE.BufferGeometry().setFromPoints(points);
}, [radius]);
return (
<primitive object={new THREE.Line(
lineGeometry,
new THREE.LineBasicMaterial({ color, transparent: true, opacity: 0.3 })
)} />
);
}
// 3. Orbiting Planet with optional Rings & Moons
interface PlanetProps {
name: string;
radius: number;
size: number;
speed: number;
color: string;
emissive?: string;
hasRings?: boolean;
ringRadius?: [number, number];
ringColor?: string;
hasMoon?: boolean;
initialAngle?: number;
onHover?: (name: string | null) => void;
}
function Planet({
name,
radius,
size,
speed,
color,
emissive = "#000000",
hasRings = false,
ringRadius = [1.2, 1.8],
ringColor = "#c084fc",
hasMoon = false,
initialAngle = 0,
onHover,
}: PlanetProps) {
const planetGroupRef = useRef<THREE.Group>(null!);
const planetMeshRef = useRef<THREE.Mesh>(null!);
const moonGroupRef = useRef<THREE.Group>(null!);
const angleRef = useRef(initialAngle);
useFrame((_, delta) => {
angleRef.current += delta * speed * 0.35;
const x = Math.cos(angleRef.current) * radius;
const z = Math.sin(angleRef.current) * radius;
if (planetGroupRef.current) {
planetGroupRef.current.position.set(x, 0, z);
}
if (planetMeshRef.current) {
planetMeshRef.current.rotation.y += delta * 1.2;
}
if (moonGroupRef.current) {
moonGroupRef.current.rotation.y += delta * 2.5;
}
});
return (
<group ref={planetGroupRef}>
{/* The Planet Sphere */}
<mesh
ref={planetMeshRef}
onPointerOver={(e) => {
e.stopPropagation();
onHover?.(name);
}}
onPointerOut={() => onHover?.(null)}
>
<sphereGeometry args={[size, 24, 24]} />
<meshStandardMaterial
color={color}
emissive={emissive}
emissiveIntensity={0.6}
roughness={0.3}
metalness={0.7}
/>
</mesh>
{/* Planetary Rings */}
{hasRings && (
<mesh rotation={[Math.PI / 2.5, 0.2, 0]}>
<ringGeometry args={[size * ringRadius[0], size * ringRadius[1], 48]} />
<meshStandardMaterial
color={ringColor}
emissive={ringColor}
emissiveIntensity={0.5}
transparent
opacity={0.65}
side={THREE.DoubleSide}
/>
</mesh>
)}
{/* Orbiting Moon */}
{hasMoon && (
<group ref={moonGroupRef}>
<mesh position={[size * 1.9, 0.15, 0]}>
<sphereGeometry args={[size * 0.28, 16, 16]} />
<meshStandardMaterial
color="#e2e8f0"
emissive="#94a3b8"
emissiveIntensity={0.4}
roughness={0.5}
/>
</mesh>
</group>
)}
</group>
);
}
// 4. Asteroid Belt (subtle, clean, not overcrowded)
function AsteroidBelt({ count = 180, innerR = 3.4, outerR = 4.2 }: { count?: number; innerR?: number; outerR?: number }) {
const beltRef = useRef<THREE.Points>(null!);
const [positions, colors] = useMemo(() => {
const pos = new Float32Array(count * 3);
const col = new Float32Array(count * 3);
const colorA = new THREE.Color("#94a3b8");
const colorB = new THREE.Color("#38bdf8");
for (let i = 0; i < count; i++) {
const r = innerR + Math.random() * (outerR - innerR);
const theta = Math.random() * Math.PI * 2;
const y = (Math.random() - 0.5) * 0.3;
pos[i * 3] = Math.cos(theta) * r;
pos[i * 3 + 1] = y;
pos[i * 3 + 2] = Math.sin(theta) * r;
const c = Math.random() > 0.4 ? colorA : colorB;
col[i * 3] = c.r;
col[i * 3 + 1] = c.g;
col[i * 3 + 2] = c.b;
}
return [pos, col];
}, [count, innerR, outerR]);
useFrame((_, delta) => {
if (beltRef.current) {
beltRef.current.rotation.y += delta * 0.06;
}
});
return (
<points ref={beltRef}>
<bufferGeometry>
<bufferAttribute attach="attributes-position" args={[positions, 3]} />
<bufferAttribute attach="attributes-color" args={[colors, 3]} />
</bufferGeometry>
<pointsMaterial
size={0.045}
vertexColors
transparent
opacity={0.55}
sizeAttenuation
/>
</points>
);
}
// 5. Composite Solar System Scene with smooth interactive tilt
function SolarSystemScene({ onHoverPlanet }: { onHoverPlanet: (name: string | null) => void }) {
const systemRef = useRef<THREE.Group>(null!);
useFrame((state) => {
if (!systemRef.current) return;
// Subtle interactive tilt following pointer
const targetRotX = 0.55 + (state.pointer.y * Math.PI) / 24;
const targetRotY = -0.25 + (state.pointer.x * Math.PI) / 20;
systemRef.current.rotation.x += (targetRotX - systemRef.current.rotation.x) * 0.04;
systemRef.current.rotation.y += (targetRotY - systemRef.current.rotation.y) * 0.04;
});
return (
<group ref={systemRef} rotation={[0.55, -0.25, 0]}>
{/* Central Star */}
<CentralStar />
{/* Planetary Tracks — calibrated so outermost radius is 6.4 */}
<OrbitTrack radius={1.7} color="#38bdf8" />
<OrbitTrack radius={2.7} color="#818cf8" />
<OrbitTrack radius={5.0} color="#c084fc" />
<OrbitTrack radius={6.4} color="#34d399" />
{/* Asteroid Belt between Orbit II and Orbit III */}
<AsteroidBelt count={190} innerR={3.5} outerR={4.3} />
{/* Planet 1: Chronos (Molten amber rocky core) */}
<Planet
name="CHRONOS // ORBIT I (TIME ENGINE)"
radius={1.7}
size={0.16}
speed={1.5}
color="#fb923c"
emissive="#ea580c"
initialAngle={0.5}
onHover={onHoverPlanet}
/>
{/* Planet 2: Aetheria (Teal Gem with Moon) */}
<Planet
name="AETHERIA // ORBIT II (FLAGSHIP SECTOR)"
radius={2.7}
size={0.25}
speed={1.0}
color="#22d3ee"
emissive="#0891b2"
hasMoon={true}
initialAngle={2.2}
onHover={onHoverPlanet}
/>
{/* Planet 3: Nebula-IX (Ringed Gas Giant) */}
<Planet
name="NEBULA-IX // ORBIT III (CREATIVE GAS GIANT)"
radius={5.0}
size={0.42}
speed={0.55}
color="#a855f7"
emissive="#7e22ce"
hasRings={true}
ringRadius={[1.3, 1.9]}
ringColor="#c084fc"
hasMoon={true}
initialAngle={4.1}
onHover={onHoverPlanet}
/>
{/* Planet 4: Void-Zero (Outer Starlight World) */}
<Planet
name="VOID-ZERO // ORBIT IV (DEEP EXPERIMENTAL)"
radius={6.4}
size={0.3}
speed={0.35}
color="#34d399"
emissive="#059669"
hasMoon={true}
initialAngle={5.6}
onHover={onHoverPlanet}
/>
</group>
);
}
export default function HeroSolarSystem() {
const [hoveredPlanet, setHoveredPlanet] = useState<string | null>(null);
return (
<div className="relative w-full aspect-square max-w-[540px] max-h-[540px] sm:max-h-[580px] flex items-center justify-center select-none mx-auto overflow-visible">
{/* Background soft ambient radial lighting */}
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className="w-64 h-64 sm:w-80 sm:h-80 bg-cyan-500/10 rounded-full blur-[80px]" />
<div className="w-56 h-56 sm:w-72 sm:h-72 bg-purple-600/10 rounded-full blur-[80px]" />
</div>
{/*
Camera position: [0, 11, 16] with fov: 42
At distance ~19.4, visible height is 15.6 units and width is >18 units.
Outermost orbit radius is 6.4 (diameter 12.8).
-> 100% Guaranteed ZERO CROPPING at all angles.
*/}
<Canvas
camera={{ position: [0, 11, 16], fov: 42 }}
dpr={[1, 1.5]}
gl={{ antialias: true, alpha: true }}
className="w-full h-full cursor-grab active:cursor-grabbing overflow-visible"
>
<ambientLight intensity={0.4} />
<directionalLight position={[10, 15, 10]} intensity={1.2} color="#ffffff" />
<directionalLight position={[-10, -10, -5]} intensity={0.6} color="#818cf8" />
<SolarSystemScene onHoverPlanet={setHoveredPlanet} />
</Canvas>
{/* Interactive HUD Telemetry Card */}
<div className="absolute bottom-2 left-1/2 -translate-x-1/2 sm:left-2 sm:translate-x-0 glass-panel px-3.5 py-1.5 rounded-xl border border-cyan-500/30 flex items-center gap-2.5 text-[11px] font-mono tracking-wider shadow-[0_0_20px_rgba(56,189,248,0.2)] pointer-events-none">
<div className="flex items-center gap-1.5">
<span className="w-2 h-2 rounded-full bg-cyan-400 animate-ping" />
<span className="text-cyan-300 font-bold">AGHATIS ORBITAL</span>
</div>
<span className="text-slate-500">|</span>
<span className="text-slate-300">
{hoveredPlanet ? (
<span className="text-cyan-400 font-bold">{hoveredPlanet}</span>
) : (
"4 ACTIVE ORBITS • TILT TO EXPLORE"
)}
</span>
</div>
{/* Orbit Speed & System Badge */}
<div className="absolute top-2 right-2 hidden sm:flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-indigo-950/40 border border-indigo-500/30 text-[10px] font-mono text-indigo-300">
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400" />
<span>SIMULATION: 1.0X</span>
</div>
</div>
);
}