vignette/docs/DESIGN_CONCEPT.md
2026-06-28 20:13:36 +09:00

951 lines
65 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-06-25
type: design-concept
project: 한신대학교 AI 심리상담 시뮬레이션 훈련 플랫폼
tags:
- 디자인컨셉
- 디자인시스템
- UX
- 아바타
- 한신대
status: 통합본 v1
---
# 한신대 AI 심리상담 시뮬레이션 플랫폼 — 통합 디자인 컨셉 문서
> **이 문서 하나로 사이트를 만들 수 있다.** 디자인 철학 → 디자인 시스템 토큰(실측값) → 가상 내담자 아바타(상세) → 상담 세션 화면 → 3역할 대시보드 → 컴포넌트·모션 → React 구현 노트 → 안티패턴 체크리스트까지, 추상적 형용사 없이 실제 hex·px·컴포넌트·인터랙션으로 적었다.
>
> 5개 영역 설계([design-language] / [design-system] / [avatar] / [session-ux] / [role-dashboards])를 단일 기준 문서로 종합한 것이다. 토큰 충돌 지점은 본 문서가 **단일 진실원본(SSOT)**으로 일원화했다.
>
> **재사용 자산 연계**: 윤찬 기존 디자인 시스템(`Resources/50_Tech_Dev/디자인/slide-base.css`)과 동일한 토큰 철학(무채 골격 + accent 교체). slide-base 표의 "한신대/의료" 빈 행을 본 문서의 `--accent`로 채운다.
>
> **2026-06-27 구현 메모**: 운영 기본은 dark 화면이다. `docs/design-concepts/generated/*.png`의 7개 주요 화면 컨셉을 기준으로 `docs/design-verification/full-pages/`에 PC/태블릿/모바일 21장 캡처를 남겼고, 자동 검사 기준은 가로 overflow 0 + 큰 흰 CSS 배경면 0이다. P1 세션 아바타는 사용자 제공 PSD `라투디 여캐_ver2.psd`에서 추출한 `seoyeon-live2d-psd-v2`를 기본값으로 쓴다. 이 세트는 Live2D식 래스터 파츠 분리 자산이며, `sad` 표정에서 PSD의 울상 눈썹·우는 입·눈물 레이어를 사용한다. 컨셉 보드 크롭 `p1-concept`는 P1 기본값으로 쓰지 않는다.
---
## 0. 한 문장 컨셉과 SSOT 결정
### 0.1 컨셉
**"불안한 사람을 다루는 사람을 위한, 차분한 임상 도구."**
상담 수련생(학습자)이 가상 내담자 AI와 음성으로 대면하고, 뒤에서 평가 AI가 조용히 관찰한다. 이 화면은 **두 종류의 신뢰**를 동시에 줘야 한다.
1. **임상적 신뢰감** — 학습자가 "이건 진지한 임상 훈련 장비다"라고 느낀다.
2. **교육적 따뜻함** — 연습 중 실수해도 안전하다고 느낀다.
자극적·게임적이면 안 되고, 차갑고 행정적이어도 안 된다. 정답은 그 사이의 **"조용한 따뜻함(quiet warmth)"** — 스펙트럼 위 **65% 임상 : 35% 따뜻함** 지점이다.
> 화면은 "상담실"이지 "대시보드"가 아니다. 평가 정보는 상담실 벽에 걸린 은은한 시계처럼 곁에 있되, 내담자의 얼굴에서 시선을 빼앗지 않는다.
### 0.2 토큰 SSOT 결정 (5개 설계 영역의 색 통일)
5개 영역이 각각 미세하게 다른 그린(`#5B7A6B` / `#3E7A6E` / `#4F6B5D` / `#0E7C7B` / `#0F766E`)을 제안했다. 본 문서는 아래로 **확정 일원화**한다.
| 용도 | 확정값 | 근거 |
|---|---|---|
| **메인 accent (전역 기본)** | `--accent: #3E7A6E` (세이지-틸) | 저채도·차분, 흰 배경 대비 약 5.0:1 (WCAG AA 통과). 흔한 메디컬 블루/형광 틸 회피. slide-base의 `#0F766E`보다 한 톤 더 낮춤. |
| **역할별 보조 accent** | 학습자 `#3E7A6E` / 교수자 `#3A5BA0` / 관리자 `#5B5F6B` | 같은 골격, accent 한 토큰만 교체. 모두 저채도. |
| **보조 온기 accent** | `--clay: #B0735C` (테라코타) | 양산형 메디컬 블루를 깨는 "사람이 만든 교육 도구" 온기. 저채도로만, 화면당 1곳. |
이유: **세이지-틸**은 임상적 차분함(자연·회복·안정)과 따뜻함(흙·식물)을 동시에 품으면서, 한국 상담/심리 분야에서 과용되지 않아 차별화된다. 의료 블루는 흔하고 차갑다.
---
## 1. 핵심 디자인 원칙 (신성불가침 5개)
### 원칙 1 — One Screen, One Intent (한 화면 한 의도)
상담 시뮬레이션은 본질적으로 집중을 요구한다. 학습자가 가상 내담자의 말에 귀 기울이는 순간 화면에 버튼 12개·카드 9개가 깔려 있으면 안 된다. 모든 화면은 그 순간의 **단 하나의 주된 행동**(말하기 / 듣기 / 피드백 읽기 / 세션 시작)을 중심으로 설계한다. 부차 정보는 위계 아래로.
- *적용*: 세션 진행 화면 = 중앙에 내담자 발화 + 음성 비주얼 하나. 평가 피드백은 화면 가장자리 차분한 사이드 패널로, 절대 모달로 튀지 않는다.
### 원칙 2 — 위계는 색 블록이 아니라 타이포 weight + 여백으로
Stripe·Linear의 공통점: 테두리·색 박스로 구역을 나누지 않고 **여백과 글자 굵기로** 나눈다. 강조는 ①font-weight(400→600) ②accent 텍스트/언더라인 ③상단 kicker(소제목) ④accent dot 으로만. **border-left 강조선·좌측 사이드바 강조줄·색 박스 카드 격자 절대 금지.**
- *적용*: 평가 피드백 "공감 반영: 우수"를 초록 배지로 칠하지 않는다. kicker("공감 반영") + 본문 한 줄 + 미세한 accent dot 한 점으로 위계를 만든다.
### 원칙 3 — 임상적 차분함 = 채도를 죽인 중성 베이스 + 절제된 단일 악센트
Calm/Headspace에서 배울 건 파스텔 그라데이션이 아니라 **고채도·고대비를 의도적으로 피하는 절제**다. 베이스는 따뜻한 회백(off-white)·차분한 슬레이트. 악센트는 **세이지-틸 단 하나**를 화면당 1군데만 배급(Linear의 "accent rationing"). 빨강·주황 경고색은 진짜 오류/위험에만.
- *근거*: 불안한 내담자를 다루는 훈련 도구이므로 자극적 색은 학습자 정서·임상 톤 양쪽에 해롭다. 녹색은 우울·불안·스트레스 점수를 가장 많이 낮춘 색이며 "go/긍정" 신호로도 조용히 작동한다.
### 원칙 4 — 따뜻함은 "둥근 카드"가 아니라 "휴머니스트 타이포 + 따뜻한 중성톤 + 넉넉한 여백"
따뜻함을 둥근 모서리·말랑한 일러스트로 내면 임상 신뢰가 깨진다(애들 앱처럼 보임). 대신 **헤드라인에 휴머니스트 세리프 한 톤 옵션**(therapy 웹의 정설: serif=신뢰·인간미), 본문은 깔끔한 산세리프. 순백(#FFF) 대신 따뜻한 종이색, 순흑 대신 잉크 네이비-그린. 이 미세한 온기가 "행정 시스템"과 "사람을 위한 도구"를 가른다.
- *주의*: 한글 본문은 Pretendard 단일 패밀리를 기본으로 한다(국문 상담 도메인 가독·중립). 세리프 헤드라인은 랜딩·표지 같은 희소 지점에서만 선택 적용(본명조). UI 전반은 산세리프 weight 위계로 통일.
### 원칙 5 — 평가 AI는 판사가 아니라 조용한 멘토 (Non-judgmental surfacing)
실시간 피드백이 빨간 X·점수 폭격·"틀렸습니다"로 뜨면 학습자는 위축된다. 피드백은 **관찰("이 지점에서 내담자가 방어적으로 반응했어요") → 제안("열린 질문으로 바꿔볼까요?")** 순서의 **서술형·저채도·비모달**로. 점수는 세션이 끝난 뒤 회고 화면에서만, 절대값이 아니라 성장 추세로.
---
## 2. 무드 좌표 (임상 ↔ 따뜻함 균형)
양 극단(차가운 EHR / 말랑한 명상앱) 사이, **65% 임상 : 35% 따뜻함**.
| 축 | 임상 신뢰(차가움) ← | **→ 우리 좌표 ←** | → 따뜻함(부드러움) |
|---|---|---|---|
| 베이스색 | 순백·차가운 그레이 | **따뜻한 off-white `#FBFAF8` + 차분한 슬레이트** | 크림·파스텔 |
| 악센트 | 임상 블루 | **세이지-틸 `#3E7A6E`** | 코랄·더스티 로즈 |
| 헤드라인 | 기하 산세리프 | **산세리프 weight 위계 (희소 지점만 본명조 옵션)** | 손글씨·라운드 |
| 모서리 | 직각 | **6~8px (거의 직각, 미세 라운드)** | 16px+ 둥근 |
| 그림자 | 없음(헤어라인) | **1px 헤어라인 + 아주 약한 그림자** | 부드러운 큰 blur |
| 모션 | 즉각·없음 | **200~320ms ease-out, 절제** | 느린 호흡 애니메이션 |
> 단 하나의 예외 — 음성 듣기 중 마이크/오브의 **느린 호흡 펄스**. 이건 "지금 듣고 있다"는 정서적 안심 신호라 의도적으로 명상앱 호흡 모션을 차용한다.
---
## 3. 디자인 시스템 토큰 (그대로 `:root`에 붙여 쓰는 실측값)
CSS 변수는 primitive(원시값) → semantic(의미 별칭) 2계층. 컴포넌트는 semantic만 참조 → 다크모드 1곳에서 스왑.
### 3.1 중성 베이스 (Neutral) — 골격
순백/순흑 금지. 따뜻한 종이색 + 잉크 네이비-그린.
```css
:root {
/* ── Primitive: Neutral (따뜻한 종이 + 쿨 슬레이트) ── */
--paper: #FBFAF8; /* 본문 배경: 따뜻한 종이색 (순백 아님) */
--paper-2: #F4F2EE; /* 카드/패널 미세 단차 (테두리 대신 톤차) */
--surface: #FFFFFF; /* 카드 표면 (캔버스가 종이색이라 분리됨) */
--neutral-100: #ECEFF1; /* 표면 hover / subtle fill */
--neutral-150: #E5E1DA; /* 카드 보더 baseline = hairline */
--neutral-200: #D5DBDE; /* divider 진함 */
--neutral-400: #98A4A9; /* placeholder / disabled */
--ink: #1C2A2A; /* 본문 텍스트: 잉크 네이비-그린 (순흑 아님) */
--ink-2: #5A6663; /* 보조 텍스트: 슬레이트 */
--ink-3: #93A09C; /* 캡션/메타 */
--hair: #E5E1DA; /* 1px 헤어라인 (구역 분리는 이걸로) */
}
```
### 3.2 악센트 — 1주 + 1보조 (저채도)
```css
:root {
/* ── Sage-Teal (주 악센트 = 상담/신뢰), 화면당 1곳 배급 ── */
--accent: #3E7A6E; /* ★ 메인 악센트 (버튼/링크/포커스). 흰 배경 대비 5.0:1 AA */
--accent-deep: #316257; /* hover / 진한 강조 텍스트 */
--accent-tint: #EEF4F2; /* 악센트 배경 틴트 (콜아웃·선택·active) */
--accent-bright:#5F968B; /* dot·진행바 fill (화면 전용) */
/* ── Terracotta (보조 악센트 = 학습/온기), 저채도, 화면당 1곳 ── */
--clay: #B0735C; /* ★ 보조 악센트 (학습자 온기 포인트, 내담자 측 신호) */
--clay-deep: #94604C;
--clay-tint: #F6F0EC;
}
```
`--accent #3E7A6E`는 흰 배경 명도대비 약 5.0:1 → 본문 링크/버튼 텍스트 WCAG AA 통과. **2색을 동시에 큰 면적으로 쓰지 않는다** — sage가 전역 기본, clay는 학습자 모드/온기 포인트에서만 점·언더라인·소형 fill로.
### 3.3 의미색 (Semantic feedback) — solid + tint 페어
각 의미색은 아이콘/텍스트용 solid + 배경용 tint. tint 위 text는 모두 AA(4.5:1↑).
```css
:root {
/* 긍정 = 녹색 (상담 진전·라포 형성·가드레일 통과·잘함) */
--pos-text: #2C6E49; --pos-solid: #3B8C5E; --pos-tint: #E8F3EC;
/* 주의 = 앰버 (라포 약화·과도한 침묵·페이싱) — 빨강 대신 머스터드 */
--warn-text: #8A5A00; --warn-solid:#C28A2C; --warn-tint: #FAF1E0;
/* 위험 = 적색 (가드레일 위반·세션 강제중단·임상적 위급) — 오직 진짜 위급만 */
--crit-text: #A8352C; --crit-solid:#C4453A; --crit-tint: #FAEAE8;
/* 정보 = 슬레이트블루 (평가 AI 피드백·시스템 안내, 중립) */
--info-text: #2E5A7A; --info-solid:#3C7299; --info-tint: #EAF1F6;
--neutral-sig:#8895A2; /* 데이터 없음·미평가 */
}
```
**핵심 원칙: 평가 AI의 실시간 피드백 기본 톤은 `info`(슬레이트블루) 또는 `pos`(녹색)** 으로 — 학습자가 비난받는 느낌을 받지 않게. 빨강은 코칭 피드백에 절대 쓰지 않고, 가드레일/위급에만.
### 3.4 시맨틱 별칭 (라이트 모드)
컴포넌트는 primitive를 직접 부르지 않고 이 별칭만 참조.
```css
:root {
--bg-app: var(--paper); /* 앱 캔버스 */
--bg-surface: var(--surface); /* 카드/패널 */
--bg-surface-2: var(--paper-2); /* 중첩 표면/입력 */
--bg-tint: var(--accent-tint); /* 선택·강조 배경 */
--bg-stage: #1E2724; /* 내담자 아바타 영역 (깊은 차콜그린, 시선 집중) */
--text-strong: var(--ink); /* 제목 */
--text-body: var(--ink-2); /* 본문 보조 */
--text-muted: var(--ink-3); /* 캡션 */
--text-on-accent:#FBFAF8; /* accent 버튼 위 텍스트 */
--border-subtle: var(--neutral-150);
--border-strong: var(--neutral-200);
--border-focus: var(--accent);
--focus-ring: color-mix(in srgb, var(--accent) 45%, transparent);
}
```
### 3.5 다크 모드 (gloom 회피 — 충분한 밝은 면 + 절제된 악센트)
배경은 한색 슬레이트(순흑 아님). 악센트는 명도를 올려 가독 확보.
운영 기본 표면은 dark이며, 저장 theme 값이 없거나 API preference가 `system`이면 light로 떨어지지 않고 앱 초기 dark 값을 따른다. dark 화면 안의 대형 카드/섹션은 순백·밝은 베이지 면을 쓰지 않는다.
```css
[data-theme="dark"] {
--bg-app: #131A1E; --bg-surface: #1A2429; --bg-surface-2: #222E34;
--bg-tint: #1E2E2A; --bg-stage: #0E1614;
--text-strong: #EAF0F1; --text-body: #C4CFD3; --text-muted: #88969C;
--text-on-accent:#0F1A17;
--border-subtle: #2A363C; --border-strong: #38454C; --border-focus: #6FB3A4;
--accent: #6FB3A4; --accent-deep: #84C2B4; --accent-tint: #1E2E2A;
--clay: #CC8F77;
--pos-text: #7FD0A0; --pos-solid: #5FB682; --pos-tint: #16271D;
--warn-text: #E2B566; --warn-solid:#D4A24A; --warn-tint: #2A2415;
--crit-text: #E89086; --crit-solid:#D86459; --crit-tint: #2A1715;
--info-text: #79B0D4; --info-solid:#5C97BE; --info-tint: #15222C;
}
```
### 3.6 타이포그래피
| 역할 | 폰트 | 이유 |
|---|---|---|
| **본문/UI 기본** | **Pretendard Variable** | 한글 UI 사실상 표준. 9 weight 가변, 숫자 정렬 우수. 임상 데이터·평가 점수 표기에 깔끔. |
| **숫자·타임코드** | Pretendard + `tabular-nums` | 세션 타이머·점수는 정렬 필요 → `font-variant-numeric: tabular-nums`. |
| (옵션) 랜딩 헤드라인 | Noto Serif KR (본명조) | 신뢰·인간미. **희소 지점만**(표지·히어로). UI 전반은 산세리프. |
```css
:root {
--font-sans: "Pretendard Variable", Pretendard, -apple-system,
"Apple SD Gothic Neo", "Noto Sans KR", system-ui, sans-serif;
--font-serif:"Noto Serif KR", "Source Serif 4", serif; /* 랜딩 헤드만 */
--font-num: "Pretendard Variable", "JetBrains Mono", ui-monospace, monospace;
}
body { font-family: var(--font-sans); -webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility; }
.tabular { font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
```
CDN: `https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.min.css`
**타입 스케일** (기준 본문 16px / 1.6, 한글 자간 -0.01~-0.02em. 위계는 크기보다 weight로):
| 토큰 | px / rem | line-height | weight | letter-spacing | 용도 |
|---|---|---|---|---|---|
| `--fs-display` | 40 / 2.5rem | 1.2 | 700 | -0.02em | 표지·랜딩 대제목 (희소) |
| `--fs-h1` | 30 / 1.875rem | 1.3 | 700 | -0.02em | 페이지 제목 |
| `--fs-h2` | 24 / 1.5rem | 1.35 | 600 | -0.015em | 섹션 제목 |
| `--fs-h3` | 20 / 1.25rem | 1.4 | 600 | -0.01em | 카드/패널 제목 |
| `--fs-lead` | 18 / 1.125rem | 1.6 | 400 | -0.01em | 리드 문장 |
| `--fs-body` | 16 / 1rem | 1.6 | 400 | -0.01em | 본문 기본 |
| `--fs-sm` | 14 / 0.875rem | 1.55 | 400 | 0 | 보조·폼 라벨 |
| `--fs-xs` | 13 / 0.8125rem | 1.5 | 500 | 0.01em | 캡션·메타·배지 |
| `--fs-kicker` | 12 / 0.75rem | 1.4 | 600 | 0.08em | 상단 kicker 소제목 |
**강조 방식(철칙):** 색 블록·border-left 금지. ① weight 400→600 ② accent 텍스트 컬러 ③ 은은한 `--accent-tint` 배경 틴트 ④ 상단 kicker(작은 도트 동반). kicker가 양산형 좌측바를 대체하는 위계 신호다.
### 3.7 스페이싱 (8pt 기반, 넉넉하게)
```css
:root {
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
--sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px; --sp-9: 96px;
}
```
원칙: **컴포넌트 내부 패딩은 8의 배수, 섹션 간 간격은 48~96px 넉넉히.** 불안 완화의 핵심은 여백. 카드 내부 패딩 기본 `--sp-5`(24px), 패널 `--sp-6`(32px), 읽기 영역 max-width 640~680px.
### 3.8 그리드·형태
```css
:root {
--maxw: 1200px; /* 대시보드 콘텐츠 최대폭 */
--maxw-read: 680px; /* 읽기 영역 */
--nav-w: 240px; /* 좌측 네비 펼침 */
--nav-w-collapsed: 72px; /* 좌측 네비 아이콘 only */
--radius: 8px; /* 카드/버튼/입력 (거의 직각) */
--radius-sm: 6px; /* 입력·칩 */
--radius-lg: 12px; /* 패널 */
--gutter: 24px;
}
```
- `border-radius`: 카드 8px, 버튼 8px, 입력 6px (거의 직각, 미세 라운드만). **원형은 음성 오브·아바타·dot만 예외.**
- **깊이는 1px 헤어라인(`--hair`) + 화면용 아주 약한 그림자.** glow·gradient-text·큰 blur 금지.
```css
:root {
--shadow-sm: 0 1px 2px rgba(28,42,42,.05);
--shadow-md: 0 4px 14px rgba(28,42,42,.07); /* 모달·팝오버만 */
}
```
### 3.9 모션
```css
:root {
--ease-out: cubic-bezier(.22,.61,.36,1);
--ease-in-out: cubic-bezier(.45,.05,.55,.95);
--dur-fast: 120ms; /* hover·포커스 */
--dur-base: 200ms; /* 버튼·토글·드롭다운 */
--dur-slow: 320ms; /* 패널 전환·모달 */
--dur-breathe: 3200ms; /* 음성 호흡 펄스 */
}
@media (prefers-reduced-motion: reduce) {
*,*::before,*::after { animation-duration:.01ms!important; transition-duration:.01ms!important; }
}
```
원칙: **차분·짧게·자연 이징.** 불안 도구이므로 튀는 스프링/바운스 금지. 화면 전환은 페이드+미세 슬라이드(translateY 8px 이하). 실시간 피드백 칩은 **자리 미리 확보 후 fade**(밀어내기/점프 금지 — 레이아웃 시프트가 불안 유발). `prefers-reduced-motion` 필수 대응.
---
## 4. 가상 내담자 아바타 (이 플랫폼의 심장)
학습자의 시선이 30~50분간 머무는 단 하나의 오브젝트. 산만하면 라포 연습을 방해하고, 과하면 실제 환자로 오인되며, 빈약하면 몰입이 깨진다.
### 4.1 추천: "반(半)구상 페르소나 카드 (Semi-figurative Persona Card)"
사실적 얼굴도, 추상 오브도 아닌 그 사이. **사실성 35~45%의 양식화 반구상 흉상 + 호흡하는 광배(aura)**.
#### 표현 방식 비교 (왜 이걸 골랐나)
| 방식 | 몰입 | 제작비용(20주) | 윤리/오인 위험 | 불쾌한 골짜기 | 결론 |
|---|---|---|---|---|---|
| A. 추상 오브 / 음성 비주얼라이저 | 낮음 | 매우 낮음(1주) | 없음 | 없음 | **폴백으로만**(미선택/로딩/에러) |
| **B. 2D 양식화 일러스트(반구상)** | 높음 | 중간(3~6주) | 낮음 | 회피 가능 | **★ 1차 채택** |
| C. 실사 / AI생성 얼굴 | 매우 높음 | 높음 | **높음** | **직격(최악)** | 탈락 |
| D. Live2D / 3D | 매우 높음 | 매우 높음(6~10주+) | 중간 | 리깅 품질 의존 | 2차/장기 후보 |
- **B를 고른 이유**: 사실성을 의도적으로 35~45%에 고정 → 불쾌한 골짜기 회피. 벡터라 페르소나별 파라미터(피부톤·헤어·눈 형태·연령감)를 **데이터로 찍어내 시스템화 가능**(페르소나 무한 확장). 눈·눈썹·입꼬리·어깨선 4채널만으로 저항/라포/정서를 은은히 표현. 윤찬 미니멀 톤과 정합.
- **C 탈락**: 80% 사실성에서 미세 립싱크 오차가 더 크게 불쾌. 미성년·취약 내담자를 실사로 그리면 "이 아이 실존?" 윤리 문제 + 데이터 편향.
- **A를 폴백으로 흡수**: ElevenLabs Orb 같은 성숙한 React 자산을 페르소나 미선택/로딩/에러 화면에 영구 잔존.
#### 카드 구조
```
┌─────────────────────────────────────┐
│ [상단 kicker] 교육용 가상 내담자 │ ← 상시 라벨(오인 차단)
│ │
│ ╭───────────────╮ │
│ │ 양식화 흉상 │ │ ← 어깨~머리, 평면 벡터
│ │ (얼굴 35% 사실) │ │ 배경에 호흡하는 광배
│ ╰───────────────╯ │
│ │
│ 서연 · 17세 · 고2 │ ← 페르소나 메타 1줄
│ ────────── │
│ 지금: 머뭇거리며 듣는 중 │ ← 상태 텍스트 1줄
└─────────────────────────────────────┘
```
핵심: **얼굴은 양식화하되 "사람"으로 읽히고, 절대 "실존 인물"로는 안 읽히게.** 코·주름·모공 없음. 눈·눈썹·입꼬리·어깨 각도가 정서를 나르는 4개 채널.
### 4.2 음성 발화 중 반응 — 상태 모델 (4-state)
음성 UI 표준 idle/listening/thinking/speaking을 내담자 맥락으로 재정의.
| 상태 | 트리거 | 입 | 눈/눈썹 | 광배(aura) | 어깨 호흡 |
|---|---|---|---|---|---|
| **listening (학습자 발화 중)** | 마이크 입력 감지 | 닫힘, 미세 입꼬리 | **학습자 쪽 응시**, 깜빡임 4~6s | 차분 펄스 0.06 opacity, 5.5s | 진폭 1.5px, 4s |
| **thinking (응답 생성 대기)** | STT 종료~TTS 시작 | 살짝 다묾 | 시선 살짝 아래/옆, 깜빡임 느려짐 | 안쪽 수축, 채도 -8% | 정지에 가깝게 |
| **speaking (내담자 발화)** | TTS 오디오 재생 | **립싱크 진폭** | 정면 복귀, 눈썹 정서 반영 | 발화 진폭에 약동기(0.04~0.12) | 발화 리듬따라 미세 |
| **idle (시작 전/일시정지)** | 무입력 | 닫힘 | 천천히 깜빡, 가끔 시선 이동 | 최소 펄스 | 느린 호흡 3.5s |
### 4.3 립싱크 — "정밀 음소 매칭 안 함"이 정답
35% 사실성 얼굴에 정밀 비짐(viseme) 매핑은 오히려 불쾌. **오디오 진폭(RMS) → 입 열림 높이** 1채널 매핑.
```ts
// Web Audio AnalyserNode → 매 프레임 RMS → 입 SVG path 세로 스케일
const rms = getRMS(analyser); // 0~1
const mouthOpen = smooth(rms, 0.18); // 지수평활(튐 방지), τ≈180ms
// <path class="mouth" style={{ transform:`scaleY(${0.35 + mouthOpen*0.65})` }}/>
```
- 입 모양: 닫힘=얇은 호, 열림=타원. `scaleY`만 변형. **이빨·혀 절대 안 그림.**
- **데드존**: rms < 0.04는 닫힘 고정 무음 구간 떨림 제거.
- 평활 필수: raw RMS 직결하면 입이 경련함. τ=150~200ms.
### 4.4 모션 진폭 가이드 (산만함 차단의 핵심)
| 모션 | 진폭 | 주기/속도 | 비고 |
|---|---|---|---|
| 어깨 호흡(idle) | translateY 1.5~2.5px | 3.5~5.5s ease-in-out 무한 | "있는 모르게" |
| 깜빡임 | scaleY 10.081 | 120ms, 간격 4~7s 랜덤 | 생체감의 80% 여기서 |
| 광배 펄스 | opacity ±0.04~0.08 | 5~6s | speaking 때만 오디오 동기 |
| 시선 이동(saccade) | ±3px | 0.3s, 간격 6~10s | thinking에서 빈도 |
| 립싱크 | scaleY 0.35~1.0 | 오디오 실시간 | 데드존+평활 |
> 원칙: **동시에 움직이는 채널 ≤ 2개.** speaking이면 입+광배만. listening이면 깜빡임+호흡만.
### 4.5 정서 시각화 — 6파라미터 상태머신
valence/arousal 축을 아바타 파라미터로 인코딩. **과장 절대 금지**(만화적 눈물·홍조·땀방울 전부 금지). 상담 도구의 정서는 "감지되되 단언되지 않는" 수준.
| 내담자 정서 | /눈썹 | 입꼬리 | 자세(어깨선) | 광배 색조 | 호흡 |
|---|---|---|---|---|---|
| **중립/라포** | 눈썹 수평, 눈맞춤 | 미세 상향 | 정면, 약간 열림 | 세이지 `#3E7A6E` 4% | 안정 4s |
| **우울(저각성·부정)** | 눈꺼풀 1~2px 하강, 시선 아래 | 수평~미세 하향 | 어깨 안으로·아래로 | 청회색 `#5B6B73` 5% | 느리고 얕게 5.5s |
| **불안(고각성·부정)** | 깜빡임↑(2~4s), saccade | 다묾, 긴장 | 약간 들썩 | 차가운 `#3B6E8F` 5%, 빠른 펄스 | 빠르고 얕게 3s |
| **저항/방어** | 시선 회피(/아래 고정) | 굳게 닫힘 | 반쯤 돌아선 각도(turn 8°) | 중립 회색, 무펄스 | 정지에 가깝게 |
상태머신이 `(eyelidDrop, gazeAvert, shoulderTurn, breathRate, auraHue, blinkInterval)` 6개 숫자만 바꾸면 정서 전환. **라포가 쌓이면(세션 진행) 저항 페르소나가 shoulderTurn 8°→0°, gazeAvert→눈맞춤으로 서서히 완화** 학습자가 "내가 라포를 만들었다" 시각적으로 체감. **이게 이 도구의 교육적 핵심.** 정서 전환은 0.8~1.2s ease로 천천히, 동시 변하는 파라미터 3개.
### 4.6 페르소나 파라미터 시스템 (새 페르소나 = 새 숫자 묶음)
```jsonc
// persona/seoyeon.json — 청소년 페르소나 예시
{
"id": "seoyeon",
"label": "서연 · 17세 · 고2",
"appearance": {
"ageBand": "teen", // teen | youngAdult | adult | senior
"skinTone": "#E8C9A8",
"hair": { "style": "long-straight", "color": "#2B2723" },
"faceRatio": { "eyeSize": 1.15, "jawWidth": 0.92 }, // teen=큰 눈·좁은 턱
"outfit": "hoodie", // 실루엣만, 디테일 X
"realism": 0.40 // 0.35~0.45 고정(불쾌한 골짜기 회피)
},
"voice": { "provider": "openai", "preset": "soft-young-fem", "rate": 0.96 },
"baseAffect": "anxious", // 시작 정서
"resistance": 0.6, // 0~1, 라포로 감소
"auraHueShift": -6
}
```
#### 연령대 외형 규칙
| ageBand | 크기 | /얼굴 | 실루엣 | 광배 채도 | 음성 |
|---|---|---|---|---|---|
| **teen** | 1.1~1.2× | 좁은 ·둥근 | 후디·체크 | 약간 높음(생기) | 부드럽고 높은 |
| **youngAdult** | 1.0× | 표준 | 캐주얼 | 중간 | 표준 |
| **adult** | 0.95× | 각진 | 셔츠·니트 | 낮음(차분) | 낮고 안정 |
| **senior** | 0.92× | 부드러운 윤곽 | 단정 | 낮고 따뜻 | 느린 |
- **미성년 페르소나는 realism을 0.35로 낮추고** `교육용 가상 내담자(미성년 시뮬레이션)` 라벨 강화 실존 미성년 오인 원천 차단.
- 외형은 인종·특정 외모 stereotype 회피를 위해 **중립 팔레트 3~4종** 제공(편향 최소화).
### 4.7 아바타 구현 기술 — SVG 1차, Rive 2차
| 기술 | 적합 | 근거 |
|---|---|---|
| **SVG + CSS/Web Animations + Web Audio** | 1차 | 페르소나=벡터 파라미터, 립싱크=RMS 1채널, 의존성 0, React 친화, 미니멀 정합 |
| **Rive (상태머신)** | 2차 고도화 | 상태머신이 .riv에 내장, React는 input만 wiring. Lottie 대비 파일 10~15× 작음 |
| Lottie | 보조 | 정형 애니(로딩·전환) OK, 실시간 오디오 반응엔 부적합 |
| Live2D/3D | 장기 | 표현력 최고지만 20주·시스템화 불리 |
#### 1차안 컴포넌트 구조 (SVG)
```
<ClientAvatar persona state affect analyser/>
├─ <AuraLayer hue affect state/> // 배경 광배: radial-gradient, opacity 펄스
├─ <BodySilhouette persona/> // 어깨선, shoulderTurn 각도
├─ <FaceGroup persona affect>
│ ├─ <Eyes blink gaze eyelidDrop/>
│ ├─ <Brows affect/> // 정서별 각도 2~3px
│ └─ <Mouth analyser state/> // RMS→scaleY 립싱크
└─ <PersonaLabel/> // "교육용 가상 내담자" 상시
```
```tsx
// 단일 rAF 루프, 의존성 0
function useAvatarMotion(state, affect, analyser) {
const [frame, setFrame] = useState(initFrame(affect));
useEffect(() => {
let raf, t0 = performance.now();
const loop = (t) => {
const dt = (t - t0) / 1000;
const breath = Math.sin(dt * (2*Math.PI/affect.breathPeriod)) * affect.breathAmp;
const mouth = state==='speaking' ? smoothRMS(analyser) : 0;
const blink = blinkSchedule(t, affect.blinkInterval);
setFrame({ breath, mouth, blink, gaze: gazeFor(state) });
raf = requestAnimationFrame(loop);
};
raf = requestAnimationFrame(loop);
return () => cancelAnimationFrame(raf);
}, [state, affect, analyser]);
return frame;
}
```
- **퍼포먼스**: SVG 변형은 `transform`(GPU 합성), layout 트리거 속성(width/top) 금지. 단일 rAF, 60fps 여유.
- **RN 이전 대비**: SVG는 `react-native-svg`, Web Audio는 `react-native-audio-api` 대체 로직 재사용. Rive도 RN 런타임 있음.
- **접근성**: `prefers-reduced-motion` 켜지면 호흡·광배 정지, 상태는 텍스트로만.
---
## 5. 상담 세션 화면 (메인 화면)
핵심 긴장: **몰입 vs 평가 가시성.** 실시간 피드백이 라포 형성을 방해하면 되고, 평가가 사후로만 묶이면 학습 효과가 떨어진다. 해법 = **2단(two-tier) 피드백 모델** 실시간은 "신호(signal)" 수준, 정밀 평가는 "회기말 리뷰".
### 5.1 3-column 골격 (데스크탑 ≥1280px)
```
┌──────────────────────────────────────────────────────────────────────────┐
│ 상단 바 (56px) 좌:세션 제목/시나리오 중앙:회기 단계 우:경과시간·종료 │
├──────────────────┬──────────────────────────────────┬──────────────────────┤
│ LEFT (320px) │ CENTER (flexible) │ RIGHT (300px) │
│ ───────────── │ ───────────────── │ ───────────── │
│ 회기 단계 트랙커 │ 내담자 아바타 / 음성 STAGE │ 피드백 신호 패널 │
│ (라포→탐색→ │ (어두운 배경, 중앙 집중) │ (은은한, 평시 접힘) │
│ 개입→정리) │ │ │
│ 내담자 컨텍스트 │ [ 아바타 + 음성 오브 ] │ ── 내담자 상태 ── │
│ 카드 │ │ ── 라이브 신호 ── │
│ │ 실시간 자막 (아래→위 흐름) │ (최대 1개, 페이드) │
│ │ │ ── 셀프 노트 ── │
├──────────────────┴──────────────────────────────────┴──────────────────────┤
│ 하단 컨트롤 바 (80px) 마이크 · 일시정지 · [몰입│은은│코칭] · 회기 종료 확인 │
└──────────────────────────────────────────────────────────────────────────┘
```
**비율 의도: 시각적 무게 = 주의 배분.** 내담자 stage 60%, 평가 패널 15%(평시 대부분 접힘). 화면은 대시보드가 아니라 상담실이다.
**반응형:**
- 태블릿(768~1279px): RIGHT 패널이 오버레이 drawer(평시 숨김, 우상단 신호 도트만). LEFT 280px.
- 모바일/RN(<768px): 단일 컬럼. stage 상단 고정(40vh), 자막 스크롤, 단계는 상단 가는 진행선, 평가는 하단 시트(bottom sheet). 컨트롤 하단 고정.
### 5.2 중앙 STAGE — 음성 오브 (Voice Orb, 4상태)
자극적 막대 파형 대신 **차분한 호흡(breathing) 애니메이션**. 아바타(원형 220px) 둘레 오브 .
| 상태 | 시각 | | 모션 |
|---|---|---|---|
| **내담자 말하는 중** | 따뜻한 , 음량 따라 미세 진동 | `--clay` glow, 두께 4px | 음량 연동 amplitude(0.5~3px), 0% 형광 |
| **학습자 말하는 중** | 세이지 , 호흡 펄스 | `--accent` glow | 1.4s ease breathing scale 1.01.04 |
| **대기/침묵(thinking)** | 가는 점선 매우 느리게 회전 | `--ink-3` | 8s/회전, 거의 보일 정도 |
| **일시정지** | 반투명 오버레이 + "일시정지" | `--bg-stage` 60% | 정지 |
```css
.orb {
position: absolute; inset: -14px; border-radius: 50%;
box-shadow: 0 0 0 3px var(--ring-color),
0 0 28px 4px color-mix(in srgb, var(--ring-color) 35%, transparent);
transition: box-shadow 320ms ease;
}
.orb[data-state="learner"] { --ring-color: var(--accent); animation: breathe 1.4s ease-in-out infinite; }
.orb[data-state="client"] { --ring-color: var(--clay); /* JS가 RMS 음량을 --amp로 주입 */ }
@keyframes breathe { 0%,100%{ transform: scale(1) } 50%{ transform: scale(1.035) } }
```
음량 연동은 JS `onVolumeChange`/RMS CSS 변수 `--amp` box-shadow blur 미세 모듈레이션. **막대 파형(equalizer) 금지** 너무 "녹음 "스럽고 자극적. 호흡하는 빛이 임상적이다.
### 5.3 실시간 자막 (Transcript) — 대본 스타일
음성이 , 자막은 보조. stage 하단, **아래→위 흐름**. 채팅 버블 양산형 회피, 대본(script) 스타일:
```
─────────────────────────────────────
내담자 14:32
요즘은 그냥… 아침에 일어나는 게
제일 힘들어요.
나(학습자) 14:33
아침에 일어나는 것조차 버겁게
느껴지시는군요. 그 마음을 조금
더 들려주실 수 있을까요?
─────────────────────────────────────
```
- 화자 라벨 12px 600 메타톤. 내담자 발화는 `--clay-tint` 옅은 배경 틴트 블록, 학습자 발화는 `--accent-tint` 틴트. **버블 외곽선·꼬리·border-left 없음.** 틴트 블록만으로 화자 구분.
- 진행 발화(partial) `--ink-3` 흐릿하게 타이핑되다 확정되면 `--ink` 또렷하게.
- 자동 스크롤, 위로 스크롤하면 자동스크롤 해제 + "최신으로" 작은 .
### 5.4 회기 단계 표시 (라포 → 탐색 → 개입 → 정리)
LEFT 패널 세로 트랙커 + 상단 가로 미니. **현재 단계만 또렷, 나머지는 은은히** (단계 압박 방지).
```
회기 진행 ← kicker
● 라포 형성 09:12 ← 완료: 채워진 sage 도트 + 소요시간
◉ 탐색 진행중 ← 현재: 링+채움, accent, 굵게
○ 개입 ← 예정: 빈 도트, ink-3
○ 정리
```
- 연결선 1px `--hair`, 완료 구간만 `--accent-bright`.
- **자동 추적 기본, 수동 보정 가능.** 백그라운드 평가 AI가 대화로 현재 단계 추정해 `◉` 이동. 학습자가 직접 "다음 단계로" 가능(자각 촉진). 추정과 인식 어긋나면 회기말 리뷰에서 짚음.
- **자극 배제:** 단계 전환 화면 전환·효과음·축하 애니 없음. 도트가 조용히 채워질 (400ms ease).
### 5.5 실시간 피드백 — "거슬리지 않게" (이 설계의 심장)
**3단계 강도 모델** 학습자가 토글로 고른다 (하단 컨트롤 segmented control, 기본=은은한 신호):
| 모드 | 실시간 표시 | 대상 |
|---|---|---|
| **몰입(Immersive)** | 라이브 신호 전혀 없음. 백그라운드 기록만. 모든 피드백 회기말. | 숙련·실전 압박 연습 |
| **은은한 신호(Ambient)** 기본 | 우측 패널에 **앰비언트 도트 1개만**, 색으로 톤만. 텍스트 없음(호버 ) | 일반 연습 |
| **코칭(Coached)** | 발화 직후 짧은 텍스트 힌트 페이드인 | 초보·특정 기법 집중 |
#### 앰비언트 신호 (기본 모드 핵심)
우측 패널에 **단 하나의 부드러운 도트**가 직전 발화 평가 톤만 색으로 전한다. 점수·숫자·순위 **없음.**
```
라이브 신호 ← kicker
● 공감적 반영 ← pos 도트 + 한 단어. 6초 후 페이드.
최근 흐름 · · ● · ◦ · ● ← 최근 6개 발화 톤 미니 시퀀스(클릭 가능)
```
- 도트 색: `--pos-solid`(잘함) / `--warn-solid`(살펴볼 ) / `--ink-3`(중립). **빨강·점수 없음.**
- 등장: 발화 종료+평가 완료 opacity 01, 350ms. **6초 후 자동 페이드** 누적되면 대시보드가 .
- 거슬림 최소화 3원칙: 번에 1개 텍스트 기본 숨김(색만) 시간 제한 페이드. 진동/소리/번쩍임 전무. 주변시로 "느낄" 수준.
#### 코칭 모드 텍스트 힌트
```
코칭 힌트 ← kicker
방금 질문은 '예/아니오'로 닫혀 있었어요.
내담자가 더 말하도록 열어보면 어떨까요?
예: "그때 어떤 마음이 드셨는지 들려주세요."
[ 알겠어요 ] ← 가볍게 dismiss
```
- `--accent-tint` 배경 틴트 블록(border 없음), 13~14px. 예시 문장 `--ink-2` 이탤릭. 번에 1개, 힌트 오면 이전 교체(stack ).
- **위험 신호만 예외적 즉시 표시(모드 무관):** 자해·위기 언급을 학습자가 놓치면 모드 무관하게 우측에 차분한(빨강 아닌 `--warn-solid`) 알림 "안전 점검: 방금 위기 신호가 있었어요." 교육적으로 놓치면 되는 지점이라 항상 노출.
#### 내담자 상태 미터 (우측 상단) — "반응 읽기 연습"의 거울
```
내담자 상태
감정 톤 불안 ▓▓▓▓░░ ← 가로 게이지, clay 계열, 라벨 텍스트
마음 열림 ▓▓░░░░ ← 라포 진척 대리지표
```
게이지는 매우 천천히(2s ease) 실시간 흔들림이 산만하지 않게. 막대 라운드 없는 사각, 4px 높이.
### 5.6 하단 컨트롤 바
- **마이크 버튼( 컨트롤):** 56px 원형. 학습자 말하는 = `--accent` 채움 + 호흡. 음소거 = 아웃라인. push-to-talk 또는 토글. 상태 텍스트 ("듣고 있어요" / "마이크 꺼짐").
- **일시정지:** 타이머·평가·녹음 모두 정지. 정지 stage 차분한 오버레이.
- **종료:** 오발동 방지 숨은 제스처가 아니라 명시적 **회기 종료** 버튼 + 확인 다이얼로그. 종료가 유일하게 진한 경고색(`--crit-solid`) 허용 영역.
- 접근성: 키보드(Space=마이크, P=일시정지), `--focus-ring` 2px. 음성 상태는 색만이 아니라 텍스트 병기(색각 이상 대응).
### 5.7 회기 종료 후 리뷰 화면 (진짜 학습이 일어나는 곳)
실시간에선 일부러 참았던 정밀 평가를 여기서 푼다. 구조: **타임라인 + 기법 라벨 + 슈퍼바이저 코멘트 + 개선점.**
리뷰도 라이브 세션과 같은 dark 작업면을 유지한다. 저장된 발화가 없는 상태에서도 카드로 빠지지 않고, 근거 대기/평가 대기/워크시트 대기를 어두운 패널로 보여준다.
```
┌──────────────────────────────────────────────────────────────────────────┐
│ 리뷰 · 시나리오:우울 호소 20대/회기1 오디오 다시듣기▷ PDF 내보내기 │
├──────────────────────────────────────────────────────────────────────────┤
│ 한 줄 요약 (큰 문장 하나, 24px/600 — 에디토리얼 미니멀의 핵심) │
│ "라포는 안정적으로 형성됐지만, 탐색 단계에서 닫힌 질문이 반복돼 │
│ 내담자의 자기개방이 일찍 멈췄습니다." │
├───────────────────────────────────────┬──────────────────────────────────┤
│ LEFT (62%) 타임라인 + 자막 │ RIGHT (38%) 분석 사이드 │
│ 회기 타임라인(가로 막대) │ ── 기법 사용 분포 ── │
│ 라포▏▏탐색▏▏▏▏▏개입▏▏정리▏ │ 반영적 경청 ▓▓▓▓▓▓ │
│ ▲ 마커(코멘트·기법·하이라이트) │ 개방형 질문 ▓▓ │
│ ─── 스크롤 자막(마커 연동) ─── │ 닫힌 질문 ⚠ ▓▓▓▓▓ (살펴볼 점) │
│ 나 14:33 ◆[감정 반영] … │ ── 잘한 순간 ── │
│ └ 슈퍼바이저: "좋은 반영…" │ ── 다음 회기 개선점(최대 3개) ── │
└───────────────────────────────────────┴──────────────────────────────────┘
```
- **타임라인(가로):** 4단계 너비 비례 구간으로 농담 구분. 마커 = 기법 라벨·살펴볼 순간·잘한 순간·슈퍼바이저 코멘트(이모지 아님, SVG 글리프/도트). 클릭하면 좌측 자막 점프 + 오디오 시점으로.
- **자막 + 인라인 분석:** 학습자 발화마다 기법 라벨 (`[반영적 경청]` `[개방형 질문]` `[닫힌 질문]`), `--accent-tint`/`--warn-tint` 배경, border 없음 11px. 라벨 아래 들여쓰기로 슈퍼바이저 코멘트(AI 자동 + 교수자 직접). AI코멘트 `--ink-2`, 사람 코멘트 `--accent` + "교수자" 태그.
- **분석 사이드:** 기법 사용 분포(가로 게이지, 점수 아님 빈도+적절성, 과다·과소만 `--warn` 라벨). 잘한 먼저, 개선점 **최대 3개**(실행 가능 구체적, 항목 타임라인 마커 연결). 다음 회기 개선점은 "다음에 시도할 문장" 형태.
- **톤:** 점수·등급·합불 **없음.** 상담 역량은 성장 곡선이지 시험이 아니다. 추세는 별도 "학습자 성장" 화면에서만, 단일 리뷰엔 절대점수 보임. PDF 내보내기(슈퍼바이저 제출), 오디오 다시듣기, 클립 공유.
---
## 6. 3역할 대시보드 (학습자 / 교수자 / 관리자)
### 6.1 4가지 설계 결정 (근거)
| 결정 | 근거 |
|---|---|
| **레이더차트 금지, small-multiples 라인 채택** | 레이더는 항목 순서로 모양 왜곡 + 범주선 "증가/감소" 착시. Tufte small-multiples + 공통 축이 정확. 윤찬 "카드덤프 금지"와도 정합. |
| **신뢰·차분 = 단일 accent + 넉넉한 여백 + 위계** | 의료 UI: blue=신뢰, green=정상범위, **red는 진짜 임상 긴급에만 예약**. whitespace·typography로 불안 완화. |
| **교수자 화면은 "인지"가 아니라 "개입"까지** | 교사용 LA 대시보드 대부분이 awareness만 주고 actionable intervention이 없다는 비판 화면을 "개입 필요 학생" 액션 큐로. |
| **역할 전환 = 컨텍스트 라벨 + accent 토큰** | 과한 ·뱃지 남용은 양산형. 좌상단 역할 라벨 + accent 토큰 교체로 "지금 누구의 화면인지" 조용히. |
### 6.2 역할별 accent 오버라이드
```css
body[data-role="learner"] { --accent:#3E7A6E; --accent-bright:#5F968B; --accent-tint:#EEF4F2; } /* 세이지-틸: 성장 */
body[data-role="instructor"] { --accent:#3A5BA0; --accent-bright:#5478C4; --accent-tint:#EAEFF7; } /* 인디고-블루: 감독 */
body[data-role="admin"] { --accent:#5B5F6B; --accent-bright:#7D818E; --accent-tint:#EEEFF1; } /* 슬레이트: 운영 */
```
역할 모두 채도를 낮춰 자극 없게. red(`--crit-solid`) 어느 역할에서도 장식으로 쓴다 오직 "지금 개입해야 하는 학생/세션" .
### 6.3 공통 앱 셸 (Shell)
같은 골격 공유, 좌측 네비 항목 + 좌상단 컨텍스트 라벨만 차이. 역할 전환 화면 리셋이 아니라 메뉴·accent만 바뀜.
- 톱바 56px `background:var(--surface); border-bottom:1px solid var(--hair);` (그림자 없음).
- 좌측 네비 기본 72px 아이콘 전용(Lucide stroke 1.75), hover/포커스 220px 슬라이드(160ms). 활성 = 아이콘 `color:var(--accent)` + **3px 강조바 금지** 아이콘 배경 `var(--accent-tint)` `border-radius:8px` 알약형(네비 알약만 8px 관용).
- **역할 컨텍스트 라벨**: 톱바 좌측, `font-family:var(--font-num); font-size:13px; letter-spacing:0.04em; color:var(--accent);` "학습 대시보드"/"교수 콘솔"/"운영 콘솔". "지금 누구로 보고 있나" 유일하고 조용한 신호.
- **권한 표현 원칙: 권한 없으면 DOM에서 제거.** disabled 회색처리도 존재를 숨김. 화면이 깨끗해지고 "내가 하는 " 노이즈 제거. 임상 데이터 프라이버시(관리자는 학생 개별 성장곡선·transcript 기본 접근 불가, 메뉴 자체 렌더 ).
### 6.4 학습자 대시보드 (홈 = "당신은 나아지고 있다")
```
COUNSELING PRACTICE · 4주차 ← kicker
수련생님, 지금까지 12회 연습했어요. ← h1 28px/700
최근 라포 형성이 눈에 띄게 안정됐습니다. ← lead, accent .em
┌─────────────────────────────┐ ┌───────────────────────────┐ ← cols 7:5 비대칭
│ 종합 상담 역량 │ │ 다음 연습 │
│ ╭───────╮ │ │ ▸ 불안 호소 내담자·중급 │
│ │ 72 │ +6 ▲ │ │ 이전 약점: 침묵 다루기 │
│ ╰───────╯ 지난주 대비 │ │ [ 연습 시작 → ] │
│ (단일 게이지, 둘레 progress)│ │ 추천 이유: 라포는 올랐지만 │
└─────────────────────────────┘ │ 위기개입 정확도 정체 │
└───────────────────────────┘
역량별 추이 (최근 8회) ← kicker
┌────────┐┌────────┐┌────────┐┌────────┐ ← small multiples 4열, 공통 y축 0-100
│라포형성 ││기법사용 ││개입정확도││공감반영 │
╲__ ││ __ ││ ╲__╲ ││ __
│ 82 ▲ ││ 68 → ││ 61 ▼ ││ 75 ▲ │
└────────┘└────────┘└────────┘└────────┘
최근 피드백 모아보기 (테이블, 카드 아님) ← kicker
6/24 불안 내담자 │ "침묵 견디지 못하고 성급히 해결책 제시…" — 개입 ▸
6/22 분노 내담자 │ "반영 정확. 다만 감정 명명이 늦음." — 공감 ▸
```
- **종합 게이지(radar 대체):** 단일 원형. SVG `<circle>` 트랙 `stroke:var(--neutral-150)`, fill arc `stroke:var(--accent); stroke-linecap:round`. 중앙 숫자 48px/700. 변화량 `+6 ▲` = `--pos-solid`, 하락이면 `--warn-solid`(앰버, 빨강 아님). 아래 문장 자연어 요약.
- **역량별 추이 = small multiples:** 4개 동일 크기 미니 라인. **공통 y축 0-100**( 카드만 0/50/100 옅게 표기). 라인 `stroke:var(--ink-2); stroke-width:1.5`. 마지막 점만 `r:3; fill:var(--accent)`. 카드 `background:var(--surface); border:1px solid var(--hair); border-radius:8px; padding:16px`. **상단 강조선·좌측바 금지.** 우하단 최신값+추세 화살표(▲`--pos`, `--ink-3`, `--warn`). 호버 툴팁, 클릭 세션 상세.
- **피드백 모아보기 = 테이블, 카드 아님:** 날짜/내담자유형/인용 코멘트/태그/`▸`. zebra 없이 `border-bottom:1px solid` `--paper-2`. hover `background:var(--accent-tint)`. 카드 격자로 흩뿌리지 않고 시간순 컬럼 위계.
### 6.5 교수자 콘솔 (홈 = "누구를 먼저 도와야 하는가")
핵심: **awareness가 아니라 triage.** 화면 최상단이 "개입 필요 학생" 액션 .
```
상담실습 II · 28명 담당 ← kicker
이번 주, 3명에게 개입이 필요합니다. ← h1, accent .em
┌──────────────────────────────────────────────────────────────┐ ← 개입 큐(최우선, 풀폭)
│ ● 박서연 개입정확도 3주 연속 하락(61→52→44) 미연습 5일 ▸ │ 좌측 dot = --crit-solid
│ ● 이도현 위기상담 시뮬 중도이탈 2회 마지막 6/20 ▸ │
│ ● 최민준 라포 점수 급락, 피드백 미열람 7건 ▸ │
└──────────────────────────────────────────────────────────────┘
학생별 현황 [정렬: 위험도▾] [영역: 전체▾]
학생 세션 라포 기법 개입 공감 추세 마지막 상태
김수련 12 82↗ 68→ 61↘ 75↗ ▁▃▅▆▇ 6/24 양호
박서연 8 55↘ 49↘ 44↘ 58↘ ▇▅▃▂▁ 6/19 ● 개입
이도현 14 88↗ 79↗ 71→ 84↗ ▅▆▆▇▇ 6/23 양호
```
- **개입 (triage):** 풀폭 패널. 좌측 dot `8px; background:var(--crit-solid)`(red의 유일한 정당한 사용처). 사유 = 수치 변화 + 행동 신호(미연습일·미열람·중도이탈) 자연어로. 알고리즘이 뽑되 교수가 최종 판단하도록 "" 노출.
- ** 평균 역량 분포 = 가로 막대**(레이더 아님): fill `var(--accent)`, 트랙 `var(--paper-2)`. **최저 항목만** 우측 `← 취약` `color:var(--warn-solid)`. 나머지 차분한 무채.
- **학생별 테이블:** sparkline(▁▃▅▆▇, 7px SVG, 최근 8회 종합점수). 역량 `82↗`(화살표 색만 시맨틱). 정렬 기본 위험도 . 상태 "양호" `--ink-3` 무채, "● 개입" `--crit-solid` dot. red를 곳에 집중. 클릭 학생 드릴다운(학습자 화면 + 세션별 utterance-level 평가 타임라인).
### 6.6 관리자 콘솔 (홈 = "시스템이 건강한가 · 누가 무엇을 했는가")
핵심: **운영 신뢰성 + 감사.** 학습 내용엔 개입 하고 시스템·사용·교수활동 감사에 집중. 무채 슬레이트로 가장 차분.
- **정보구조:** `/admin` 운영 홈으로 고정한다. 사용자 CRUD는 `/admin/users`, 역할·그룹·권한 정책은 `/admin/access`, 사용자 문제·불만·장애 접수는 `/admin/tickets` 분리한다. 설정은 계속 `/settings`.
- **증거 원칙:** 운영 티켓은 `app.support_ticket`, 헬스 샘플 이력은 raw `app.admin_health_event` daily `app.admin_health_daily_rollup` 저장된 실제 행만 표시한다. 티켓 중복 표시는 저장된 `fingerprint`/`parent_ticket_id` 기반 힌트와 관리자 수동 연결만 보여주며, 자동 병합이나 자동 수정처럼 보이게 만들지 않는다. 관리자 화면 조회와 synthetic sampler가 샘플을 적재할 있지만, "SLA 업타임"처럼 표현하지 않고 "최근 헬스 샘플 정상률/중단 기록"으로 표시한다. 세분 그룹 CRUD처럼 저장소/API가 없는 항목은 상태 또는 정책 초안으로 남기며, 운영 수치처럼 보이는 목업 숫자는 금지한다.
- **운영 KPI 5:** 사용자/강좌/세션주/가동%/API오류. mono 32px. 오류 0 초과 해당 KPI만 `--warn-solid`, 임계 초과 `--crit-solid`. 정상 전부 무채 "조용한 정상".
- **세션 추이 = 단일 라인차트**(막대 아님). 피크 1점만 라벨.
- **음성·AI 사용 + 비용:** OpenAI 음성 /평가 토큰/추정 비용/예산 대비 게이지(80% 넘으면 `--warn-solid`). 운영비 가시화(윤찬 graphify 비용 통제 문화).
- **교수 활동 감사 테이블:** 교수별 피드백 열람률(품질 신호시나리오 발행·마지막 활동. 저조 지표만 `← 저조` `--warn`. "⚠ 점검" = 관리자 리마인드 대상.
- **Audit log:** 시간순 컬럼. 행위자·행위·대상. 없음(감사는 중립). 클릭 상세.
### 6.7 데이터 시각화 하드룰 (전 역할 공통)
| 상황 | 채택 | 금지 |
|---|---|---|
| 사람 여러 역량 **추이** | small multiples 라인(공통 y축) | 레이더/스파이더 |
| 여러 역량 **현재값 비교** | 가로 막대(공통 0-100), 최저값만 강조 | 레이더, 전항목 색칠 |
| 지표 **시간 추이** | 단일 라인(피크/최신 1점만 라벨) | 3D·면적 그라데이션 |
| 테이블 **추세 압축** | sparkline(7px) + 화살표 | 셀마다 미니 도넛 |
| **종합 한 숫자** | 단일 원형 게이지 + 변화량 | 여러 도넛 격자 |
**차트 공통 스타일:** 격자선 최소(y축 0/50/100 옅은 점선만, 세로 격자 없음). 라인 `stroke-width:1.5`, 점은 최신/이상치만. 색은 데이터 의미에만(추세 `--pos`/↘`--warn`/→무채, 평상시 라인 `--ink-2` 무채 인플레이션 방지). 진입 라인 draw 280ms, 게이지 arc 400ms ease-out 1회만. 깜빡임·펄스·glow 없음. 모든 수치 `tabular-nums`.
---
## 7. 컴포넌트 원칙 (요약 카탈로그)
공통: **border-radius 절제(6~12px, 알약 금지), 그림자 절제(헤어라인 우선), border는 `--hair`.** 카드는 쓰되 균등 4-4-4 격자 남용 금지 비대칭··도식.
### 7.1 버튼 (위계 3단, 알약형 금지 radius 8px)
| 종류 | 배경 | 텍스트 | 보더 | 용도 |
|---|---|---|---|---|
| Primary | `--accent` | `--text-on-accent` | none | 세션 시작·저장 (화면당 1~2개) |
| Secondary | `--bg-surface` | `--accent` | 1px `--accent` | 보조 액션 |
| Ghost | transparent | `--text-body` | none | 취소·텍스트 액션 |
| Danger | `--crit-solid` | #fff | none | 세션 강제 종료 위급만 |
```css
.btn { font: 600 var(--fs-sm)/1 var(--font-sans); padding: 10px 18px;
border-radius: var(--radius); border:1px solid transparent;
transition: background .16s ease, transform .12s ease; cursor:pointer; }
.btn-primary { background: var(--accent); color: var(--text-on-accent); }
.btn-primary:hover { background: var(--accent-deep); }
.btn:active { transform: translateY(.5px); } /* 미세 누름, 과한 모션 X */
.btn:focus-visible { outline:none; box-shadow: 0 0 0 3px var(--focus-ring); }
```
### 7.2 입력 (radius 6px, 포커스 시 보더색 + 얇은 ring, 좌측바 X)
```css
.input { width:100%; background: var(--bg-surface-2); color: var(--text-body);
border:1px solid var(--border-strong); border-radius: var(--radius-sm);
padding:10px 12px; font:var(--fs-body)/1.5 var(--font-sans);
transition:border-color .15s, box-shadow .15s; }
.input:focus { border-color: var(--border-focus); outline:none; box-shadow: 0 0 0 3px var(--focus-ring); }
.input[aria-invalid="true"] { border-color: var(--crit-solid); }
```
### 7.3 카드 / 패널 (헤어라인 + 미세 그림자, 상단 강조선 금지)
```css
.card { background: var(--bg-surface); border:1px solid var(--border-subtle);
border-radius: var(--radius); padding: var(--sp-5); box-shadow: var(--shadow-sm); }
.panel { background: var(--bg-surface); border:1px solid var(--border-subtle);
border-radius: var(--radius-lg); padding: var(--sp-6); }
.panel-tint { background: var(--bg-tint); border-color: transparent; } /* 강조 패널: 틴트 배경 */
```
### 7.4 평가 피드백 콜아웃 (이 플랫폼 핵심, 좌측 컬러바 금지 → 배경 틴트 + 도트 + kicker)
```css
.callout { border-radius: var(--radius); padding: var(--sp-4) var(--sp-5);
font-size: var(--fs-sm); line-height:1.6; }
.callout .clh { font: 600 var(--fs-xs)/1.4; letter-spacing:.04em;
display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.callout .clh::before { content:""; width:7px; height:7px; border-radius:50%; } /* dot, 바 아님 */
.callout.pos { background:var(--pos-tint); color:var(--pos-text); }
.callout.pos .clh::before { background:var(--pos-solid); }
.callout.info { background:var(--info-tint); color:var(--info-text); }
.callout.info .clh::before { background:var(--info-solid); }
.callout.warn { background:var(--warn-tint); color:var(--warn-text); }
.callout.warn .clh::before { background:var(--warn-solid); }
.callout.crit { background:var(--crit-tint); color:var(--crit-text); } /* 가드레일 위반만 */
.callout.crit .clh::before { background:var(--crit-solid); }
```
피드백 강도 매핑: **잘함→`pos`(녹색), 일반 코칭/관찰→`info`(슬레이트), 페이싱·라포 주의→`warn`(앰버), 가드레일/위급→`crit`(적색).** 학습자 화면 기본 피드백은 info/pos가 다수가 되도록.
### 7.5 라이브 음성 오브 (§5.2 참조)
내담자 발화=sage, 학습자 발화=clay로 화자 구분(채도 낮게). 깜빡이는 빨강 금지 호흡 펄스.
---
## 8. React 구현 노트
### 8.1 컴포넌트 트리
```
<AppShell role={role}> // body[data-role] 설정, 네비·톱바
<RoleNav items={navByRole}/> // 권한 없는 항목 필터링 후 렌더(DOM 제거)
<ContextLabel/> // mono accent 라벨
<Outlet/>
├ <LearnerHome> Hero1줄 + cols(Gauge, NextPractice) + MiniMultiples×4 + FeedbackTable
├ <InstructorHome> InterventionQueue + KPIs + ClassDistribution + StudentTable(sparkline)
├ <AdminHome> OpsKPIs + OnlineUsers + ResourceHealth + UsageCost + IntegrationEmptyStates
├ <AdminUsers> UserList + RegisterTab + ActivityTab
├ <AdminAccess> RolePolicy + GroupPolicy + PermissionMatrix
└ <AdminTickets> TicketQueueEmpty + CategoryPolicy + ResponseRules
<SessionScreen>
├ <SessionTopBar scenario stage elapsed onEnd/>
├ <SessionLayout> // CSS grid 320/1fr/300, RN은 Flex
│ ├ <StagePanel> <StageTracker/> <ClientContextCard/> // LEFT
│ ├ <ClientStage> // CENTER
│ │ ├ <ClientAvatar persona state affect analyser/> // §4 아바타
│ │ ├ <VoiceOrb state amplitude/>
│ │ └ <LiveTranscript turns partial/>
│ └ <FeedbackRail mode> // RIGHT
│ ├ <ClientStateMeter tone openness/>
│ ├ <AmbientSignal latest recentSequence/> // 은은한 신호
│ ├ <CoachHint hint onDismiss/> // 코칭 모드만
│ └ <SelfNote/>
└ <ControlBar mic paused mode onMic onPause onModeChange onEnd/>
<ReviewScreen>
├ <ReviewHeader scenario onExportPdf onReplay/>
├ <ReviewHeadline summary/> // 큰 한 문장
├ <SessionTimeline phases markers onSeek/>
├ <AnnotatedTranscript turns techniqueLabels supervisorComments audioSync/>
└ <AnalysisSide techniqueDistribution highlights improvements/>
```
### 8.2 상태 관리
- 음성 이벤트(`onModeChange`/`onVolumeChange`/partial transcript) OpenAI Realtime 스트림 단일 `SessionStore`(Zustand 권장) 모아 `VoiceOrb`·`LiveTranscript`·`FeedbackRail`·`ClientAvatar` 구독.
- 평가 AI는 **별도 채널(백그라운드)** 발화 단위 신호를 throttle해서 push. `FeedbackRail` 6초 페이드 큐로 소비. 평가와 음성 상태 표시는 분리(평가가 음성 UX를 막지 않게).
- 차트 프리미티브 4종 먼저 구축: `<Gauge>` `<SparkLine>` `<MiniMultiple>` `<HBar>` 6.7 내장, props=data+role토큰). 학습자 컴포넌트가 교수 드릴다운에서 재사용됨.
### 8.3 구현 순서
1. `tokens.css`3) + 6.3) 셸은 3역할 공통이므로 1회만.
2. 차트 프리미티브 4종.
3. 학습자 교수 관리자 (재사용 극대화).
4. 세션 화면: 폴백 추상 오브 먼저(음성 파이프라인·4-state 배선 검증) 반구상 SVG 아바타 정서 6파라미터 페르소나 JSON.
5. 리뷰 화면 + utterance-level 평가 타임라인.
6. 역할 가드: 라우터에서 `role` 기반 메뉴·라우트 **렌더 제외**(disable 아님).
7. (여유) Rive 아바타 고도화. 되면 SVG 1차안으로 출시(폴백 안전).
### 8.4 RN 전환 대비
레이아웃 토큰은 절대 px 의존 최소화(rem·flex 우선). SVG`react-native-svg`, Web Audio`react-native-audio-api`, RiveRN 런타임. 브레이크포인트 sm:640/md:768/lg:1024/xl:1280.
---
## 9. 안티패턴 체크리스트 (HARD NO — 출시 전 자가검증)
1. **border-left 강조선 / 좌측 사이드바 형태 강조줄** 피드백·콜아웃·카드·활성표시에 막대 금지. 위계는 kicker+weight+여백+dot+배경틴트.
2. **이모지** UI·일러스트·SVG 내부 장식까지 전부 금지. 아이콘은 Lucide(stroke 2, 직각). 평가 결과에 체크/엑스 이모지 금지. 추세는 ▲▼→ 기하 화살표.
3. **카드 덤프 / 균등 그리드 무한반복(4-4-4)** 비대칭(7:5) 레이아웃·데이터 테이블·도식으로. 학습자 홈은 게이지+small-multiples+테이블, 교수 홈은 triage +KPI+테이블.
4. **양산형 SaaS 랜딩** "그라데이션 히어로 + 떠다니는 mockup + 3컬럼 feature 카드 + 보라 그라데이션 CTA" 공식 금지.
5. **과한 그라데이션·glow·gradient-text·큰 blur** 깊이는 1px 헤어라인.
6. **둥근 모서리 과다(16px+)·말랑 일러스트** 거의 직각(6~12px). 원형은 오브·아바타·dot만.
7. **게임화 폭격** 점수 팡파레, 빨간 X, 레벨업 배지, 별점 5개 즉시. 평가는 서술형·비모달·회고 시점.
8. **순흑(#000)·순백(#FFF)** `--ink:#1C2A2A` / `--paper:#FBFAF8`.
9. **고채도 메디컬 블루 단독 의존** 세이지-틸로 차별화 + 온기.
10. **실시간 피드백 모달** 상담 흐름 팝업 금지. 차분한 사이드 패널로.
11. **레이더/스파이더 차트** small-multiples 라인 + 단일 게이지로.
12. **권한 없는 메뉴 disabled 회색 나열** DOM에서 제거.
13. **빨강 장식 사용** `--crit-solid` (교수)개입 ·"개입" 상태·(관리자)임계 오류에만.
14. **One screen, one message 위반** 화면 최상단 h1이 화면 단일 메시지("나아지고 있다"/"3명 개입 필요"/"정상 운영"/"듣고 있어요").
---
## 10. 핵심 의사결정 5줄 (윤찬이 기억할 것)
1. **컬러: 세이지-틸 `#3E7A6E` 단일 accent + 테라코타 `#B0735C` 온기 보조.** 의료 블루 회피, 저채도로 임상+따뜻함 동시. 역할별 accent 토큰만 교체.
2. **아바타: 사실적 얼굴(오인·불쾌한 골짜기·편향)도 추상 오브(비언어 연습 불가)도 답 아님 → 사실성 35~45% 양식화 반구상 흉상 + 호흡 광배.** ·눈썹··어깨 4채널 × 정서 6파라미터. SVG 1차 Rive 2차. 미성년은 realism 낮추고 `교육용 가상 내담자` 라벨 상시.
3. **세션 화면: 실시간 피드백은 "신호(색 도트, 6초 페이드, 1개)"까지만, 정밀 평가는 회기말 리뷰로.** 학습자가 모드(몰입/은은/코칭) 고른다. 음성 상태는 막대 파형이 아니라 빛의 호흡(sage=학습자, clay=내담자).
4. **시각적 무게 = 주의 배분.** 내담자 stage 60%, 평가 패널 15평시 접힘. 화면은 대시보드가 아니라 상담실.
5. **대시보드: 레이더 금지 → small-multiples 라인 + 단일 게이지.** 점수·합불 없음(성장 추세만). 교수자 화면은 triage . 권한 없으면 DOM 제거.
---
## 참고 (실조사 출처)
**디자인 언어·시스템**
- Linear Brand Guidelines / Stripe Design / Calm·Headspace (accent rationing, 저채도, 호흡 모션)
- Fuzzy Math Color Palettes of Mental Healthcare UI / Villa Healing Center Calming Colors
- Halo Lab Digital Healthcare UX Trends 2026 / Progress Color Psychology in Healthcare
- Pretendard (orioncactus/pretendard) / az-loc Best Fonts for CJK Websites 2026
- Aufait UX Accessible Color Tokens / WCAG Contrast Guide 2026
**아바타**
- Behavioral Sciences 2026 Human-like/Animal-like/Object-like LLM Virtual Doctor Avatar
- arXiv 2506.11890 Graduated Realism (AI Avatars in VR Teacher Training)
- PMC12692777 AI Physician Avatars (윤리·편향·오인 위험)
- NYU Steinhardt AI Avatar for Social Work Counseling Practice
- ElevenLabs UI Orb / orb-ui (4-state) / Rive vs Lottie 2026 / arXiv 2502.16038 (Valence-Arousal-Dominance)
**세션·대시보드**
- arXiv 2502.18673 Scaffolding Empathy (utterance-level 피드백 학습효과 vs 인지부하) 2단 피드백 모델 근거
- arXiv 2505.02428 LLM-Simulated Practice/Feedback for Counselors
- assistant-ui / Vocalis / Agora (음성 상태 시각화)
- Scott Logic·Observable Radar Charts 비판 (small-multiples 대체 근거)
- GoReact Counseling Skills Rubric / Springer Open LA Dashboard actionable intervention 비판
- Eleken·Fuselab Healthcare UI/UX 2026
**vault 연계 자산**
- `Resources/50_Tech_Dev/디자인/slide-base.css` (무채 골격·강조 위계 계승)
- `Resources/50_Tech_Dev/디자인/[디자인 시스템] HTML 슬라이드·보고서 베이스 (2026-06).md` (한신대/의료 행에 `--accent:#3E7A6E` 채움)