TrendShift 딥다이브 · 2026-07-18 · Daily #14

microsoft/comic-chat 딥다이브
— 1996년 "채팅을 만화로 그려주던" IRC 클라이언트의 소스가 30년 만에 공개되다

Comic Chat1996년 마이크로소프트가 만든 IRC 채팅 클라이언트로, 사람들이 주고받는 텍스트를 실시간으로 "만화 스트립(comic strip)"으로 자동 렌더링하던 전설적인 프로그램이다. 사용자는 만화 캐릭터(아바타)가 되고, 대사는 말풍선에 담기며, 표정·포즈·컷 배치가 전부 규칙 기반 전문가 시스템(expert system)에 의해 자동으로 결정됐다. 인터넷 익스플로러 3.0에 번들로 실려 배포됐고, 2026년 7월 마이크로소프트가 1996~1998년 개발 당시의 C++/MFC 원본 소스 전체를 MIT 라이선스로 아카이브 공개하면서 다시 화제가 됐다. 이 문서는 공개된 소스를 직접 클론해, "30년 전 사람들은 어떻게 텍스트를 자동으로 만화로 바꿨는가"를 코드 수준에서 해부한다. 지금 봐도 배울 것이 많은 데이터 주도 감정 엔진레거시 코드 현대화가 이 저장소의 진짜 보물이다. (저장소: microsoft/comic-chat · C++/MFC 4.x · Win32(x86) · 소스 스냅샷 4종(1996 pre ~ 1998 v2.5b) + 현대화 예제 2종 · MIT License · 원저자 DJ Kurlander(Microsoft Research) · TrendShift Daily #14)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 지금 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 텍스트가 만화가 되기까지
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 기술별 배울 것
  7. 빌드 · 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"당신이 타이핑하면, 프로그램이 그 문장을 읽고 알아서 만화 한 컷을 그려준다."

Comic Chat은 표준 IRC(인터넷 릴레이 챗) 서버에 접속하는 평범한 채팅 클라이언트다. 하지만 화면에는 텍스트 로그 대신 4컷 만화 같은 컷들이 실시간으로 쌓인다. 내가 "Hi everyone! :)"라고 치면, 내 아바타가 손을 흔드는 포즈로 그려지고, 웃는 표정이 얼굴에 붙고, 말풍선에 대사가 들어가고, 다른 대화 상대와 함께 한 컷에 배치된다 — 이 모든 것을 내가 아무 그림 조작도 하지 않아도 프로그램이 문장을 분석해 자동으로 해낸다.

한 문장 비유

"채팅창에 자막 대신 웹툰이 그려지는 카카오톡"을 1996년에 만든 것

지금으로 치면, 단톡방에서 내가 글자를 치는 순간 그 말투와 내용을 AI가 읽고 캐릭터 표정·포즈·컷 구도를 자동으로 그려 웹툰으로 보여주는 앱이다. 다만 Comic Chat은 딥러닝이 없던 시절이라, "AI" 자리에 사람이 손으로 짠 규칙 뭉치(전문가 시스템)가 들어가 있다. 이 규칙들이 어떻게 생겼는지 보는 것이 이 저장소의 핵심 재미다.

용어
IRC (Internet Relay Chat)
1988년에 만들어진 텍스트 기반 실시간 채팅 프로토콜. "채널(#방이름)"에 들어가 여러 명이 대화하는 방식으로, 지금의 디스코드·슬랙의 조상 격이다. Comic Chat은 이 표준 IRC를 그대로 쓰기 때문에, 만화로 보는 사람과 그냥 텍스트로 보는 사람이 같은 방에서 대화할 수 있었다.
용어
전문가 시스템 (Expert System)
"만약 문장에 ~가 있으면 → ~한 표정을 준다" 같은 사람이 미리 정해둔 규칙(rule)의 모음으로 판단을 내리는 옛날 방식의 AI. 학습 데이터로 스스로 배우는 요즘 머신러닝과 반대로, 규칙을 사람이 직접 짜 넣는다. Comic Chat의 표정·포즈 자동 선택이 바로 이 방식이다.

저장소는 단일 프로그램이 아니라 개발 역사 전체의 소스 스냅샷 모음이다. 1996년 8월 프리릴리스(v1.0-pre)부터 1998년 6월 2.5 베타(v2.5-beta-1)까지 4개의 소스 버전과, 2026년에 이 옛 코드를 현대 Visual Studio에서 다시 빌드되게 고친 "현대화 예제" 2개, 그리고 SDK·봇 샘플·문서가 담긴 artifacts/로 구성된다.

2왜 지금 주목받는가

30년 된 코드가 2026년 GitHub 트렌딩 14위에 오른 이유

① "역사적 유물"의 공개 — 소스가 처음으로 세상에 나왔다

Comic Chat은 90년대 인터넷을 겪은 사람들에게 강렬한 향수를 남긴 프로그램이다. 특히 기본 캐릭터 중 하나였던 "Bob"은 밈(meme)으로 남아 지금도 회자된다. 그런데 그 원본 소스 코드가 30년간 마이크로소프트 내부에만 있다가 2026년 7월 MIT 라이선스로 공개됐다. "그 시절 그 프로그램이 실제로 어떻게 짜여 있었나"를 처음으로 들여다볼 수 있게 된 것이다.

비유

박물관 유리 너머로만 보던 옛 명작 시계를, 처음으로 뒷판을 열어 톱니바퀴 배열을 직접 볼 수 있게 된 것과 같다. 완성품(실행 파일)은 예전부터 돌아다녔지만, "그 안에서 톱니가 어떻게 맞물렸는지"를 보여주는 설계도(소스)가 이번에 처음 공개됐다.

② "레거시 코드 현대화"의 살아있는 교재

단순히 옛 소스를 던져놓은 게 아니라, 마이크로소프트가 1996년 Visual C++ 4.x용 코드를 2026년 Visual Studio 2022에서 빌드·실행되도록 고친 과정을 *-modern 폴더와 docs/MODERNIZATION.md에 통째로 기록해뒀다. "30년 된 C++/MFC 프로그램을 요즘 컴퓨터에서 되살리려면 뭘 고쳐야 하나"에 대한 매우 구체적인 사례집이다 — 이건 지금도 실무에서 마주치는 문제다.

③ 딥러닝 없이 "감성 분석 + 자동 연출"을 해낸 설계

요즘이라면 감정 분석·이미지 생성에 신경망을 쓰겠지만, Comic Chat은 전부 규칙과 기하학 계산으로 해냈다. 문장에서 감정을 추출하는 규칙 엔진, 감정을 원(circle) 위의 각도로 표현한 감정 휠(emotion wheel), 가장 가까운 포즈를 찾는 최근접 탐색, 컷 구도를 짜는 자동 페이지 배치까지 — "자원이 극도로 제한된 환경에서 똑똑한 결과를 뽑아내는" 엔지니어링의 교과서다.

비교 축Comic Chat (1996)요즘 방식 (2026)
감정 인식키워드/대문자 규칙 엔진LLM·감성분석 모델
표정·포즈 선택감정 휠 + 최근접 포즈 매칭생성 모델·리깅 애니메이션
컷 배치규칙 기반 자동 페이지(autopage)레이아웃 엔진·수동 편집
필요 자원486 CPU · 8MB RAMGPU · 수 GB VRAM
렌더링DIB 비트맵 + TWIP 좌표GPU 래스터/벡터
오해 주의
"실행되는 최신 채팅앱"이 아니다

이 저장소는 유지보수되지 않는 역사적 아카이브다. README도 명시하듯 "참조·연구·보존용"이지 새로 쓰라고 공개한 제품이 아니다. *-modern 폴더조차 "완성된 리릴리스"가 아니라 "고치는 법을 보여주는 예제(worked example)"일 뿐, 프로덕션 수준으로 다듬어지지 않았다. 목적을 "옛 코드에서 배우기"로 잡아야 실망하지 않는다.

3기술 스택 전체 지도

1996년 윈도우 데스크톱 앱은 무엇으로 만들어졌나 — 지금과의 차이까지

핵심 언어·프레임워크 (클라이언트 본체)

계층기술역할 / 지금으로 치면
언어C++ (구형 방언)본체 전부. 지금 기준으론 문법이 오래됨(뒤에서 설명)
UI 프레임워크MFC 4.xMicrosoft Foundation Classes. 윈도우 창·메뉴·다이얼로그를 C++ 클래스로 다루는 라이브러리. 요즘의 WinUI/WPF 조상
플랫폼Win32 (x86)32비트 윈도우 네이티브 API
문서 모델MFC Doc/View"데이터(Document)"와 "화면(View)"을 분리하는 패턴. 지금의 MVC/MVVM의 뿌리
컴포넌트OLE / COM브라우저(IE) 안에 만화 화면을 끼워넣는 임베딩 기술. 요즘의 iframe·웹컴포넌트 격
빌드NMAKE + .mak마이크로소프트판 make. chat.mak이 컴파일 순서를 지정
용어
MFC (Microsoft Foundation Classes)
윈도우의 저수준 C API(Win32)를 C++ 클래스로 감싼 UI 라이브러리. 창 하나가 CWnd, 문서가 CDocument, 화면이 CView 식으로 대응된다. Comic Chat의 CChatDoc(대화 데이터)·CChatView(만화 화면)가 전형적인 예다. 2020년대에도 산업용 윈도우 앱에 종종 살아있다.

렌더링 · 그래픽

기술설명
DIB (Device-Independent Bitmap)dib.cpp. 장치에 독립적인 비트맵. 아바타·배경 그림을 메모리에서 조립한 뒤 화면에 한 번에 그린다(더블 버퍼링)
TWIP 좌표계1 TWIP = 1/1440 인치. 화면 해상도와 무관하게 만화 컷을 그리기 위한 장치 독립 단위. 그래서 프린터로 뽑아도 비율이 유지됐다
스플라인 / 벡터 기하spline.cpp·arc.cpp·vector2d.cpp. 말풍선 꼬리 곡선, 캐릭터 배치 궤적(trajectory)을 수학으로 계산
바운딩 박스bbox.cpp. 아바타·말풍선이 차지하는 사각 영역을 계산해 겹치지 않게 배치

네트워크 · 프로토콜

기술설명
WinSock 위 IRCircsock.cpp·ircproto.cpp. 표준 IRC 프로토콜을 직접 구현. 텍스트 IRC 클라이언트와 100% 호환
확장 프로토콜아바타 정보·감정 데이터를 IRC 메시지에 얹어 Comic Chat 사용자끼리 추가로 주고받음(비-Comic Chat 사용자에겐 안 보이게)
OLE 자동화 (v2.x)bindauto.cpp 등. 외부 스크립트/봇이 클라이언트를 제어할 수 있는 자동화 인터페이스

2026 현대화 계층 (*-modern 폴더)

추가된 것왜 필요했나
Visual Studio 2022 / 최신 MFC 빌드원본 Visual C++ 4.x·NT DDK 빌드 시스템이 사라져서, 현대 컴파일러로 다시 컴파일되게 문법·매크로·링커 라이브러리를 수정
고해상도(High-DPI) 대응SetProcessDPIAware + DpiScale() 헬퍼. 4K 모니터에서 UI가 깨알같이 작아지던 문제 해결
Common Controls v6 매니페스트툴바(rebar)가 최신 윈도우에서 안 뜨던 것 수정
네이티브 TLS (SChannel)요즘 IRC 서버가 요구하는 암호화 접속 지원(docs/tls.md)
GitHub Actions 클라우드 빌드고정된 Windows 러너에서 두 현대화 클라이언트를 자동 빌드·패키징·SHA-256 해시까지 생성
비유

본체 스택이 "1996년형 자동차 엔진"이라면, *-modern 폴더는 "그 클래식카를 오늘 도로에서 굴리기 위한 개조 키트"다. 엔진(핵심 로직)은 거의 그대로 두고, 요즘 연료(현대 컴파일러)·요즘 도로(고해상도 모니터·암호화 서버)에 맞게 주변부만 손봤다.

4아키텍처 심화 — 텍스트가 만화가 되기까지

"Hi! :)" 한 줄이 만화 한 컷이 되는 4단계 파이프라인을 코드로 추적한다

Comic Chat의 심장은 "문장 → 감정 → 포즈 → 컷 배치"로 이어지는 자동 연출 파이프라인이다. 실제 소스에서 이 흐름을 담당하는 파일들을 순서대로 따라가 보자.

[ 사용자 입력 ] "Hi everyone! I think it's great :)" | v ┌─────────────────────────────────────────────────────────┐ │ ① 감정 추출 textpose.cpp : GetEmotionsFromString() │ │ 문장을 규칙(general/word/sentence)에 대조해 감정 후보 수집 │ │ "Hi"로 시작 → WAVE / "I"로 시작 → POINTSELF / ":)" → HAPPY │ └─────────────────────────────────────────────────────────┘ | CEmotionOpts (감정 후보 목록 + 강도) v ┌─────────────────────────────────────────────────────────┐ │ ② 감정 → 좌표 avatar.h : 감정 휠(emotion wheel) │ │ 감정을 "원 위의 각도"로 표현 (HAPPY=0, ANGRY=5/8 바퀴...) │ │ 강도(intensity)는 원 중심에서의 거리(반지름) │ └─────────────────────────────────────────────────────────┘ | CEmotion(각도 angle, 강도 intensity) v ┌─────────────────────────────────────────────────────────┐ │ ③ 포즈 선택 avatar.cpp : GetBodyFromEmotion() │ │ 내 캐릭터가 가진 얼굴/몸통 그림들 중 │ │ "감정 좌표에 가장 가까운" 그림을 최근접 탐색으로 고름 │ └─────────────────────────────────────────────────────────┘ | CBody (얼굴 그림 + 몸통 그림) v ┌─────────────────────────────────────────────────────────┐ │ ④ 컷 구성 autopage.cpp / panel.cpp / balloon.cpp │ │ 누구를 이 컷에 넣을지, 말풍선 위치, 줌 배율, │ │ 언제 새 컷으로 넘어갈지를 규칙으로 자동 결정 │ └─────────────────────────────────────────────────────────┘ | v [ 만화 한 컷 렌더링 ] DIB 비트맵으로 조립 → 화면에 blit

① 감정 추출 — 데이터 주도 규칙 엔진

이 부분이 이 저장소에서 가장 배울 게 많은 코드다. 핵심은 "규칙을 C++ 코드에 하드코딩하지 않고, 문자열 리소스로 빼서 데이터처럼 읽어들인다"는 설계다. textpose.cppRegisterRule()"FindString"·"CheckWord"·"CheckStart"·"AllCaps" 같은 함수 이름과 인자를 문자열로 받아 규칙 목록에 등록한다.

// textpose.cpp — 규칙 종류에 따라 세 목록으로 분류
void RegisterRule(float emotion, const char *function,
                  const char *arg, int strength) {
    if (!stricmp(function, "AllCaps")) {        // 전부 대문자면
        capsStrength = strength; capsEmotion = emotion;  // → 소리치기
    }
    else if (!stricmp(function, "FindString"))    // 문장 어디든 포함
        AddToGeneral(StringUnit(emotion, arg, strength, TRUE));
    else if (!stricmp(function, "CheckWord"))     // 단어로 존재
        AddToWord(StringUnit(emotion, arg, strength, TRUE));
    else if (!stricmp(function, "CheckStart"))    // 문장 시작
        AddToSentence(StringUnit(emotion, arg, strength, TRUE));
}

실행 시 GetEmotionsFromString()이 입력 문장을 이 세 목록(general/word/sentence)과 대문자 규칙에 차례로 대조해, 매칭될 때마다 emOpts.Add(감정, 1.0, 강도)감정 후보를 강도(strength)와 함께 쌓는다. 여러 규칙이 동시에 걸리면 강도가 높은 쪽이 우선된다.

배울 점
규칙을 코드가 아니라 데이터로 — "설정으로 행동을 바꾼다"

규칙을 if문으로 소스에 박아두면 규칙을 하나 바꿀 때마다 재컴파일해야 한다. Comic Chat은 규칙을 문자열 리소스(ID_RULE_WAVE 등)로 빼두고 런타임에 파싱해, 코드 수정 없이 규칙 세트를 교체할 수 있게 했다. 요즘 앱이 로직을 JSON/YAML 설정으로 빼는 것과 똑같은 발상을 30년 전에 한 것이다.

실제로 초기 버전에는 규칙이 코드에 직접 박혀 있었는데(지금은 #if 0으로 비활성화된 CheckForLaughs·CheckStarts 함수에서 확인 가능), "ROTFL"→크게 웃기, "LOL"→약하게 웃기, "are you"/"will you"→상대 가리키기, "i'm"/"i'll"→자기 가리키기, "HI"/"Bye"/"Hello"→손 흔들기 같은 매핑이 그대로 남아 있어 "당시 사람들이 감정을 어떻게 문장에서 읽어냈나"의 화석을 볼 수 있다.

② 감정 휠 — 감정을 "각도와 거리"로 표현하다

가장 우아한 설계. Comic Chat은 감정을 이름표가 아니라 2차원 극좌표(원 위의 위치)로 다룬다. avatar.h를 보면 8가지 감정이 원을 8등분한 각도에 배치돼 있다.

// avatar.h — 감정 = 원(2*PI)을 8등분한 각도
#define NEMOTIONS   8
#define EM_HAPPY   ((float)(0 * 2 * PI / 8))   // 0시 방향
#define EM_COY     ((float)(1 * 2 * PI / 8))   // 수줍음
#define EM_BORED   ((float)(2 * 2 * PI / 8))   // 지루함
#define EM_SCARED  ((float)(3 * 2 * PI / 8))   // 무서움
#define EM_SAD     ((float)(4 * 2 * PI / 8))   // HAPPY의 정반대!
#define EM_ANGRY   ((float)(5 * 2 * PI / 8))
#define EM_SHOUT   ((float)(6 * 2 * PI / 8))
#define EM_LAUGH   ((float)(7 * 2 * PI / 8))

여기엔 의도된 기하학이 숨어 있다. HAPPY(0)의 정반대(원의 반대편, 4/8 바퀴)에 SAD가 놓였다. 감정의 "반대말"이 원 위에서 물리적으로 마주 보게 배치한 것이다. 강도(intensity)는 별도 축으로, 원 중심에서 얼마나 멀리 있느냐(반지름)가 감정의 세기를 뜻한다. 중심(반지름 0)은 무표정(neutral).

비유 — 감정 휠

실제 UI에서 사용자는 화면 구석의 작은 원판(bodycam, "감정 휠")에서 마우스를 끌어 표정을 직접 고를 수도 있었다. 마우스를 위로 올리면 기쁨, 아래로 내리면 슬픔, 중심에서 멀리 끌수록 그 감정이 격해진다. bodycam.cppemotion.m_intensity = point_magn(vec) / m_bullRadius; 한 줄이 정확히 "중심에서의 거리 ÷ 원의 반지름 = 감정 강도"를 계산한다. 색상환에서 색을 고르는 컬러 피커와 똑같은 발상이다.

③ 포즈 선택 — 최근접 탐색(nearest-neighbor)

감정 좌표가 정해지면, 내 캐릭터가 가진 여러 얼굴/몸통 그림 중 그 좌표에 가장 가까운 그림을 고른다. avatar.cppGetBodyFromEmotion()은 얼굴과 몸통을 따로 매칭한다 — "각도 차이가 가장 작은 얼굴"과 "각도 차이가 작으면서 강도 차이도 작은 몸통"을 각각 고른다.

// avatar.cpp — 감정 좌표에 가장 가까운 얼굴 그림 찾기
double nearestAngle = 3*PI;      // 아주 큰 값에서 시작
for (int i = 0; i < nFaces; i++) {
    double thisAngle = fabs(subtract_angles(fRec[i].emotion,
                                            emotion.m_emotion));
    if (thisAngle <= nearestAngle) {   // 더 가까운 얼굴 발견
        double delta_i = fabs(emotion.m_intensity - fRec[i].intensity);
        // 각도가 같으면 강도 차이가 작은 쪽 우선
        if (thisAngle == nearestAngle && delta_i >= intensityOfNearest)
            continue;
        nearestAngle = thisAngle; intensityOfNearest = delta_i;
        nearestI = i;
    }
}
SetFace(body, nearestI);          // 고른 얼굴을 몸에 붙임

몸통 선택에는 재밌는 디테일이 있다. int index = (m_lastTorso + 1 + i) % nTorsos;직전에 쓴 몸통 다음 인덱스부터 탐색을 시작한다. 같은 감정이 연속돼도 똑같은 포즈만 반복되지 않고 조금씩 다른 그림이 나오게 해 만화가 지루해지지 않도록 한 장치다. 정답이 여럿일 때 살짝 무작위성을 섞는, 연출을 아는 코드다.

④ 컷 구성 — 자동 페이지 배치(autopage)

마지막으로 autopage.cpp·panel.cpp"이 대사를 어느 컷에, 누구와 함께, 어떤 줌으로 그릴지"를 결정한다. README가 정리한 자동 결정 항목은: 어떤 캐릭터를 컷에 넣을지, 표정·제스처, 캐릭터의 위치와 방향, 말풍선 모양·꼬리·배치, 새 컷으로 넘어갈 타이밍, 컷별 줌 배율이다. bbox.cpp가 각 요소의 사각 영역을 계산해 겹침을 피하고, spline.cpp가 말풍선 꼬리 곡선을 그린다.

용어
말풍선 라우팅 (balloon routing)
balloon.cpp. 말풍선이 말하는 캐릭터의 입에서 나오는 것처럼 보이도록 꼬리를 그리고, 여러 말풍선이 겹치지 않게 배치하는 로직. 코드에 m_routeRgn(라우팅 영역)이 등장하는 이유다. 만화의 "읽는 순서"를 자동으로 만들어내는, 의외로 어려운 문제다.
전체를 한 문장으로

Comic Chat은 "보이지 않는 만화 연출가"다. 배우(아바타)에게 대본(문장)을 주면, 연출가가 대본을 읽고 → 배우의 감정을 정하고(①②) → 그에 맞는 표정·포즈를 지시하고(③) → 카메라 앵글과 배우 위치, 컷 전환까지 짜서(④) 한 컷을 완성한다. 이 연출가가 딥러닝이 아니라 사람이 손으로 짠 규칙과 삼각함수로 되어 있다는 것이 이 저장소의 핵심이다.

5디렉토리 구조 해부

저장소 최상위 = "개발 역사의 지층" — 어느 폴더부터 열어야 하나
comic-chat/ ├─ v1.0-pre/ 1996-08 프리릴리스 스냅샷 (rup 206 "Beta 2") [173 파일] │ └─ client/ ← 여기가 본체 소스 (chat.cpp, avatar.cpp ...) ├─ v1.0/ 1996-08 1.0 정식 릴리스 소스 + 빌드/도움말/설치 [195 파일] │ └─ client/ ← 100개 .cpp/.h — 감정 엔진의 원형 ├─ v2.1b/ 1998-02 2.1 베타 (IRC 다중 서버·OLE 자동화) [725 파일] ├─ v2.5-beta-1/ 1998-06 2.5 베타1 — 가장 발전된 버전 [312 파일] │ ├─ textpose.cpp ← ① 감정 추출 규칙 엔진 │ ├─ avatar.cpp/.h ← ②③ 감정 휠 + 포즈 최근접 탐색 │ ├─ autopage.cpp ← ④ 자동 컷 배치 │ ├─ balloon/panel/bbox/spline.cpp ← 말풍선·컷·기하 계산 │ ├─ ircproto/ircsock.cpp ← IRC 프로토콜 │ └─ rules.cpp/.h ← 봇용 자동응답 규칙 엔진(.crs) ├─ artifacts/ 1998-01 SDK · JChat(자바 클라이언트) · 봇 샘플 [1247 파일] ├─ v1.0-pre-modern/ 2026 현대화 예제: VS2022 빌드 + 고DPI ├─ v2.5-beta-1-modern/2026 현대화 예제: nmake 재작성 + 실서버 접속 ├─ docs/ MODERNIZATION.md · dpi-awareness.md · tls.md ├─ scripts/ 빌드/패키징 스크립트 ├─ file dates.txt 각 스냅샷 원본 파일의 수정 시각 기록 └─ README.md

어느 버전을 봐야 하나?

목적추천 폴더이유
감정 엔진 원리 학습v2.5-beta-1/가장 완성도 높고 파일 이름이 정리됨. textpose.cpp·avatar.cpp가 핵심
지금 컴퓨터에서 실행v2.5-beta-1-modern/최신 nmake 빌드 + 실 IRC 접속 가능. README에 빌드법
가장 단순한 원형v1.0/client/기능이 적어 코드가 작음(파일 100개). 1.0-pre와 99/111 파일이 다름
봇·SDK 확장artifacts/Comic Chat SDK, 자바 클라이언트 JChat, Betty Bot 샘플, 내부 설계 문서
읽는 팁
버전 간 diff로 "무엇이 언제 추가됐나" 보기
v1.0/v2.5-beta-1/을 나란히 놓고 파일 목록을 비교하면, IRC 다중 서버 지원(chatsrv.cpp)·OLE 자동화(bindauto.cpp)·규칙 엔진(rules.cpp)·일본어 지원(jis2sjis.cpp)이 2.x에서 새로 붙은 걸 알 수 있다. "소프트웨어가 2년간 어떻게 자랐나"를 시간순으로 관찰할 수 있는 드문 자료다.

6학습 포인트 — 기술별 배울 것

이 저장소에서 실제로 챙겨갈 수 있는 엔지니어링 교훈

가. 데이터 주도 설계 (Data-Driven Design)

규칙·감정 매핑을 코드가 아니라 데이터(문자열 리소스)로 분리한 것. 이 발상은 지금도 게임 AI, 챗봇 의도 분류, 룰 엔진, 피처 플래그 등 어디에나 쓰인다. textpose.cpp의 규칙 파서를 정독하면 "행동을 설정으로 빼는" 패턴의 원형을 배운다.

나. 기하학으로 UX 문제 풀기

감정을 극좌표(각도+거리)로 모델링해 연속적인 감정 공간을 만들고, 최근접 탐색으로 이산적인 그림에 매핑한 것. "연속 입력 → 이산 자원 매핑"은 추천 시스템·벡터 검색·임베딩 최근접 탐색(요즘의 RAG!)과 본질이 같다. 30년 전 코드로 그 원형을 본다.

연결 고리
감정 휠 최근접 탐색 ≈ 요즘의 벡터 유사도 검색

GetBodyFromEmotion()이 "감정 좌표에 가장 가까운 포즈"를 찾는 건, 요즘 AI가 "질문 임베딩에 가장 가까운 문서"를 찾는 벡터 검색과 수학적으로 같은 문제다. 차원이 2D(각도·강도)냐 1536D(임베딩)냐만 다를 뿐. 최근접 탐색의 직관을 이 작은 예제로 잡아두면 벡터 DB를 이해하기 쉬워진다.

다. 레거시 코드 현대화 실전

docs/MODERNIZATION.md"30년 된 C++를 요즘 컴파일러에서 되살리는 체크리스트" 그 자체다. 실제로 고친 것들:

옛 코드 문제현대화 수정
for(i=0;...) 뒤에서 i 재사용C++ 표준 강화로 for 변수 스코프가 좁아짐 → for(int i=0;...)로 명시
void f() inline {} (뒤에 inline)inline void f() {}로 위치 이동
strchr 결과를 char*에 대입const 정확성 강화 → 캐스팅/const 처리
사라진 uuid3.lib 링크uuid.lib로 교체 + spectre 완화 ATLMFC 링크
없어진 TTS DLL(lhwrap.dll) 임포트스텁(빈 함수)으로 대체
고DPI에서 UI가 작아짐SetProcessDPIAware + DpiScale() 스케일링
함정
"옛 코드 스타일을 그대로 배우면 안 된다"

이 소스는 1996년 관습으로 쓰였다 — malloc/free 수동 메모리 관리, 전역 변수(CEmotionOpts emo;), #if 0로 죽여둔 코드가 곳곳에 있다. "당시엔 이렇게 했구나"의 사료로 읽되, 오늘 코드의 본보기로 삼지는 말 것. 배울 것은 설계 아이디어이지 문법 습관이 아니다.

라. MFC Doc/View와 컴포넌트 임베딩(OLE)

CChatDoc(대화 데이터) / CChatView(만화 화면)의 분리는 관심사 분리(separation of concerns)의 고전적 예다. 또 OLE로 브라우저(IE) 안에 만화 화면을 끼워 넣은 것은 오늘날 iframe·마이크로 프론트엔드·웹컴포넌트의 조상 격 발상이다.

7빌드 · 시스템 요구사항

원본 그대로 vs. 2026 현대화 — 무엇이 필요한가

원본 빌드 (1996 방식)

항목요구
컴파일러Visual C++ 4.x (또는 호환 NMAKE 툴체인)
라이브러리MFC 4.x
OSWindows 95 또는 Windows NT 4.0
실행 최소사양486 CPU · 8MB RAM · 256색 비디오
빌드 명령NMAKE /f "chat.mak" CFG="chat - Win32 Release"

현대화 빌드 (2026, *-modern)

:: v2.5-beta-1-modern — Visual Studio 2022 개발자 환경에서
call "<VisualStudio>\VC\Auxiliary\Build\vcvars32.bat"
cd v2.5-beta-1-modern
nmake /f chat.mak CFG="chat - Win32 Release"   :: 평소 사용
nmake /f chat.mak CFG="chat - Win32 Debug"     :: assert+TRACE 디버그

직접 빌드가 부담되면 두 가지 지름길이 있다. ① 2000년대 초 배포판인 Comic Chat 2.5를 외부 팬 사이트(mermeliz.com)에서 받거나, ② 저장소 릴리스의 비공식 현대 빌드(고해상도 지원 v1.0·v2.5b1)를 내려받으면 클론·빌드 없이 바로 실행해볼 수 있다. GitHub Actions의 Build unofficial modern clients 워크플로를 포크에서 직접 돌릴 수도 있다(비밀키 불필요).

참고
32비트 전용 (Win32 x86)
현대화 버전도 여전히 32비트로 빌드된다. MFC 4.x 시절 코드라 64비트 포팅은 범위 밖으로 남겨뒀다. 그래서 vcvars32.bat(32비트 환경)을 부른다. 실행 자체는 64비트 윈도우의 WOW64 위에서 잘 돌아간다.

8직접 해볼 수 있는 실습 과제

클론해서 코드를 읽고 손대보는 난이도별 과제
난이도 ★☆☆ — 코드 읽기

1. 감정 규칙 목록 뽑아내기

v2.5-beta-1/textpose.cpp#if 0로 비활성화된 CheckForLaughs·CheckForPoints·CheckStarts를 읽고, "어떤 단어가 어떤 감정/제스처로 이어지는가" 표를 직접 만들어 보라. (예: "HI"→WAVE, "i'm"→POINTSELF) 30년 전 사람들의 채팅 말투가 규칙에 화석처럼 남아 있다.

난이도 ★☆☆ — 개념 재현

2. 감정 휠을 종이/코드로 그려보기

avatar.h의 8개 EM_* 각도를 원 위에 찍어 감정 휠을 그리고, "HAPPY의 반대편에 SAD가 있다" 같은 배치 의도를 확인하라. 여유가 있으면 파이썬 matplotlib로 극좌표 산점도를 그려 재현해 본다.

난이도 ★★☆ — 이식(포팅)

3. 감정 추출기를 파이썬/JS로 다시 짜기

GetEmotionsFromString()의 규칙 매칭 로직(general/word/sentence + AllCaps)을 현대 언어로 200줄 안에 재구현하라. 입력 문장을 넣으면 감정 후보와 강도를 출력하는 작은 CLI를 만들면, 데이터 주도 규칙 엔진을 몸으로 익힐 수 있다.

난이도 ★★☆ — 빌드 도전

4. *-modern 실제로 빌드해 실행하기

Visual Studio 2022 + C++/MFC 워크로드를 설치하고 v2.5-beta-1-modernnmake로 빌드해, 공개 IRC 서버에 접속해 스스로에게 말을 걸어 만화가 그려지는지 확인하라. 빌드가 막히면 docs/MODERNIZATION.md의 수정 목록을 대조한다.

난이도 ★★★ — 확장

5. 감정 → 이모지/스티커 매퍼 만들기

Comic Chat의 규칙 엔진 아이디어를 빌려, 채팅 문장을 받아 어울리는 이모지·스티커를 자동 추천하는 웹앱을 만들어 보라. 규칙 버전으로 먼저 만든 뒤, 같은 입출력을 작은 감성분석 모델로 바꿔 "규칙 vs. 학습"의 차이를 체감하면 좋은 학습이 된다.

9관련 기술 심화 학습 로드맵

이 저장소를 발판으로 넓혀갈 4주 코스
주차주제할 것
1주차레거시 C++ 읽기MFC Doc/View 패턴, C-접두 클래스 관습, malloc/freeCPtrList 같은 옛 컨테이너 이해. chat.cppchatdoc.cppchatview.cpp 순으로 흐름 추적
2주차규칙 엔진 · 데이터 주도 설계textpose.cpp 정독 → 파이썬으로 재구현. 이어서 현대 룰 엔진(예: 간단한 인텐트 분류) 원리 학습
3주차기하학과 최근접 탐색극좌표·벡터 연산(vector2d.cpp·spline.cpp) 복습 → 최근접 탐색을 벡터 유사도 검색(코사인 유사도, k-NN)으로 확장. 임베딩 개념 연결
4주차레거시 현대화 실습docs/MODERNIZATION.md·dpi-awareness.md·tls.md를 교재 삼아, 직접 빌드 오류를 하나씩 해결. 고DPI·TLS 등 "주변부 현대화"를 경험

10핵심 키워드 사전

이 문서에 나온 용어 빠른 정리
키워드
IRC1988년 텍스트 실시간 채팅 프로토콜. Comic Chat은 이 표준 위에서 동작
전문가 시스템사람이 짠 규칙 모음으로 판단하는 옛 방식 AI. 감정·포즈 자동 선택의 두뇌
감정 휠(emotion wheel)감정을 원 위의 각도(종류)+거리(강도)로 표현한 2D 모델. 8개 감정 배치
최근접 탐색주어진 좌표에 "가장 가까운" 항목을 찾기. 감정 좌표→포즈 그림 매핑
데이터 주도 설계로직을 코드가 아닌 데이터(설정·리소스)로 빼서 재컴파일 없이 바꾸는 방식
MFCWin32를 C++ 클래스로 감싼 마이크로소프트의 데스크톱 UI 프레임워크
Doc/View데이터(Document)와 화면(View)을 분리하는 MFC 패턴. MVC의 조상
OLE/COM프로그램끼리 기능을 끼워넣고 제어하는 컴포넌트 기술. IE 임베딩에 사용
DIB장치 독립 비트맵. 아바타·배경을 메모리에서 조립해 한 번에 그림(더블 버퍼)
TWIP1/1440인치 단위. 해상도와 무관하게 만화를 그리는 장치 독립 좌표
High-DPI 인식고해상도 모니터에서 UI가 작아지지 않게 스케일링하는 현대화 작업
NMAKE / .mak마이크로소프트판 make. 빌드 순서를 기술하는 파일

11참고 링크

더 파고들 곳
자료주소 / 위치
저장소github.com/microsoft/comic-chat
현대화 종합 문서docs/MODERNIZATION.md
고DPI 대응 상세docs/dpi-awareness.md
TLS(SChannel) 상세docs/tls.md
2.5 현대화 클라이언트v2.5-beta-1-modern/README.md
감정 엔진 핵심 파일v2.5-beta-1/textpose.cpp · avatar.cpp/.h
비공식 현대 빌드 다운로드저장소 Releases(unofficial-modern-builds-2026-07)
원저자DJ Kurlander (Microsoft Research) — 관련 논문 "Comic Chat"(SIGGRAPH 1996)