메인 콘텐츠로 건너뛰기

“그냥 TUI”가 아니다: Claude Code 렌더링이 게임 엔진인 이유

요약

Claude Code를 처음 보면 “터미널에서 돌아가는 UI(=TUI)겠지” 하고 넘기기 쉽습니다. 그런데 내부를 들여다보면, 이건 단순히 글자를 찍는 프로그램이라기보다 매 프레임을 계산해 화면을 그려내는 “작은 게임 엔진”에 가깝습니다.

이번 글에서는 Chris Lloyd의 설명을 실마리로, Claude Code가 왜 게임 엔진 같은 렌더링 파이프라인을 택했는지, 그리고 그 선택이 깜빡임(flicker)·지연(latency) 같은 체감 문제와 어떻게 연결되는지 쉽게 풀어보겠습니다.

Claude Code는 왜 “작은 게임 엔진”처럼 움직일까

우리가 터미널에서 무언가를 볼 때, 뇌는 이렇게 상상합니다. “프로그램이 텍스트를 출력하면 터미널이 예쁘게 그려준다.”

하지만 Claude Code가 제공하려는 경험은 단순 출력이 아니라, 창 크기 변화에 적응하고, 여러 패널을 배치하고, 스크롤·입력·상태 표시가 동시에 부드럽게 돌아가는 ‘인터랙티브 화면’입니다. 즉, 문서(텍스트)를 내보내는 게 아니라 장면(scene)을 매 순간 갱신해야 하죠.

그래서 Chris Lloyd는 사람들이 생각하는 “그냥 TUI”라는 mental model이 실제와 다르다고 말합니다. Claude Code는 매 프레임 장면을 만들고, 그 장면을 화면으로 변환한 다음, 필요한 최소 변경분만 터미널에 전달하는 방식으로 움직입니다.1

React 장면 그래프부터 ANSI 시퀀스까지: 한 프레임의 여정

게임이 매 프레임 “월드 상태 → 화면 픽셀”로 바꾸듯, Claude Code도 비슷한 변환 체인을 가집니다. 흐름을 이야기처럼 따라가 볼게요.

첫 장면은 React입니다. 매 프레임마다 React로 “장면 그래프(scene graph)”를 구성합니다. 여기서 장면 그래프란 “어디에 어떤 박스/텍스트/강조가 놓일지”를 트리 구조로 표현한 설계도 같은 겁니다.1

그다음은 레이아웃입니다. 각 요소의 위치와 크기를 계산해 “이 박스는 몇 칸, 저 텍스트는 어느 줄” 같은 결정을 내립니다.

이후 래스터라이징 단계에서, 그 설계도를 실제 터미널의 2D 격자(행/열)로 바꿉니다. 터미널은 본질적으로 “문자 셀들의 바둑판”이니까요.

그 다음이 핵심인데, 바로 diff(차이 비교)입니다. 새로 만든 화면과 이전 화면을 비교해 “바뀐 셀만” 추립니다. 마지막으로 그 변경분을 ANSI 시퀀스로 만들어 터미널에 전송해 화면을 갱신합니다.1

결국 Claude Code는 “전체를 다시 그리는” 대신 “바뀐 부분만 그리는” 방향으로 최적화된 렌더러를 갖고 있는 셈입니다.

16ms 프레임 예산과 5ms 변환: 숫자가 말해주는 긴박함

여기서 갑자기 숫자 얘기가 나오면 어렵게 느껴지지만, 사실 직관적입니다.

사람이 “부드럽다”고 느끼는 상호작용은 대개 60fps 근처에서 만들어집니다. 60fps는 1초를 60장으로 쪼개는 거라, 한 장(한 프레임)에 약 16ms밖에 시간이 없습니다.

Chris Lloyd의 설명에 따르면 Claude Code도 대략 이 16ms 프레임 예산을 전제로 움직이고, 그중 React 장면 그래프에서 ANSI로 바꾸는 구간을 약 5ms 안에 끝내야 합니다.1 “터미널인데 5ms?”라고 느껴질 수 있지만, 매 키 입력마다 화면이 갱신되는 제품이라면 이 정도 타이트함이 체감 품질을 좌우합니다.

깜빡임(flicker)과 GC 멈춤: 사용자가 느끼는 진짜 문제

사용자는 “렌더링 파이프라인”을 보지 않고, 딱 두 가지만 느낍니다. 화면이 깜빡이거나, 타이핑이 버벅이는지.

Hacker News에서 Chris Lloyd는 Claude Code가 렌더링 시스템을 새로 쓰고(diff 기반 렌더러를 배포), “동기화 출력(synchronized output)”을 지원하는 환경에서는 깜빡임을 크게 줄일 수 있다고 설명했습니다.2 이는 단순히 ‘더 빨라져서’라기보다, “한 프레임을 깔끔하게 마무리하고 보여주는 방식”에 가까운 개선입니다.

또 하나의 복병은 GC(가비지 컬렉션)입니다. 화면을 매 프레임 만들다 보면 객체 할당이 늘고, 어느 순간 VM이 잠깐 멈추며 메모리를 정리합니다. 이 “잠깐”이 개발자 눈에는 짧아 보여도, 사용자는 입력 한 글자가 늦게 찍히는 걸로 바로 체감합니다. Chris Lloyd는 느린 머신에서는 이런 멈춤이 ms가 아니라 초 단위로도 보일 수 있었다고 말합니다.2

그래서 JSX 할당을 줄이기 위한 메모이제이션, 버퍼를 TypedArray로 바꾸는 식의 “예측 가능한 성능” 확보가 중요해졌고요.2

“왜 이렇게까지?”의 답: 터미널도 결국 병목이 있다

터미널은 단순한 듯하지만, 사실 “출력한 바이트를 반대편 에뮬레이터가 해석해 그리는 과정” 자체가 병목이 될 수 있습니다. 그래서 화면 전체를 매번 다시 출력하는 방식은 특정 상황에서 대역폭과 처리량 문제를 곧장 맞습니다.

이 지점에서 diff 기반 렌더링이 설득력을 얻습니다. 전체를 다시 보내지 않고, 바뀐 것만 보내면 터미널이 처리해야 할 양이 줄어들고, 그만큼 깜빡임과 지연 가능성도 내려가니까요. “게임 엔진스럽게” 들리는 구조가 사실은 터미널이라는 제약 속에서 사용자 경험을 지키기 위한 선택이었던 셈입니다.13

시사점 내용 (핵심 포인트 정리 + 개인적인 생각 또는 실용적 조언)...

Claude Code 렌더링 논쟁은 “React를 썼네/안 썼네” 같은 취향 싸움으로 끝내기 아까운 주제입니다. 핵심은 이거예요. Claude Code는 터미널 위에서 ‘앱 같은 경험’을 만들려 했고, 그 순간부터 문제는 텍스트 출력이 아니라 프레임·지연·병목·예측 가능성의 싸움이 됩니다.

만약 여러분이 TUI나 CLI 도구를 만들고 있다면, 이 사례가 주는 실용적 힌트는 분명합니다. 화면 전체를 다시 그리는 접근은 생각보다 빨리 한계에 부딪힐 수 있고, “바뀐 것만 그리기(diff)”와 “멈춤이 없는 성능(예측 가능성)”이 사용자 만족도를 가르는 진짜 기준이 될 수 있습니다.

참고

1Quoting Thariq Shihipar

2Claude Chill: Fix Claude Code's flickering in terminal | Hacker News

3Is drawing a monospace terminal display straightforward? | Clifford Ressel

#클로드 코드#터미널 UI#diff 기반 렌더링#성능 최적화#깜빡임과 지연

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

Tilnote 를 사용해 보세요.

키워드만 입력하면 나만의 학습 노트가 완성돼요.

책이나 강의 없이, AI로 위키 노트를 바로 만들어서 읽으세요.

콘텐츠를 만들 때도 사용해 보세요. AI가 리서치, 정리, 이미지까지 초안을 바로 만들어 드려요.