기록이 남지 않으면 의미가 없다
6일차가 되니까 깨달은 게 있습니다. 매일 뭔가를 만들고 있는데, 기록이 없습니다.
어제 뭘 만들었는지는 기억나는데, 3일 전에 뭘 만들었는지는 가물가물합니다. git log를 뒤져보면 되긴 하지만, "왜 이걸 만들었는지", "만들면서 뭘 배웠는지"는 커밋 메시지에 안 남습니다.
그래서 오늘은 블로그를 만들기로 했습니다. 그리고 남는 시간에 SEO 세팅과 Canvas 물리 시뮬레이션 게임까지.
1. MDX 블로그 시스템
왜 MDX인가
블로그 플랫폼을 쓸 수도 있었지만, 이 프로젝트 안에 블로그를 직접 만들고 싶었습니다. 코드 하이라이팅, 커스텀 컴포넌트, React 컴포넌트 임베딩 같은 것들을 자유롭게 쓰려면 MDX가 맞습니다.
구조는 단순합니다.
content/blog/폴더에.mdx파일을 넣으면 자동으로 목록과 상세 페이지가 생성gray-matter로 frontmatter(제목, 날짜, 태그) 파싱next-mdx-remote로 서버사이드 MDX 렌더링rehype-pretty-code(Shiki)로 코드 하이라이팅
파일 하나 추가하면 바로 블로그에 뜹니다. CMS 없이, 데이터베이스 없이. 글쓰기 허들을 최대한 낮추는 게 핵심이었습니다. 허들이 높으면 결국 안 쓰게 되니까요.
시행착오 — MDX 파싱 이슈
MDX에서 마크다운 문법이 100% 호환되지 않는다는 걸 배웠습니다.
- 마크다운 테이블이 렌더링 안 되는 경우가 있음 → 리스트로 대체
- 인라인 코드에 bold를 감싸면 파싱 깨짐 → bold 제거
rehype-pretty-code가 생성한 스타일을 커스텀 컴포넌트가 덮어쓰면 코드 하이라이팅이 사라짐
이런 것들은 직접 부딪혀봐야 알 수 있는 문제입니다.
2. SEO — 보이지 않는 곳에서 일하는 것들
5일차에 서치콘솔과 GA4를 세팅했으니, 6일차에는 나머지 메타 정보를 채웠습니다.
- favicon — 16px, 32px, ICO, apple-touch-icon, Android Chrome 아이콘
- OG meta — 페이지별 Open Graph 태그
- Twitter Card — summary 카드 메타 태그
- robots.ts — 크롤러 허용 규칙 + sitemap 경로
- manifest.ts — PWA manifest (이름, 아이콘, 테마컬러)
- 페이지별 layout — 각 서비스 페이지에 개별 메타데이터 적용
이런 작업은 눈에 안 보입니다. 사용자가 직접 느끼지 못합니다. 하지만 누군가 카카오톡으로 링크를 공유했을 때 미리보기가 깨져 나오면, "이 사이트 뭔가 허술하네"라는 인상을 줍니다.
보이지 않는 곳을 정리하는 건, 보이는 기능을 만드는 것만큼 중요합니다.
3. 꿈 양동이 — "당신의 꿈은 어디에서 새고 있나요?"
오늘의 메인 프로젝트입니다. Canvas 2D + 물리 엔진을 직접 구현한 인터랙티브 시뮬레이션.
컨셉
화면 위쪽에서 마우스(터치)로 공을 떨어뜨립니다. 공은 깔때기 → S자 커브 경로를 따라 아래로 흘러갑니다. 그런데 경로 중간에 구멍이 있습니다.
하나는 "완벽주의", 다른 하나는 "미루기".
이 구멍으로 공이 빠져나갑니다. 아래 그릇까지 도달한 공만 "성공"으로 카운트됩니다.
100일 챌린지를 하면서 느끼는 감정 그대로입니다. 완벽하게 만들려다 시작도 못 하고, 내일 하겠다고 미루다가 결국 안 하고. 그 사이로 꿈이 새어나갑니다.
물리 엔진을 직접 만든 이유
물리 엔진 라이브러리(Matter.js 등)를 쓸 수도 있었지만, 바이브코딩이니까 직접 만들어봤습니다.
- Verlet Integration — 위치 기반 물리 시뮬레이션. 속도를 직접 관리하지 않고, 이전 위치와 현재 위치의 차이로 속도를 추론
- 선분 충돌 — 깔때기, 커브 벽, 그릇과의 충돌 처리
- 공끼리 충돌 — Spatial Hash Grid로 O(n) 최적화. 300개 공이 동시에 움직여도 부드러움
- Object Pool — GC 압력 최소화. 공을 새로 생성하지 않고 풀에서 재사용
const MAX_BALLS = 300;
const GRAVITY = 0.35;
const DAMPING = 0.99;
const BOUNCE = 0.3;처음에 GRAVITY를 1.0으로 했더니 공이 너무 빠르게 떨어져서 구멍을 지나치기도 전에 바닥에 도달했습니다. 0.35로 줄이니까 공이 천천히 떨어지면서 경로를 따라 흘러가는 느낌이 났습니다. 물리 상수 하나가 게임의 재미를 완전히 바꿉니다.
마일스톤 메시지
시도 횟수에 따라 동기부여 메시지가 뜹니다.
- 100회: "시작이 반이다. 당신은 이미 움직이고 있다."
- 500회: "꾸준함은 천재를 이긴다."
- 1000회: "1000번의 시도. 당신은 이미 대단하다."
이 챌린지를 하면서 저한테 하고 싶은 말이기도 합니다.
6일차 회고
오늘은 "보이지 않는 인프라" 작업이 많았습니다. 블로그, SEO, 메타데이터. 사용자가 직접 보지 않지만 검색 노출과 공유 경험에 큰 영향을 주는 것들.
꿈 양동이 시뮬레이션은 만들면서 가장 즐거웠던 프로젝트입니다. 물리 엔진을 처음부터 짜본 건 처음인데, Verlet Integration이 생각보다 직관적이었습니다. 그리고 "완벽주의"와 "미루기" 구멍 컨셉이 100일 챌린지를 하는 제 마음을 정확히 반영하고 있어서 만들면서 웃었습니다.
6일째. 아직 94일 남았지만, 6일 전의 나보다는 확실히 나아졌습니다.