공간·멀티모달 인터페이스
Spatial Computing과 멀티모달 AI가 디자인 시스템에 가져오는 새로운 차원
핵심 요약
- 디자인 시스템은 공간(3D)·음성·제스처라는 새 모달리티를 위해 depth·volume·청각 피드백 토큰과 인터랙션 영역 확장을 준비해야 합니다.
- Apple visionOS 26 Liquid Glass(표면 앵커링·위젯 배치)와 Meta Horizon OS는 콘텐츠를 약 1m 거리·시선보다 약간 아래에 배치하는 인체공학 원칙을 제시합니다.
- 공간 토큰은 depth(near/default/far/overlay)·volume·앵커링으로 정의하고 2D 토큰을 px/z-index에서 meter/depth로 매핑합니다.
- 2026년 Agentic VUI는 명령 인식을 넘어 행동까지 수행하므로, 음성 피드백·타이밍 토큰과 음성-시각 연동 컴포넌트가 필요합니다.
- 기존 DS를 버리지 않고 코어→음성→공간→통합의 레이어드 확장과 모달리티 리졸버(spatial→voice→touch→text 폴백)·어댑터 패턴으로 멀티모달에 대응합니다.
2D 스크린의 시대가 저물고, 공간 컴퓨팅과 멀티모달 AI가 인터페이스의 새로운 차원을 엽니다. 이제 디자인 시스템은 3D 공간과 음성, 제스처라는 새 모달리티까지 끌어안아야 합니다.
인터페이스 진화의 흐름
디자인 시스템이 준비해야 할 세 가지 새로운 축:
| 차원 | 핵심 변화 | DS 영향 |
|---|---|---|
| 공간 (3D) | 윈도우가 물리 공간에 배치 | depth, volume 토큰 필요 |
| 음성 | 에이전트가 행동을 수행 | 청각 피드백 토큰, 타이밍 설계 |
| 제스처 | 핸드/아이 트래킹 기반 조작 | 인터랙션 영역 확장 |
Spatial Computing 디자인 원칙
Apple visionOS 26 + Liquid Glass
2025년 Apple이 Liquid Glass 디자인 언어를 내놓았습니다. 2013년 iOS 7 이후 가장 큰 비주얼 개편이며, visionOS 26에서 공간 인터페이스의 새 기준을 제시합니다.
Liquid Glass 핵심 원칙
반투명성(translucency), 깊이감(depth), 유동적 반응성(fluid responsiveness)으로 디지털 요소가 물리 환경과 자연스럽게 어우러지게 합니다.
- 표면 앵커링: 앱 윈도우를 벽, 테이블 등 물리적 표면에 정렬하고 "잠금" 가능 (재시작 후에도 동일 위치 유지)
- 위젯 배치: 환경 곳곳에 위젯을 앵커링하여 공간적 정보 배치
- 공유 경험: 같은 방의 사용자 간 실시간 협업, FaceTime을 통한 원격 참여
Meta Horizon OS
Meta는 Horizon OS로 몰입형 경험을 위한 체계적인 UI 프레임워크를 제공합니다.
- Horizon OS UI Set: 몰입형 경험 전용 UI 컴포넌트 세트 (Figma 디자인 파일 제공)
- Spatial SDK: 게임 엔진 없이 Quest 앱 개발 가능
- Navigator: 앱과 빠른 동작의 중앙 허브
배치 원칙
콘텐츠는 사용자로부터 약 1m 거리, 시선보다 약간 아래에 두는 게 인체공학적으로 가장 좋습니다. 오래 써도 목이 덜 피로하도록 잡아 둔 핵심 가이드라인입니다.
공간 디자인 토큰
기존 2D 디자인 토큰에 깊이(depth), 볼륨(volume), 공간 레이아웃(spatial layout) 카테고리를 더해야 합니다.
// tokens/spatial.ts
export const spatialTokens = {
depth: {
near: '0.5m', // 오버레이, 툴팁
default: '1.0m', // 주요 콘텐츠 기본 배치
far: '2.0m', // 배경 정보, 보조 패널
overlay: '0.3m', // 밀착 오버레이 (알림 등)
},
volume: {
small: { width: '0.3m', height: '0.3m', depth: '0.05m' }, // 위젯
medium: { width: '0.6m', height: '0.4m', depth: '0.05m' }, // 패널
large: { width: '1.0m', height: '0.6m', depth: '0.1m' }, // 앱 윈도우
immersive: { width: '2.0m', height: '1.2m', depth: '0.2m' },
},
spatialLayout: {
anchor: {
wall: { surface: 'wall', offset: '0.02m' },
table: { surface: 'table', offset: '0.01m' },
floating: { surface: 'none', offset: '0m' },
},
gazeBias: '-5deg', // 시선보다 약간 아래 (인체공학 최적)
minTargetSize: '60px', // 최소 상호작용 영역
},
} as const2D-공간 토큰 매핑
2D 스크린에서는 px/z-index를, 공간에서는 meter/depth를 쓰도록 자동 매핑합니다.
| 2D 토큰 | 스크린 값 | 공간 값 |
|---|---|---|
| spacing.sm | 8px | 0.02m |
| spacing.md | 16px | 0.04m |
| spacing.lg | 24px | 0.06m |
| elevation.raised | z-index: 10 | depth: 0.05m |
| elevation.overlay | z-index: 50 | depth: 0.1m |
| elevation.modal | z-index: 100 | depth: 0.15m |
음성 UI (Voice User Interface)
2026년 Agentic VUI
음성 UI는 단순한 질의응답을 넘어 행동을 수행하는 에이전트로 진화합니다. 웹 탐색, 일정 조율, 양식 작성처럼 복잡한 태스크도 음성만으로 끝냅니다.
- 하이브리드 처리: 온디바이스 우선(저지연) + 클라우드 보강(복잡한 추론)
- 인지 AI: 명령 기반에서 컨텍스트 인식 대화형 에이전트로 전환
- 멀티턴 대화: 이전 맥락을 유지하며 자연스러운 대화 흐름 지원
음성 디자인 토큰
// tokens/voice.ts
export const voiceTokens = {
feedback: {
confirmation: { tone: 'positive', duration: 'short', haptic: 'light' },
error: { tone: 'alert', duration: 'medium', haptic: 'strong' },
processing: { tone: 'neutral', duration: 'loop', haptic: 'none' },
waiting: { tone: 'subtle', duration: 'short', haptic: 'none' },
},
timing: {
listenTimeout: '5000ms', // 음성 입력 대기
responseDelay: '200ms', // 응답 전 최소 지연
interruptWindow: '500ms', // 끼어들기 허용 구간
sessionTimeout: '30000ms', // 대화 세션 유지
},
personality: {
tone: 'professional-friendly',
verbosity: 'concise',
confirmationLevel: 'destructive-only',
},
} as const음성-시각 연동 패턴
// components/voice-feedback.tsx
interface VoiceFeedbackProps {
state: 'idle' | 'listening' | 'processing' | 'responding' | 'error'
}
/**
* 음성 상태를 시각적으로 표현하는 컴포넌트
* @ai-hint 음성 인터랙션 시 시각 피드백 필수 제공
*/
export function VoiceFeedback({ state }: VoiceFeedbackProps) {
const visualMap = {
idle: { icon: 'mic', color: '{colors.muted}', animation: 'none' },
listening: { icon: 'mic-active', color: '{colors.primary}', animation: 'pulse' },
processing: { icon: 'loader', color: '{colors.primary}', animation: 'spin' },
responding: { icon: 'speaker', color: '{colors.success}', animation: 'wave' },
error: { icon: 'mic-off', color: '{colors.destructive}', animation: 'shake' },
}
return <FeedbackIndicator {...visualMap[state]} />
}멀티모달 통합 전략
모달리티별 강점과 약점
| 모달리티 | 강점 | 약점 | 적합한 태스크 |
|---|---|---|---|
| 텍스트 | 정밀한 입력, 편집 용이 | 느린 입력 속도 | 검색, 데이터 입력, 코드 |
| 음성 | 빠른 명령, 핸즈프리 | 소음 환경 불리, 프라이버시 | 네비게이션, 빠른 액션 |
| 시각/제스처 | 직관적 3D 조작 | 정밀도 낮음, 피로 누적 | 오브젝트 조작, 공간 탐색 |
| 시선(Gaze) | 암시적 의도 파악 | 의도치 않은 활성화 | 포커스 힌트, 관심 추적 |
모달리티 폴백 전략
환경이나 사용자 상태에 맞춰 가장 적합한 모달리티로 자동 전환해야 합니다.
// lib/modality-resolver.ts
type Modality = 'spatial' | 'voice' | 'touch' | 'text'
interface ModalityCapabilities {
spatial: boolean // WebXR / visionOS 지원 여부
voice: boolean // 마이크 접근 + 저소음 환경
touch: boolean // 터치스크린 존재
text: boolean // 항상 true (최종 폴백)
}
/** 폴백 체인: spatial → voice → touch → text */
export function resolveModality(
capabilities: ModalityCapabilities,
preference?: Modality
): Modality {
if (preference && capabilities[preference]) return preference
const chain: Modality[] = ['spatial', 'voice', 'touch', 'text']
return chain.find((m) => capabilities[m]) ?? 'text'
}디자인 시스템 적응 전략
레이어드 확장 모델
기존 반응형이 스크린 크기에 맞췄다면, 멀티모달 시대의 반응형은 모달리티 자체에도 맞춰야 합니다. 기존 DS를 버리지 않고 레이어를 쌓아 확장합니다.
점진적 확장 로드맵
| 단계 | 기간 | 작업 | 산출물 |
|---|---|---|---|
| 1단계 | 1-2주 | 기존 DS 감사, 확장 포인트 식별 | 확장 계획서 |
| 2단계 | 2-4주 | 음성 토큰 + 피드백 패턴 추가 | 음성 지원 DS |
| 3단계 | 4-8주 | 공간 토큰 + 3D 컴포넌트 | 공간 지원 DS |
| 4단계 | 지속적 | 모달리티 리졸버 + 어댑티브 토큰 통합 | 멀티모달 DS |
컴포넌트 어댑터 패턴
하나의 추상 컴포넌트 정의로 여러 모달리티에서 렌더링합니다.
// components/adaptive-button.tsx
interface AdaptiveButtonSpec {
label: string
action: () => void
variant: 'primary' | 'secondary' | 'destructive'
voiceAlias?: string[]
gestureType?: 'tap' | 'pinch' | 'grab'
}
/**
* 모달리티에 따라 자동으로 렌더링 방식 결정
* - screen → Button, voice → VoiceCommand, spatial → SpatialButton
*/
export function AdaptiveButton(spec: AdaptiveButtonSpec) {
const modality = useModality()
switch (modality) {
case 'spatial':
return (
<SpatialButton
label={spec.label}
onGesture={spec.gestureType ?? 'tap'}
onActivate={spec.action}
depth={spatialTokens.depth.default}
/>
)
case 'voice':
return (
<VoiceCommand
trigger={[spec.label, ...(spec.voiceAlias ?? [])]}
onActivate={spec.action}
visualHint={<Button variant={spec.variant}>{spec.label}</Button>}
/>
)
default:
return (
<Button variant={spec.variant} onClick={spec.action}>
{spec.label}
</Button>
)
}
}어댑터 패턴의 장점
디자인 의사결정은 한 번만 내리고, 모달리티별 렌더링은 어댑터에 맡깁니다. 새 모달리티가 추가돼도 기존 컴포넌트 스펙은 그대로 둬도 됩니다.