Attyx: 작고 빠른 GPU 가속 터미널 에뮬레이터

발행: (2026년 3월 1일 오전 04:37 GMT+9)
11 분 소요
원문: Dev.to

Source: Dev.to

Neovim, tmux, git, SSH — 그게 내 하루 전체다. 나는 iTerm2, Alacritty, Kitty, Ghostty 등 모든 터미널 에뮬레이터를 사용해봤다. 모두 훌륭했다.

하지만 나는 실제로 내부에서 무슨 일이 일어나는지 이해하지 못했다. 바이트가 쉘에서 나오고, 이스케이프 시퀀스가 파싱되고, 문자들이 화면에 나타난다. ESC[38;2;255;100;0m 은 내부 상태에 무엇을 하는 걸까? 키 입력이 의사 터미널을 통해 어떻게 전달되고 다시 텍스트로 돌아오는가? 나는 전혀 몰랐다.

내가 무언가를 배우는 유일한 방법은 직접 만드는 것이다.

그래서 나는 Attyx 를 만들었다 — Zig로 처음부터 만든 GPU 가속 터미널 에뮬레이터. 토요일에 시작해서, 5일 뒤에는 매일 사용하고 있었다. 지금도 매일 사용하고 있다.

왜 이렇게 만들었는가

“우리는 또 다른 터미널 에뮬레이터가 필요하지 않다.”
물론. 하지만 나는 세상이 필요해서 만든 것이 아니다. 두 가지 이기적인 이유 때문에 만들었다.

1. Zig를 배우고 싶었다

문서와 튜토리얼이 아니라 시스템 프로그래밍 문제를 직접 마주하게 해줄 실제 프로젝트에서 배우고 싶었다. 터미널 에뮬레이터는 모든 것을 포함한다: 파싱, GPU 렌더링, 폰트 래스터화, 유니코드, PTY 관리, 플랫폼 API. 완벽했다.

2. 테스트 가능한 터미널 코어가 필요했다

이 부분은 덜 명확하니 설명하겠다.

나는 TUI 앱을 만든다. Glyph 를 만들었는데, 이는 터미널용 React 렌더러다. Flexbox, 컴포넌트, 훅 등 모든 기능을 제공하지만 브라우저가 아니라 터미널에 렌더링한다. 이를 기반으로 Aion (캘린더 TUI)와 Epist (vim 키 바인딩을 갖춘 이메일 클라이언트)를 만들었다. 매일 실제로 사용하는 앱들이다.

문제: TUI 앱이 실제로 어떻게 보이는지 어떻게 테스트할 수 있을까? 컴포넌트 상태나 로직은 테스트할 수 있지만, 터미널이 이스케이프 시퀀스를 해석한 뒤의 문자와 스타일 그리드라는 최종 출력은 블랙홀이다. 스크린샷 비교? 깨지기 쉽다. Asciinema 녹화? 자동화되지 않는다. 원시 이스케이프 코드를 단위 테스트? 해석 버그를 잡지 못한다.

내가 원했던 것은 아주 간단한 것이었다 — 바이트를 터미널 엔진에 넣고, 결정적인 그리드를 받아서 그것과 비교한다. 이를 할 수 있는 터미널 앱은 없었기에, 핵심이 처음부터 순수하도록 만든 것이다.

var engine = try Engine.init(allocator, 24, 80);
engine.feed(my_app_output);
const cell = engine.state.grid.getCell(0, 0);
try expectEqual('A', cell.char);
try expect(cell.style.bold);

전체 화면 모드 진입
전체 화면 모드 종료

GPU도 없고, 창도 없고, PTY도 없다. 바이트를 넣고, 상태를 얻는다. 이것이 내가 수년간 원해왔던 테스트 원시다.

얻을 수 있는 것

  • GPU‑가속 렌더링 — macOS에서는 Metal, Linux에서는 OpenGL 3.3.
  • 전체 VT100/xterm 호환성. 트루 컬러, 256‑컬러, 모든 기능 지원.
  • 마우스 트래킹, 인라인 이미지용 Kitty 그래픽스 프로토콜, 하이퍼링크, 대체 화면 버퍼, 스크롤 영역, 커서 모양.
  • 리사이즈 시 리플로우가 가능한 20 000줄 스크롤백.
  • 세션 위에 떠 있는 팝업 터미널.
  • 검색.
  • 핫‑리로드가 가능한 TOML 설정.

모두 5 MB 이하.

전체 — GPU 렌더링, VT 파서, 폰트 처리, 플랫폼 코드 — 가 작은 바이너리 하나에 들어갑니다. 최소한의 의존성으로 Zig를 작성하고, GUI 툴킷을 번들링하는 대신 네이티브 플랫폼 프레임워크를 사용하며, 컴파일러가 사용되지 않는 코드를 제거하도록 하면 이런 결과가 나옵니다. 런타임 없음. 가비지 컬렉터 없음. Electron 없음. OS와 대화하는 Zig 바이너리일 뿐입니다.

내부 구조 (지루하게 만들지 않으면서)

전체 세부 사항을 원한다면 Semos 블로그에 깊이 있는 기술 다이브를 썼습니다. 하지만 핵심은 다음과 같습니다.

모든 것이 파이프라인을 통해 흐릅니다:

Raw bytes → Parser → Actions → State → Grid

Enter fullscreen mode
Exit fullscreen mode

  • Parser – 증분 상태 머신입니다. 한 바이트씩 읽어 “print H”, “move cursor to row 3 col 5”, “set foreground to red” 같은 동작을 내보냅니다. 고정 크기 버퍼, 힙 할당 없음, read() 경계에서 부분 시퀀스를 처리합니다. 전체 파서 구조체는 스택에 할당됩니다.

  • Grid – 셀들의 평면 배열입니다. 각 셀은 유니코드 코드포인트, 두 개의 결합 문자 슬롯(다이아크리틱용), 스타일, 그리고 하이퍼링크 ID를 저장합니다. 초기화 시 한 번만 할당됩니다. 스크롤 영역은 연속 메모리에서 memcpy 로 처리됩니다. 연결 리스트도, 간접 참조도 없습니다.

  • Damage tracking – 렌더링을 빠르게 유지합니다. 256‑비트 더티 비트셋(네 개의 u64). 상태 머신이 행을 건드릴 때 비트를 뒤집습니다. 렌더러는 더티한 행만 다시 그립니다. 대부분의 프레임에서는 한두 행만 다시 그리면 됩니다.

  • Two threads, no locks – PTY 스레드가 바이트를 읽어 공유 셀 버퍼에 채웁니다. 메인 스레드는 vsync 시점에 렌더링합니다. 시퀀스 락(단순 원자적 생성 카운터)으로 찢어진 읽기를 방지합니다. 렌더러가 PTY가 쓰는 중간에 읽게 되면 해당 프레임을 건너뛰고, 프레임 손실을 눈치채지 못합니다. 대신 뮤텍스 경쟁은 눈에 띕니다.

  • GPU rendering – 각 문자를 텍스처가 입힌 사각형으로 변환합니다. 글리프는 필요할 때 GPU 메모리에 있는 아틀라스로 래스터화됩니다. 10 000 셀을 그리는 비용은 100 셀을 그리는 비용과 거의 같습니다—이것이 GPU에 오프로드하는 핵심 이유입니다. CPU는 파싱과 상태 관리를, GPU는 픽셀 처리를 담당합니다. 각각이 잘하는 일을 수행합니다.

Semos 스택

  • Glyph – React 터미널 렌더러입니다. JSX, flexbox, hooks를 사용해 터미널 앱을 작성하세요 — 웹에서 익숙한 동일한 개발 경험(DX)을 제공하지만 터미널에 그립니다.
  • AionEpist – Glyph 위에 구축된 앱들(캘린더와 이메일).
  • Attyx – 루프를 완성합니다. Glyph 앱은 테스트 가능한 터미널이 필요했고, Attyx는 실제 앱을 통해 스트레스 테스트가 필요했습니다. 서로를 앞당겨 나갑니다.

한 번 시도해 보세요

brew install semos-labs/tap/attyx

전체 화면 모드 진입
전체 화면 모드 종료

또는 소스에서 직접 빌드:

git clone https://github.com/semos-labs/attyx
cd attyx
zig build -Doptimize=ReleaseFast

전체 화면 모드 진입
전체 화면 모드 종료

또는 다운로드하여 Mac을 사용 중이라면 웹사이트에서 바로 받을 수 있습니다. 이 경우 자동 업데이트도 지원됩니다.

설정 파일은 ~/.config/attyx/attyx.toml에 위치합니다 — 폰트, 색상, 키 바인딩, 투명도, 블러 등을 여기서 지정합니다. 파일을 수정하고 Ctrl+Shift+R을 누르면 바로 적용됩니다. 재시작이 필요 없습니다.

오픈 소스이며 MIT 라이선스를 따릅니다.

Ghostty나 Kitty만큼 성숙했나요? 아직은 아닙니다. 하지만 코드를 한 줄씩 모두 이해하고 매일 사용하며, 전체 용량이 5 MB 이하에 들어갑니다. 이것도 충분히 의미 있는 점이라고 생각합니다.

0 조회
Back to Blog

관련 글

더 보기 »

구리지 않은 시맨틱 무효화

캐싱 문제 웹 애플리케이션을 어느 정도 기간 동안 작업해 본 사람이라면 캐싱에 대한 상황을 잘 알 것입니다. 캐시를 추가하면 모든 것이 빨라지고, 그 다음에 누군가…