Sinhu Jung Software Engineer
Section

3D 이력서 사이트 성능 최적화

2026.09·개인 프로젝트 · AI 도구와 함께 분석·개선
Next.jsReactThree.js성능 측정

프로젝트 핵심 요약

문제에서 결과까지
홈 리소스 전송 본문
95.7% ↓
도시 유휴 draw call
0회
기본 개발 의존성
약 144MiB ↓
문제
3D 이력서가 첫 진입에 전국 지도·건물·HDR을 모두 받고, 상세 페이지를 읽는 동안에도 Canvas를 유지해 네트워크와 GPU 비용이 컸습니다.
판단
포트폴리오의 3D 탐색을 유지하면서, 방문한 화면에 필요한 리소스만 받도록 바꾸고 지도 삼각분할을 사전 생성 단계로 옮겼습니다.
내 기여
AI 코딩 도구와 함께 병목을 점검하고, 지도 분할·사전 생성, Scene 지연 로딩, 도시 demand 렌더링, 오류 복구와 경량 배포 구성을 적용했습니다.
결과
최적화 당시 홈 리소스 전송 본문을 약 10.74MiB에서 469.3KiB로 줄였습니다. 도시 유휴 draw call은 0회였고, 모델 변환기를 분리해 기본 개발 의존성도 약 144MiB 줄였습니다.

범위와 측정 기준 · 2026-09-06 최적화 직후의 기록: Windows, Node.js 22.14.0, Chrome 148, 로컬 프로덕션 서버, 캐시 비활성화, 1440×1000. Resource Timing encodedBodySize 합계로 HTML·HTTP 헤더는 제외했습니다. 이번 콘텐츠 보강·프로젝트 목록 표시 시간 조정 이전 수치이며 FPS·로딩 시간 개선율로 환산하지 않았습니다.

Overview

이 사이트는 한국 지도에서 서울·부산의 건물을 선택해 경력을 탐색하는 포트폴리오입니다. 첫 화면에서 방문하지 않은 지역·건물까지 불러오는 문제를 찾아, 콘텐츠 접근성을 유지하면서 전송량과 렌더링 비용을 줄였습니다.

Background

  • ▸초기 화면에서 약 25.7MB의 전국 GeoJSON과 모든 도시 건물, HDR 조명을 함께 요청했습니다.
  • ▸경력 상세 화면에서도 3D Canvas를 유지하고, 정지된 도시 지도도 매 프레임 다시 그렸습니다.
  • ▸지도나 Scene 청크가 실패하면 본문 접근이 막히고, 재시도하기 어려웠습니다.
  • ▸일회성 OBJ 변환기의 큰 하위 의존성이 평소 개발 설치에도 포함되어 있었습니다.

Architecture

현재 사이트 코드의 콘텐츠·3D 로딩 경계와 지도 사전 처리·배포 구조입니다.

검증 근거 · 현재 resume 저장소의 컴포넌트, 지도 로더, 빌드·패키징 스크립트 및 프로덕션 빌드로 대조했습니다.

→ 요청 · 전달⇢ 코드 의존성 (점선)→ 빌드 · 배포

콘텐츠 우선 표시와 선택적 3D 로딩

서버 HTML을 먼저 표시하고, 홈에서만 지도 모듈을 준비합니다.

노드 선택 · Ctrl/⌘ + 휠로 확대 · 드래그로 이동
100%
콘텐츠 우선 표시와 선택적 3D 로딩. 서버 HTML을 먼저 표시하고, 홈에서만 지도 모듈을 준비합니다. 아래에 동일한 연결 관계를 텍스트로 제공합니다.hydrate홈 · 지도 모드목록 유지loadMap도시 선택useGLTF정적 HTML — 소개 · 프로젝트 상세정적 HTML소개 · 프로젝트 상세SceneRoot — 경로 · 모드 · 오류 처리SceneRoot경로 · 모드 · 오류 처리Scene / Canvas — 홈에서 동적 importScene / Canvas홈에서 동적 import프로젝트 목록 — 첫 진입 최소 1.5초프로젝트 목록첫 진입 최소 1.5초지도 JSON — 선택 지역 · Promise 캐시지도 JSON선택 지역 · Promise 캐시RegionMap — 도시 선택 시 lazy importRegionMap도시 선택 시 lazy import도시 건물 GLB — 선택 도시 모델 로딩도시 건물 GLB선택 도시 모델 로딩
  • • 목록의 최소 표시 시간과 지도 준비는 병렬입니다. 상세 URL은 3D를 요청하지 않고, 지도 실패·동작 줄이기·데이터 절약에서는 목록 경로를 제공합니다.
  • • 도시는 demand 렌더링을 사용합니다. 한국 지도는 페이지가 보이고 동작 줄이기가 꺼져 있을 때 마커 애니메이션을 계속 렌더링합니다.
연결 관계를 텍스트로 보기
  • 정적 HTML → SceneRoot · hydrate
  • SceneRoot → Scene / Canvas · 홈 · 지도 모드
  • SceneRoot → 프로젝트 목록 · 목록 유지
  • Scene / Canvas → 지도 JSON · loadMap
  • Scene / Canvas → RegionMap · 도시 선택
  • RegionMap → 도시 건물 GLB · useGLTF

지도 사전 처리와 배포 패키징

지도 갱신 작업과 일반 사이트 빌드를 분리해 운영 시 원본 지리 데이터를 처리하지 않습니다.

노드 선택 · Ctrl/⌘ + 휠로 확대 · 드래그로 이동
100%
지도 사전 처리와 배포 패키징. 지도 갱신 작업과 일반 사이트 빌드를 분리해 운영 시 원본 지리 데이터를 처리하지 않습니다. 아래에 동일한 연결 관계를 텍스트로 제공합니다.갱신 입력파일 생성빌드 입력산출물필요 파일배포 · 실행VERCEL=1원본 지도 데이터 — 지도 갱신 시 사용원본 지도 데이터지도 갱신 시 사용maps:build — 단순화 · 삼각형 메시maps:build단순화 · 삼각형 메시해시 지도 파일 — JSON · manifest해시 지도 파일JSON · manifest사이트 소스 — 콘텐츠 · 컴포넌트사이트 소스콘텐츠 · 컴포넌트next build — 정적 경로 · JS 청크next build정적 경로 · JS 청크배포 패키징 — 일반 서버 · 필요 에셋배포 패키징일반 서버 · 필요 에셋Vercel — 플랫폼 어댑터Vercel플랫폼 어댑터Node 서버 — HTML · 청크 · 정적 파일Node 서버HTML · 청크 · 정적 파일
  • • maps:build는 지도 갱신 때만 실행합니다. 일반 서버용 빌드는 standalone을 패키징하고, VERCEL=1에서는 standalone을 끄고 Vercel의 플랫폼 어댑터가 산출물을 처리합니다.
  • • 해시 지도에는 immutable 캐시를 적용합니다. 고정 경로의 건물 모델은 1시간 후 재검증하며, 배포에는 사용 중인 에셋만 포함합니다.
연결 관계를 텍스트로 보기
  • 원본 지도 데이터 → maps:build · 갱신 입력 (빌드·배포)
  • maps:build → 해시 지도 파일 · 파일 생성 (빌드·배포)
  • 사이트 소스 → next build · 빌드 입력 (빌드·배포)
  • next build → 배포 패키징 · 산출물 (빌드·배포)
  • 해시 지도 파일 → 배포 패키징 · 필요 파일 (빌드·배포)
  • 배포 패키징 → Node 서버 · 배포 · 실행 (빌드·배포)
  • next build → Vercel · VERCEL=1 (빌드·배포)

Key Decisions

결정이유결과
지역별 지도 분할·메시 사전 생성방문자마다 전국 데이터를 받고 삼각분할할 필요가 없음첫 지도 전송 본문 8.32MiB → 83.6KiB
홈에서만 Scene 로드·상세에서 Canvas 해제본문을 읽는 동안 3D 초기화와 렌더링이 필요하지 않음상세 직접 진입의 지도·GLB 요청 0개
도시 demand 렌더링·복제 자원 dispose화면 변화가 없는 프레임과 전환 후 잔여 자원 감소도시 유휴 draw 0회, 20회 전환 시 버퍼 계수 일정
HDR·실시간 그림자 제거, DPR 상한 1.25정교한 조명보다 읽기와 안정적인 탐색을 우선조명 리소스·추가 패스 감소, 선명도와의 절충
모델 변환기 분리·standalone 배포가끔 쓰는 개발 도구와 사용하지 않는 에셋의 기본 포함 방지기본 개발 의존성 약 144MiB 감소

What I Did

  • ▸AI 코딩 도구와 함께 프로덕션 요청·번들·GPU 동작을 점검하고, 가장 큰 지도 데이터 병목부터 개선했습니다.
  • ▸고정 원본에서 지역별 메시를 생성하고, 공유 경계·해시·영역 수·삼각형 인덱스를 검사했습니다.
  • ▸상세 경로의 3D 로딩을 분리하고, 지도 실패 재시도·건물 대체 표시·목록 탐색을 추가했습니다.
  • ▸Puppeteer로 모바일 뷰포트, 실제 건물 클릭, 오류 복구, 도시 반복 전환과 캐시 헤더를 검증했습니다.

Before / After

항목BeforeAfter
홈 리소스 전송 본문11,261,990 B480,601 B (약 -95.7%)
첫 지도 전송 본문8,721,526 B85,582 B (약 -99.0%)
홈 GLB / HDR 요청4개 / 1개0개 / 0개
도시 유휴 렌더링매 프레임 갱신관찰 구간 draw call 0회
기본 개발 의존성769,771,310 B618,636,866 B

Impact

  • ▸최적화 직후 지도 회귀 테스트 7개·브라우저 검사 40개를 통과했습니다. 당시 버전의 검사 결과입니다.
  • ▸서울↔부산 20회 전환에서 live WebGL buffer 계수가 30개로 일정했습니다. 전체 메모리 누수 부재를 뜻하는 수치는 아닙니다.
  • ▸JavaScript·WebGL을 사용할 수 없거나 지도 요청이 실패해도, 경력과 프로젝트 링크에 접근하도록 개선했습니다.
  • ▸한국 마커 애니메이션은 유지하고, 모바일의 세밀한 지도 라벨은 확대해서 보도록 해 표현과 비용의 절충을 남겼습니다.

Tech Stack

Frontend
Next.js 16React 19TypeScriptTailwind CSS
3D / Data
Three.jsReact Three FiberTopoJSONBufferGeometry
Verification
PuppeteerResource TimingNode.js testESLint