502 lines
22 KiB
TypeScript
502 lines
22 KiB
TypeScript
"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>
|
|
);
|
|
}
|