콘텐츠로 이동

Ink 렌더러

Claude Code의 터미널 인터페이스는 단순한 텍스트 출력이 아닙니다. 스피너 애니메이션, 실시간 스트리밍, 대화형 확인 다이얼로그까지 갖춘 풍부한 UI를 터미널에서 구현하고 있습니다. 이 모든 것이 React/Ink 프레임워크 위에서 동작합니다.

Ink 는 React 컴포넌트 모델을 터미널 환경에 적용한 라이브러리입니다. 웹 브라우저의 DOM 대신 터미널 화면을 렌더링 대상으로 사용합니다.

웹 React Ink (터미널 React)
────────────── ──────────────────
<div> → <Box>
<span> → <Text>
CSS 스타일링 → Ink 레이아웃 속성
DOM 렌더링 → 터미널 ANSI 렌더링

Claude Code는 Ink을 사용하여 복잡한 터미널 UI를 선언적으로 구현합니다.

Claude의 응답은 완성되기를 기다리지 않고 생성되는 즉시 터미널에 표시됩니다. Ink의 상태 업데이트 메커니즘이 이를 가능하게 합니다.

// 개념적 구현
function StreamingResponse({ text }: { text: string }) {
return (
<Box>
<Text>{text}</Text>
{isStreaming && <Spinner />}
</Box>
)
}

text 상태가 업데이트될 때마다 Ink이 터미널의 해당 영역만 다시 렌더링합니다. 전체 화면을 지우고 다시 그리는 대신, 변경된 부분만 업데이트하여 깜빡임 없는 자연스러운 스트리밍이 구현됩니다.

도구 실행 승인이 필요할 때 인라인 다이얼로그가 표시됩니다.

┌─────────────────────────────────────┐
│ Bash 실행 허용하시겠습니까? │
│ │
│ 명령어: git push origin main │
│ │
│ [y] 예 [n] 아니오 [a] 항상 허용 │
└─────────────────────────────────────┘

이 다이얼로그는 React 컴포넌트로 구현되어 있으며, 사용자 입력을 받는 동안 나머지 출력은 그대로 유지됩니다.

도구가 실행 중일 때 시각적 피드백을 제공합니다.

⠋ 파일 읽는 중...
⠙ 파일 읽는 중...
⠸ 파일 읽는 중...
⠼ 파일 읽는 중...

Ink의 useInterval 훅이 애니메이션 프레임을 제어합니다. 도구 실행이 완료되면 스피너는 결과로 교체됩니다.

일반 터미널 출력은 스크롤되어 사라지지만, Ink은 특정 메시지를 터미널 상단에 고정하거나 스크롤 버퍼에 영속적으로 유지할 수 있습니다. 이전 도구 실행 결과가 새 출력에 밀려나지 않고 계속 참조 가능합니다.

React 컴포넌트 모델의 터미널 적용

섹션 제목: “React 컴포넌트 모델의 터미널 적용”

Ink이 터미널에 React를 적용하는 방식은 개념적으로 다음과 같습니다.

컴포넌트 상태 변경
↓
React Virtual DOM 비교 (diffing)
↓
변경된 부분 계산
↓
ANSI 이스케이프 시퀀스 생성
↓
터미널 해당 위치만 업데이트

<Box>, <Text> 같은 Ink 기본 컴포넌트들이 터미널의 레이아웃 엔진 역할을 합니다.

// Ink 레이아웃 예시
<Box flexDirection="column" padding={1}>
<Box marginBottom={1}>
<Text bold color="blue">Claude Code</Text>
</Box>
<Box>
<Text dimColor>모델: </Text>
<Text>{modelName}</Text>
</Box>
</Box>

CSS flexbox와 유사한 레이아웃 시스템이 터미널 좌표 계산을 추상화합니다.

Claude Code의 UI 상태는 크게 세 가지로 구분됩니다.

| 상태 | 내용 | 업데이트 빈도 | |------|------|-------------| | 메시지 히스토리 | 지금까지의 대화 내용 | 메시지 완성 시 | | 스트리밍 버퍼 | 현재 생성 중인 텍스트 | 토큰마다 | | 도구 상태 | 실행 중인 도구와 진행도 | 도구 이벤트마다 |

스트리밍 버퍼는 매우 빈번하게 업데이트되므로, Ink의 배치 업데이트 메커니즘으로 과도한 리렌더링을 방지합니다.

| 장점 | 설명 | |------|------| | 선언적 UI | 상태만 관리하면 렌더링은 자동 | | 컴포넌트 재사용 | 스피너, 다이얼로그 등 재사용 가능한 UI 블록 | | 상태 기반 렌더링 | 명시적 화면 제어 코드 불필요 | | React 생태계 활용 | useState, useEffect 등 익숙한 패턴 사용 | | 테스트 용이성 | React Testing Library로 터미널 UI 테스트 가능 |

Ink 덕분에 Claude Code는 복잡한 ANSI 이스케이프 코드를 직접 다루지 않고도 풍부한 터미널 경험을 제공합니다.