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

+190
View File
@@ -0,0 +1,190 @@
"use client";
import React from "react";
import { motion } from "framer-motion";
import { Shield, Sparkles, Cpu, Eye, Code, Compass } from "lucide-react";
export default function About() {
const pillars = [
{
icon: Shield,
title: "Radical Autonomy",
description:
"We are 100% self-directed. Every hour in our studio is dedicated to original research, bespoke engineering, and crafting immersive experiences.",
badge: "Sovereign IP",
accent: "from-cyan-500/20 to-blue-500/10",
border: "border-cyan-500/30",
},
{
icon: Cpu,
title: "Relentless Engineering",
description:
"From low-latency native algorithms to custom GLSL shaders and responsive spatial architectures, our software is engineered for speed, stability, and longevity.",
badge: "Deep Tech",
accent: "from-purple-500/20 to-indigo-500/10",
border: "border-purple-500/30",
},
{
icon: Sparkles,
title: "Artistic Depth",
description:
"Games and software shouldn't just be functional—they should carry soul. We handcraft atmospheric aesthetics, celestial soundscapes, and intuitive interaction rituals.",
badge: "Bespoke Art",
accent: "from-pink-500/20 to-rose-500/10",
border: "border-pink-500/30",
},
{
icon: Eye,
title: "Long-Horizon Vision",
description:
"We build digital artifacts that endure. Rather than following transient hype cycles or rushed deliverables, we invest in foundational systems and timeless experiences.",
badge: "Decade Mindset",
accent: "from-indigo-500/20 to-cyan-500/10",
border: "border-indigo-500/30",
},
];
return (
<section id="about" className="relative py-28 overflow-hidden">
{/* Background radial accent */}
<div className="absolute top-1/2 left-0 w-96 h-96 bg-indigo-600/10 rounded-full blur-[140px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Section Header */}
<div className="flex flex-col items-center text-center max-w-3xl mx-auto mb-20 space-y-4">
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full glass-panel border border-indigo-500/30 text-xs font-mono text-indigo-300">
<Compass className="w-3.5 h-3.5 text-indigo-400" />
<span>ORIGIN & MISSION</span>
</div>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-black tracking-tight text-white">
Forged in the Pursuit of <br />
<span className="text-gradient-nebula">Creative Sovereignty.</span>
</h2>
<p className="text-base sm:text-lg text-slate-400 leading-relaxed pt-2">
Aghatis Studio was established with a singular conviction: the most resonant
software and interactive worlds are crafted with unwavering focus, deep curiosity,
and total creative sovereignty.
</p>
</div>
{/* Narrative Feature Row: Manifesto statement */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-stretch mb-16">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7 }}
className="lg:col-span-7 glass-panel-glow p-8 sm:p-10 rounded-3xl relative overflow-hidden flex flex-col justify-between"
>
<div className="absolute top-0 right-0 p-8 opacity-10 pointer-events-none">
<Code className="w-48 h-48 text-cyan-400" />
</div>
<div className="space-y-6 relative z-10">
<div className="text-xs font-mono tracking-widest text-cyan-400 uppercase">
// THE STUDIO NARRATIVE
</div>
<h3 className="text-2xl sm:text-3xl font-bold text-white leading-snug">
The Craft of an Independent Product Lab.
</h3>
<p className="text-slate-300 leading-relaxed text-sm sm:text-base">
At <span className="text-cyan-300 font-semibold">Aghatis Studio</span>, our mission is purposeful:
we design, build, and publish our own digital products. By channeling our entire team&apos;s energy
into in-house intellectual property, we maintain complete creative control over every mechanic, interface, and artistic decision.
</p>
<p className="text-slate-400 leading-relaxed text-sm sm:text-base">
Every line of code, geometric asset, and algorithmic pipeline we author belongs to a cohesive creative ecosystem.
This focused environment grants us the freedom to polish mechanics until they shine, engineer tools with
uncompromising standards, and publish digital experiences that leave a lasting impression.
</p>
</div>
<div className="mt-8 pt-6 border-t border-white/10 flex items-center justify-between text-xs font-mono text-slate-400">
<span>FOUNDED IN INDEPENDENCE</span>
<span className="text-cyan-400">PURE IN-HOUSE IP</span>
</div>
</motion.div>
{/* Right Quote / Philosophy card */}
<motion.div
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7, delay: 0.1 }}
className="lg:col-span-5 glass-card p-8 sm:p-10 rounded-3xl flex flex-col justify-between border-indigo-500/20 bg-gradient-to-b from-indigo-950/30 to-purple-950/10"
>
<div className="space-y-4">
<div className="w-10 h-10 rounded-xl bg-cyan-400/10 border border-cyan-400/30 flex items-center justify-center text-cyan-400">
<Sparkles className="w-5 h-5" />
</div>
<blockquote className="text-lg sm:text-xl font-medium text-slate-200 italic leading-relaxed">
&ldquo;We measure our success by the elegance of our architecture, the atmosphere of our worlds, and the enduring quality of the software and games we release into the universe.&rdquo;
</blockquote>
</div>
<div className="mt-8 pt-6 border-t border-white/10 flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-gradient-to-tr from-cyan-400 to-indigo-500 flex items-center justify-center text-slate-950 font-bold text-xs">
AS
</div>
<div>
<div className="text-xs font-mono font-bold text-white tracking-wider">
AGHATIS CORE LAB
</div>
<div className="text-[11px] font-mono text-slate-400">
CREATIVE ARCHITECTURE COUNCIL
</div>
</div>
</div>
</motion.div>
</div>
{/* Pillars Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{pillars.map((pillar, i) => {
const Icon = pillar.icon;
return (
<motion.div
key={pillar.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.1 }}
className="glass-card p-6 sm:p-7 rounded-2xl flex flex-col justify-between group hover:border-cyan-400/40 relative overflow-hidden"
>
<div className={`absolute top-0 right-0 w-28 h-28 bg-gradient-to-bl ${pillar.accent} rounded-bl-full pointer-events-none opacity-40 group-hover:opacity-100 transition-opacity`} />
<div className="space-y-4 relative z-10">
<div className="flex items-center justify-between">
<div className="w-10 h-10 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center text-cyan-400 group-hover:scale-110 transition-transform">
<Icon className="w-5 h-5" />
</div>
<span className="text-[10px] font-mono uppercase px-2 py-0.5 rounded-full bg-white/5 border border-white/10 text-slate-400">
{pillar.badge}
</span>
</div>
<h4 className="text-lg font-bold text-white group-hover:text-cyan-300 transition-colors">
{pillar.title}
</h4>
<p className="text-xs sm:text-sm text-slate-400 leading-relaxed">
{pillar.description}
</p>
</div>
<div className="mt-6 pt-4 border-t border-white/5 flex items-center justify-between text-[11px] font-mono text-slate-400">
<span>PILLAR 0{i + 1}</span>
<span className="text-cyan-400 font-mono">NOMINAL</span>
</div>
</motion.div>
);
})}
</div>
</div>
</section>
);
}
+252
View File
@@ -0,0 +1,252 @@
"use client";
import React, { useMemo, useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import * as THREE from "three";
// 1. Refined, clean Starfield (neat, elegant points of light)
function StarField({ count = 650 }: { count?: number }) {
const pointsRef = useRef<THREE.Points>(null!);
const [positions, colors] = useMemo(() => {
const pos = new Float32Array(count * 3);
const col = new Float32Array(count * 3);
const colorWhite = new THREE.Color("#ffffff");
const colorIcy = new THREE.Color("#93c5fd");
const colorSilver = new THREE.Color("#e2e8f0");
for (let i = 0; i < count; i++) {
const radius = 30 + Math.random() * 80;
const theta = Math.random() * 2 * Math.PI;
const phi = Math.acos(2 * Math.random() - 1);
pos[i * 3] = radius * Math.sin(phi) * Math.cos(theta);
pos[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
pos[i * 3 + 2] = radius * Math.cos(phi);
const r = Math.random();
const chosen = r > 0.7 ? colorIcy : r > 0.3 ? colorSilver : colorWhite;
col[i * 3] = chosen.r;
col[i * 3 + 1] = chosen.g;
col[i * 3 + 2] = chosen.b;
}
return [pos, col];
}, [count]);
useFrame((state, delta) => {
if (!pointsRef.current) return;
pointsRef.current.rotation.y += delta * 0.005;
pointsRef.current.rotation.x += delta * 0.002;
const targetX = (state.pointer.x * Math.PI) / 60;
const targetY = (state.pointer.y * Math.PI) / 60;
pointsRef.current.rotation.y += (targetX - pointsRef.current.rotation.y) * 0.02;
pointsRef.current.rotation.x += (-targetY - pointsRef.current.rotation.x) * 0.02;
});
return (
<points ref={pointsRef}>
<bufferGeometry>
<bufferAttribute attach="attributes-position" args={[positions, 3]} />
<bufferAttribute attach="attributes-color" args={[colors, 3]} />
</bufferGeometry>
<pointsMaterial
size={0.7}
vertexColors
transparent
opacity={0.8}
sizeAttenuation
depthWrite={false}
blending={THREE.AdditiveBlending}
/>
</points>
);
}
// 2. Bright, Glowing Background Planet (Astraea - Upper Right)
function BackgroundPlanetAstraea() {
const groupRef = useRef<THREE.Group>(null!);
const planetRef = useRef<THREE.Mesh>(null!);
const atmosphereRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
if (planetRef.current) {
planetRef.current.rotation.y += delta * 0.05;
}
if (atmosphereRef.current) {
atmosphereRef.current.rotation.y -= delta * 0.03;
}
if (groupRef.current) {
// Subtle floating parallax
const targetX = 16 + (state.pointer.x * 2.5);
const targetY = 9 + (state.pointer.y * 2.0);
groupRef.current.position.x += (targetX - groupRef.current.position.x) * 0.02;
groupRef.current.position.y += (targetY - groupRef.current.position.y) * 0.02;
}
});
return (
<group ref={groupRef} position={[16, 9, -16]}>
{/* Bright Planet Core Sphere */}
<mesh ref={planetRef}>
<sphereGeometry args={[4.2, 48, 48]} />
<meshStandardMaterial
color="#38bdf8"
emissive="#0284c7"
emissiveIntensity={0.85}
roughness={0.25}
metalness={0.7}
/>
</mesh>
{/* Radiant Atmospheric Halo Rim */}
<mesh ref={atmosphereRef}>
<sphereGeometry args={[4.6, 32, 32]} />
<meshBasicMaterial
color="#7dd3fc"
transparent
opacity={0.35}
side={THREE.BackSide}
blending={THREE.AdditiveBlending}
/>
</mesh>
{/* Outer Luminous Glow Aura Ring */}
<mesh rotation={[Math.PI / 3, 0.4, 0]}>
<ringGeometry args={[4.8, 6.8, 48]} />
<meshBasicMaterial
color="#38bdf8"
transparent
opacity={0.22}
side={THREE.DoubleSide}
/>
</mesh>
</group>
);
}
// 3. Bright, Glowing Background Planet (Kore - Lower Left with Ring)
function BackgroundPlanetKore() {
const groupRef = useRef<THREE.Group>(null!);
const planetRef = useRef<THREE.Mesh>(null!);
const ringRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
if (planetRef.current) {
planetRef.current.rotation.y += delta * 0.04;
}
if (ringRef.current) {
ringRef.current.rotation.z += delta * 0.02;
}
if (groupRef.current) {
// Gentle floating parallax
const targetX = -18 - (state.pointer.x * 3.0);
const targetY = -12 - (state.pointer.y * 2.5);
groupRef.current.position.x += (targetX - groupRef.current.position.x) * 0.02;
groupRef.current.position.y += (targetY - groupRef.current.position.y) * 0.02;
}
});
return (
<group ref={groupRef} position={[-18, -12, -22]}>
{/* Bright Violet Core Planet */}
<mesh ref={planetRef}>
<sphereGeometry args={[5.5, 48, 48]} />
<meshStandardMaterial
color="#a855f7"
emissive="#6366f1"
emissiveIntensity={0.75}
roughness={0.3}
metalness={0.8}
/>
</mesh>
{/* Atmospheric Halo */}
<mesh>
<sphereGeometry args={[5.9, 32, 32]} />
<meshBasicMaterial
color="#c084fc"
transparent
opacity={0.3}
side={THREE.BackSide}
blending={THREE.AdditiveBlending}
/>
</mesh>
{/* Luminous Majestic Planetary Ring */}
<mesh ref={ringRef} rotation={[Math.PI / 2.3, 0.35, 0]}>
<ringGeometry args={[6.8, 10.2, 64]} />
<meshStandardMaterial
color="#c084fc"
emissive="#a855f7"
emissiveIntensity={0.6}
transparent
opacity={0.45}
side={THREE.DoubleSide}
/>
</mesh>
</group>
);
}
// 4. Distant Luminous Stellar Moon Orb
function DistantLuminousOrb() {
const orbRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
if (!orbRef.current) return;
const t = state.clock.getElapsedTime();
orbRef.current.position.y = 14 + Math.sin(t * 0.8) * 0.6;
orbRef.current.position.x = -8 + Math.cos(t * 0.5) * 0.8;
});
return (
<mesh ref={orbRef} position={[-8, 14, -18]}>
<sphereGeometry args={[1.2, 24, 24]} />
<meshStandardMaterial
color="#34d399"
emissive="#10b981"
emissiveIntensity={1.2}
roughness={0.1}
/>
</mesh>
);
}
export default function CosmicGalaxy() {
return (
<div className="fixed inset-0 pointer-events-none z-0 overflow-hidden">
<Canvas
camera={{ position: [0, 0, 32], fov: 50 }}
dpr={[1, 1.5]}
gl={{ antialias: true, alpha: true, powerPreference: "high-performance" }}
className="w-full h-full"
>
<color attach="background" args={["#0a0a12"]} />
{/* Cinematic Starlight Illumination */}
<ambientLight intensity={0.5} />
<directionalLight position={[20, 20, 10]} intensity={1.8} color="#e0f2fe" />
<directionalLight position={[-20, -15, -5]} intensity={1.0} color="#c084fc" />
{/* Clean, Neat Starfield */}
<StarField count={650} />
{/* Bright Circular Planet-Like Objects in the Background */}
<BackgroundPlanetAstraea />
<BackgroundPlanetKore />
<DistantLuminousOrb />
</Canvas>
{/* Atmospheric depth vignettes (subtle gradient, no harsh boxes) */}
<div className="absolute inset-0 bg-radial from-transparent via-[#0a0a12]/30 to-[#0a0a12] pointer-events-none" />
{/* Soft circular glowing light fountains behind the planets */}
<div className="absolute -top-10 right-10 w-96 h-96 bg-cyan-500/10 rounded-full blur-[100px] pointer-events-none" />
<div className="absolute -bottom-10 left-10 w-[450px] h-[450px] bg-purple-600/10 rounded-full blur-[120px] pointer-events-none" />
</div>
);
}
+11
View File
@@ -0,0 +1,11 @@
"use client";
import dynamic from "next/dynamic";
const CosmicGalaxy = dynamic(() => import("./CosmicGalaxy"), {
ssr: false,
});
export default function CosmicGalaxyDynamic() {
return <CosmicGalaxy />;
}
+168
View File
@@ -0,0 +1,168 @@
"use client";
import React, { useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { Float } from "@react-three/drei";
import * as THREE from "three";
function CosmicArtifact() {
const groupRef = useRef<THREE.Group>(null!);
const ring1Ref = useRef<THREE.Mesh>(null!);
const ring2Ref = useRef<THREE.Mesh>(null!);
const ring3Ref = useRef<THREE.Mesh>(null!);
const coreRef = useRef<THREE.Mesh>(null!);
const outerGeomRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
if (!groupRef.current) return;
// Dual-axis rotation for the rings (gyroscope / celestial sphere effect)
if (ring1Ref.current) {
ring1Ref.current.rotation.x += delta * 0.4;
ring1Ref.current.rotation.y += delta * 0.2;
}
if (ring2Ref.current) {
ring2Ref.current.rotation.y += delta * 0.35;
ring2Ref.current.rotation.z += delta * 0.25;
}
if (ring3Ref.current) {
ring3Ref.current.rotation.z += delta * 0.3;
ring3Ref.current.rotation.x += delta * 0.15;
}
// Core pulsing & rotation
if (coreRef.current) {
coreRef.current.rotation.y += delta * 0.5;
const t = state.clock.getElapsedTime();
const scale = 1 + Math.sin(t * 2) * 0.05;
coreRef.current.scale.set(scale, scale, scale);
}
// Outer wireframe geodesic
if (outerGeomRef.current) {
outerGeomRef.current.rotation.y -= delta * 0.15;
outerGeomRef.current.rotation.x += delta * 0.08;
}
// Interactive pointer sway
const targetX = (state.pointer.x * Math.PI) / 8;
const targetY = (state.pointer.y * Math.PI) / 8;
groupRef.current.rotation.y += (targetX - groupRef.current.rotation.y) * 0.05;
groupRef.current.rotation.x += (-targetY - groupRef.current.rotation.x) * 0.05;
});
return (
<Float speed={2} rotationIntensity={0.6} floatIntensity={1}>
<group ref={groupRef}>
{/* Core glowing sphere */}
<mesh ref={coreRef}>
<sphereGeometry args={[1.2, 32, 32]} />
<meshStandardMaterial
color="#38bdf8"
emissive="#6366f1"
emissiveIntensity={0.8}
roughness={0.15}
metalness={0.9}
wireframe={false}
/>
</mesh>
{/* Inner light source */}
<pointLight color="#38bdf8" intensity={4} distance={8} />
<pointLight color="#a855f7" intensity={3} distance={10} position={[0, -2, 0]} />
{/* Outer wireframe icosahedron/geodesic */}
<mesh ref={outerGeomRef}>
<icosahedronGeometry args={[2.0, 1]} />
<meshBasicMaterial
color="#818cf8"
wireframe
transparent
opacity={0.3}
/>
</mesh>
{/* Celestial Orbital Ring 1 */}
<mesh ref={ring1Ref}>
<torusGeometry args={[2.5, 0.025, 16, 100]} />
<meshStandardMaterial
color="#38bdf8"
emissive="#38bdf8"
emissiveIntensity={1.5}
roughness={0.1}
/>
</mesh>
{/* Celestial Orbital Ring 2 (Cross tilt) */}
<mesh ref={ring2Ref} rotation={[Math.PI / 3, 0, 0]}>
<torusGeometry args={[3.0, 0.02, 16, 100]} />
<meshStandardMaterial
color="#c084fc"
emissive="#a855f7"
emissiveIntensity={1.3}
roughness={0.1}
/>
</mesh>
{/* Celestial Orbital Ring 3 (Outer edge) */}
<mesh ref={ring3Ref} rotation={[-Math.PI / 4, Math.PI / 6, 0]}>
<torusGeometry args={[3.4, 0.015, 16, 120]} />
<meshStandardMaterial
color="#67e8f9"
emissive="#06b6d4"
emissiveIntensity={1.0}
roughness={0.1}
/>
</mesh>
{/* Orbital Starlight Satellite Node 1 */}
<mesh position={[2.6, 0.4, 0]}>
<sphereGeometry args={[0.08, 16, 16]} />
<meshBasicMaterial color="#38bdf8" />
</mesh>
{/* Orbital Starlight Satellite Node 2 */}
<mesh position={[-2.2, 1.8, 0.5]}>
<sphereGeometry args={[0.07, 16, 16]} />
<meshBasicMaterial color="#f472b6" />
</mesh>
{/* Orbital Starlight Satellite Node 3 */}
<mesh position={[0.8, -2.8, -0.6]}>
<sphereGeometry args={[0.09, 16, 16]} />
<meshBasicMaterial color="#a78bfa" />
</mesh>
</group>
</Float>
);
}
export default function HeroCosmicOrb() {
return (
<div className="relative w-full h-[380px] sm:h-[450px] lg:h-[550px] flex items-center justify-center">
{/* Background radial glow */}
<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-indigo-500/20 rounded-full blur-[80px]" />
<div className="w-48 h-48 sm:w-60 sm:h-60 bg-cyan-400/20 rounded-full blur-[60px]" />
</div>
<Canvas
camera={{ position: [0, 0, 7.5], fov: 45 }}
dpr={[1, 1.5]}
gl={{ antialias: true, alpha: true }}
className="w-full h-full cursor-grab active:cursor-grabbing"
>
<ambientLight intensity={0.4} />
<directionalLight position={[10, 10, 5]} intensity={1.5} color="#e0e7ff" />
<directionalLight position={[-10, -10, -5]} intensity={0.8} color="#c084fc" />
<CosmicArtifact />
</Canvas>
{/* Holographic coordinates overlay badge */}
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 sm:left-6 sm:translate-x-0 px-3 py-1 rounded-full glass-panel border border-cyan-500/20 flex items-center gap-2 pointer-events-none text-[11px] text-cyan-300 font-mono tracking-wider shadow-lg">
<span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
<span>CORE ARTIFACT // AG-01 ACTIVE</span>
</div>
</div>
);
}
+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>
);
}
+200
View File
@@ -0,0 +1,200 @@
"use client";
import React from "react";
import { motion } from "framer-motion";
import { Terminal, Gamepad2, Sparkles, Orbit, CheckCircle2, Compass } from "lucide-react";
export default function StudioCreed() {
const softwareFocus = [
{
title: "Local-First & High Performance",
desc: "We build native, low-latency tools compiled in Rust and WebGPU that respect cognitive flow and user data sovereignty.",
},
{
title: "Tactile Spatial Interfaces",
desc: "Re-imagining workstations and creative pipelines with fluid, cockpit-inspired spatial ergonomics.",
},
{
title: "Zero-Bloat Engineering",
desc: "Every binary is optimized for minimal memory footprint, instant boot times, and decades-long utility.",
},
{
title: "Tools for Deep Thinkers & Creators",
desc: "Software designed from the ground up for technical artists, developers, and focused thinkers.",
},
];
const gamesFocus = [
{
title: "Atmospheric & Narrative Immersion",
desc: "Evocative interstellar worlds driven by rich speculative fiction, tactile acoustics, and memorable art direction.",
},
{
title: "Kinetic & Physics-First Mechanics",
desc: "Crafting gameplay rooted in Newtonian motion, orbital dynamics, and tactile interactive feedback.",
},
{
title: "Standalone, Complete Experiences",
desc: "Crafting finished artistic works that respect player time—no predatory loops, just pure interactive craft.",
},
{
title: "Original Audiovisual Synthesis",
desc: "Bespoke procedural audio engines and dynamic synthesizer soundtracks that react in real-time.",
},
];
return (
<section id="creed" className="relative py-28 overflow-hidden">
{/* Background radial glow */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[500px] bg-indigo-600/10 rounded-full blur-[180px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Section Header */}
<div className="flex flex-col items-center text-center max-w-3xl mx-auto mb-20 space-y-4">
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full glass-panel border border-cyan-500/30 text-xs font-mono text-cyan-300">
<Compass className="w-3.5 h-3.5 text-cyan-400" />
<span>STUDIO CREED & CRAFT PHILOSOPHY</span>
</div>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-black tracking-tight text-white">
Where Our Energy Goes: <br />
<span className="text-gradient-cyan">The Pursuit of Pure Craft.</span>
</h2>
<p className="text-base sm:text-lg text-slate-400 leading-relaxed pt-2">
Aghatis Studio exists to invent, polish, and publish original software products and immersive interactive worlds.
Our roadmap is driven entirely by craftsmanship, curiosity, and product excellence.
</p>
</div>
{/* Side-by-side Dual Focus Arena */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 items-stretch">
{/* Column 1: Software & Tools Focus */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="glass-panel-glow p-8 sm:p-10 rounded-3xl relative overflow-hidden flex flex-col justify-between border-cyan-500/30 bg-gradient-to-b from-cyan-950/20 via-slate-950/60 to-black/80"
>
<div className="space-y-6">
<div className="flex items-center justify-between pb-4 border-b border-white/10">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-cyan-400/10 border border-cyan-400/30 flex items-center justify-center text-cyan-400">
<Terminal className="w-5 h-5" />
</div>
<div>
<h3 className="text-lg font-bold font-mono text-white">
SOFTWARE & CREATIVE TOOLS
</h3>
<span className="text-[11px] font-mono text-cyan-300">
SYSTEMS, WORKSTATIONS & PIPELINES
</span>
</div>
</div>
<span className="w-2.5 h-2.5 rounded-full bg-cyan-400 shadow-[0_0_10px_#38bdf8]" />
</div>
<div className="space-y-4">
{softwareFocus.map((item, idx) => (
<div
key={idx}
className="p-4 rounded-2xl bg-white/5 border border-white/5 flex items-start gap-3.5 hover:border-cyan-400/20 transition-colors"
>
<CheckCircle2 className="w-4 h-4 text-cyan-400 shrink-0 mt-0.5" />
<div>
<h4 className="text-sm font-bold text-white font-mono">
{item.title}
</h4>
<p className="text-xs text-slate-300 leading-relaxed mt-1">
{item.desc}
</p>
</div>
</div>
))}
</div>
</div>
<div className="mt-8 pt-6 border-t border-white/10 text-xs font-mono text-cyan-300 flex items-center gap-2">
<Sparkles className="w-4 h-4 text-cyan-400" />
<span>Engineered to empower creators with speed, clarity, and precision.</span>
</div>
</motion.div>
{/* Column 2: Games & Interactive Media Focus */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.1 }}
className="glass-card p-8 sm:p-10 rounded-3xl relative overflow-hidden flex flex-col justify-between border-purple-500/30 bg-gradient-to-b from-purple-950/20 via-slate-950/60 to-black/80"
>
<div className="space-y-6">
<div className="flex items-center justify-between pb-4 border-b border-white/10">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-purple-500/10 border border-purple-500/30 flex items-center justify-center text-purple-400">
<Gamepad2 className="w-5 h-5" />
</div>
<div>
<h3 className="text-lg font-bold font-mono text-white">
ATMOSPHERIC GAMES
</h3>
<span className="text-[11px] font-mono text-purple-300">
WORLDS, PHYSICS & NARRATIVE
</span>
</div>
</div>
<span className="w-2.5 h-2.5 rounded-full bg-purple-400 shadow-[0_0_10px_#a855f7]" />
</div>
<div className="space-y-4">
{gamesFocus.map((item, idx) => (
<div
key={idx}
className="p-4 rounded-2xl bg-white/5 border border-white/5 flex items-start gap-3.5 hover:border-purple-400/20 transition-colors"
>
<CheckCircle2 className="w-4 h-4 text-purple-400 shrink-0 mt-0.5" />
<div>
<h4 className="text-sm font-bold text-white font-mono">
{item.title}
</h4>
<p className="text-xs text-slate-300 leading-relaxed mt-1">
{item.desc}
</p>
</div>
</div>
))}
</div>
</div>
<div className="mt-8 pt-6 border-t border-white/10 text-xs font-mono text-purple-300 flex items-center gap-2">
<Orbit className="w-4 h-4 text-purple-400" />
<span>Handcrafted interactive universes built with artistic depth and soul.</span>
</div>
</motion.div>
</div>
{/* Central Creed Statement */}
<motion.div
initial={{ opacity: 0, y: 15 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="mt-12 p-8 rounded-2xl glass-panel text-center max-w-4xl mx-auto border border-white/10 relative overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-cyan-500/5 to-transparent pointer-events-none" />
<p className="text-sm sm:text-base font-mono text-slate-200 tracking-wide leading-relaxed">
&ldquo;Our commitment is simple: build products of enduring depth, craft experiences we are fiercely proud of, and explore the outer boundaries of software and interactive art.&rdquo;
</p>
<div className="mt-4 text-xs font-mono text-cyan-400 uppercase tracking-widest">
— AGHATIS STUDIO CORE TENET
</div>
</motion.div>
</div>
</section>
);
}
+252
View File
@@ -0,0 +1,252 @@
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Layers, Terminal, Gamepad2, FlaskConical, ArrowUpRight, CheckCircle2 } from "lucide-react";
export default function CoreFocus() {
const [activeTrack, setActiveTrack] = useState<number>(0);
const tracks = [
{
id: "software",
number: "01",
title: "Software Products",
category: "CREATIVE & DEVELOPER TOOLS",
icon: Terminal,
tagline: "High-performance utilities engineered for creators, coders, and deep-focus thinkers.",
description:
"We build standalone software tools that respect user attention and privacy. Our software stack emphasizes local-first execution, instantaneous boot times, minimal memory footprints, and fluid spatial aesthetics.",
stack: ["Rust", "TypeScript", "WebGPU", "Local-First SQLite", "Tauri", "Custom GLSL"],
principles: [
"Zero telemetry bloat or intrusive subscription traps",
"Deterministic local-first file system workflows",
"Sub-16ms latency interface responsiveness",
"Minimalist spatial design inspired by cockpit HUDs",
],
currentInitiatives: [
{ name: "NebulaFlow", stage: "Public Alpha", note: "Real-time visual node graph for generative coders" },
{ name: "Voidwalker OS", stage: "Prototype", note: "Ultra-distraction-free spatial terminal" },
],
accentColor: "from-cyan-500 to-blue-600",
pillBorder: "border-cyan-500/30 text-cyan-400 bg-cyan-500/10",
glowColor: "rgba(56, 189, 248, 0.15)",
},
{
id: "games",
number: "02",
title: "Original Games",
category: "ATMOSPHERIC & INDIE TITLES",
icon: Gamepad2,
tagline: "Evocative, mechanics-first game experiences set in interstellar and surreal realities.",
description:
"Our games emphasize tactile physics, memorable soundscapes, and evocative storytelling. We reject predatory monetization and live-service treadmills—focusing exclusively on handcrafted, complete experiences that respect the player's time.",
stack: ["Godot Engine", "Custom C++ GDExtension", "Bespoke Shaders", "FMOD / WebAudio", "Procreate / Blender"],
principles: [
"Uncompromising, single-purchase complete artistic vision",
"Kinetic, physics-grounded flight and orbital mechanics",
"Original dynamic synthesizer soundtracks and reactive foley",
"Rich speculative sci-fi lore and evocative environmental narrative",
],
currentInitiatives: [
{ name: "Aetheria: Chrono Drift", stage: "In Active Dev", note: "Tactical sci-fi flight RPG with time-dilation" },
{ name: "Singularity Pulse", stage: "Playable Slice", note: "Hypnotic orbital defense rhythm-strategy" },
],
accentColor: "from-purple-500 to-pink-600",
pillBorder: "border-purple-500/30 text-purple-400 bg-purple-500/10",
glowColor: "rgba(168, 85, 247, 0.15)",
},
{
id: "lab",
number: "03",
title: "Experimental Lab",
category: "CREATIVE COMPUTING & R&D",
icon: FlaskConical,
tagline: "Unconstrained research in procedural systems, audio synthesis, and algorithmic art.",
description:
"The Aghatis Lab is our continuous skunkworks playground. Here we prototype procedural cosmos generators, WebAudio modular synths, chaotic attractor simulations, and emergent artificial life models that inform our core products.",
stack: ["Three.js / R3F", "GLSL Compute", "Web Audio API", "WebAssembly", "Generative Math"],
principles: [
"Rapid computational sketches without commercial pressure",
"Algorithmic exploration of celestial mathematics & fractals",
"Open prototypes released to the creative technology community",
"Direct R&D incubator for upcoming software & game mechanics",
],
currentInitiatives: [
{ name: "ChromaSynth", stage: "Lab Sandbox", note: "Audio-reactive procedural geometry synthesizer" },
{ name: "Project Event Horizon", stage: "R&D Prototype", note: "Planetary terrain generation via compute shaders" },
],
accentColor: "from-emerald-500 to-cyan-500",
pillBorder: "border-emerald-500/30 text-emerald-400 bg-emerald-500/10",
glowColor: "rgba(16, 185, 129, 0.15)",
},
];
const current = tracks[activeTrack];
return (
<section id="focus" className="relative py-28 overflow-hidden">
{/* Background ambient lighting */}
<div className="absolute top-1/3 right-0 w-[500px] h-[500px] bg-purple-600/10 rounded-full blur-[160px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Section Header */}
<div className="flex flex-col items-center text-center max-w-3xl mx-auto mb-16 space-y-4">
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full glass-panel border border-cyan-500/30 text-xs font-mono text-cyan-300">
<Layers className="w-3.5 h-3.5 text-cyan-400" />
<span>OPERATIONAL TRACKS</span>
</div>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-black tracking-tight text-white">
Three Dedicated Arenas of <br />
<span className="text-gradient-cyan">In-House Creation.</span>
</h2>
<p className="text-base sm:text-lg text-slate-400 leading-relaxed pt-2">
Every project inside Aghatis Studio originates from one of three symbiotic disciplines,
channeling our entire focus into original software, atmospheric games, and computational experiments.
</p>
</div>
{/* Track Selector Tabs */}
<div className="flex flex-wrap items-center justify-center gap-3 mb-12">
{tracks.map((track, idx) => {
const Icon = track.icon;
const isSelected = activeTrack === idx;
return (
<button
key={track.id}
onClick={() => setActiveTrack(idx)}
className={`flex items-center gap-3 px-5 py-3 rounded-2xl font-mono text-xs uppercase tracking-wider transition-all duration-300 cursor-pointer ${
isSelected
? "glass-panel-glow border-cyan-400/50 text-white shadow-[0_0_25px_rgba(56,189,248,0.25)] scale-[1.02]"
: "glass-card text-slate-400 hover:text-slate-200 hover:border-white/20"
}`}
>
<span className="text-slate-400 font-bold">{track.number}</span>
<Icon className={`w-4 h-4 ${isSelected ? "text-cyan-400" : "text-slate-400"}`} />
<span className="font-semibold">{track.title}</span>
</button>
);
})}
</div>
{/* Active Track Deep Dive Display */}
<AnimatePresence mode="wait">
<motion.div
key={current.id}
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.4 }}
className="glass-panel-glow p-8 sm:p-12 rounded-3xl relative overflow-hidden border border-white/10"
style={{
boxShadow: `0 0 60px -15px ${current.glowColor}`,
}}
>
{/* Ambient accent top bar */}
<div className={`absolute top-0 left-0 right-0 h-1.5 bg-gradient-to-r ${current.accentColor}`} />
<div className="grid grid-cols-1 lg:grid-cols-12 gap-10">
{/* Left Column: Track Philosophy & Overview */}
<div className="lg:col-span-7 space-y-6">
<div className="flex items-center gap-3">
<span className={`px-2.5 py-1 rounded-md text-[11px] font-mono tracking-widest uppercase border ${current.pillBorder}`}>
TRACK {current.number} // {current.category}
</span>
</div>
<h3 className="text-2xl sm:text-3xl lg:text-4xl font-extrabold text-white leading-tight">
{current.tagline}
</h3>
<p className="text-slate-300 text-sm sm:text-base leading-relaxed">
{current.description}
</p>
{/* Principles checklist */}
<div className="space-y-3 pt-4">
<div className="text-xs font-mono uppercase tracking-wider text-slate-400">
// CORE ARCHITECTURAL COMMITMENTS
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{current.principles.map((principle, i) => (
<div key={i} className="flex items-start gap-2.5 text-xs text-slate-300">
<CheckCircle2 className="w-4 h-4 text-cyan-400 shrink-0 mt-0.5" />
<span>{principle}</span>
</div>
))}
</div>
</div>
{/* Stack Badges */}
<div className="pt-4">
<div className="text-xs font-mono uppercase tracking-wider text-slate-400 mb-2.5">
// TECHNICAL ENGINE & TOOLCHAIN
</div>
<div className="flex flex-wrap gap-2">
{current.stack.map((tech) => (
<span
key={tech}
className="px-3 py-1 rounded-lg text-xs font-mono bg-white/5 border border-white/10 text-slate-300 hover:border-cyan-400/40 hover:text-white transition-colors"
>
{tech}
</span>
))}
</div>
</div>
</div>
{/* Right Column: Active In-Forge Projects in this track */}
<div className="lg:col-span-5 flex flex-col justify-between space-y-6 bg-black/40 p-6 sm:p-8 rounded-2xl border border-white/5">
<div>
<div className="flex items-center justify-between pb-4 border-b border-white/10">
<span className="text-xs font-mono uppercase tracking-wider text-slate-300 font-semibold">
IN THE FORGE (CURRENT IP)
</span>
<span className="w-2 h-2 rounded-full bg-cyan-400 animate-ping" />
</div>
<div className="space-y-4 mt-6">
{current.currentInitiatives.map((item, idx) => (
<div
key={idx}
className="glass-card p-4 rounded-xl border-white/5 hover:border-cyan-500/30 group"
>
<div className="flex items-center justify-between mb-1.5">
<h4 className="text-sm font-bold text-white font-mono group-hover:text-cyan-300 transition-colors">
{item.name}
</h4>
<span className="text-[10px] font-mono uppercase px-2 py-0.5 rounded bg-indigo-500/20 text-indigo-300 border border-indigo-400/30">
{item.stage}
</span>
</div>
<p className="text-xs text-slate-400">
{item.note}
</p>
</div>
))}
</div>
</div>
{/* Direct quick jump CTA */}
<a
href="#portfolio"
className="w-full flex items-center justify-center gap-2 py-3 px-4 rounded-xl font-mono text-xs uppercase tracking-wider font-semibold text-white glass-panel hover:border-cyan-400/50 hover:bg-white/10 transition-all duration-200 group"
>
<span>View All Works in Showcase</span>
<ArrowUpRight className="w-4 h-4 text-cyan-400 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform" />
</a>
</div>
</div>
</motion.div>
</AnimatePresence>
</div>
</section>
);
}
+260
View File
@@ -0,0 +1,260 @@
"use client";
import React, { useState } from "react";
import {
Sparkles,
ArrowRight,
Check,
Radio,
Globe,
Shield,
} from "lucide-react";
export default function Footer() {
const [email, setEmail] = useState("");
const [subscribed, setSubscribed] = useState(false);
const handleSubscribe = (e: React.FormEvent) => {
e.preventDefault();
if (email.trim().length > 3) {
setSubscribed(true);
setEmail("");
}
};
const socialLinks = [
{
name: "GitHub",
href: "https://github.com",
svg: (
<svg className="w-4 h-4 fill-current" viewBox="0 0 24 24">
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" />
</svg>
),
},
{
name: "X (Twitter)",
href: "https://x.com",
svg: (
<svg className="w-4 h-4 fill-current" viewBox="0 0 24 24">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
),
},
{
name: "Discord",
href: "https://discord.com",
svg: (
<svg className="w-4 h-4 fill-current" viewBox="0 0 24 24">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994.021-.041.001-.09-.041-.106a13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.929 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.894.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
</svg>
),
},
{
name: "Steam",
href: "https://store.steampowered.com",
svg: (
<svg className="w-4 h-4 fill-current" viewBox="0 0 24 24">
<path d="M12 2a10 10 0 0 0-10 10c0 4.767 3.339 8.75 7.828 9.742l3.418-4.992a3.02 3.02 0 0 1-.246-.145l-4.524 1.86a2.022 2.022 0 0 1-2.476-2.476l1.86-4.524a3 3 0 0 1 4.14-4.14l4.524-1.86a2.02 2.02 0 0 1 2.476 2.476l-1.86 4.524c.063.078.113.162.15.251l4.992-3.418A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16z" />
</svg>
),
},
{
name: "itch.io",
href: "https://itch.io",
svg: (
<svg className="w-4 h-4 fill-current" viewBox="0 0 24 24">
<path d="M2.5 5.5v2.2c0 .9.7 1.8 1.6 1.8.9 0 1.6-.9 1.6-1.8V5.5H2.5zm4.8 0v2.2c0 .9.7 1.8 1.6 1.8.9 0 1.6-.9 1.6-1.8V5.5H7.3zm4.8 0v2.2c0 .9.7 1.8 1.6 1.8.9 0 1.6-.9 1.6-1.8V5.5h-3.2zm4.8 0v2.2c0 .9.7 1.8 1.6 1.8.9 0 1.6-.9 1.6-1.8V5.5h-3.2zm4.8 0v2.2c0 .9.7 1.8 1.6 1.8.9 0 1.6-.9 1.6-1.8V5.5h-3.2zM2 11.5c0 1.7 1.1 3.2 2.7 3.5v5.5c0 .8.7 1.5 1.5 1.5h11.6c.8 0 1.5-.7 1.5-1.5V15c1.6-.3 2.7-1.8 2.7-3.5H2zm7 3h6v2H9v-2z" />
</svg>
),
},
];
return (
<footer className="relative border-t border-white/10 bg-[#08080f] pt-20 pb-12 overflow-hidden">
{/* Background ambient lighting */}
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[600px] h-[300px] bg-indigo-500/10 rounded-full blur-[140px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Top Section: Newsletter Transmissions */}
<div className="glass-panel p-8 sm:p-12 rounded-3xl border border-white/10 mb-16 relative overflow-hidden">
<div className="absolute top-0 right-0 w-80 h-80 bg-cyan-500/10 rounded-full blur-[100px] pointer-events-none" />
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
<div className="lg:col-span-7 space-y-3">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-cyan-500/10 border border-cyan-400/20 text-[11px] font-mono text-cyan-300">
<Radio className="w-3 h-3 text-cyan-400 animate-pulse" />
<span>FREQUENCY DISPATCH // DIRECT FEED</span>
</div>
<h3 className="text-2xl sm:text-3xl font-extrabold text-white font-mono">
Join the Aghatis Orbital Transmissions
</h3>
<p className="text-sm text-slate-400 max-w-xl">
Receive confidential dispatches on original software alpha testing, closed game playtests, and deep-dive engineering devlogs. Zero marketing spam.
</p>
</div>
<div className="lg:col-span-5">
{subscribed ? (
<div className="p-4 rounded-2xl bg-cyan-950/40 border border-cyan-400/30 flex items-center gap-3 text-xs font-mono text-cyan-300">
<Check className="w-5 h-5 text-cyan-400" />
<span>SIGNAL LOCKED. You are registered for upcoming playtests.</span>
</div>
) : (
<form onSubmit={handleSubscribe} className="flex flex-col sm:flex-row gap-3">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="[email protected]"
required
className="flex-1 px-4 py-3 rounded-xl bg-white/5 border border-white/15 text-white placeholder-slate-500 text-xs font-mono focus:outline-none focus:border-cyan-400 transition-colors"
/>
<button
type="submit"
className="px-6 py-3 rounded-xl bg-gradient-to-r from-cyan-400 to-indigo-400 text-slate-950 font-mono text-xs uppercase tracking-wider font-bold hover:opacity-90 transition-opacity flex items-center justify-center gap-2 shrink-0 cursor-pointer shadow-lg"
>
<span>Tune In</span>
<ArrowRight className="w-3.5 h-3.5 text-slate-950" />
</button>
</form>
)}
</div>
</div>
</div>
{/* Middle Section: Studio Details & Links */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-10 pb-16 border-b border-white/10">
{/* Col 1: Studio Brand */}
<div className="lg:col-span-5 space-y-4">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-gradient-to-tr from-cyan-400 to-indigo-500 flex items-center justify-center text-slate-950 font-black text-xs">
AS
</div>
<span className="font-mono font-bold tracking-widest text-lg text-white">
AGHATIS STUDIO
</span>
</div>
<p className="text-xs text-slate-400 leading-relaxed max-w-sm">
An independent product laboratory crafting original software, atmospheric games,
and experimental systems. Dedicated exclusively to our own in-house creative universe.
</p>
<div className="flex items-center gap-2 text-xs font-mono text-cyan-400 pt-2">
<span className="w-2 h-2 rounded-full bg-cyan-400 animate-ping" />
<span>ORBITAL BEACON: ACTIVE // SECTOR 01</span>
</div>
</div>
{/* Col 2: Navigation */}
<div className="lg:col-span-2 space-y-3">
<h4 className="text-xs font-mono uppercase tracking-wider text-white font-bold">
NAVIGATION
</h4>
<ul className="space-y-2 text-xs font-mono text-slate-400">
<li>
<a href="#about" className="hover:text-cyan-300 transition-colors">
Studio Narrative
</a>
</li>
<li>
<a href="#focus" className="hover:text-cyan-300 transition-colors">
Core Tracks
</a>
</li>
<li>
<a href="#portfolio" className="hover:text-cyan-300 transition-colors">
Product Fleet
</a>
</li>
<li>
<a href="#creed" className="hover:text-cyan-300 transition-colors">
Sovereign Creed
</a>
</li>
<li>
<a href="/admin" className="text-cyan-400 hover:text-cyan-300 transition-colors flex items-center gap-1">
<span>Admin Cockpit</span>
<span className="text-[9px] px-1 rounded bg-cyan-500/20">DB</span>
</a>
</li>
</ul>
</div>
{/* Col 3: Product Tracks */}
<div className="lg:col-span-2 space-y-3">
<h4 className="text-xs font-mono uppercase tracking-wider text-white font-bold">
PORTFOLIO
</h4>
<ul className="space-y-2 text-xs font-mono text-slate-400">
<li>
<a href="#portfolio" className="hover:text-cyan-300 transition-colors">
Aetheria: Chrono Drift
</a>
</li>
<li>
<a href="#portfolio" className="hover:text-cyan-300 transition-colors">
NebulaFlow
</a>
</li>
<li>
<a href="#portfolio" className="hover:text-cyan-300 transition-colors">
Voidwalker OS
</a>
</li>
<li>
<a href="#portfolio" className="hover:text-cyan-300 transition-colors">
ChromaSynth Lab
</a>
</li>
</ul>
</div>
{/* Col 4: Transmissions & Socials */}
<div className="lg:col-span-3 space-y-3">
<h4 className="text-xs font-mono uppercase tracking-wider text-white font-bold">
CHANNELS
</h4>
<div className="flex flex-wrap gap-2 pt-1">
{socialLinks.map((link) => (
<a
key={link.name}
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="p-2.5 rounded-xl glass-card text-slate-400 hover:text-white hover:border-cyan-400/50 hover:bg-white/5 transition-all"
aria-label={link.name}
>
{link.svg}
</a>
))}
</div>
<p className="text-[11px] font-mono text-slate-400 pt-2">
PGP Encrypted Public Key: 0x8F4E...91A
</p>
</div>
</div>
{/* Bottom Bar & Implicit In-House Studio Disclaimer */}
<div className="pt-8 flex flex-col md:flex-row items-center justify-between gap-6">
{/* Studio Focus Charter */}
<div className="flex items-start sm:items-center gap-3 text-xs font-mono text-slate-400 max-w-2xl">
<Shield className="w-4 h-4 text-cyan-400 shrink-0 mt-0.5 sm:mt-0" />
<p>
<strong className="text-slate-300">STUDIO CHARTER:</strong> An independent product laboratory dedicated to engineering high-performance creative software and publishing atmospheric, narrative-driven games.
</p>
</div>
<div className="text-xs font-mono text-slate-400 shrink-0">
© 2026 Aghatis Studio. All rights reserved.
</div>
</div>
</div>
</footer>
);
}
+180
View File
@@ -0,0 +1,180 @@
"use client";
import React from "react";
import dynamic from "next/dynamic";
import { motion } from "framer-motion";
import { ArrowRight, Terminal, Sparkles, Orbit } from "lucide-react";
// Dynamically import 3D Hero Solar System with sleek animated fallback
const HeroSolarSystem = dynamic(
() => import("../canvas/HeroSolarSystem"),
{
ssr: false,
loading: () => (
<div className="relative w-full h-[400px] sm:h-[480px] lg:h-[540px] flex items-center justify-center">
{/* Animated CSS Solar System Loading State */}
<div className="relative w-72 h-72 sm:w-96 sm:h-96 flex items-center justify-center">
{/* Central Sun Glow */}
<div className="w-16 h-16 rounded-full bg-gradient-to-tr from-cyan-400 to-indigo-500 shadow-[0_0_50px_#38bdf8] animate-pulse" />
{/* Orbit Track 1 */}
<div className="absolute w-36 h-36 rounded-full border border-cyan-500/30 animate-[spin_6s_linear_infinite]">
<div className="w-3 h-3 rounded-full bg-amber-400 shadow-[0_0_10px_#fbbf24] -translate-x-1.5" />
</div>
{/* Orbit Track 2 */}
<div className="absolute w-56 h-56 rounded-full border border-indigo-500/30 animate-[spin_10s_linear_infinite]">
<div className="w-4 h-4 rounded-full bg-cyan-400 shadow-[0_0_12px_#38bdf8] -translate-x-2" />
</div>
{/* Orbit Track 3 */}
<div className="absolute w-80 h-80 rounded-full border border-purple-500/25 animate-[spin_16s_linear_infinite]">
<div className="w-5 h-5 rounded-full bg-purple-400 shadow-[0_0_15px_#c084fc] -translate-x-2.5" />
</div>
<div className="absolute bottom-4 px-3 py-1 rounded-full glass-panel text-[11px] font-mono text-cyan-300">
CONNECTING STELLAR TELEMETRY...
</div>
</div>
</div>
),
}
);
export default function Hero() {
const telemetryStats = [
{ label: "IP Ownership", value: "100%", subtext: "In-House Creations" },
{ label: "Product Focus", value: "Pure IP", subtext: "Dedicated In-House Pipeline" },
{ label: "Active Tracks", value: "3", subtext: "Software, Games, Lab" },
{ label: "Studio State", value: "Autonomous", subtext: "Self-Sovereign Roadmap" },
];
return (
<section className="relative min-h-[92vh] pt-28 sm:pt-32 pb-20 flex flex-col justify-center overflow-hidden">
{/* Decorative cosmic glow halos */}
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[400px] bg-gradient-to-tr from-indigo-500/10 via-purple-500/10 to-cyan-500/10 blur-[130px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10 w-full">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-8 items-start">
{/* Left Column: Brand Statement & Typography */}
<div className="lg:col-span-6 space-y-6 text-center lg:text-left">
{/* Main Headline */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7 }}
className="space-y-3"
>
<h1 className="text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-black tracking-tight leading-[1.08]">
Synthesizing <br />
<span className="text-gradient-cyan">Original Software</span> <br />
<span className="text-white">& Interactive Worlds.</span>
</h1>
<p className="text-base sm:text-lg lg:text-xl text-slate-400 font-normal max-w-2xl mx-auto lg:mx-0 leading-relaxed pt-2">
Aghatis Studio operates exclusively as an autonomous product laboratory.
We engineer bespoke software tools, forge atmospheric indie games,
and explore experimental computational frontiers with relentless dedication to craft.
</p>
</motion.div>
{/* Core Capability Chips */}
<motion.div
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.15 }}
className="flex flex-wrap items-center justify-center lg:justify-start gap-2 pt-1"
>
{[
"GPU Shaders & WebGPU",
"Kinetic Orbital Physics",
"Local-First Architectures",
"Procedural Audio Engines",
].map((chip) => (
<span
key={chip}
className="px-2.5 py-1 rounded-md text-[11px] font-mono bg-white/5 border border-white/10 text-slate-300 hover:border-cyan-400/40 hover:text-white transition-colors"
>
{chip}
</span>
))}
</motion.div>
{/* Call to Actions */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.2 }}
className="flex flex-col sm:flex-row items-center justify-center lg:justify-start gap-4 pt-2"
>
<a
href="#portfolio"
className="w-full sm:w-auto px-7 py-3.5 rounded-xl font-mono text-xs uppercase tracking-widest font-bold text-slate-950 bg-gradient-to-r from-cyan-400 via-sky-300 to-indigo-300 hover:opacity-95 shadow-[0_0_30px_rgba(56,189,248,0.4)] transition-all duration-300 flex items-center justify-center gap-2 group hover:scale-[1.02] active:scale-95"
>
<Sparkles className="w-4 h-4 text-slate-950" />
<span>Explore Fleet</span>
<ArrowRight className="w-4 h-4 text-slate-950 group-hover:translate-x-1 transition-transform" />
</a>
<a
href="#creed"
className="w-full sm:w-auto px-6 py-3.5 rounded-xl font-mono text-xs uppercase tracking-widest font-semibold text-slate-300 hover:text-white glass-panel hover:border-indigo-500/50 transition-all duration-300 flex items-center justify-center gap-2 group"
>
<Terminal className="w-4 h-4 text-indigo-400" />
<span>The Studio Creed</span>
</a>
</motion.div>
{/* Studio Focus Badge */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.8, delay: 0.3 }}
className="pt-2 text-xs font-mono text-slate-400 flex items-center justify-center lg:justify-start gap-2"
>
<Orbit className="w-3.5 h-3.5 text-indigo-400" />
<span>Dedicated strictly to researching, building, and publishing our own product ecosystem.</span>
</motion.div>
</div>
{/* Right Column: 3D Solar System Visualization (Full Frustum Uncropped, Raised to Align with Headline) */}
<div className="lg:col-span-6 relative flex items-center justify-center lg:-mt-10 xl:-mt-14">
<HeroSolarSystem />
</div>
</div>
{/* Telemetry Stats Bar */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.4 }}
className="mt-16 sm:mt-20 pt-8 border-t border-white/10"
>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 sm:gap-8">
{telemetryStats.map((stat, i) => (
<div
key={i}
className="glass-card p-5 rounded-2xl relative overflow-hidden group hover:border-cyan-500/30"
>
<div className="absolute top-0 left-0 w-12 h-1 bg-gradient-to-r from-cyan-400 to-indigo-500 group-hover:w-full transition-all duration-500" />
<div className="text-2xl sm:text-3xl font-black font-mono tracking-tight text-white group-hover:text-cyan-300 transition-colors">
{stat.value}
</div>
<div className="text-xs font-mono uppercase tracking-wider text-slate-300 mt-1">
{stat.label}
</div>
<div className="text-[11px] font-mono text-slate-400 mt-1">
{stat.subtext}
</div>
</div>
))}
</div>
</motion.div>
</div>
</section>
);
}
+161
View File
@@ -0,0 +1,161 @@
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Sparkles, Menu, X, Compass, Layers, ShieldCheck, Box } from "lucide-react";
import CosmicAudioToggle from "../ui/CosmicAudioToggle";
export default function Navbar() {
const [scrolled, setScrolled] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 20);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const navLinks = [
{ name: "About", href: "#about", icon: Compass },
{ name: "Core Tracks", href: "#focus", icon: Layers },
{ name: "Showcase", href: "#portfolio", icon: Box },
{ name: "Studio Creed", href: "#creed", icon: ShieldCheck },
];
return (
<header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
scrolled
? "py-3 bg-[#0a0a12]/80 backdrop-blur-xl border-b border-white/10 shadow-[0_4px_30px_rgba(0,0,0,0.5)]"
: "py-5 bg-transparent"
}`}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between">
{/* Brand Logo */}
<a
href="#"
className="flex items-center gap-3 group focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-400 rounded-lg p-1"
>
<div className="relative flex items-center justify-center w-10 h-10 rounded-xl bg-gradient-to-br from-indigo-500/20 via-purple-500/10 to-cyan-500/20 border border-white/15 group-hover:border-cyan-400/50 transition-colors shadow-inner">
<span className="w-2.5 h-2.5 rounded-full bg-cyan-400 group-hover:scale-125 transition-transform shadow-[0_0_12px_#38bdf8]" />
<div className="absolute inset-0 rounded-xl border border-indigo-500/30 group-hover:rotate-45 transition-transform duration-500 pointer-events-none" />
</div>
<div className="flex flex-col">
<div className="flex items-center gap-2">
<span className="font-extrabold tracking-widest text-lg text-white group-hover:text-cyan-200 transition-colors">
AGHATIS
</span>
<span className="text-[10px] font-mono tracking-widest uppercase px-1.5 py-0.5 rounded bg-indigo-500/15 border border-indigo-400/20 text-indigo-300">
STUDIO
</span>
</div>
<span className="text-[10px] font-mono text-slate-400 tracking-wider">
ORIGINAL IP LAB
</span>
</div>
</a>
{/* Desktop Navigation Links */}
<nav className="hidden md:flex items-center gap-1 glass-panel px-4 py-1.5 rounded-full border border-white/10">
{navLinks.map((link) => (
<a
key={link.name}
href={link.href}
className="px-3.5 py-1.5 text-xs font-mono uppercase tracking-wider text-slate-300 hover:text-white rounded-full hover:bg-white/5 transition-all duration-200"
>
{link.name}
</a>
))}
</nav>
{/* Right actions: Audio Toggle, Live Status & CTA */}
<div className="hidden sm:flex items-center gap-3">
<CosmicAudioToggle />
{/* In-house status pill */}
<div className="hidden lg:flex items-center gap-2 px-3 py-1.5 rounded-full bg-indigo-950/40 border border-indigo-500/20 text-[11px] font-mono text-indigo-200">
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" />
<span>100% PRODUCT LAB</span>
</div>
<a
href="#portfolio"
className="relative inline-flex items-center justify-center px-4 py-2 text-xs font-mono tracking-wider font-semibold uppercase text-slate-900 bg-gradient-to-r from-cyan-400 via-sky-300 to-indigo-300 rounded-lg shadow-[0_0_20px_rgba(56,189,248,0.35)] hover:shadow-[0_0_25px_rgba(56,189,248,0.6)] transition-all duration-300 hover:scale-[1.02] active:scale-95"
>
<Sparkles className="w-3.5 h-3.5 mr-1.5 text-slate-950" />
Explore IP
</a>
</div>
{/* Mobile Menu Button */}
<div className="flex sm:hidden items-center gap-2">
<CosmicAudioToggle />
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="p-2 rounded-lg glass-panel text-slate-300 hover:text-white focus:outline-none"
aria-label="Toggle navigation menu"
>
{mobileMenuOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
</button>
</div>
</div>
</div>
{/* Mobile Drawer Menu */}
<AnimatePresence>
{mobileMenuOpen && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.25 }}
className="sm:hidden border-b border-white/10 bg-[#0a0a12]/95 backdrop-blur-2xl overflow-hidden"
>
<div className="px-6 py-6 space-y-4">
<div className="flex items-center justify-between pb-3 border-b border-white/10 text-xs font-mono text-slate-400">
<span>SECTOR // AGH-MOBILE-HUD</span>
<span className="text-cyan-400">STATUS: NOMINAL</span>
</div>
<div className="space-y-1">
{navLinks.map((link) => {
const Icon = link.icon;
return (
<a
key={link.name}
href={link.href}
onClick={() => setMobileMenuOpen(false)}
className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-mono text-slate-300 hover:text-white hover:bg-white/5 transition-colors"
>
<Icon className="w-4 h-4 text-cyan-400" />
<span>{link.name}</span>
</a>
);
})}
</div>
<div className="pt-2">
<a
href="#portfolio"
onClick={() => setMobileMenuOpen(false)}
className="w-full flex items-center justify-center gap-2 px-4 py-3 text-xs font-mono uppercase tracking-wider font-semibold text-slate-950 bg-gradient-to-r from-cyan-400 to-indigo-400 rounded-lg shadow-lg"
>
<Sparkles className="w-4 h-4 text-slate-950" />
Explore Original IP
</a>
</div>
<div className="text-[11px] font-mono text-center text-slate-400 pt-2 border-t border-white/5">
Independent Product Studio • Original Software & Games
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</header>
);
}
+501
View File
@@ -0,0 +1,501 @@
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
Sparkles,
ArrowUpRight,
Gamepad2,
Terminal,
FlaskConical,
X,
ExternalLink,
Cpu,
Layers,
Calendar,
ShieldCheck,
} from "lucide-react";
interface Product {
id: string;
title: string;
category: "software" | "games" | "lab";
categoryLabel: string;
tagline: string;
status: string;
statusType: "active" | "alpha" | "prototype" | "upcoming";
releaseTarget: string;
description: string;
longDescription: string;
features: string[];
stack: string[];
accentGradient: string;
borderGlow: string;
icon: typeof Gamepad2;
}
export default function Portfolio() {
const [filter, setFilter] = useState<string>("all");
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);
const [productsList, setProductsList] = useState<Product[]>([]);
React.useEffect(() => {
setProductsList(initialProducts);
async function fetchFromDB() {
try {
const res = await fetch("/api/projects");
if (res.ok) {
const json = await res.json();
if (json.success && Array.isArray(json.data) && json.data.length > 0) {
interface ApiProject {
id: string;
title: string;
category: "software" | "games" | "lab";
categoryLabel: string;
tagline: string;
status: string;
statusType: "active" | "alpha" | "prototype" | "upcoming";
releaseTarget: string;
description: string;
longDescription: string;
features: string[];
stack: string[];
accentGradient: string;
borderGlow: string;
iconName: string;
}
const mapped: Product[] = json.data.map((p: ApiProject) => ({
...p,
icon:
p.iconName === "Gamepad2"
? Gamepad2
: p.iconName === "FlaskConical"
? FlaskConical
: Terminal,
}));
setProductsList(mapped);
}
}
} catch {
// Fallback silently to initial products
}
}
fetchFromDB();
}, []);
const initialProducts: Product[] = [
{
id: "aetheria",
title: "Aetheria: Chrono Drift",
category: "games",
categoryLabel: "Tactical Flight RPG",
tagline: "Atmospheric spaceflight RPG driven by Newtonian physics & relativistic time mechanics.",
status: "In Active Dev",
statusType: "active",
releaseTarget: "Alpha 2027",
description:
"Pilot handcrafted atmospheric ships through uncharted cosmic sectors. Engage in tactical orbital maneuvers where time dilates with engine velocity.",
longDescription:
"Aetheria is our flagship narrative sci-fi title. Designed without live-service grind or predatory mechanics, it centers on contemplative space exploration, deep Newtonian flight kinematics, and an original interactive dark-ambient synth score.",
features: [
"True orbital mechanics and gravitational slingshots",
"Non-linear stellar narrative with faction autonomy",
"Zero-compromise single-player standalone artistic experience",
"Procedurally synthesized nebula volumetric rendering",
],
stack: ["Godot 4.3", "C++ GDExtension", "Bespoke GLSL", "FMOD Sound Engine"],
accentGradient: "from-cyan-500/20 via-blue-600/10 to-transparent",
borderGlow: "hover:border-cyan-400/50 hover:shadow-[0_0_30px_rgba(56,189,248,0.25)]",
icon: Gamepad2,
},
{
id: "nebulaflow",
title: "NebulaFlow",
category: "software",
categoryLabel: "Creative Shader Pipeline",
tagline: "Node-based real-time GPU shader workbench & procedural VFX engine.",
status: "Private Alpha",
statusType: "alpha",
releaseTarget: "Beta Q3 2027",
description:
"A high-performance visual coding environment for creative coders, game devs, and technical artists compiling directly to WGSL and GLSL.",
longDescription:
"NebulaFlow re-imagines real-time shader generation. Designed with a lightweight Rust core and a distraction-free spatial interface, it compiles visual nodes directly into native shaders at 120 FPS with instantaneous hot-reloading.",
features: [
"Instant compilation to WGSL, GLSL, and Metal Shading Language",
"Deterministic local-first project workspace without cloud locks",
"Live audio-reactive parameter modulation via WebAudio / ASIO",
"Integrated raymarching and compute shader node library",
],
stack: ["Rust", "WebGPU", "Tauri", "TypeScript", "WGSL"],
accentGradient: "from-purple-500/20 via-indigo-600/10 to-transparent",
borderGlow: "hover:border-purple-400/50 hover:shadow-[0_0_30px_rgba(168,85,247,0.25)]",
icon: Terminal,
},
{
id: "voidwalker",
title: "Voidwalker OS",
category: "software",
categoryLabel: "Spatial Workstation",
tagline: "Distraction-free spatial terminal and local knowledge workstation for intense focus.",
status: "Prototype",
statusType: "prototype",
releaseTarget: "Q4 2027",
description:
"An experimental desktop environment stripping away notification clutter in favor of an ergonomic cosmic workspace and local neural indexing.",
longDescription:
"Voidwalker replaces chaotic desktop windows with an infinite 2.5D orbital plane. Crafted for independent developers and creative writers who demand absolute cognitive quiet.",
features: [
"Local-first vector indexing over personal markdown & codebases",
"Orbital workspace clustering with keyboard-centric navigation",
"Sub-10ms input latency with custom GPU text rendering engine",
"Zero tracking, zero analytics, zero telemetry overhead",
],
stack: ["Rust", "SQLite", "Vulkan / Metal", "Tree-Sitter"],
accentGradient: "from-indigo-500/20 via-sky-600/10 to-transparent",
borderGlow: "hover:border-indigo-400/50 hover:shadow-[0_0_30px_rgba(99,102,241,0.25)]",
icon: Terminal,
},
{
id: "singularity-pulse",
title: "Singularity Pulse",
category: "games",
categoryLabel: "Kinetic Rhythm-Strategy",
tagline: "Orbital rhythm defense game where celestial gravitational waves dictate combat tempo.",
status: "Playable Slice",
statusType: "prototype",
releaseTarget: "2027",
description:
"Defend dying binary stars from quantum anomalies by aligning resonant frequencies in time with an escalating electronic pulse.",
longDescription:
"Built at the intersection of rhythm gaming and orbital physics, Singularity Pulse challenges players to synchronize defensive shields with gravitational wave oscillations in real-time.",
features: [
"Dynamic sound-reactive procedural enemy generation",
"Precise sub-millisecond input synchronization",
"Full support for analog sticks, arcade sticks, and MIDI input",
"Minimalist wireframe vector aesthetic inspired by 80s arcade radars",
],
stack: ["Godot", "WebAudio", "Procedural GLSL"],
accentGradient: "from-pink-500/20 via-rose-600/10 to-transparent",
borderGlow: "hover:border-pink-400/50 hover:shadow-[0_0_30px_rgba(244,63,94,0.25)]",
icon: Gamepad2,
},
{
id: "chromasynth",
title: "ChromaSynth Lab",
category: "lab",
categoryLabel: "Spatial Sound Synthesis",
tagline: "WebGPU audio-reactive 3D synthesis tool exploring geometric resonance.",
status: "Public Experiment",
statusType: "alpha",
releaseTarget: "Live Now",
description:
"A browser-based generative instrument generating real-time higher-dimensional geometric manifolds modulated by live microphone and MIDI input.",
longDescription:
"ChromaSynth began as a weekend exploration in our experimental lab. It treats polyphonic audio frequencies as physical forces that deform complex geometric meshes in real time.",
features: [
"Modular 8-oscillator additive & FM synthesis engine",
"Real-time 4D hypercube and manifold geometry projection",
"Exportable high-res WebM / MP4 video stems for VJs",
"Open-source computational code released for researchers",
],
stack: ["Three.js", "Web Audio API", "GLSL Compute", "WebAssembly"],
accentGradient: "from-emerald-500/20 via-teal-600/10 to-transparent",
borderGlow: "hover:border-emerald-400/50 hover:shadow-[0_0_30px_rgba(16,185,129,0.25)]",
icon: FlaskConical,
},
{
id: "event-horizon",
title: "Project Event Horizon",
category: "lab",
categoryLabel: "Procedural Cosmos R&D",
tagline: "Compute-shader planetary terrain synthesis & atmospheric Rayleigh scattering.",
status: "R&D Prototype",
statusType: "prototype",
releaseTarget: "Continuous R&D",
description:
"Algorithmic generation of continental scale geological plates, biome micro-climates, and photorealistic atmospheric scattering.",
longDescription:
"The technological foundation for our future game worlds. Event Horizon runs entirely on GPU compute shaders to generate planet-scale terrain down to individual pebbles seamlessly.",
features: [
"Seamless transition from interplanetary orbit down to surface level",
"Physical simulation of tectonic drift and erosion patterns",
"Atmospheric volumetric cloud synthesis using 3D Worley noise",
"Powers the underlying engine for upcoming Aghatis game titles",
],
stack: ["WGSL Compute", "Rust", "WebGPU"],
accentGradient: "from-amber-500/20 via-orange-600/10 to-transparent",
borderGlow: "hover:border-amber-400/50 hover:shadow-[0_0_30px_rgba(245,158,11,0.25)]",
icon: FlaskConical,
},
];
const filteredProducts =
filter === "all"
? productsList
: productsList.filter((p) => p.category === filter);
return (
<section id="portfolio" className="relative py-28 overflow-hidden">
{/* Background celestial glow */}
<div className="absolute top-1/2 left-1/3 w-[600px] h-[600px] bg-cyan-600/10 rounded-full blur-[170px] pointer-events-none" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Section Header */}
<div className="flex flex-col items-center text-center max-w-3xl mx-auto mb-16 space-y-4">
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full glass-panel border border-indigo-500/30 text-xs font-mono text-indigo-300">
<Sparkles className="w-3.5 h-3.5 text-indigo-400" />
<span>ORIGINAL IP FLEET</span>
</div>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-black tracking-tight text-white">
Proprietary Works & <br />
<span className="text-gradient-cyan">Upcoming Titles.</span>
</h2>
<p className="text-base sm:text-lg text-slate-400 leading-relaxed pt-2">
Every product showcased below is conceived, engineered, and published in-house
as part of our permanent creative universe and software ecosystem.
</p>
</div>
{/* Filter Controls */}
<div className="flex flex-wrap items-center justify-center gap-2 sm:gap-3 mb-14">
{[
{ id: "all", label: "All Works (06)" },
{ id: "software", label: "Software Products" },
{ id: "games", label: "Original Games" },
{ id: "lab", label: "Experimental Lab" },
].map((tab) => (
<button
key={tab.id}
onClick={() => setFilter(tab.id)}
className={`px-4 py-2 rounded-xl font-mono text-xs uppercase tracking-wider transition-all duration-200 cursor-pointer ${
filter === tab.id
? "bg-cyan-500/20 border border-cyan-400/50 text-cyan-300 shadow-[0_0_15px_rgba(56,189,248,0.25)]"
: "glass-card text-slate-400 hover:text-slate-200 hover:border-white/20"
}`}
>
{tab.label}
</button>
))}
</div>
{/* Products Grid */}
<motion.div
layout
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8"
>
<AnimatePresence>
{filteredProducts.map((product) => {
const Icon = product.icon;
return (
<motion.div
layout
key={product.id}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.3 }}
className={`glass-card rounded-2xl flex flex-col justify-between overflow-hidden relative group cursor-pointer transition-all duration-300 ${product.borderGlow}`}
onClick={() => setSelectedProduct(product)}
>
{/* Visual card header area with cosmetic cosmic pattern */}
<div className={`relative h-44 w-full bg-gradient-to-b ${product.accentGradient} p-6 flex flex-col justify-between border-b border-white/5`}>
<div className="flex items-center justify-between">
<span className="text-[10px] font-mono uppercase px-2.5 py-1 rounded-full bg-black/50 backdrop-blur-md border border-white/10 text-cyan-300">
{product.categoryLabel}
</span>
<span className="text-[10px] font-mono uppercase px-2.5 py-1 rounded-full bg-indigo-950/60 border border-indigo-400/20 text-indigo-300 flex items-center gap-1.5">
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" />
{product.status}
</span>
</div>
{/* Centered stylized graphic watermark */}
<div className="flex items-center justify-between">
<div className="w-12 h-12 rounded-2xl bg-black/40 border border-white/10 flex items-center justify-center text-cyan-400 group-hover:scale-110 transition-transform shadow-lg">
<Icon className="w-6 h-6" />
</div>
<span className="text-[11px] font-mono text-slate-400">
TARGET: {product.releaseTarget}
</span>
</div>
</div>
{/* Card Body */}
<div className="p-6 space-y-4 flex-1 flex flex-col justify-between">
<div>
<h3 className="text-xl font-bold font-mono text-white group-hover:text-cyan-300 transition-colors">
{product.title}
</h3>
<p className="text-xs font-mono text-cyan-400/80 mt-1">
{product.tagline}
</p>
<p className="text-xs text-slate-400 leading-relaxed mt-3">
{product.description}
</p>
</div>
<div className="space-y-4 pt-2">
{/* Tech stack badges */}
<div className="flex flex-wrap gap-1.5">
{product.stack.map((item) => (
<span
key={item}
className="text-[10px] font-mono px-2 py-0.5 rounded bg-white/5 border border-white/10 text-slate-300"
>
{item}
</span>
))}
</div>
{/* Card Footer action */}
<div className="pt-3 border-t border-white/5 flex items-center justify-between text-xs font-mono text-slate-400 group-hover:text-cyan-300 transition-colors">
<span>INSPECT SPEC & ARCHITECTURE</span>
<ArrowUpRight className="w-4 h-4 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform" />
</div>
</div>
</div>
</motion.div>
);
})}
</AnimatePresence>
</motion.div>
{/* In-House Notice banner */}
<div className="mt-16 p-6 rounded-2xl glass-panel border border-cyan-500/20 flex flex-col sm:flex-row items-center justify-between gap-4">
<div className="flex items-center gap-3">
<ShieldCheck className="w-5 h-5 text-cyan-400 shrink-0" />
<div className="text-xs font-mono text-slate-300">
<span className="font-bold text-white">AUTONOMOUS PRODUCT FLEET // </span>
Every title and utility is designed, developed, and maintained by Aghatis Studio from initial prototype to continuous release.
</div>
</div>
<a
href="#creed"
className="shrink-0 text-xs font-mono text-cyan-400 hover:text-cyan-300 flex items-center gap-1 underline underline-offset-4"
>
<span>Read Studio Philosophy</span>
<ArrowUpRight className="w-3.5 h-3.5" />
</a>
</div>
</div>
{/* Product Spec Detail Modal */}
<AnimatePresence>
{selectedProduct && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6">
{/* Backdrop */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setSelectedProduct(null)}
className="absolute inset-0 bg-black/80 backdrop-blur-xl"
/>
{/* Modal Dialog */}
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
transition={{ duration: 0.25 }}
className="relative w-full max-w-2xl bg-[#0e0e1c] border border-cyan-500/30 rounded-3xl p-6 sm:p-8 shadow-[0_0_60px_rgba(56,189,248,0.2)] max-h-[90vh] overflow-y-auto z-10 space-y-6"
>
{/* Close Button */}
<button
onClick={() => setSelectedProduct(null)}
className="absolute top-6 right-6 p-2 rounded-full glass-panel text-slate-400 hover:text-white transition-colors"
aria-label="Close modal"
>
<X className="w-5 h-5" />
</button>
{/* Header */}
<div className="space-y-2 pr-8">
<div className="flex items-center gap-2">
<span className="text-[11px] font-mono tracking-widest uppercase px-2.5 py-0.5 rounded bg-cyan-500/20 border border-cyan-400/30 text-cyan-300">
{selectedProduct.categoryLabel}
</span>
<span className="text-[11px] font-mono uppercase px-2.5 py-0.5 rounded bg-indigo-500/20 border border-indigo-400/30 text-indigo-300">
{selectedProduct.status}
</span>
</div>
<h3 className="text-2xl sm:text-3xl font-extrabold text-white font-mono">
{selectedProduct.title}
</h3>
<p className="text-sm font-mono text-cyan-400">
{selectedProduct.tagline}
</p>
</div>
{/* Overview & Narrative */}
<div className="space-y-3 pt-2 border-t border-white/10">
<h4 className="text-xs font-mono uppercase tracking-wider text-slate-400">
// PRODUCT MANIFESTO & PHILOSOPHY
</h4>
<p className="text-sm text-slate-300 leading-relaxed">
{selectedProduct.longDescription}
</p>
</div>
{/* Architectural Highlights */}
<div className="space-y-3">
<h4 className="text-xs font-mono uppercase tracking-wider text-slate-400">
// KEY ARCHITECTURAL CAPABILITIES
</h4>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5">
{selectedProduct.features.map((feat, i) => (
<div
key={i}
className="p-3 rounded-xl bg-white/5 border border-white/10 text-xs text-slate-300 flex items-start gap-2"
>
<Sparkles className="w-3.5 h-3.5 text-cyan-400 shrink-0 mt-0.5" />
<span>{feat}</span>
</div>
))}
</div>
</div>
{/* Tech Stack */}
<div className="space-y-3">
<h4 className="text-xs font-mono uppercase tracking-wider text-slate-400">
// COMPILED STACK & RUNTIME
</h4>
<div className="flex flex-wrap gap-2">
{selectedProduct.stack.map((item) => (
<span
key={item}
className="px-3 py-1 rounded-lg text-xs font-mono bg-indigo-950/40 border border-indigo-500/30 text-indigo-200"
>
{item}
</span>
))}
</div>
</div>
{/* Footer Meta */}
<div className="pt-4 border-t border-white/10 flex flex-col sm:flex-row items-center justify-between gap-4">
<div className="flex items-center gap-2 text-xs font-mono text-slate-400">
<Calendar className="w-4 h-4 text-cyan-400" />
<span>Target Deployment: {selectedProduct.releaseTarget}</span>
</div>
<button
onClick={() => setSelectedProduct(null)}
className="w-full sm:w-auto px-6 py-2.5 rounded-xl text-xs font-mono uppercase tracking-wider font-semibold bg-cyan-400 text-slate-950 hover:bg-cyan-300 transition-colors"
>
Close Specification
</button>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
</section>
);
}
+113
View File
@@ -0,0 +1,113 @@
"use client";
import React, { useState, useEffect, useRef } from "react";
import { Volume2, VolumeX } from "lucide-react";
export default function CosmicAudioToggle() {
const [isPlaying, setIsPlaying] = useState(false);
const audioCtxRef = useRef<AudioContext | null>(null);
const masterGainRef = useRef<GainNode | null>(null);
const osc1Ref = useRef<OscillatorNode | null>(null);
const osc2Ref = useRef<OscillatorNode | null>(null);
const toggleSound = () => {
if (isPlaying) {
if (masterGainRef.current && audioCtxRef.current) {
masterGainRef.current.gain.setTargetAtTime(
0,
audioCtxRef.current.currentTime,
0.5
);
setTimeout(() => {
setIsPlaying(false);
}, 500);
}
} else {
try {
const AudioCtx =
window.AudioContext ||
(window as unknown as { webkitAudioContext: typeof AudioContext })
.webkitAudioContext;
const ctx = audioCtxRef.current || new AudioCtx();
audioCtxRef.current = ctx;
if (ctx.state === "suspended") {
ctx.resume();
}
const masterGain = ctx.createGain();
masterGain.gain.setValueAtTime(0, ctx.currentTime);
masterGain.gain.linearRampToValueAtTime(0.08, ctx.currentTime + 1.5);
masterGain.connect(ctx.destination);
masterGainRef.current = masterGain;
// Lowpass filter for deep cosmic drone
const filter = ctx.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.setValueAtTime(140, ctx.currentTime);
filter.Q.setValueAtTime(2, ctx.currentTime);
filter.connect(masterGain);
// Oscillator 1: 55Hz sub drone
const osc1 = ctx.createOscillator();
osc1.type = "sine";
osc1.frequency.setValueAtTime(55, ctx.currentTime);
osc1.connect(filter);
osc1.start();
osc1Ref.current = osc1;
// Oscillator 2: 110.2Hz warm harmonic with slight detune
const osc2 = ctx.createOscillator();
osc2.type = "triangle";
osc2.frequency.setValueAtTime(110.3, ctx.currentTime);
const osc2Gain = ctx.createGain();
osc2Gain.gain.setValueAtTime(0.03, ctx.currentTime);
osc2.connect(osc2Gain);
osc2Gain.connect(filter);
osc2.start();
osc2Ref.current = osc2;
setIsPlaying(true);
} catch {
// Fallback gracefully if Web Audio is blocked
}
}
};
useEffect(() => {
return () => {
if (audioCtxRef.current && audioCtxRef.current.state !== "closed") {
try {
audioCtxRef.current.close();
} catch {
// Ignore
}
}
};
}, []);
return (
<button
onClick={toggleSound}
title={isPlaying ? "Mute Deep Space Ambience" : "Enable Deep Space Ambience"}
className="flex items-center gap-2 px-3 py-1.5 rounded-full glass-panel hover:border-indigo-500/40 text-xs font-mono tracking-wider text-slate-300 transition-all duration-300 hover:text-white group"
aria-label="Toggle Cosmic Soundscape"
>
{isPlaying ? (
<>
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-500"></span>
</span>
<Volume2 className="w-3.5 h-3.5 text-cyan-400 group-hover:scale-110 transition-transform" />
<span className="hidden sm:inline text-[11px] text-cyan-300">AUDIO: RESONANCE ON</span>
</>
) : (
<>
<VolumeX className="w-3.5 h-3.5 text-slate-400 group-hover:scale-110 transition-transform" />
<span className="hidden sm:inline text-[11px] text-slate-400">AUDIO: VOID</span>
</>
)}
</button>
);
}