← 블로그로 돌아가기
Day 4

만다라트 목표 설정 도구 만들기 — 9x9 그리드 + 키보드 네비게이션

2026년 3월 31일 AM 12:20

devlogreact만다라트

만다라트를 만들게 된 계기

혼자 고민하는 시간이 길었습니다. "오늘은 뭘 만들지?"

3일차까지는 그때그때 떠오른 아이디어로 밀어붙였는데, 4일차부터는 "사람들이 실제로 쓸 만한 도구"를 만들고 싶어졌습니다. 고민 끝에 떠올린 게 만다라트(Mandal-Art)였습니다.

오타니 쇼헤이가 고등학생 때 작성한 만다라트가 유명하죠. 핵심 목표 1개 → 세부 목표 8개 → 실행 항목 64개. 총 81칸을 채우면서 목표를 구체적으로 쪼개는 프레임워크입니다.

검색해보니 기존 만다라트 웹 도구들이 있긴 한데, 대부분 디자인이 투박하거나 기능이 부족했습니다. "이쁘고 쓰기 편한 만다라트"를 만들어보자고 결정했습니다.

만들면서 느꼈는데, 만다라트 이쁘당 구우우웃.


가장 어려웠던 것 — 양방향 싱크

만다라트의 핵심 구조는 이렇습니다.

문제는 양방향 싱크입니다. 가운데 블록에서 "기술 역량"이라고 적으면, 해당 바깥 블록의 중앙에도 "기술 역량"이 자동으로 들어가야 합니다. 반대로도 마찬가지고요.

// 블록(br, bc) 안의 셀(cr, cc)을 1차원 인덱스로 변환
const idx = (br * 3 + cr) * 9 + (bc * 3 + cc);

인덱싱을 잘못 잡으면 엉뚱한 칸이 동기화됩니다. 이 로직을 디버깅하는 데 시간을 꽤 썼습니다. 콘솔에 81칸을 다 찍어보면서 "이 칸이 저 칸과 연결되는 게 맞는지" 일일이 확인했습니다.


사용성에 투자한 시간

키보드 네비게이션

81칸을 마우스로 하나하나 클릭하면서 채우면 손이 아픕니다. 방향키로 셀 이동, Enter로 편집, Escape로 취소할 수 있게 만들었습니다.

이 기능을 넣은 뒤에 직접 만다라트를 작성해봤는데, 마우스 없이 81칸을 채우는 경험이 생각보다 좋았습니다. 한 칸 쓰고 → 오른쪽 → 한 칸 쓰고 → 아래. 흐름이 끊기지 않습니다.

5가지 컬러 팔레트

만다라트는 시각적으로 예뻐야 동기부여가 됩니다. Rainbow, Pastel, Ocean, Sunset, Mono 다섯 가지 팔레트를 만들었고, 커스텀 색상 선택도 가능합니다.

블록별로 자동 색상 매핑이 들어가는데, 밝은 배경에는 어두운 텍스트, 어두운 배경에는 밝은 텍스트가 나와야 합니다. RGBA 블렌딩 함수를 만들어서 다크/라이트 모드에서 둘 다 잘 보이게 처리했습니다.

저장 슬롯

localStorage에 3개 슬롯으로 저장할 수 있습니다. 만다라트를 한 번에 완성하는 사람은 거의 없고, 며칠에 걸쳐 수정하면서 채워가니까 저장 기능은 필수였습니다. 각 슬롯에 타임스탬프를 표시해서 어떤 버전인지 구분할 수 있게 했습니다.

이미지 내보내기에서 만난 함정

html2canvas로 완성된 만다라트를 PNG로 내보내는 기능을 넣었는데, 한 가지 함정이 있었습니다. input 요소는 canvas에서 렌더링되지 않습니다. 내보내기 시점에 input을 span으로 교체하고, 캡처 후 다시 input으로 복원하는 처리가 필요했습니다.

이걸 몰라서 처음에 "내보내기 했는데 왜 칸이 다 비어있지?"라며 당황했습니다.


유튜브 다운로더 고도화

이날은 만다라트 외에 유튜브 다운로더의 라이브 영상 다운로드 기능도 추가했습니다. 10시간 이상의 라이브 방송도 다운로드할 수 있도록 개선했습니다.


1시간 17분의 밀도

00:20에 시작해서 01:37에 끝. 평일 야근 후라 컨디션이 좋지 않았지만, 2일차의 교훈("피곤하면 억지로 하지 말자")을 기억하면서 집중할 수 있는 시간만 앉았습니다.

짧은 시간이었지만 만다라트는 꽤 만족스러운 결과물이 나왔습니다. 특히 키보드 네비게이션이 들어간 후 직접 써보면서 "이건 나도 쓰겠다"는 느낌이 들었습니다.

사용자가 나 자신일 때, 만드는 속도가 가장 빠릅니다. 내가 원하는 걸 정확히 아니까요.