포트폴리오 스킬
탭을 닫은 후에도 채용 담당자, 리크루터, 또는 클라이언트가 기억하는 포트폴리오를 만드세요: 하나의 확신 있는 시각적 아이디어, 구체적인 카피, 이유 있는 모션, 그리고 누군가 DevTools를 열었을 때 버틸 수 있는 엔지니어링.
테마는 사람에 따라 선택됩니다. 여기에는 색상, 글꼴 또는 레이아웃 스타일이 고정되어 있지 않습니다. 이 파일의 모든 구체적인 값은 패턴의 예시일 뿐, 복사할 기본값이 아닙니다.
1. 품질 기준 (완료 전에 모두 확인)
- 하나의 아트 디렉션, 일관되게 실행. 명명된 컨셉이 서체, 색상, 레이아웃, 모션, 카피 톤을 결정합니다. 한 사이트에 관련 없는 스타일(유리 + 네온 + 브루탈리즘 + 그라데이션)을 절대 섞지 마세요.
- 실제적이고 구체적인 콘텐츠. 모든 주장은 사용자의 이력서, 리포지토리, 프로필 또는 메시지에서 가져옵니다. 구체적인 숫자, 스택 이름, 역할, 날짜. 로렘 입숨, 지어낸 지표, "열정적인 개발자, 코딩을 사랑합니다"는 쓰지 마세요.
- 작업이 주인공입니다. 상위 2-4개 프로젝트가 가장 많은 공간을 차지하며, 이상적으로는 각각 대화형 요소가 있는 자체 케이스 스터디 페이지를 갖습니다. 나머지는 훑어보고 필터링 가능한 인덱스에 있습니다.
- 타이포그래피가 디자인을 이끕니다. 표현적인 디스플레이 서체 + 가독성 좋은 텍스트 서체 + 선택적 모노/유틸리티 서체. 유동적인
clamp()크기. Inter, Roboto, Arial 또는 시스템 스택은 디스플레이 목소리가 될 수 없습니다. - 모션은 안무되어 있고, 뿌려진 것이 아닙니다. 인트로, 스크롤 리빌, 그리고 1-2개의 시그니처 모먼트. 모든 것은
prefers-reduced-motion을 존중하고 깔끔하게 저하됩니다. - 모든 곳에서 작동합니다. 360px부터 울트라와이드까지, 키보드 조작 가능, WCAG AA 대비, 빠른 최초 페인트, WebGL이나 JS 애니메이션 없이도 완전히 읽을 수 있습니다.
- 출시합니다. 제로 타입 오류, 프로덕션 빌드 통과, 경로별 메타/OG 태그, 이력서 링크, 전달되는 연락처 경로, 배포 구성.
2. 작업 흐름
- 자료 수집. 제공된 모든 것을 읽으세요: 이력서 PDF/DOCX, 기존 사이트, README, GitHub 데이터, 노트. 누락된 필수 항목(이름, 역할, 대상 고객, 2-4개의 플래그십 프로젝트, 링크, 시각적 선호도)에 대해서만 물어보세요. 선호도가 주어지지 않으면 직접 방향을 선택하고 어떤 방향인지, 왜 그런지 말하세요.
- 아키타입과 야망 수준(섹션 6A.2)을 사람과 일정에 맞게 선택한 다음, UI 코드를 작성하기 전에 디자인 브리프(섹션 3)를 작성하세요.
- 기초 구축(섹션 5): 콘텐츠 모듈, 토큰, 서체, 라우터, 부드러운 스크롤.
- 제시 가능한 순서로 페이지 구성: 콘텐츠 -> 토큰/서체 -> 탐색/푸터 -> 히어로 -> 플래그십 -> 작업 인덱스 -> 소개/역량/연혁 -> 연락처 -> 케이스 스터디 페이지 -> 404. 그런 다음 모션(섹션 6). WebGL과 시그니처 효과는 마지막에.
- 실제 브라우저(섹션 9)에서 ~1440px 및 ~390px로 확인하세요. 코드만 읽고 완료되었다고 선언하지 마세요.
리포지토리가 이미 스택(Next.js, Astro, SvelteKit, 일반 HTML)을 사용하는 경우 유지하세요. 아래 모든 패턴은 변환 가능합니다.
3. 아트 디렉션
3.1 사람으로부터 테마 도출하기
질문: 누가 이것을 볼 것인가, 5초 안에 무엇을 느껴야 하는가, 이 사람의 작업은 어떻게 생겼는가? 그것을 컨셉에 매핑하세요. 사용자가 지정한 브랜드 색상, 글꼴 또는 테마는 항상 우선합니다.
| 사람 / 신호 | 예시 방향 (하나 선택하거나 새로 고안) |
|---|---|
| 백엔드 / 시스템 / 인프라 | 에디토리얼 종이 + 잉크; 청사진/기술 도면; 터미널 브루탈리즘; 데이터 시각화 악센트가 있는 스위스 그리드 |
| 프론트엔드 / 크리에이티브 개발 | 대담한 운동성 서체; WebGL 주도 몰입형; 장난기 있는 스티커/진; 하나의 네온이 있는 고대비 단색 |
| 제품 / UX 디자이너 | 차분한 갤러리 여백; 따뜻한 스튜디오(크림, 테라코타, 부드러운 세리프); 케이스 스터디 매거진 |
| ML / 연구 / 데이터 | 연구실 노트(모눈종이, 단색 주석); 과학 저널; 플롯된 선이 있는 어두운 천문대 |
| 모바일 개발자 | 디바이스 중심 쇼케이스; 부드러운 촉감 표면; 라이브 폰 목업이 있는 앱 스토어 수준의 완성도 |
| 사진작가 / 아티스트 | 이미지 우선 풀블리드; 미니멀 크롬; 다크 시네마; 접촉 사진 그리드 |
| 창업자 / 제너럴리스트 | 자신감 있는 에디토리얼; 선언문 타이포그래피; 지표 기반 신뢰도 |
| 학생 / 초기 경력자 | 깔끔하고, 활기차고, 정직함; 프로젝트와 학습 경로를 직함보다 강조 |
AI 생성으로 읽히는 기본값은 피하세요: 흰색 바탕에 보라색-파란색 그라데이션, 일반적인 글래스모피즘 카드, "안녕하세요, 저는 X입니다" + 웨이브 이모지가 있는 중앙 히어로, 세 개의 동일한 기능 카드, 재고 3D 블롭.
3.2 디자인 브리프 템플릿 (먼저 작성)
컨셉: <이름 + 의도 한 문장>
대상: <누구, 그들이 무엇을 가져가야 하는가>
팔레트: 배경, 배경-2, 전경, 전경-2, 음소거, 라인, 강조 (+ 사용된 경우 프로젝트별 강조)
서체: 디스플레이 / 텍스트 / 단색 (폴백 포함), 스케일 비율
레이아웃 문법: 그리드, 거터, 섹션 리듬, 규칙/테두리 vs 카드
모션: 성격 (선명함/탄력적/느림/기계적), 주요 이징, 지속 시간
시그니처: 사람들이 기억할 1-2개의 순간
텍스처: 입자 / 그리드 라인 / 없음 / 셰이더
3.3 토큰 (구조는 고정, 값은 테마별)
:root {
/* 팔레트: 테마별로 값 교체 */
--bg: #eeeae2; --bg-2: #e5e0d5;
--fg: #121210; --fg-2: #2a2925;
--muted: #6d695f;
--line: rgba(18,18,16,.14);
--accent: #ff4d1c;
/* 서체 음성 */
--display: 'Instrument Serif', 'Times New Roman', serif;
--text: 'Geist', 'Helvetica Neue', sans-serif;
--mono: 'Geist Mono', ui-monospace, monospace;
/* 리듬 */
--gutter: clamp(1.1rem, 3.2vw, 2.75rem);
--ease: cubic-bezier(.16, 1, .3, 1);
/* 케이스 스터디 페이지가 이것들을 재정의하여 리테마할 수 있도록 하는 페이지 수준 별칭 */
--page-bg: var(--bg); --page-fg: var(--fg); --page-muted: var(--muted);
--page-line: var(--line); --page-accent: var(--accent);
}
컴포넌트는 --page-*만 참조합니다. 케이스 스터디 페이지는 <main>에 새 --page-* 값을 설정하고 전체 UI(버튼, 규칙, 커서, 선택)가 무료로 리테마됩니다.
3.4 타이포그래피 규칙
- 대비로 페어링: 세리프 디스플레이 + 그로테스크 텍스트, 또는 헤비 그로테스크 디스플레이 + 단색, 또는 콘덴스드 디스플레이 + 휴머니스트 텍스트.
display=swap및preconnect와 함께 Google Fonts 또는 자체 호스팅 woff2를 통해 로드하세요. - clamp를 사용한 유동적 스케일, 예:
h-xl: clamp(3.6rem, 14.5vw, 15rem),h-lg: clamp(2.8rem, 8vw, 8.5rem),h-md: clamp(2.1rem, 5vw, 4.6rem),lede: clamp(1.05rem, 1.45vw, 1.3rem). - 디스플레이: 타이트한 행간(0.85-0.95) 및 네거티브 자간(-0.02 ~ -0.04em). 본문: 1.5-1.65 행간,
max-width38-62ch. - 메타데이터는 약간의 자간이 있는 작은 대문자 단색으로 ("(02) Selected work", "2024 - Present").
- 헤드라인에서 한 단어에 이탤릭체 또는 무게 변화를 사용하여 음성을 추가하세요 ("The ones I'd demo first.").
- 카운터와 통계에는
font-variant-numeric: tabular-nums.
3.5 레이아웃 문법
- 풀블리드 히어로 (
min-height: 100svh), 콘텐츠는 정중앙이 아닌 왼쪽 하단 또는 그리드 전체에 고정. - 섹션 헤더는 얇은 규칙과 왼쪽에 번호가 매겨진 단색 레이블, 오른쪽에 컨텍스트로.
- 그림자 카드보다는 가는 라인과 그리드를 선호하세요 (컨셉이 촉각적/부드러운 경우는 제외).
- 섹션 리듬을 다양화: 큰 진술, 밀집 인덱스, 가로 릴, 두 컬럼 분할. 결코 여섯 개의 동일한 섹션을 연속으로 배치하지 마세요.
- 모든 곳에서 일관된
--gutter; 섹션 패딩clamp(5rem, 13vw, 11rem).
3.6 텍스처 옵션
필름 그레인 (body::after에 SVG feTurbulence 데이터-URI, 불투명도 0.04-0.08, pointer-events:none), 청사진 그리드 라인, 미묘한 방사형 그라데이션, 또는 WebGL 필드. 하나를 선택하고 쌓지 마세요.
4. 콘텐츠 전략
4.1 정보 아키텍처
홈 (단일 스크롤):
- 히어로: 이름, 한 줄 포지셔닝, 1-2 문장 레드, 기본 CTA (작업 보기) + 보조 (이력서 / 연락처), 작은 메타 행 (역할, 전문 분야, 위치, 가용성).
- 진술 / 소개: 당사자 목소리로 2-4 문장, 참된 3-4개의 통계 (출시된 프로젝트, 연수, 사용자, 별표, 학생인 경우 CGPA).
- 플래그십: 2-4개의 히어로 프로젝트, 큰 카드, 각각 케이스 스터디 페이지로 연결.
- 작업 인덱스: 다른 모든 프로젝트를 행으로 (번호, 이름, 한 줄 요약, 스택, 연도/링크), 종류별로 필터 가능.
- 역량: 그룹화된 기술 (예: 백엔드, 모바일, AI, 도구), 면접에서 방어할 수 있는 것만.
- 경로 / 연혁: 교육, 역할, 주목할 만한 성과.
- 연락처: 큰 CTA 헤드라인, 이메일, 양식, 소셜 링크, 이력서 다운로드.
플래그십당 케이스 스터디 페이지: 테마가 있는 히어로 (이름, 태그라인, 역할, 스택, 링크), 문제, 구축된 것, 대화형 데모 (시뮬레이터, 놀이터, 라이브 목업, 호버 가능한 아키텍처 다이어그램), 주요 결정/트레이드오프, 지표/결과, 그런 다음 "다음 프로젝트" 핸드오프 및 연락처.
같은 음성의 404 페이지.
4.2 카피 규칙
- 1인칭, 평이, 구체적. 무엇이 구축되었고 왜 중요한지로 시작하고, 그 다음에 어떻게.
- 좋은 예: "자신의 AWS, GCP 및 Azure 계정을 연결하면 무료 티어가 하나의 디스크처럼 작동합니다." 나쁜 예: "최첨단 기술을 활용한 혁신적인 클라우드 솔루션."
- 금지된 채우기 단어: 열정적인, 최첨단, 활용, 원활한, 견고한, 혁신적인, 여정, 탐구하다, "저는 코딩을 사랑합니다".
- 모든 지표는 출처가 있거나 생략됩니다. 절대 지어내지 마세요.
- 마이크로카피는 개성이 있지만 명확해야 함 (("Lost in the reel." 404에서, "Scroll to pan" 힌트).
4.3 단일 콘텐츠 모듈
모든 카피와 데이터는 src/content.ts에 있습니다. 컴포넌트는 절대 전기 텍스트를 하드코딩하지 않습니다.
export const PROFILE = { name, role, location, email, github, linkedin, resume: '/resume.pdf', statement };
export type Metric = { value: string; label: string };
export type Flagship = {
slug: string; path: string; index: string; name: string; kicker: string; tagline: string;
summary: string; role: string; stack: string[]; metrics: Metric[]; repo: string;
accent: string; bg: string; fg: string; // 프로젝트별 테마
};
export const FLAGSHIPS: Flagship[] = [ /* 2-4 */ ];
export type WorkKind = 'Systems' | 'AI' | 'Mobile' | 'Web'; // 사람에 맞게 조정
export const WORKS: { name: string; blurb: string; stack: string[]; kind: WorkKind; year: string; href: string; route?: string }[] = [];
export const CAPABILITIES: { title: string; items: string[] }[] = [];
export const PATH: { when: string; what: string; detail: string }[] = [];
export const STATS: Metric[] = [];
5. 아키텍처
5.1 기본 스택
Vite + React + TypeScript; 사용자 정의 속성을 사용한 일반 CSS (팀이 선호하는 경우 Tailwind 허용); gsap + @gsap/react (ScrollTrigger); 부드러운 스크롤을 위한 lenis; 방향이 WebGL을 사용하는 경우에만 three; 연락처를 위한 nodemailer; Vercel/Netlify에 배포.
5.2 구조
index.html 글꼴, 기본 메타/OG, noscript 대체 텍스트
public/ favicon.svg, resume.pdf, og-image
src/content.ts 모든 카피와 데이터
src/index.css 토큰, 서체, 레이아웃, 컴포넌트, 반응형, 축소 모션
src/lib/smooth.ts Lenis + GSAP 티커, 축소 모션 플래그, 스크롤 속도
src/lib/motion.tsx useReveals, useHeroIntro, <Split>, useMeta
src/lib/router.tsx 히스토리 라우터 + 커튼 전환 + <Link>
src/components/Chrome.tsx 탐색, 모바일 메뉴, 커서, 프리로더, 푸터/연락처
src/components/Field.tsx 선택적 WebGL 히어로 배경
src/components/CaseShell.tsx 공유 케이스 스터디 스캐폴드
src/pages/*.tsx 홈, 플래그십당 한 페이지, NotFound
api/contact.ts 서버리스 메일 핸들러
vercel.json SPA 재작성
5.3 라우팅
작은 히스토리 라우터는 포트폴리오에 충분하며 전환을 소유할 수 있게 합니다:
normalizePath(후행 슬래시 제거, 소문자화).navigate(to): 동일한 경로 + 해시 -> 앵커로 부드러운 스크롤; 다른 경로 -> 커튼 재생, 덮인 상태에서 페이지 교체, 맨 위로 스크롤, 그런 다음 표시.popstate수신; 각 경로 변경 후ScrollTrigger.refresh()호출; 교체 후 보류 중인#hash처리.<Link>: 외부 (http,mailto)는target="_blank" rel="noopener noreferrer"와 함께 일반 앵커를 렌더링합니다. 내부는metaKey/ctrlKey/shiftKey또는 왼쪽이 아닌 버튼이 아닌 한 클릭을 가로채므로 새 탭이 계속 작동합니다.- Next.js/Astro: 해당 라우터를 사용하고 레이아웃/전환 훅에서 커튼을 구현합니다.
5.4 경로별 SEO
useMeta(title, description, themeColor)는 각 경로에서 document.title, description, og:*, twitter:*, theme-color 및 canonical을 업데이트합니다. index.html에는 <noscript> 텍스트 요약과 함께 완전한 기본값이 포함되어 있습니다. 가능하면 summary_large_image Twitter 카드와 OG 이미지를 추가하세요. JSON-LD Person 스키마를 고려하세요.
5.5 연락처 API (서버리스, api/contact.ts)
요구 사항:
- POST만 허용 (그 외는 405),
Cache-Control: no-store. - 허니팟 필드 (예: 숨겨진
website): 채워지면 200을 반환하고 드롭. - 모든 필드를 트림하고 길이 제한; 간단한 정규식으로 이메일 검증; 최소 메시지 길이.
- 헤더/제목에 사용되는 모든 항목에서
\r\n제거 (헤더 인젝션); HTML 본문에 있는 모든 것을 HTML 이스케이프. replyTo= 발신자;from= 사용자의 SMTP 사용자.- IP당 최선의 노력 속도 제한 (예: 메모리 내 Map을 통해 10분당 3회, IP는
x-forwarded-for에서). - SMTP 환경 변수가 없으면 친숙한 "email me directly" 메시지와 함께 503을 반환합니다. UI는 대체 수단으로 이메일을 표시해야 합니다.
- 환경 변수:
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,CONTACT_TO..env.example을 제공하세요. 절대 시크릿을 커밋하지 마세요. - 프론트엔드 폼: 유휴/전송 중/전송됨/오류 상태,
aria-live="polite"상태, 전송 중 제출 비활성화, 모든 입력에 레이블.
5.6 배포
Vercel vercel.json:
{ "cleanUrls": true,
"rewrites": [{ "source": "/((?!api/|assets/|.*\..*).*)", "destination": "/" }] }
Netlify: _redirects에 /* /index.html 200. 이력서는 public/resume.pdf에 있습니다; 모든 이력서 버튼은 download와 함께 그곳으로 링크됩니다.
6. 모션 시스템
6.1 원칙
- 하나의 하우스 이징 (예:
expo.out/cubic-bezier(.16,1,.3,1)), 리빌은 0.6-1.4초, 호버는 0.3-0.6초. transform,opacity,clip-path만 애니메이션. 절대 레이아웃 속성을 애니메이션하지 마세요.- 마스크된 리빌 (
overflow:hidden상자에서 텍스트가 올라오는 것)은 고급스러워 보이고, 일반 페이드는 싸 보입니다. - 안무: 히어로 인트로는 프리로더/커튼이 사라질 때까지 기다립니다 (공유
intro.delay). - 모든 효과는
prefersReducedMotion플래그에 의해 게이트됩니다.
6.2 모션 패턴
- 히어로 인트로: 각 요소(배경, 이름, 역할, lede, CTA)가 0.1초 지연으로 연속적으로 올라갑니다. 전체 시퀀스 약 1.2초.
- 스크롤 리빌:
useReveals(ref, { from: 'y 48' | 'opacity 0' | 'clip' | 'scale' }). 기본값: y 48 + opacity 0, 지속 시간 0.8초, 이징--ease, 트리거top 85%. - 작업 카드 호버: 덮개가 올라가고/페이드 인. 또는 마우스를 따라 카드가 살짝 기울어짐. 프레임워크에 의해 캡처된 경우에만
--ease를 존중하세요. - 커서: 개념이 단색/브루탈리스트가 아닌 경우 점/원 커서, 호버 시 크기 조정 또는 색상 변경. Machinel/느린 개념에서는 사라집니다.
- 카운터 / 스크롤 진행: 단색 숫자, 오른쪽 상단에 고정. 또는 단색 숫자가 있는 수평 스크롤 진행 표시줄.
- 연락처 커튼: 푸터를 클릭하면 CTA가 전체 화면으로 확장됩니다.
clip-path: circle()또는scaleY를 뒤집어서.
6.3 reduce-motion 게이트
// src/lib/smooth.ts
export const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
export const motion = {
get reveal() { return prefersReducedMotion ? { y: 0, opacity: 1 } : { y: 48, opacity: 0 }; },
get duration() { return prefersReducedMotion ? 0 : 0.8; },
get scrollDuration() { return prefersReducedMotion ? 0 : 1.2; },
// etc
};
7. 페이지 구성 가이드
7.1 홈
(뒤에서 언급되는 h-xl, h-lg, h-md를 오름차순 크기로 가정)
- 히어로: 풀블리드, 하단 고정. 또는 반 그리드. 무거운 디스플레이 + 작은 lede. 배경은 깔끔한 WebGL 또는 텍스처. CTA가 "작업 보기" 또는 빠른 스크롤.
- 플래그십: 큰 카드 그리드. 각각: 이미지/데모, 이름, 태그라인, 스택 태그, CTA. 2-3개의 플래그십은 한 줄, 4개는 2x2.
- 작업 인덱스: 테이블 느낌. 번호, 프로젝트 이름, 한 줄 요약, 스택, 연도, 링크. 종류별 필터 (버튼, 활성화 시 강조).
- 경로: 수평 타임라인 또는 표. 각 행: 시기(연도/날짜), 무슨 일, 세부 정보.
- 연락처: 큰 CTA 헤드라인 + 이메일 양식 + 소셜.
7.2 케이스 스터디 (CaseShell에서 제공)
- 히어로: 이름, 태그라인, 역할, 스택, 링크. 케이스의 강조 색상이 있는 배경.
--page-accent는 여기에서 설정됩니다. 각 프로젝트는 고유한 색상을 가집니다. - 요약: 문제, 구축된 것, 영향. 한두 문단 + 2-3개의 지표.
- 대화형 데모: 놀이터, 시뮬레이터, 라이브 목업, 호버 가능한 아키텍처 다이어그램. 포트폴리오의 쇼스토퍼. 코드 없이 작동해야 함.
- 의사 결정: 3-4개의 주요 선택. 각각: "문제"와 "해결책". 스택, 아키텍처, 트레이드오프에 대해 솔직해야 함.
- 결과: 긍정적인 경우 출시된 것, 배운 것, 지표. 숫자가 없는 경우, "더 나은 아키텍처" 대신 구체적인 기술적 교훈.
- 다음 프로젝트 / 연락처: 손으로 하는 핸드오프 + CTA.
7.3 404
같은 목소리와 모션. 코믹 또는 미니멀. "이 페이지는 존재하지 않습니다." + 검색 또는 홈으로 돌아가기.
PICO-8 풍선
_____________________
< 이 페이지는 존재하지 않습니다 >
---------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
8. 성능 및 접근성
8.1 성능
preconnect+dns-prefetch모든 타사 출처.- WebP/AVIF 이미지,
<picture>또는loading="lazy". - GSAP
gsap.quickTo또는 네이티브requestAnimationFrame루프; 히어로 외부에will-change를 피하세요. - Lenis: 랩탑에서 절대 30fps 아래로 떨어지지 않음.
- Lighthouse: 모바일에서 95+ 성능, 100 접근성.
<link rel="preload">디스플레이 폰트.
8.2 접근성
min-height: 100svh히어로는 모바일에서 콘텐츠를 자르지 않음.- 라이트-다크 모드:
prefers-color-scheme에 대한 미디어 쿼리; 모든 테마는 완벽한 대비를 가짐. 다크 모드는 개념과 함께 작동해야 하는 경우에만 사용(예: 어두운 천문대). 밝은 배경이 기본. - 모든 스크롤 트리거는 키보드 포커스/ActiveElement를 존중합니다. ScrollTrigger는 포커스된 요소를 가리지 않음.
- 전환: 모든 스크롤 트리거 이전에 계산된
respect-reduced-motion. - 키보드: 모든 것에 Tab 키; 건너뛰기 링크;
aria-expanded메뉴. - 모든 양식 입력에는 관련된
<label>이 있습니다. <noscript>: 전체 포트폴리오 텍스트 요약 + 연락처 이메일 + 이력서 링크.
9. 검증 체크리스트
| 기준 | 방법 |
|---|---|
| 오류 없음 | npx tsc --noEmit, npm run build가 성공 |
| 반응형 | 390px 및 1440px에서 각 페이지. 내용이 360px 이하로 누락되지 않음 |
| 대비 | WCAG AA (4.5:1 텍스트, 3:1 큰 텍스트). DevTools 접근성 검사기 |
| 키보드 | Tab, Shift+Tab, Enter, Escape을 통한 전체 흐름. 포커스 링을 볼 수 있음 |
| 축소 모션 | window.matchMedia('(prefers-reduced-motion: reduce)')에서 모션 없음, 애니메이션 없음, 흐림 없음 |
| 오프라인 테스트 | 3G 조절, WebGL 꺼짐, JS 꺼짐 (noscript 테스트) |
| 소셜 카드 | og:image가 페이스북/트위터/슬랙에서 작동; summary_large_image |
| 연락처 양식 | 전송, 오류, 속도 제한, SMTP 누락 |
| 이력서 | /resume.pdf가 다운로드 |
| 배포 | Vercel/Netlify에서 성공. 사용자 정의 도메인이 설정된 경우 HTTPS가 리디렉션됨 |
| SEO | 각 페이지의 고유 메타 설명; 페이지 제목에 "포트폴리오" 반복 없음 (대신 플래그십 이름) |
| curl 테스트 | ```shell |
| curl https://yoursite.com/some-page | |
| curl -I https://yoursite.com/some-page |