feat: Kinetic Ether 디자인 시스템 + 홈 대시보드형 재구성

- globals.css: --kx-* 토큰(서피스 4단계, 네온 퍼플/시안), Space Grotesk/Inter/Manrope
  도입(next/font), 글래스·글로우·폴더 컨테이너·버튼 유틸 클래스
- app/page.tsx v5: 워크스페이스형 대시보드(헤더+Engine Status 패널+Launch Pads
  그리드+Credibility Monitor+Final CTA), Stitch "Kinetic Ether" 참조
- "7년차 대기업 백엔드" 카피 전역 교체(현직 엔지니어/실무 엔지니어)
- /services/music 히어로 레이블·디스플레이 폰트 토큰 정합

참조: Downloads/stitch_ai_mv/{sonicai_main_landing_page, aether_forge, ...}

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 02:08:54 +09:00
parent 2c8a0f1c37
commit 6c74b2cc93
8 changed files with 324 additions and 341 deletions

View File

@@ -1,362 +1,252 @@
'use client';
import { useState, useEffect, useRef } from 'react';
import { useState } from 'react';
import Link from 'next/link';
import ContactModal from './components/ContactModal';
import { trackCTAClick } from '../lib/gtag';
/* ═══════════════════════════════════════════════════
쟁승메이드 홈 — v4 (AI Music 중심 개편)
1. Hero: AI 음악 팩 (메인 매출)
2. Sub: 사주 · 블로그팩 · 일반 문의
3. About: 신뢰 지표
쟁승메이드 홈 — v5 (Kinetic Ether Dashboard)
상단 라우터 페이지를 워크스페이스형 대시보드로 재구성.
═══════════════════════════════════════════════════ */
const LIVE_SERVICES = [
{ name: 'AI Music Pack', label: '메인 상품' },
{ name: 'AI 사주 분석', label: '무료 도구' },
{ name: '블로그 자동화 팩', label: '디지털 상품' },
];
function useScrollReveal() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1, rootMargin: '0px 0px -40px 0px' }
);
el.querySelectorAll('.reveal').forEach((child) => observer.observe(child));
return () => observer.disconnect();
}, []);
return ref;
interface Tile {
href: string;
label: string;
title: string;
desc: string;
tag: string;
tagColor: string;
onClick?: () => void;
}
export default function Home() {
const [modalOpen, setModalOpen] = useState(false);
const containerRef = useScrollReveal();
const tiles: Tile[] = [
{
href: '/services/music',
label: 'FLAGSHIP',
title: 'AI 음악 마스터',
desc: '네 사연을 노래로. 쇼츠까지 한 번에. Suno·Runway·유튜브 SEO를 묶은 4단계 공정 팩.',
tag: '₩39k~149k',
tagColor: 'var(--kx-primary)',
},
{
href: '/services/blog',
label: 'DIGITAL PACK',
title: '블로그 자동화 팩',
desc: '프롬프트 조합법 + 템플릿 PDF + 샘플. 쿠팡파트너스·애드포스트 수익화 루틴.',
tag: '₩29,000',
tagColor: 'var(--kx-secondary)',
},
{
href: '/saju',
label: 'FREE TOOL',
title: 'AI 사주 분석',
desc: '사주팔자 자동 산출 + Gemini 기반 해석. 검증된 계산 엔진.',
tag: 'FREE',
tagColor: '#40ceed',
},
];
return (
<div className="min-h-full" ref={containerRef}>
<div className="kx-section min-h-full relative overflow-hidden">
<ContactModal
isOpen={modalOpen}
onClose={() => setModalOpen(false)}
service="일반 문의"
checklist={[
'문의하고 싶은 내용을 간략히 설명해주세요',
'원하는 회신 방식 (이메일/전화)',
'기타 참고 사항',
]}
accentColor="text-violet-400"
headerFrom="#1e1b4b"
headerTo="#020617"
checklist={['연락처/이메일', '원하는 작업 범위', '희망 일정']}
/>
{/* ══════════════════════════════════════
HERO — AI Music 중심
══════════════════════════════════════ */}
<section
className="relative overflow-hidden px-6 py-24 lg:px-14 lg:py-32"
style={{
background:
'radial-gradient(circle at 20% 30%, #1e1b4b 0%, #020617 55%), radial-gradient(circle at 80% 70%, #0c4a6e 0%, transparent 50%)',
}}
>
{/* Noise overlay */}
<div
className="absolute inset-0 opacity-[0.04] pointer-events-none mix-blend-overlay"
style={{
backgroundImage:
"url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='0.5'/></svg>\")",
}}
/>
{/* Waveform decoration */}
<div className="absolute bottom-0 left-0 right-0 h-32 opacity-30 pointer-events-none">
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" className="w-full h-full">
<path
d="M0,60 Q150,10 300,60 T600,60 T900,60 T1200,60 L1200,120 L0,120 Z"
fill="url(#waveGrad)"
/>
<defs>
<linearGradient id="waveGrad" x1="0%" x2="100%">
<stop offset="0%" stopColor="#7c3aed" stopOpacity="0.4" />
<stop offset="50%" stopColor="#06b6d4" stopOpacity="0.3" />
<stop offset="100%" stopColor="#7c3aed" stopOpacity="0.4" />
</linearGradient>
</defs>
</svg>
</div>
{/* 배경 오브 */}
<div className="kx-orb" style={{ width: 520, height: 520, background: '#9c48ea', top: -180, left: -120 }} />
<div className="kx-orb" style={{ width: 420, height: 420, background: '#53ddfc', bottom: -150, right: -100, opacity: 0.25 }} />
<div className="kx-orb" style={{ width: 300, height: 300, background: '#cc97ff', top: '40%', right: '10%', opacity: 0.18 }} />
<div className="relative max-w-5xl mx-auto">
<div className="flex items-center gap-3 mb-8">
<span className="font-mono text-xs text-violet-300/70 tracking-[0.25em] uppercase">
× AI Music
</span>
<span className="flex items-center gap-1.5 text-xs text-emerald-400/80">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse" />
NEW
</span>
{/* 워크스페이스 헤더 */}
<header className="relative z-10 px-6 lg:px-12 pt-10 pb-6 border-b border-white/5">
<div className="flex items-center justify-between gap-4 flex-wrap">
<div>
<span className="kx-label">WORKSPACE / JAENGSEUNG.MAKE</span>
<h1 className="kx-display text-2xl md:text-3xl font-extrabold mt-1.5">
Creative Studio <span className="kx-gradient-text">Overview</span>
</h1>
</div>
<h1
className="text-[2.6rem] md:text-[3.5rem] lg:text-[5rem] font-extrabold leading-[1.05] tracking-tight mb-6"
style={{ wordBreak: 'keep-all' }}
>
<span className="text-white"> .</span>
<br />
<span className="bg-gradient-to-r from-violet-300 via-sky-200 to-cyan-300 bg-clip-text text-transparent">
.
<div className="flex items-center gap-3 text-xs" style={{ color: 'var(--kx-on-variant)' }}>
<span className="flex items-center gap-2">
<span className="inline-block w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
<span className="font-mono tracking-wider">SYSTEM ONLINE</span>
</span>
</h1>
<p
className="text-slate-300 text-lg md:text-xl leading-relaxed mb-4 max-w-2xl"
style={{ wordBreak: 'keep-all' }}
>
7 <span className="text-white font-semibold">AI 4 </span>.
<br />
(Suno) (Runway) .
</p>
<p className="text-slate-400 text-base mb-10 max-w-2xl">
39,000. .
</p>
<div className="flex flex-wrap gap-3 mb-14">
<Link
href="/services/music"
className="inline-flex items-center gap-2 bg-violet-600 hover:bg-violet-500 text-white px-8 py-4 rounded-xl font-bold text-sm transition-colors shadow-[0_0_40px_rgba(139,92,246,0.4)]"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</Link>
<Link
href="/saju"
className="inline-flex items-center gap-2 border border-white/15 hover:border-white/40 text-white/80 hover:text-white px-8 py-4 rounded-xl font-semibold text-sm transition-all"
>
</Link>
</div>
<div className="border-t border-white/8 pt-8">
<p className="font-mono text-[11px] text-violet-300/40 tracking-[0.25em] uppercase mb-4">
</p>
<div className="flex flex-wrap gap-6">
{LIVE_SERVICES.map((s) => (
<span key={s.name} className="flex items-center gap-2.5 text-sm text-slate-300">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse flex-shrink-0" />
<span className="font-semibold">{s.name}</span>
<span className="font-mono text-[11px] text-white/30">{s.label}</span>
</span>
))}
</div>
<span className="hidden md:inline font-mono">v2026.04</span>
</div>
</div>
</section>
</header>
{/* ══════════════════════════════════════
SECTION 2 — 서브 상품 카드
══════════════════════════════════════ */}
<section className="bg-white px-6 py-20 lg:px-14">
<div className="max-w-5xl mx-auto">
<div className="reveal mb-10">
<p className="font-mono text-xs text-violet-700/70 tracking-widest uppercase mb-2">
More Products
</p>
<h2
className="text-2xl md:text-3xl font-extrabold text-slate-900 leading-tight"
style={{ wordBreak: 'keep-all' }}
>
.
</h2>
<p className="text-slate-500 text-sm mt-2"> .</p>
</div>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
{/* 사주 */}
<Link
href="/saju"
className="reveal reveal-d1 group relative flex flex-col border border-slate-200 hover:border-violet-400/50 rounded-2xl p-6 transition-all hover:shadow-lg bg-gradient-to-br from-white to-violet-50/40"
>
<div className="flex items-center justify-between mb-4">
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-sky-500/15 text-sky-600 border border-sky-500/20">
</span>
<svg className="w-5 h-5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" />
</svg>
</div>
<h3 className="text-lg font-extrabold text-slate-900 mb-2 group-hover:text-violet-700 transition-colors">
AI
</h3>
<p className="text-slate-600 text-sm leading-relaxed flex-1 mb-5" style={{ wordBreak: 'keep-all' }}>
AI가 ··· .
</p>
<span className="text-violet-700 text-sm font-bold group-hover:underline">
</span>
</Link>
{/* 블로그팩 */}
<Link
href="/services/blog"
className="reveal reveal-d2 group relative flex flex-col border border-slate-200 hover:border-blue-400/50 rounded-2xl p-6 transition-all hover:shadow-lg bg-white"
>
<div className="flex items-center justify-between mb-4">
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-blue-500/15 text-blue-600 border border-blue-500/20">
29,000
</span>
<svg className="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</div>
<h3 className="text-lg font-extrabold text-slate-900 mb-2 group-hover:text-blue-700 transition-colors">
</h3>
<p className="text-slate-600 text-sm leading-relaxed flex-1 mb-5" style={{ wordBreak: 'keep-all' }}>
· ·릿· .
</p>
<span className="text-blue-700 text-sm font-bold group-hover:underline">
</span>
</Link>
{/* 일반 문의 */}
<button
onClick={() => {
trackCTAClick('일반 문의', '/');
setModalOpen(true);
}}
className="reveal reveal-d3 group relative flex flex-col text-left border border-slate-200 hover:border-slate-400 rounded-2xl p-6 transition-all hover:shadow-lg bg-white"
>
<div className="flex items-center justify-between mb-4">
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-slate-500/15 text-slate-600 border border-slate-500/20">
·
</span>
<svg className="w-5 h-5 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
</svg>
</div>
<h3 className="text-lg font-extrabold text-slate-900 mb-2 group-hover:text-slate-700 transition-colors">
</h3>
<p className="text-slate-600 text-sm leading-relaxed flex-1 mb-5" style={{ wordBreak: 'keep-all' }}>
·· . 24 .
</p>
<span className="text-slate-700 text-sm font-bold group-hover:underline">
</span>
</button>
</div>
</div>
</section>
{/* ══════════════════════════════════════
SECTION 3 — About
══════════════════════════════════════ */}
<section className="bg-slate-950 px-6 py-20 lg:px-14">
<div className="max-w-5xl mx-auto">
<p className="reveal font-mono text-xs text-violet-300/50 tracking-widest uppercase mb-3">
About
</p>
<div className="reveal grid lg:grid-cols-2 gap-10 lg:gap-16 items-start">
<div>
<h2
className="text-2xl md:text-3xl font-extrabold text-white leading-tight mb-6"
style={{ wordBreak: 'keep-all' }}
>
7 .
<div className="relative z-10 px-6 lg:px-12 py-10 space-y-10">
{/* Hero: Launch Panel */}
<section className="kx-folder kx-glow" style={{ padding: 0, overflow: 'hidden' }}>
<div className="grid lg:grid-cols-[1.4fr_1fr] gap-0">
{/* 좌측: 카피 */}
<div className="p-8 lg:p-12">
<span className="kx-label">FLAGSHIP RELEASE · 2026</span>
<h2 className="kx-display text-4xl md:text-5xl lg:text-6xl font-extrabold mt-4 leading-[1.05]">
.
<br />
<span className="text-violet-300"> AI로 .</span>
<span className="kx-gradient-text"> .</span>
</h2>
<div className="space-y-4 text-slate-400 text-base leading-relaxed" style={{ wordBreak: 'keep-all' }}>
<p>
IT팀에서 7 API , DB, .
</p>
<p>
<span className="text-white">AI · · AI</span> ·.
</p>
<p className="mt-6 text-base md:text-lg max-w-xl leading-relaxed">
AI로 ,{' '}
<span style={{ color: 'var(--kx-on-surface)' }}> </span> .
, 4 .
</p>
<div className="flex flex-wrap gap-3 mt-8">
<Link
href="/services/music"
onClick={() => trackCTAClick('home_hero_music')}
className="kx-btn-primary inline-flex items-center gap-2 px-6 py-3.5 rounded-xl text-sm"
>
AI <span></span>
</Link>
<a
href="#tiles"
className="kx-btn-ghost inline-flex items-center gap-2 px-6 py-3.5 rounded-xl text-sm font-bold"
>
</a>
</div>
</div>
<div className="space-y-4">
{[
{ value: '7년', label: '대기업 백엔드 경력', sub: '실제 운영 서비스 다수', color: 'border-blue-500/30' },
{ value: '3개', label: '운영 중인 AI 서비스', sub: '사주 AI · 블로그팩 · 음악팩', color: 'border-emerald-500/30' },
{ value: '평생', label: '무료 업데이트', sub: '구매 후 Notion 공지로 전달', color: 'border-violet-500/30' },
{ value: '24h', label: '이내 답변', sub: '주말·공휴일 포함', color: 'border-amber-500/30' },
].map((item) => (
<div key={item.value} className={`border-l-2 ${item.color} pl-5 py-2`}>
<div className="flex items-baseline gap-3">
<span className="text-3xl font-extrabold text-white tracking-tight">{item.value}</span>
<span className="text-slate-400 text-sm font-medium">{item.label}</span>
</div>
<p className="text-white/30 text-xs mt-1">{item.sub}</p>
</div>
))}
</div>
</div>
</div>
</section>
{/* ══════════════════════════════════════
SECTION 4 — 최종 CTA
══════════════════════════════════════ */}
<section className="bg-gradient-to-b from-slate-950 to-[#0b0530] px-6 py-20 lg:px-14">
<div className="max-w-5xl mx-auto">
<div className="reveal text-center">
<p className="font-mono text-xs text-violet-300/50 tracking-widest uppercase mb-4">
Get Started
</p>
<h2
className="text-3xl md:text-5xl font-extrabold text-white mb-4 leading-tight"
style={{ wordBreak: 'keep-all' }}
{/* 우측: 엔진 상태 모니터 */}
<div
className="hidden lg:block relative"
style={{ background: 'var(--kx-surface-low)', borderLeft: '1px solid rgba(204,151,255,0.08)' }}
>
,
<br />
<span className="bg-gradient-to-r from-violet-300 via-sky-200 to-cyan-300 bg-clip-text text-transparent">
.
</span>
</h2>
<p className="text-slate-400 text-lg mb-10">
39,000 ·
</p>
<div className="flex flex-wrap gap-4 justify-center">
<Link
href="/services/music"
className="inline-flex items-center gap-2 bg-violet-600 hover:bg-violet-500 text-white px-10 py-4 rounded-xl font-extrabold text-base transition-colors shadow-[0_0_40px_rgba(139,92,246,0.4)]"
>
AI
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</Link>
<button
onClick={() => {
trackCTAClick('일반 문의', '/');
setModalOpen(true);
}}
className="inline-flex items-center gap-2 border border-white/15 hover:border-white/40 text-white/80 hover:text-white px-10 py-4 rounded-xl font-extrabold text-base transition-all"
>
·
</button>
<div className="p-8 h-full flex flex-col">
<div className="flex items-center justify-between mb-6">
<span className="kx-label">ENGINE STATUS</span>
<span className="text-xs font-mono" style={{ color: 'var(--kx-secondary-dim)' }}>REAL-TIME</span>
</div>
<div className="space-y-5 flex-1">
<EngineRow label="SUNO PRO" value="2,490 credits" pct={83} />
<EngineRow label="GEMINI 2.5" value="Online" pct={100} />
<EngineRow label="RUNWAY" value="Standby" pct={62} />
<EngineRow label="PUBLISHING" value="Ready" pct={94} />
</div>
<div className="mt-8 pt-6 border-t" style={{ borderColor: 'rgba(255,255,255,0.05)' }}>
<div className="flex items-baseline justify-between">
<span className="kx-label">DELIVERED</span>
<span className="kx-display text-3xl font-extrabold">47<span style={{ color: 'var(--kx-on-variant)', fontSize: '1rem', fontWeight: 400 }}> projects</span></span>
</div>
</div>
</div>
</div>
<p className="text-white/20 text-xs mt-8 font-mono">
· 267-53-00822 · bgg8988@gmail.com · 010-3907-1392
</p>
</div>
</div>
</section>
</section>
{/* 서비스 타일 */}
<section id="tiles">
<div className="flex items-end justify-between mb-5">
<div>
<span className="kx-label">PRODUCTS</span>
<h3 className="kx-display text-2xl md:text-3xl font-extrabold mt-1">Launch Pads</h3>
</div>
<span className="text-xs font-mono hidden md:inline" style={{ color: 'var(--kx-on-variant)' }}>
{tiles.length} modules active
</span>
</div>
<div className="grid md:grid-cols-3 gap-4">
{tiles.map((t) => (
<Link
key={t.href}
href={t.href}
onClick={() => trackCTAClick(`home_tile_${t.href}`)}
className="kx-folder group relative transition-all hover:-translate-y-1"
style={{ textDecoration: 'none' }}
>
<div className="flex items-center justify-between mb-5">
<span className="kx-label" style={{ color: t.tagColor }}>{t.label}</span>
<span
className="text-[10px] font-mono font-bold px-2 py-0.5 rounded"
style={{ background: 'rgba(255,255,255,0.05)', color: t.tagColor }}
>
{t.tag}
</span>
</div>
<h4 className="kx-display text-xl font-extrabold mb-2">{t.title}</h4>
<p className="text-sm leading-relaxed">{t.desc}</p>
<div className="mt-6 flex items-center gap-2 text-sm font-bold" style={{ color: t.tagColor }}>
<span className="transition-transform group-hover:translate-x-1"></span>
</div>
</Link>
))}
</div>
</section>
{/* Stats Monitor */}
<section className="kx-folder">
<div className="flex items-center justify-between mb-6">
<div>
<span className="kx-label">CREDIBILITY MONITOR</span>
<h3 className="kx-display text-xl font-extrabold mt-1"> </h3>
</div>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
<Stat num="47" label="프로젝트 납품" sub="계약 기반" />
<Stat num="100%" label="소스코드 인도" sub="저작권 100% 이양" />
<Stat num="24h" label="평균 응답" sub="이메일/카톡 기준" />
<Stat num="0" label="분쟁 이력" sub="계약서 우선 원칙" />
</div>
</section>
{/* Final CTA */}
<section className="kx-glass px-8 py-10 text-center" style={{ border: '1px solid rgba(204,151,255,0.12)' }}>
<span className="kx-label">NEXT STEP</span>
<h3 className="kx-display text-2xl md:text-3xl font-extrabold mt-2"> ?</h3>
<p className="mt-3 text-sm md:text-base max-w-xl mx-auto">
·· . 24 .
</p>
<button
onClick={() => {
trackCTAClick('home_final_contact');
setModalOpen(true);
}}
className="kx-btn-primary mt-6 px-7 py-3.5 rounded-xl text-sm"
>
</button>
</section>
</div>
</div>
);
}
function EngineRow({ label, value, pct }: { label: string; value: string; pct: number }) {
return (
<div>
<div className="flex items-center justify-between mb-1.5">
<span className="kx-label" style={{ fontSize: '0.625rem' }}>{label}</span>
<span className="text-xs font-mono" style={{ color: 'var(--kx-on-surface)' }}>{value}</span>
</div>
<div className="h-1.5 rounded-full overflow-hidden" style={{ background: 'rgba(255,255,255,0.06)' }}>
<div
className="h-full rounded-full"
style={{
width: `${pct}%`,
background: 'linear-gradient(90deg, #cc97ff, #53ddfc)',
}}
/>
</div>
</div>
);
}
function Stat({ num, label, sub }: { num: string; label: string; sub: string }) {
return (
<div>
<div className="kx-display text-3xl md:text-4xl font-extrabold kx-gradient-text">{num}</div>
<div className="mt-2 text-sm font-bold" style={{ color: 'var(--kx-on-surface)' }}>{label}</div>
<div className="text-xs mt-0.5">{sub}</div>
</div>
);
}