목록으로

AI랑 3일 만에 블로그 끝내기

2023년에 리포만 파놓고 잠수. 2026년 여름, 3일 69커밋으로 부활시킨 기록.

· 7분 읽기

git log를 열어보면 이 블로그의 역사가 한눈에 보인다. 2023년 1월 10일, 의욕 넘치게 리포를 만들고 세팅 커밋을 찍었다. 그리고 6월까지 띄엄띄엄 40여 커밋을 남긴 뒤, 잠수를 탔다. 그 40여 커밋도 열어보면 대부분 세팅이다. 린트 규칙을 고르고, 폴더 구조를 잡고, 컴포넌트 이름을 고민했다. 정작 글은 한 편도 안 썼다.

3년간 아무 일도 일어나지 않았다.

블로그는 내일부터

그러다 2026년 7월 20일에 다시 열었고, 22일에 끝났다. 사흘간 커밋 69개가 쌓였는데 둘째 날 하루에만 46개다. 3년 미룬 일치고는 허무할 정도로 금방 끝나서, 그동안 뭐가 겁나서 안 열었나 싶었다.

사흘 동안 일어난 일

커밋 로그를 날짜별로 보면 사흘의 성격이 다 다르다.

첫째 날은 공사판이었다. 패키지 매니저를 bun으로 갈고, 디자인 토큰과 다크 테마를 잡고, i18next를 걷어내고 자체 i18n을 만들어 일본어까지 붙였다. 블로그 목록·상세·태그 페이지, Supabase 기반 무서버 댓글, OG 이미지·사이트맵·RSS 같은 SEO 기반, 404 페이지. 저녁쯤엔 뼈대가 서 있었다.

둘째 날은 46커밋짜리 폭주였다. ⌘K 검색, 다크모드 리디자인, 문장 하이라이트 공유, 읽기 설정, 모바일 스와이프, 댓글 랜덤 닉네임, 코나미 커맨드. 이 글에서 자랑할 것들이 거의 다 이날 나왔다. 중간에 Next.js 16 업그레이드와 Biome 전환 같은 공사까지 끼어 있는데, 예전 같으면 이것만으로 주말 하나가 갔을 거다.

셋째 날은 마감이었다. 파비콘을 두 눈 디자인으로 갈고, 서치콘솔·네이버 등록, OG 카드 리디자인. 그리고 이 글을 썼다.

물론 이 리듬은 혼자서 낸 게 아니다.

3일이 가능했던 이유

달라진 건 내가 아니라 도구다. 이번엔 처음부터 끝까지 AI랑 같이 만들었다.

작년에 MVP는 아직도 유효한가라는 글에서 "AI 덕분에 '최소'의 기준이 올라갔다"고 썼는데, 그 글의 증거물이 이 블로그가 될 줄은 몰랐다. 페이지 전환, 스와이프 제스처, 문장 단위 공유, 댓글 시스템. 예전 같으면 하나하나가 "언젠가 붙이고 싶은 것" 목록에 들어갔을 기능들이, 3일짜리 개인 블로그에 다 들어 있다. 개인 블로그의 "최소"도 올라간 것이다.

만드는 방식도 달라졌다. 예전의 나라면 토스트 라이브러리를 고르느라 반나절을 썼을 텐데, 이번엔 고르는 대신 만들었다.

라이브러리 문서 정독하기 vs AI랑 그냥 직접 만들기

허세가 아니라 경제적인 판단이었다. AI랑 같이 짜면 웬만한 인터랙션은 200줄 안에서 나온다. 라이브러리 문서를 읽고 설정과 씨름하는 시간이나, 원하는 동작을 처음부터 만드는 시간이나 비슷해졌다. 그럼 내 손에 맞는 쪽을 고르게 된다. 이 블로그의 토스트도, 제스처도, 댓글도 전부 그렇게 직접 만든 코드다. 덤으로 전부 내가 동작을 설명할 수 있는 코드이기도 하다.

여기서 바로 해볼 수 있는 것들

3일 동안 만든 것 중 세 개만 골랐다. 셋 다 지금 읽고 있는 이 페이지에서 작동한다. 모바일이면 화면을 옆으로 당겨보고, 데스크탑이면 ⌘K를 눌러보면 된다.

1. 모바일에서 글 넘기기

모바일에서 글을 다 읽으면 목록으로 돌아가서 다음 글을 찾아야 한다. 그 동선이 싫어서, 책장 넘기듯 옆으로 당겨서 넘어가게 만들었다.

글 상세를 옆으로 당기면 이전 글 제목이 나타나고, 놓으면 슬라이드 전환으로 이동한다

제스처 라이브러리 없이 터치 이벤트 세 개로 만들었는데, 코드보다 판정 규칙 정하는 게 일이었다.

  • 가로 이동이 10px을 넘고 세로의 1.2배보다 클 때만 스와이프로 본다
  • 판정 전에 세로로 12px 이상 움직이면 스크롤 의도로 보고 끝까지 무시한다
  • 코드블록이나 표처럼 자체 가로 스크롤이 있는 요소에서 시작한 터치도 무시한다
  • 일단 스와이프로 인정되면 그때부터 preventDefault()로 스크롤을 잠근다

당기는 "감각"은 함수 하나가 만든다.

ts
const THRESHOLD = 88;
const damp = (p: number) =>
  0.32 * Math.min(p, THRESHOLD) + 0.14 * Math.max(0, p - THRESHOLD);

손가락이 움직인 만큼 화면을 그대로 밀면 싸 보인다. 임계점까지는 0.32배, 그 뒤로는 0.14배로 눌러야 고무줄 같은 저항감이 생긴다. 이 계수는 AI가 못 정해준다. 실제 폰에서 손으로 당겨보면서 맞춘 값이다. 놓으면 뷰 전환의 슬라이드가 이어받아서, 당기던 방향 그대로 페이지가 넘어간다. 이동할 수 있는 글은 미리 prefetch해 두니까 놓는 순간 기다림도 없다.

녹화하다가 웃긴 일도 있었다. 분명 만든 기능인데 왼쪽으로 당겨도 아무 반응이 없어서 버그인 줄 알았다. 알고 보니 최신 글이라 다음 글이 없었고, 갈 곳이 없으면 제스처를 거부하도록 내가 짜뒀던 거다.

내가 짠 방어 로직 vs 스와이프 안 된다고 화내는 나

2. 토스트 대신 캡슐

이 사이트엔 알림 토스트가 없다. 링크 복사든 테마 변경이든, 모든 알림은 상단의 내비게이션 캡슐이 늘어나면서 보여준다. 글에 들어가면 "읽는 데 약 4분 걸려요" 하고 먼저 알려주는 것도 이 캡슐이다.

테마를 전환하면 캡슐이 늘어나며 메시지를 보여준다

CSS는 width: auto로 가는 애니메이션을 못 한다. 그래서 현재 폭을 픽셀로 고정하고 다음 프레임에 목표 폭을 지정하는 FLIP 방식으로 만들었다. 상태 관리는 70줄짜리 자체 스토어 하나. 어느 컴포넌트든 islandStore.notify() 한 줄이면 캡슐이 말을 대신 해준다.

기능이 돌아간 뒤에는 오히려 자잘한 규칙에 시간을 더 썼다. 스크롤을 내리면 숨고 올리면 나타나되, 6px 이하 움직임은 무시해서 떨리지 않게 했다. 말하는 중에는, 그러니까 메시지가 떠 있는 동안에는 스크롤해도 숨지 않는다.

반나절짜리 버그도 여기서 나왔다. 어느 날 캡슐의 블러가 통째로 사라졌는데, 캡슐 코드는 아무리 봐도 멀쩡했다. 범인은 레이아웃 정리하면서 부모 래퍼에 넣은 overflow 한 줄. 조상 요소에 클리핑이 생기면 backdrop-filter가 조용히 죽는다는 걸 이날 알았다. 버그는 항상 내가 안 보고 있는 파일에 있다.

3. 도메인의 비밀

⌘K를 누르면 검색 팔레트가 뜨는데, 사실 이건 터미널이기도 하다. help, theme dark, whoami 같은 명령이 통하고, 그중 qwerty가 핵심이다.

⌘K 팔레트에 qwerty 최민기를 입력하면 chlalsrl이 출력된다

qwerty 최민기를 치면 chlalsrl이 나온다. 한영키를 안 누른 채 "최민기"를 치면 그대로 chlalsrl. 이 도메인이 왜 chlalsrl.com인지에 대한 답을 팔레트 안에 숨겨뒀다. 도메인을 불러줄 때마다 설명이 길어지는 게 단점이지만, 설명을 다 들은 사람은 한 번에 기억한다.

방향키로 코나미 커맨드를 치면 캡슐이 반겨주고, 콘솔에는 배포된 커밋 해시가 찍혀 있다. 아무도 못 찾아도 상관없지만, 언젠가 누가 ⌘K에 sudo를 쳐보고 웃는다면 만든 보람은 충분하다.

하나 더: 문장 공유

셋만 고르겠다고 했는데 이건 그냥 못 지나가겠다. 본문에서 문장을 드래그하면 공유 버튼이 뜨고, 누르면 그 문장으로 바로 이동하는 링크가 복사된다.

본문에서 문장을 선택하면 공유 버튼이 뜨고, 누르면 문장 링크가 복사된다

글 링크를 통째로 받는 것보다 누가 내 글의 한 문장을 긁어서 보내주는 쪽이 훨씬 기분 좋다. 그 문장이 그 사람한테 남았다는 뜻이니까.

재미있는 건 이 기능에서 서버가 하는 일이 없다는 점이다. 링크는 브라우저 표준인 Text Fragment(#:~:text=) 문법이라, 여는 쪽 브라우저가 알아서 해당 문장까지 스크롤하고 하이라이트까지 해준다. 내 코드는 선택 영역을 감지해서 URL을 만드는 게 전부다. 공유된 문장은 집계해 뒀다가, 여러 명이 겹치면 글 하단에 "독자들이 밑줄 그은 문장"으로 보여준다. 어떤 문장이 남을지는 나도 궁금하다.

AI랑 일해보니

3일 중 AI가 코드를 쓴 시간이 압도적으로 길다. 그런데 돌아보면 내가 한 일이 없었냐면, 전혀 아니다. 역할이 달랐을 뿐이다.

AI는 만드는 걸 잘한다. 스와이프의 터치 이벤트 처리, 캡슐의 FLIP, Supabase 연동 같은 건 설명하면 금방 나온다. 다크 모드에서 새로고침할 때 흰 화면이 번쩍이는 문제를 막으려고 첫 페인트 전에 인라인 스크립트를 심는 처리 같은, 알 만한 사람만 아는 요령도 알아서 챙긴다.

대신 "얼마나"는 못 정한다. 감쇠 계수 0.32, 캡슐이 숨는 스크롤 기준 6px, 닉네임이 바뀌는 간격 70ms. 이런 숫자들은 전부 직접 만져보고 정한 값이다. 화면을 만져보지 않고 좋은 값을 낼 방법은 없고, 손끝의 판단까지 맡길 수는 없었다.

미묘한 버그를 잡는 것도 결국 같이 했다. 한글 태그 페이지가 전부 404가 난 적이 있는데, 빌드 시점에 태그를 미리 인코딩해서 넘긴 게 원인이었다. 프레임워크가 한 번 더 인코딩해서 이중 인코딩된 경로로 페이지가 만들어진 거다. 증상만 보면 원인을 짐작하기 어려운 종류의 버그라, 이런 건 여전히 사람이 상황을 좁혀줘야 잡힌다.

만들고 지운 것들

이번 작업에서 제일 뜻밖이었던 건, 빼는 결정을 이렇게 많이 하게 될 줄 몰랐다는 거다. 커밋 로그에 영수증이 다 남아 있다.

  • 방명록 페이지를 만들었다가 몇 시간 만에 지웠다
  • 좋아요를 멀티 이모지 리액션 바로 바꿨다가 커밋 하나 만에 되돌렸다
  • 홈에 프로젝트 섹션과 업데이트 히스토리를 붙였다가 그날 밤에 뗐다
  • 스와이프 프리뷰는 화살표 칩에 라벨 카드까지 요란했는데, 두 번 갈아엎고 오버레이와 제목만 남겼다
  • 댓글 입력 카드는 스타일 커밋만 네 개 쌓였다
  • OG 카드는 여섯 번째 버전까지 갔다가 결국 세 번째 버전으로 롤백했다

하이라이트는 OG 카드다. 공유될 때 보이는 카드에 두 눈 마스코트를 넣었는데, 커밋 기록 기준 3분 만에 뺐다. 00:51 추가, 00:54 제거. 1200×630 안에서는 제목이 주인공이어야 하는데 눈이 자꾸 시선을 가져가서였다.

자동 생성되는 오픈 그래프 이미지

만드는 게 싸지니까 일단 만들어보고 판단하는 게 가능해졌고, 그러다 보니 뭘 남기고 뭘 버릴지 고르는 일이 본업이 됐다. 코드는 AI가 쓰고, 나는 지우는 걸 결정했다. 셋 중 뭐가 제품을 만드는 일이냐고 물으면, 나는 지우는 쪽이라고 답하겠다.

그 외에 들어간 것들

여기까지 쓰고도 남은 게 있다.

댓글 폼은 이름 칸이 빈 채로 열리지 않는다. 처음부터 랜덤 닉네임이 들어 있고, 옆의 버튼을 누르면 슬롯처럼 돌아간다. 아바타는 이름 해시로 그리기 때문에 같은 이름은 언제나 같은 얼굴이 나온다. 이름 칸이 비어 있으면 뭘 쓸지 고민하다 창을 닫게 된다는 게 내 가설인데, 맞는지는 댓글이 쌓여봐야 알겠다.

이름 뽑기 버튼을 누르면 닉네임이 슬롯처럼 돌아가다 멈춘다

읽는 쪽도 손을 댔다. 집중 모드를 켜면 화면 중앙 근처의 문단만 밝게 남는데, 긴 글에서 눈이 자꾸 딴 줄로 새는 내가 첫 사용자다. 다크 모드에서 텍스트를 긁으면 기본 반전 셀렉션이 흰 면으로 번쩍이길래, 액센트 색을 살짝 섞은 면으로 바꿔서 눌렀다.

파비콘의 두 눈은 이미지 파일 없이 코드로 그린다. 원안 SVG의 비율을 상수로 옮겨둬서, 64px 파비콘부터 512px 홈 화면 아이콘까지 같은 코드에서 나온다. 언어는 한국어, 영어, 일본어 셋을 지원하고 번역이 없는 글은 원문으로 폴백된다. 이 글은 셋 다 있다.

3일이면 된다

3년 미룬 이유를 이제 와 생각해보면, 머릿속 견적이 2023년에 멈춰 있었다. 블로그 개편을 몇 달짜리 일로 적어놨으니 엄두가 안 났고, 엄두가 안 나니 열어보지도 않았다. 도구는 바뀌었는데 견적만 옛날 것을 들고 있었던 셈이다. 열어보니 사흘이었다.

만들 건 다 만들었으니 이제 글을 쓸 차례다.

관련 글

댓글