'use client'; import Link from 'next/link'; import { useState, useEffect, useRef } from 'react'; /* ══════════════════════════════════════════════ DATA ══════════════════════════════════════════════ */ const portfolio = [ { title: '한남동 단독주택', cat: '주거 인테리어', area: '245㎡', img: 'https://i.pinimg.com/1200x/a7/56/f4/a756f4482ad282353fe89b6ddc4ba3e1.jpg' }, { title: '청담 파인다이닝', cat: '상업 공간', area: '190㎡', img: 'https://i.pinimg.com/736x/f2/68/a7/f268a7cb3405e960a3d1bf7c44c9c7e5.jpg' }, { title: '성수 브랜드 오피스', cat: '업무 공간', area: '380㎡', img: 'https://i.pinimg.com/736x/f3/15/2a/f3152a792b7310b6475b40cf912ae0c1.jpg' }, { title: '용산 아파트 리모델링', cat: '리모델링', area: '95㎡', img: 'https://i.pinimg.com/474x/76/14/4a/76144a948cea14b77dd2fd43f0da8484.jpg' }, { title: '강남 카페 에스프레소랩', cat: '상업 공간', area: '120㎡', img: 'https://i.pinimg.com/736x/03/72/b0/0372b0f07d36982f4d3889290a7c762f.jpg' }, ]; const services = [ { title: '주거 인테리어', sub: 'Residential', desc: '생활의 리듬에 맞춘 공간을 설계합니다. 단독주택부터 아파트까지, 당신의 일상이 더 아름다워지도록 모든 디테일을 손수 고릅니다.', details: ['공간 기획 및 3D 시뮬레이션', '자재 선정 동행 서비스', '시공 전 과정 PM', '준공 후 AS 1년'], img: 'https://i.pinimg.com/736x/1d/af/b2/1dafb2117511994568cc45ceed09a64c.jpg', }, { title: '상업 공간 디자인', sub: 'Commercial', desc: '브랜드의 철학이 공간 언어로 번역됩니다. 첫 방문객이 문을 열었을 때 느끼는 그 감정까지 설계의 범위입니다.', details: ['브랜드 아이덴티티 반영', '동선 및 고객 UX 설계', '조명·음향 플래닝', '설비 협력사 연계'], img: 'https://www.lunalightstudios.com/cdn/shop/files/contemporary-aluminum-funnel-suspension-pendant-lamp-fits-study-room-or-cafe-6-5-10-inch-wide-1-light-grey-226.webp?v=1768032185&width=675', }, { title: '리모델링 & 재생', sub: 'Remodeling', desc: '기존 공간의 가능성을 새로운 시선으로 바라봅니다. 구조적 변경부터 마감재 교체까지, 완전한 변신을 지원합니다.', details: ['현장 실측 및 구조 분석', '철거~완공 원스톱', '예산 내 최적 시공', '친환경 자재 우선 적용'], img: 'https://i.pinimg.com/474x/76/14/4a/76144a948cea14b77dd2fd43f0da8484.jpg', }, ]; const testimonials = [ { name: '하윤서', role: '한남동 단독주택 의뢰인', u: 'hayunseo', rating: 5, highlight: '계획보다 적은 예산', text: '처음엔 예산이 걱정됐는데, 아우라 팀이 범위를 명확히 정해줘서 오히려 계획보다 적게 들었습니다. 무엇보다 완공된 공간에서 매일 아침 커피 한 잔 하는 지금이 너무 행복해요.' }, { name: '박도현', role: '카페 에스프레소랩 대표', u: 'parkdohyun', rating: 5, highlight: '매출 340% 상승', text: '우리 브랜드 철학을 완벽하게 공간으로 옮겨줬습니다. 오픈 첫날부터 SNS 바이럴이 터졌고, 오픈 3개월 만에 매출이 전년 대비 340% 올랐어요.' }, { name: '이서진', role: '루미너스 COO', u: 'leeseojin', rating: 5, highlight: '직원 만족도 93점', text: '직원들이 출근하고 싶은 공간을 만드는 게 목표였습니다. 리모델링 후 직원 만족도 설문에서 93점, 퇴직률이 절반으로 줄었습니다.' }, ]; const steps = [ { num: '01', title: '무료 상담', desc: '공간 사진, 예산, 취향을 공유해 주세요. 72시간 내 맞춤 제안서를 드립니다.' }, { num: '02', title: '콘셉트 기획', desc: '무드보드와 3D 시뮬레이션으로 완공 이후를 미리 경험합니다.' }, { num: '03', title: '시공', desc: '전담 PM이 공정마다 현장을 점검하고 일일 리포트를 공유합니다.' }, { num: '04', title: '준공 & AS', desc: '완공 후 1년간 무상 AS. 공간이 오래 아름답도록 함께합니다.' }, ]; /* ══════════════════════════════════════════════ SVG ICONS ══════════════════════════════════════════════ */ const StarIcon = ({ filled }: { filled: boolean }) => ( ); const CheckIcon = () => ( ); const ArrowRight = ({ color = '#8B6914' }: { color?: string }) => ( ); /* ══════════════════════════════════════════════ CONSTANTS ══════════════════════════════════════════════ */ const FRAME_COUNT = 48; const BANNER_H = 40; // px — back-banner explicit height const NAV_H = 72; // px — sticky nav height /* ══════════════════════════════════════════════ PAGE COMPONENT ══════════════════════════════════════════════ */ export default function InteriorSample() { const [scrolled, setScrolled] = useState(false); const canvasRef = useRef(null); const scrollSectionRef = useRef(null); const textOverlayRef = useRef(null); const framesRef = useRef([]); useEffect(() => { /* ─── 스크롤 컨테이너: DashboardShell의 .main-content (overflow-y: auto) window가 아닌 이 요소에서 scroll 이벤트가 발생함 ─── */ const scroller: HTMLElement = (document.querySelector('.main-content') as HTMLElement | null) ?? document.documentElement; /* ── nav 투명 → 불투명 전환 ── */ const onNavScroll = () => setScrolled(scroller.scrollTop > 60); scroller.addEventListener('scroll', onNavScroll, { passive: true }); /* ── Intersection reveal ── */ const observer = new IntersectionObserver( (entries) => entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add('au-visible'); }), { threshold: 0.08, root: scroller === document.documentElement ? null : scroller } ); document.querySelectorAll('.au-reveal').forEach((el) => observer.observe(el)); /* ── WebP 프레임 프리로드 ── */ const frames: HTMLImageElement[] = new Array(FRAME_COUNT); framesRef.current = frames; let firstLoaded = false; const drawFrame = (index: number) => { const canvas = canvasRef.current; const img = frames[Math.max(0, Math.min(FRAME_COUNT - 1, index))]; if (!canvas || !img?.complete || !img.naturalWidth) return; const ctx = canvas.getContext('2d'); if (!ctx) return; const cw = canvas.width, ch = canvas.height; // cover-fit: 비율 유지하며 캔버스를 꽉 채움 const scale = Math.max(cw / img.naturalWidth, ch / img.naturalHeight); const dx = (cw - img.naturalWidth * scale) / 2; const dy = (ch - img.naturalHeight * scale) / 2; ctx.clearRect(0, 0, cw, ch); ctx.drawImage(img, dx, dy, img.naturalWidth * scale, img.naturalHeight * scale); }; for (let i = 0; i < FRAME_COUNT; i++) { const img = new Image(); img.src = `/interior-frames/frame-${String(i + 1).padStart(3, '0')}.webp`; img.onload = () => { if (!firstLoaded) { firstLoaded = true; drawFrame(0); } }; frames[i] = img; } /* ── 캔버스 크기를 컨테이너에 맞춤 ── */ const resizeCanvas = () => { const canvas = canvasRef.current; if (!canvas) return; // sticky 컨테이너의 실제 크기 사용 const parent = canvas.parentElement; canvas.width = parent?.clientWidth ?? window.innerWidth; canvas.height = parent?.clientHeight ?? window.innerHeight; drawFrame(0); }; resizeCanvas(); window.addEventListener('resize', resizeCanvas); /* ── 스크롤 스크러빙 (frame-by-frame) ── */ let rafId = 0; const onScrub = () => { cancelAnimationFrame(rafId); rafId = requestAnimationFrame(() => { const section = scrollSectionRef.current; if (!section) return; // getBoundingClientRect()는 viewport 기준 → scroller가 .main-content여도 정상 작동 const rect = section.getBoundingClientRect(); const vh = scroller === document.documentElement ? window.innerHeight : scroller.clientHeight; const scrollable = section.offsetHeight - vh; if (scrollable <= 0) return; const progress = Math.max(0, Math.min(1, -rect.top / scrollable)); drawFrame(Math.floor(progress * (FRAME_COUNT - 1))); /* 텍스트 오버레이: opacity + filter만 변경 (transform 금지) */ const overlayEl = textOverlayRef.current; if (!overlayEl) return; overlayEl.querySelectorAll('[data-milestone]').forEach((el) => { const s = parseFloat(el.dataset.start ?? '0'); const e2 = parseFloat(el.dataset.end ?? '1'); const vis = progress >= s && progress < e2; el.style.opacity = vis ? '1' : '0'; el.style.filter = vis ? 'blur(0px)' : 'blur(6px)'; }); /* 진행 바 */ const bar = overlayEl.querySelector('[data-progress-bar]'); if (bar) bar.style.width = `${progress * 100}%`; }); }; scroller.addEventListener('scroll', onScrub, { passive: true }); onScrub(); // 초기 상태 즉시 반영 return () => { scroller.removeEventListener('scroll', onNavScroll); scroller.removeEventListener('scroll', onScrub); window.removeEventListener('resize', resizeCanvas); observer.disconnect(); cancelAnimationFrame(rafId); }; }, []); /* ── 팔레트 상수 ── */ const GOLD = '#8B6914'; const DARK = '#1C1A17'; const SAGE = '#4E5C3E'; const CREAM = '#FAF8F5'; const SURFACE = '#F0ECE4'; return ( {/* ══ 폰트 + 전역 CSS ══ */} {/* ══ BACK BANNER ══ */} ← 홈페이지 제작 서비스로 돌아가기 | SAMPLE · 인테리어 업체 홈페이지 {/* ══ NAV (sticky within .main-content) ══ */} Aura Interior 아우라 인테리어 {['포트폴리오', '서비스', '프로세스', '고객 후기', '상담 신청'].map((l) => ( {l} ))} 무료 상담 신청 {/* ══ HERO — 풀블리드 비디오 ══ height = 100dvh - BANNER_H - NAV_H → 화면을 정확히 채움 */} {/* 배경 비디오 */} {/* 그라디언트 오버레이 */} {/* 어워드 배지 */} Award Winner 2024 {/* 히어로 텍스트 — 좌하단 */} 서울 기반 인테리어 디자인 공간이 당신의이야기를 담습니다. 아우라 인테리어는 12년간 247개의 공간을 완성했습니다. 무료 공간 상담 시작 포트폴리오 보기 {[['247+','완공 프로젝트'],['4.96','고객 만족도'],['12년','디자인 경력']].map(([n, l]) => ( {n} {l} ))} {/* 플로팅 리뷰 배지 */} {[1,2,3,4,5].map(i => )} 최근 완공 · 한남동 단독주택 고객 만족도 5.0 / 5.0 {/* 스크롤 유도 */} Scroll {/* ══ SCROLL SCRUBBING SECTION ══ */} {/* sticky 컨테이너: .main-content 기준으로 top:0 에 고정 */} {/* 캔버스 — frame-by-frame WebP */} {/* 그라디언트 오버레이 */} {/* ── 텍스트 오버레이 컨테이너 ── 각 au-scrub-text는 position:absolute inset:0 flex 레이아웃으로 수직 중앙 정렬. JS는 opacity + filter만 변경 — transform 불변 */} {/* Milestone 0: 0–33% */} 공간 철학 공간이 바뀌면 일상이 바뀝니다. 우리는 단순한 시공을 넘어, 당신이 매일 경험하는 삶의 배경을 설계합니다. {/* Milestone 1: 33–66% */} 실적 12년간 247개의 공간. {[['247+','완공 프로젝트'],['4.96','고객 만족도'],['98%','재의뢰율']].map(([n, l]) => ( {n} {l} ))} {/* Milestone 2: 66–100% */} 지금 시작하세요 당신의 공간 이야기를 시작하세요. 무료 상담 신청 {/* 진행 바 */} {/* 안내 레이블 */} 스크롤로 영상 탐색 {/* ══ PORTFOLIO BENTO ══ */} Portfolio 공간이 말하는우리의 언어 전체 보기 {portfolio[0].cat} {portfolio[0].title} {portfolio[0].area} {[1, 2].map((idx) => ( {portfolio[idx].cat} {portfolio[idx].title} ))} {portfolio[4].cat} {portfolio[4].title} {portfolio[4].area} {/* ══ SERVICES ZIG-ZAG ══ */} Services 우리가 잘하는 세 가지 {services.map((svc, i) => ( {svc.sub} {svc.title} {svc.desc} {svc.details.map((d) => ( {d} ))} 상담 신청하기 ))} {/* ══ PROCESS (dark) ══ */} Process 상담부터 준공까지 {steps.map((s, i) => ( 0 ? '1px solid rgba(250,248,245,.06)' : 'none' }}> {s.num} {s.title} {s.desc} ))} {/* ══ TESTIMONIALS MASONRY ══ */} Reviews 공간이 바꾼 이야기들 {testimonials.map((t, i) => ( {t.highlight} " {t.text} {[1,2,3,4,5].map(j => )} {t.name} {t.role} ))} 함께한 브랜드들 {['에스프레소랩','루미너스','플로우캔버스','스텔라랩스','넥스트비전','브릿지웍스','에스프레소랩','루미너스','플로우캔버스','스텔라랩스','넥스트비전','브릿지웍스'].map((b, i) => ( {b} ))} {/* ══ CTA ══ */} 72시간 내 제안서 발송 당신의 공간 이야기를 지금 시작하세요. 사진 한 장과 예산만 알려주세요. 72시간 내에 맞춤 제안서와 무드보드를 드립니다. 무료입니다. 무료 상담 신청하기 02-1234-5678 {['완공 보장','계약서 필수','AS 1년'].map((b) => ( {b} ))} {/* ══ FOOTER ══ */} ); }
아우라 인테리어는 12년간 247개의 공간을 완성했습니다.
공간 철학
우리는 단순한 시공을 넘어, 당신이 매일 경험하는 삶의 배경을 설계합니다.
실적
지금 시작하세요
{svc.desc}
{s.desc}
{t.text}
사진 한 장과 예산만 알려주세요. 72시간 내에 맞춤 제안서와 무드보드를 드립니다. 무료입니다.