Files
dicky arya pratama 13a47fbebf Initial Commit
Commit pertama, memindahkan repository dari github ke gitea.
2026-11-04 17:18:53 +07:00

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>
);
}