본문으로 건너뛰기
블로그 목록
AI/개발

MAGI 스타일 의사결정 콘솔 만들기

원작의 MAGI 화면을 React UI로 재해석하고, Gemini·Claude·ChatGPT가 각각 판단하는 3노드 의사결정 데모를 만든 과정입니다.

시작은 화면 하나였다

이번 프로젝트는 아주 명확한 한 장의 참고 이미지에서 시작했습니다. 원작의 MAGI 화면처럼 세 개의 큰 노드가 서로 연결되어 있고, 주변에는 상태 정보와 코드, 최종 판정이 떠 있는 UI를 만들고 싶었습니다.

처음에는 그냥 분위기만 비슷하면 된다고 생각했습니다. 하지만 막상 구현해보니 중요한 것은 색이나 글자만이 아니었습니다. 노드의 크기, 사다리꼴에 가까운 모양, 연결선이 닿는 위치, 상단 상태선의 길이, 텍스트가 도형을 침범하지 않는 정도 같은 작은 차이가 전체 인상을 결정했습니다.

그래서 이 프로젝트는 단순한 팬메이드 화면 구현이 아니라, 참고 이미지를 웹 UI 문법으로 번역하는 작업이 되었습니다.

MAGI 스타일 의사결정 콘솔 스크린샷
MAGI 스타일 의사결정 콘솔 스크린샷

기술 스택

  • React 19
  • TypeScript
  • Vite
  • CSS polygon 기반 노드 도형
  • Vercel Functions
  • Gemini, Claude, OpenAI API
  • 정적 UI만 만들었다면 훨씬 빨리 끝났을 겁니다. 하지만 이 화면이 진짜 MAGI처럼 보이려면 질문을 받고, 각 노드가 판단하고, 최종 판정을 내리는 흐름이 필요했습니다.

    가장 오래 붙잡은 것: 노드와 연결선

    처음에는 SVG나 이미지로 처리하는 방법도 생각했습니다. 하지만 반응형을 고려하면 CSS 도형으로 만드는 편이 낫다고 판단했습니다. 노드는 clip-path를 이용해 각기 다른 기울어진 변을 가진 도형으로 만들고, 연결선은 그 도형의 경사면 중점을 향하도록 맞췄습니다.

    어려웠던 부분은 선 자체가 아니라 선이 닿는 지점이었습니다.

  • 1번과 3번을 잇는 선은 비교적 빨리 안정화되었습니다.
  • 2번과 1번, 2번과 3번을 잇는 선은 노드의 기울어진 변 중점을 지나야 원작 느낌이 났습니다.
  • 모바일에서는 노드가 세로 흐름으로 재배치되기 때문에 선의 각도도 별도로 조정해야 했습니다.
  • 결국 데스크톱과 모바일의 연결선을 같은 규칙으로 억지로 맞추지 않고, 각 화면에서 자연스럽게 보이는 geometry를 따로 잡았습니다. 이 과정에서 "반응형"은 단순히 가로가 세로로 바뀌는 것이 아니라, 원래 화면의 감각을 다른 비율로 다시 작곡하는 일이라는 걸 다시 느꼈습니다.

    판정 표시는 글자가 아니라 상태 변화

    초기 버전에서는 각 노드에 가결, 부결 같은 문자를 직접 표시하려 했습니다. 그런데 원작 화면을 다시 보니 각 노드의 판단은 텍스트보다 색상 변화에 가깝게 표현되어 있었습니다.

    그래서 최종적으로는 노드 자체가 상태를 갖도록 바꿨습니다.

  • 대기 상태
  • 심의 중 상태
  • 가결 상태
  • 부결 상태
  • 보류 상태
  • 사용자는 텍스트를 읽기 전에 먼저 화면의 색과 리듬으로 결과를 느끼게 됩니다. 최종 판정 뱃지는 가결일 때 녹색, 부결일 때 적색 계열로 바꾸고, 빛번짐도 그 판정 색을 따라가게 조정했습니다.

    CRT 필터와 과하지 않은 낡음

    옛날 CRT 화면 같은 느낌도 넣고 싶었습니다. 다만 스캔라인을 세게 넣으면 금방 읽기 어려워지고, 너무 약하면 달라진 티가 나지 않습니다.

    이번 UI에서는 CRT 효과를 장식으로 과시하기보다, 화면 전체에 살짝 얹히는 질감으로 조정했습니다. 스캔라인, 미세한 글로우, 약한 화면 노이즈가 함께 있지만 입력창이나 모달의 가독성을 해치지 않는 선에서 멈췄습니다.

    이런 효과는 많이 넣는 것보다 적당히 빼는 쪽이 더 어렵습니다.

    세 노드에 실제 모델을 연결하기

    UI가 어느 정도 잡힌 뒤에는 "이게 실제로 어떻게 동작해야 하는가"라는 질문으로 넘어갔습니다. 최종 구조는 세 노드가 각각 다른 성향의 모델에 대응하는 방식입니다.

  • MELCHIOR•1: Gemini — 구조, 실행 가능성, 시스템 관점
  • BALTHASAR•2: Claude — 위험, 윤리, 안전장치
  • CASPER•3: ChatGPT — 사용자 의도, 효용, 대화적 균형
  • 브라우저는 직접 provider API 키를 갖지 않습니다. 대신 Vercel Function의 /api/judgement route가 질문을 받아 세 provider를 병렬로 호출하고, 각 노드의 판단을 JSON으로 정규화합니다.

    각 노드는 verdict, confidence, summary, reason, concern을 반환합니다. UI는 이 값을 받아 노드 상태를 애니메이션으로 공개하고, 사용자가 노드를 hover 또는 tap하면 판단 근거를 보여줍니다.

    실패해도 멈추지 않는 폴백

    이 프로젝트에서 폴백은 임시방편이 아니라 핵심 기능입니다. API 키가 없거나, 하나의 provider가 실패하거나, 응답 JSON을 파싱하지 못해도 화면은 멈추면 안 됩니다.

    그래서 각 노드는 실패 시 내부 판단 엔진으로 대체됩니다. 세 노드 중 일부만 API에 성공하면 source는 mixed가 되고, 모두 실패하면 fallback이 됩니다. 하지만 사용자 경험에서는 여전히 하나의 MAGI 판단처럼 보이도록 만들었습니다.

    여기서 중요한 점은 폴백을 "랜덤 결과"처럼 드러내지 않는 것이었습니다. 내부적으로는 다양한 결과를 만들 수 있지만, 사용자가 보는 문구는 각 노드가 자기 역할에 따라 판단한 것처럼 구성했습니다. 데모라 해도 화면 안의 세계관은 깨지지 않아야 했습니다.

    모달은 모바일에서 특히 중요했다

    데스크톱에서는 노드 hover로 판단 근거를 보여주면 자연스럽습니다. 하지만 모바일에는 hover가 없습니다. 그래서 모바일에서는 노드를 탭하면 모달이 열리고, 바깥을 탭하면 닫히도록 처리했습니다.

    또 Claude처럼 신중한 노드는 내용이 길어질 수 있습니다. 이때 모달이 화면 밖으로 밀려나거나 UI에 가려지면 안 되기 때문에 최대 높이와 스크롤 처리를 넣었습니다.

    작은 화면에서는 멋진 연출보다 닫기 쉬운 인터랙션과 읽을 수 있는 영역이 더 중요했습니다.

    배포와 문서화

    배포는 Vercel로 진행했습니다. 처음에는 Vercel 서버리스 함수가 브라우저 쪽 모듈을 import하면서 배포 환경에서 module not found 문제가 발생했습니다. 이를 해결하기 위해 api/judgement.ts를 self-contained하게 정리했고, 관련 테스트도 추가했습니다.

    현재 데모는 아래 주소에서 볼 수 있습니다.

    https://magi-sooty.vercel.app

    GitHub 저장소에는 README를 다시 작성해 로컬 실행, 환경변수, 실제 API 연결, Vercel 배포 방식을 정리했습니다.

    배운 점

  • 원작 같은 UI는 색상보다 비율과 접점이 더 중요하다.
  • 반응형은 같은 레이아웃을 줄이는 일이 아니라, 같은 감각을 다시 설계하는 일이다.
  • AI 모델 연결은 결과보다 실패 경로 설계가 먼저다.
  • 데모라도 사용자가 보는 세계관을 깨지 않는 문구가 중요하다.
  • API 없이도 동작하는 폴백은 개발 편의가 아니라 제품 안정성이다.
  • 마무리

    처음에는 "참고 이미지처럼 보이게 만들자"에서 출발했습니다. 그런데 만들다 보니 결국 UI, 인터랙션, 모델 오케스트레이션, 폴백 설계, 배포까지 모두 연결된 작은 제품이 되었습니다.

    좋은 화면은 보기만 좋은 화면이 아니라, 그 화면이 암시하는 동작까지 갖고 있어야 합니다. MAGI 프로젝트는 그걸 꽤 선명하게 느끼게 해준 작업이었습니다.

    #MAGI#React#TypeScript#Vercel#AI UI