HDKD 가구 웹사이트 리뉴얼 — PHP 구식 사이트를 React + TypeScript로 다시 짓다

30년 전통의 국내 원목 가구 브랜드 HDKD. 오랫동안 운영돼 온 PHP 기반 홈페이지를 React + TypeScript 기반의 반응형 웹사이트로 다시 지었습니다. 북유럽 미니멀 무드의 우드 톤 디자인, 스크롤 애니메이션, 문의 폼까지 — 한 페이지 랜딩 사이트로 리뉴얼한 과정을 공유합니다.

가구 브랜드의 웹사이트는 제품 사진 몇 장이 전부인 경우가 많습니다. HDKD도 예외는 아니었습니다. 상품 정보가 빽빽하게 늘어선 구식 레이아웃에 모바일에서는 글자가 잘리고, 브랜드가 가진 "30년 전통 · 장인 제작 · 천연 원목"이라는 매력이 전혀 드러나지 않았습니다. 브랜드의 품격을 그대로 전달하는 웹사이트로 새로 짓기로 했습니다.

1. 리뉴얼의 방향: 브랜드 스토리를 먼저

기술 교체가 목적이 아니었습니다. "국내 장인이 직접 만드는 원목 가구"라는 브랜드 스토리를 어떻게 웹에서 들려줄까가 출발점이었습니다. 그래서 단순한 제품 나열 대신, 히어로 → 브랜드 가치 → 제품 → 회사 소개 → 문의로 이어지는 한 페이지 스토리텔링 구조를 선택했습니다. 사용자가 스크롤을 따라 자연스럽게 브랜드 이야기를 경험하게 하는 랜딩 페이지 방식입니다.

구성내용
히어로풀스크린 배경 이미지 + 브랜드 슬로건
특징자체 제작, 천연 원목 소재, 평생 A/S
제품대표 가구 6종 카드 갤러리
회사소개30년 역사 · 누적 200+ 제품 · 98% 재구매율 카운터
문의Web3Forms 연동 문의 폼

2. 기술 스택: React + Vite, 스타일은 인라인 스타일로

스택은 React + TypeScript + Vite를 사용했습니다. 한 페이지 규모라 상태 관리 라이브러리 없이 useState만으로 충분했습니다. 흥미로운 결정은 스타일 방식이었습니다. 별도의 CSS 파일 대신 CSS 변수와 인라인 스타일로 디자인 시스템을 구축했습니다. 브랜드 컬러 6개를 상수로 정의해 두고 컴포넌트 전체에서 참조하는 방식입니다.

// 브랜드 컬러 팔레트 — 모든 컴포넌트가 이 상수를 참조
const C = {
  bg:        '#FAFAF8',
  wood:      '#8B6F47',   // 원목 브라운 (메인)
  woodLight: '#C4A882',
  text:      '#1A1A1A',
  muted:     '#6B6B6B',
  beige:     '#F5EFE6',   // 베이지 (서브)
}

원목 브라운 #8B6F47과 베이지 #F5EFE6를 중심으로 한 우드 톤 팔레트는 가구 브랜드의 정체성을 그대로 담아냅니다. 인라인 스타일이라 컴포넌트 파일 하나로 모든 스타일이 관리되는 것도 장점이었습니다.

3. 히어로: 첫 화면이 곧 브랜드의 첫인상

사이트의 첫인상은 풀스크린 히어로가 결정합니다. 원목 가구 분위기의 배경 이미지 위에 어두운 그라디언트 오버레이를 깔고, 그 위에 슬로건을 올렸습니다. "자연에서 온 가구, 삶에 스며들다" — 여기서 woodLight 색상으로 강조한 부분이 브랜드 무드를 만듭니다.

히어로의 문구는 motioninitial/animate로 부드럽게 페이드인 되고, 하단의 스크롤 인디케이터는 y: [0, 8, 0] 무한 반복 애니메이션으로 사용자의 시선을 아래로 유도합니다.

4. 스크롤 애니메이션: whileInView 하나로

이 프로젝트에서 가장 재미있었던 부분은 스크롤 기반 애니메이션이었습니다. motionwhileInView는 요소가 뷰포트에 들어오는 순간 애니메이션을 시작합니다. viewport={{ once: true }}를 함께 쓰면 사용자가 스크롤을 올렸다 내려도 애니메이션이 반복되지 않습니다.

<motion.div
  initial={{ opacity: 0, y: 24 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ duration: 0.5, delay: i * 0.12 }}
>
  ...

특징 카드에는 delay: i * 0.12를, 제품 카드에는 delay: (i % 3) * 0.1을 줘서 카드들이 순차적으로 나타나는 리듬을 만들었습니다. 같은 패턴을 반복하니 코드는 짧아지고 화면은 풍성해집니다.

5. 숫자 카운터: useCountUp 훅

회사소개 섹션에는 30년 역사 · 누적 200+ 제품 · 만족 고객 5,000+ · 재구매율 98%라는 신뢰 지표를 보여줍니다. 단순한 숫자 나열 대신, 사용자가 해당 영역을 보는 순간 0부터 실제 값까지 카운트업 되는 인터랙션을 넣었습니다.

function useCountUp(target: number, duration = 1800) {
  const [count, setCount] = useState(0)
  const ref = useRef<HTMLSpanElement>(null)
  const inView = useInView(ref, { once: true })

  useEffect(() => {
    if (!inView) return
    let start = 0
    const step = (timestamp: number) => {
      if (!start) start = timestamp
      const progress = Math.min((timestamp - start) / duration, 1)
      const eased = 1 - Math.pow(1 - progress, 3)   // easeOutCubic
      setCount(Math.round(eased * target))
      if (progress < 1) requestAnimationFrame(step)
    }
    requestAnimationFrame(step)
  }, [inView, target, duration])

  return { count, ref }
}

useInView로 카운터가 화면에 들어온 시점을 감지하고, requestAnimationFrame으로 부드럽게 숫자를 올립니다. easeOutCubic 이징을 적용해 처음엔 빠르게, 끝으로 갈수록 천천히 증가하는 자연스러운 느낌을 줍니다.

6. 제품 갤러리: 호버 인터랙션의 디테일

제품 카드에는 두 가지 호버 효과를 넣었습니다. 카드 전체는 whileHover={{ y: -8 }}로 살짝 떠오르고, 카드 안의 이미지는 whileHover={{ scale: 1.06 }}로 부드럽게 확대됩니다. 이미지가 카드 영역을 넘치지 않도록 overflow: hidden으로 감싼 것이 포인트입니다.

각 카드에는 이름과 한 줄 설명, 별점 5개를 배치해 제품의 품질감을 암시적으로 전달했습니다. 실제 상품 데이터가 있다면 API 연동으로 바꾸면 되는 구조라 확장도 쉽습니다.

7. 문의 폼: Web3Forms로 서버 없이

랜딩 페이지의 목적은 결국 문의 유도입니다. 백엔드 서버가 없는 환경이라 Web3Forms를 사용했습니다. 클라이언트에서 폼 데이터를 Web3Forms API로 POST하면 이메일로 전달되는 구조입니다.

폼에는 이름 · 연락처 · 문의 내용 세 필드를 두고, 전송 전 클라이언트 검증을 거칩니다. 오류가 있는 필드는 빨간 테두리와 함께 메시지를 표시하고, 전송 중에는 버튼이 "전송 중..."으로 바뀌며, 성공하면 체크 아이콘과 함께 완료 화면으로 전환됩니다. resize: none으로 textarea 크기 변형도 막았습니다.

반응형 처리 요약
데스크톱은 상단 네비게이션 + 모바일은 햄버거 메뉴 전환 · 폰트는 clamp()로 뷰포트에 따라 유동 조절 · 문의 카드는 모바일에서 바텀시트처럼 동작

8. 반응형: 모바일 사용자가 절반

가구 구매 문의는 대부분 모바일에서 들어옵니다. 네비게이션은 데스크톱에서 상단에 펼쳐지고, 모바일에서는 햄버거 메뉴로 접힙니다. 햄버거 아이콘은 세 줄이 X자로 변하는 CSS 애니메이션으로 직접 구현했습니다. 타이포그래피는 clamp() 함수로 뷰포트 크기에 따라 유동적으로 조절되어 320px 폰에서도 제목이 잘리지 않습니다.

핵심 정리
  1. 기술 교체가 아니라 브랜드 스토리텔링 구조부터 설계하는 것이 리뉴얼의 핵심이었습니다.
  2. 우드 톤 CSS 변수 팔레트 하나로 브랜드 정체성을 전 사이트에 일관되게 적용했습니다.
  3. motion의 whileInView + delay 조합으로 짧은 코드로 풍성한 스크롤 애니메이션을 구현했습니다.
  4. useCountUp 훅 하나로 신뢰 지표 숫자에 인터랙션을 더했습니다.
  5. Web3Forms를 사용해 백엔드 서버 없이 문의 폼을 운영할 수 있었습니다.

이 프로젝트에서 배운 것은, 웹사이트 리뉴얼의 완성도는 기술보다 디자인 결정과 스토리텔링이 좌우한다는 점입니다. 브랜드가 가진 이야기를 명확히 하고, 그 이야기를 일관된 디자인 언어로 전달하면, 어떤 스택을 쓰든 좋은 결과물이 나옵니다.

HDKD React TypeScript Framer Motion 리뉴얼 랜딩 페이지 웹사이트