Files
landing_page/refer_landing_page/docs/DESIGN.md
T

18 KiB
Raw Blame History

디자인 시스템 — "Issue 01"

AI 에이전트 네트워크 연구실 (ANL) 랜딩 페이지의 정본(canonical) 디자인 레퍼런스입니다. 코드베이스를 다시 읽지 않고도 디자인 시스템을 이해할 수 있도록 작성했습니다. 토큰의 실제 정의는 tailwind.config.tsapp/globals.css(:root)에, 폰트 로딩은 app/layout.tsx 에 있습니다.


1. 한 줄 요약 (One-liner)

연구실 웹사이트를 "한 권의 인쇄 잡지(Issue 01)"로 다룬다. 따뜻한 종이(ivory) 위에 가까운-검정 잉크(ink), 두 개의 편집 강조색 (vermillion = Agent Engineering / Orchestration, cobalt = MCP / A2A Protocol), 큰 세리프 디스플레이 타이포, 그리고 절제된 스크롤 등장 모션으로 구성된 고대비 매거진 스프레드 시스템입니다. 소수의 토큰에서 사이트 전체가 파생되며, 토큰 하나를 바꾸면 전 페이지에 전파됩니다.


2. 디자인 원칙 (Principles)

원칙 설명
편집 레이아웃 (Editorial layout) 모든 면을 잡지 스프레드처럼 다룬다. 섹션은 01 / 05 넘버링과 헤어라인 괘선으로 구획하고, 큰 디스플레이 숫자가 카드를 앵커한다.
큰 고대비 타이포 (Big high-contrast type) ink(#0A0A0A) on ivory(#F5F1E8)의 강한 대비. 히어로는 clamp() 기반 거대 세리프(Fraunces)로 잡지 표지 스케일을 만든다.
의도적 여백 (Intentional whitespace) 종이처럼 숨 쉬게 둔다. 섹션 패딩은 py-16 sm:py-24, 그리드는 gap-px bg-line 헤어라인으로 분리해 장식 테두리를 최소화한다.
움직임은 절제 (Restrained motion) 콘텐츠는 한 번 부드럽게 자리잡고 멈춘다. 튀거나 반복되지 않으며, 단일 이징으로 페이지 전체가 일관된 호흡을 갖는다.
콘텐츠 우선 (Content first) 모든 편집 데이터는 각 페이지 상단 // CUSTOMIZATION HOOK 배열에 모은다. 모션·장식은 정보를 전달하는 수단이지 그 자체가 목적이 아니다.
한/영 혼식 (KO/EN bilingual setting) 한국어 세리프(Noto Serif KR) 헤드라인과 영어 디스플레이 세리프(Fraunces)를 짝지어, 국문 제목 + 영문 디스플레이 단어의 매거진 바이링구얼 조판을 만든다.
의미 있는 색 (Semantic accent pairing) 두 강조색은 장식이 아니라 연구 영역을 인코딩한다 — vermillion = Agent Eng / Orchestration (홀수), cobalt = MCP / A2A Protocol (짝수).

3. 컬러 토큰 (Color Tokens)

tailwind.config.tstheme.extend.colors 에 정의되고, 동일 값이 app/globals.css:root CSS 변수로 미러링됩니다. 두 곳을 함께 바꾸세요 (순수 CSS 그레인·그라디언트가 CSS 변수를 재사용하기 때문).

Tailwind 토큰 Hex CSS 변수 역할 / 사용 규칙
ink (DEFAULT) #0A0A0A --ink 본문 텍스트, 괘선·테두리, 다크 면(填)
ink-soft #262420 2차 본문 텍스트
ink-mute #6B655B 3차 텍스트, 숫자, 캡션
ivory #F5F1E8 --ivory 페이지 기본 배경(따뜻한 종이)
paper #ECE6D6 --paper 인셋/호버용 어두운 종이
line #D8D1C0 --line 헤어라인 그리드 간격(gap-px bg-line)
vermillion (DEFAULT) #D9342B --vermillion Agent Eng / Orchestration 강조(Hot) · 홀수 항목
vermillion-dark #A8231C vermillion 의 호버/심도(dim) 변형
cobalt (DEFAULT) #1B3A8A --cobalt MCP / A2A Protocol 강조(Cool) · 짝수 항목
cobalt-dark #122863 cobalt 의 호버/심도(dim) 변형
brand, accent (별칭) 레거시 호환 전용. 신규 코드에서 사용 금지

개념적 역할 매핑 (Naming note)

설계 논의에서 쓰던 개념 명칭과 실제 코드 토큰의 매핑입니다. 코드에서는 항상 실제 토큰명을 사용하세요.

개념 명칭            →  실제 코드 토큰
─────────────────────────────────────────
accent.ink          →  ink            (주 잉크/텍스트)
종이(paper) 계열     →  ivory, paper, line
accent.ko (국문)     →  headline-ko 클래스가 font-serif-ko 로 처리(색은 ink)
accent.ko-warm(강조) →  vermillion     (Hot, Agent Eng / Orchestration)
accent.glow / dim    →  vermillion-dark / cobalt-dark (각 강조색의 dark 변형)
Protocol/A2A 강조    →  cobalt         (Cool, MCP / A2A Protocol)

별도의 accent.glow(발광)나 중립 회색 팔레트는 현재 정의돼 있지 않습니다. 강조가 필요하면 vermillion/cobalt 를, 심도가 필요하면 그 -dark 변형을 쓰세요.

헤어라인 그리드 관용구

gap-px bg-line  →  부모 그리드의 1px 간격이 line 색으로 드러남
└ 각 자식에 bg-ivory  →  인쇄 괘선 효과(추가 border 불필요)

4. 타이포 시스템 (Typography)

app/layout.tsx 에서 next/font/google 로 로드해 CSS 변수로 노출하고, tailwind.config.tsfontFamily 에서 패밀리로 묶습니다.

패밀리 클래스 CSS 변수 서체 용도
font-display --font-display Fraunces (영문 세리프, 300600 + italic) 페이지 히어로/매거진 제목, 이탤릭 강조어, 숫자
font-serif-ko --font-serif-ko Noto Serif KR (400/600/700) 한국어 디스플레이/헤드라인
font-sans --font-sans Pretendard(선호) → Inter(웹 폴백) 본문, 키커, UI
(mono) 미설정 코드/수치/라벨용 모노스페이스는 현재 미연동 — §10 FAQ 참고

본문 sans 스택은 tailwind.config.ts 에서 Pretendard → var(--font-sans)(Inter) → ui-sans-serif → system-ui → Apple SD Gothic Neo → Malgun Gothic 순입니다. Pretendard 는 Google Fonts 로 제공되지 않아 Inter 가 웹 폴백으로 로드됩니다.

컴포넌트 타입 클래스 (app/globals.css, @layer components)

ad-hoc 유틸리티 스택보다 아래 시맨틱 클래스를 우선 사용하세요.

클래스 결과
.display 매거진 표지급 영문 세리프, text-display, 가는 굵기, optical sizing
.headline-ko 한국어 세리프 헤드라인, semibold, 좁은 자간
.kicker 소문자 대문자화 아이브로우, tracking-caps(0.28em), 뮤트
.corner-label tabular-nums 스프레드 넘버링("01 / 05")
.pull-quote 큰 이탤릭 세리프 인용구
.container-content max-w-content(78rem) 중앙 정렬 + 반응형 패딩
.rule / .spread-card / .draw-underline 헤어라인 괘선 / 인셋 카드 / 호버 밑줄 드로우

스케일 (clamp 기반)

뷰포트에 따라 브레이크포인트 없이 유체적으로 커집니다.

단계 토큰/클래스 값 (clamp) 용도
1 — Hero text-display (.display) clamp(3rem, 10vw, 9rem) / lh 0.92 커버 디스플레이
2 — Sub-hero text-display-sm clamp(2.25rem, 6vw, 4.5rem) / lh 0.98 보조 디스플레이
3 — Page H1 (PageHeader 내) clamp 없이 text-4xl → lg:text-6xl 페이지 마스트헤드 한글 제목
4 — Section H text-2xl ~ text-3xl 고정 섹션/카드 헤드라인
5 — Lead text-base ~ text-lg 고정 리드 문단
6 — Body text-sm 고정 본문
7 — Caption text-xs 고정 캡션/메타
8 — Kicker .kicker (text-[0.7rem]) 고정 아이브로우/라벨

인트로 히어로는 인라인으로 text-[clamp(2.5rem,8vw,5.5rem)] 를 쓰기도 합니다. 새 거대 제목은 가급적 text-display / text-display-sm 토큰을 재사용하세요.


5. 모션 원칙 (Motion)

모션은 조용하고 편집적입니다. 콘텐츠가 자리잡을 뿐, 튀지 않습니다. 타이밍 토큰은 app/globals.css(--reveal-*)와 tailwind.config.ts(animation)에 있습니다.

토큰

종류 토큰 비고
Duration · reveal --reveal-duration 820ms 스크롤 등장 기본
Duration · medium (Tailwind duration-500) 500ms 호버 색 전환
Duration · marquee animate-marquee 32s / 45s(reverse) / 60s(slow) 러닝 티커
Easing · editorial-out --reveal-ease cubic-bezier(0.16, 1, 0.3, 1) 부드러운 감속(전역 단일 이징)
Keyframes stream-dash / node-pulse 6s / 4s HeroComposition SVG

원칙

  1. 스크롤 등장, 단 한 번. .reveal 이 뷰포트 진입 시 fade + translate 후 유지된다(Reveal 컴포넌트, IntersectionObserver, 라이브러리 없음).
  2. 단일 이징. 전부 editorial-out 으로 ~820ms — 페이지 전체가 한 호흡.
  3. 방향이 레이아웃을 인코딩. 좌측 컬럼은 왼쪽에서, 우측은 오른쪽에서, 히어로 아트는 scale 로 들어온다.
  4. 마퀴는 앰비언트. 3260s 연속 루프는 "관찰 대상"이 아니라 마스트헤드 배경.

사용처 가이드

모션을 쓸 때 모션을 안 쓸 때
섹션/카드가 처음 뷰포트에 들어올 때 Reveal 동일 뷰 안에서 반복 토글되는 상태
통계 수치 등장(Counter) 본문 가독성에 영향을 주는 텍스트
키워드/서지 마스트헤드(Marquee, 페이지당 1개) 정보 전달을 모션에 의존(접근성 위배)
호버 색 전환(duration-500) prefers-reduced-motion: reduce 사용자(자동 비활성화)

6. 공유 컴포넌트 카탈로그

components/ 의 신규 컴포넌트. 각 파일에 CUSTOMIZATION HOOK 주석이 있습니다.

Reveal — 스크롤 등장 모션 래퍼

스크롤 진입 시 자식을 fade + translate. 모든 모션의 기본 프리미티브.

Reveal(props: {
  children: ReactNode;
  variant?: "up" | "left" | "right" | "scale";  // 진입 방향, 기본 "up"
  delay?: number;        // 스태거(ms), transition-delay 로 적용
  as?: ElementType;      // 렌더 태그, 기본 "div"
  className?: string;
})
<Reveal variant="left" delay={120}>
  <article></article>
</Reveal>

SectionLabel — 매거진 섹션 넘버링

페이지 내부 섹션을 01 / 05 넘버링 + 아이브로우로 표시.

SectionLabel(props: {
  index: number;
  total?: number;   // 기본 5
  label: string;    // 영문 아이브로우
  className?: string;
})
<Reveal>
  <SectionLabel index={2} label="Researchers" />
</Reveal>

Counter — 0 → 값 카운트업 숫자

스크롤 진입 시 0에서 value 까지 easeOutExpo 로 틱업(rAF, 라이브러리 없음). prefers-reduced-motion 이면 즉시 최종값.

Counter(props: {
  value: number;
  duration?: number;   // 기본 1600ms
  prefix?: string;
  suffix?: string;
  className?: string;
})
<Counter value={5} suffix="+" className="display block text-ink" />

Marquee — 키워드 러닝 티커

키워드/서지/기구명을 연속 스크롤하는 마스트헤드 배너. 트랙을 2배로 렌더해 -50% 이동이 매끈하게 루프. aria-hidden(장식).

Marquee(props: {
  items: string[];
  reverse?: boolean;    // 진행 방향 반전
  className?: string;
})
<Reveal>
  <Marquee items={keywords} reverse
    className="border-y border-ink bg-ink py-3 font-display text-xl text-ivory" />
</Reveal>

HeroComposition — 추상 편집 히어로 (인트로 전용)

인라인 SVG 일러스트(에셋 없음). A2A = 에이전트 메시 노드 성좌(vermillion, node-pulse), QUIC = 다중화 스트림 흐름(cobalt, stream-dash). 색은 CSS 변수 상속, 기하만 내부 정의.

HeroComposition(props: { className?: string })
<Reveal variant="scale" delay={200} className="lg:col-span-5">
  <HeroComposition className="w-full" />
</Reveal>

함께 쓰는 관용구: 모든 페이지는 페이지 섹션 헤더 → (선택) Marquee 밴드 1개 → 통계 밴드(Counter ×3, gap-px bg-line sm:grid-cols-3) → Reveal+SectionLabel 로 여는 콘텐츠 섹션. 행 내 스태거는 delay={i * 80}~120.


7. 페이지별 디자인 차이 (잡지 비유)

라우트 index 잡지에서의 역할 특징
/ 1 커버 스프레드 거대 한/영 히어로 + HeroComposition 아트, Research Project PageView(3대 과제), 4대 핵심 분야 조판 그리드
/members 2 기고자 페이지(Contributors) 인원 통계 카운터, PI 피처 스프레드, 박/석/학부 그룹을 헤어라인 그리드 + 교차 강조색으로
/publications 3 목차/서지(Index & Bibliography) 서지 Marquee, 파생 통계, 번호 매긴 편집 목록(저널=vermillion, 학회=cobalt)
/lectures 4 강의 카탈로그(Course catalog) 45개 학기 학부·대학원 개설 교과목 이력
/standardization 5 표준화 바이라인(Standards byline) 기구 Marquee, 통계, 기관별 2열 기여 그리드, 기관마다 강조색 배정

8. 새 페이지 추가 체크리스트

  1. 내비게이션 배지 & 마스트헤드: Header.tsx 활성 배지(bg-vermillion text-white dark:text-ivory, aria-current="page")와 페이지 타이틀 섹션으로 시작.
  2. 콘텐츠 분리: 편집 데이터 전부를 파일 상단 // CUSTOMIZATION HOOK 배열에 둔다.
  3. 레이아웃: 헤어라인 그리드 관용구(gap-px bg-line + 자식 bg-ivory)로 구성, 섹션은 border-b border-ink 로 구획.
  4. 모션: 등장 가치가 있는 블록을 Reveal 로 감싸고, §2 페어링 규칙대로 vermillion/cobalt 를 교차 배정.
  5. 토큰만 사용: 디자인 토큰(ink/ivory/paper/line/vermillion/cobalt)과 컴포넌트 타입 클래스만 사용 — 임의 회색·팔레트 밖 hex 금지.

9. 접근성 (a11y) 고려사항

  • 대비비 (Contrast). 본문은 ink(#0A0A0A) on ivory(#F5F1E8)로 WCAG AAA 수준의 강한 대비. 보조 텍스트는 ink-soft/ink-mute 까지만 낮추고, 작은 본문에 ink-mute 단독 사용은 지양. 강조색 위 텍스트는 항상 ivory(흰 종이색)로 뒤집어 대비 확보.
  • 모션 줄임 (Reduced motion). @media (prefers-reduced-motion: reduce) 에서 .reveal·마퀴·[class*="animate-"]·smooth scroll 을 전부 비활성화. Counter 도 즉시 최종값으로 표기. 모션에 정보를 싣지 말 것(원칙 §5).
  • 키보드 포커스 (Keyboard focus). 링크/버튼은 시맨틱 요소(<Link>, <button>)를 사용해 기본 포커스 링을 유지. 호버 전용 정보(예: 색 전환)에 의미를 담지 말고, 콘텐츠는 호버 없이도 읽히게 둔다.
  • 장식 요소. Marquee·HeroComposition 의 텍스트 주석 등 장식은 aria-hidden 또는 role="img" + aria-label 로 스크린리더 노이즈를 차단.
  • 언어 표시. 루트 <html lang="ko">. 한/영 혼식이지만 문서 기본 언어는 한국어.

10. 자주 묻는 질문 (FAQ)

Q. 컬러를 시즌별(Issue 02 등)로 바꾸고 싶어요. A. 강조색 2개(vermillion, cobalt)와 그 -dark 변형만 교체하면 됩니다. 단, tailwind.config.tstheme.extend.colors app/globals.css:root CSS 변수(--vermillion, --cobalt)를 함께 바꾸세요(그레인/그라디언트/SVG가 변수를 참조). 종이 톤을 바꾸려면 ivory/paper/line 을 같은 방식으로 조정합니다. 의미 페어링(vermillion=Agent Eng / Orchestration, cobalt=MCP / A2A Protocol)을 유지하면 페이지 전반의 강조색 배정 로직을 건드리지 않아도 됩니다.

Q. 모션 줄이기(prefers-reduced-motion) 대응은 되어 있나요? A. 네. app/globals.css 의 미디어 쿼리에서 reveal/마퀴/keyframe/smooth scroll 을 모두 끄고, Counter 는 즉시 최종값을 표시합니다. 새 모션을 추가할 때도 이 쿼리에 비활성화 규칙을 넣고, 정보를 모션에만 의존시키지 마세요.

Q. 폰트를 한국어 웹폰트로 교체할 수 있나요? A. 본문 sans 는 이미 Pretendard 를 1순위로 두고 Inter 를 웹 폴백으로 로드합니다 (tailwind.config.ts sans 스택, app/layout.tsx). Pretendard 를 self-host 하거나 next/font/local 로 추가하면 폴백 없이 적용됩니다. 한국어 헤드라인 세리프(Noto Serif KR)나 영문 디스플레이(Fraunces)를 바꾸려면 app/layout.tsxnext/font 로더를 교체하고 --font-serif-ko / --font-display 변수명을 유지하면 됩니다.

Q. 코드/수치용 모노스페이스 폰트는 어디 있나요? A. 현재 시스템에는 모노 패밀리가 연동돼 있지 않습니다. 수치는 font-display (Fraunces) + tabular-nums, 라벨은 .kicker/.corner-label 로 처리합니다. 모노가 필요하면 app/layout.tsxIBM_Plex_Mono(또는 Geist_Mono)를 next/font 로 추가해 --font-mono 변수로 노출하고, tailwind.config.tsfontFamily.mono 에 등록하세요. (소스 변경이 필요하므로 본 문서는 현재 상태만 기록합니다.)

Q. brand / accent 토큰은 뭔가요? 써도 되나요? A. 이전(비-편집) 디자인의 레거시 호환 별칭입니다. 남은 stray 클래스가 깨지지 않게 두었을 뿐, 신규 코드에서는 사용하지 마세요. 항상 vermillion/cobalt/ink 등 정식 토큰을 쓰세요.