Victor

[연재] 성경 아틀라스 (2) 지형 위에 국경과 영향력

연재 · 2026-08-13

지도 오른쪽 위에 네모난 얼룩이 하나 있었습니다

 

7월 20일 오전, 지도를 넓게 축소해놓고 보다가 오른쪽 위에서 이상한 걸 발견했습니다.

 

카스피해 자리에 네모난 얼룩이 하나 있었어요. 바다여야 하는 자리인데 육지 색으로 칠해져 있고, 모양도 카스피해처럼 안 생겼습니다. 그냥 각진 덩어리가 하나 앉아 있었어요.

 

그날 오전 10시 36분 커밋 메시지가 이겁니다.

 

fix: 카스피해가 육지로 칠해져 깨진 네모로 보이던 문제(구멍 파냄)

 

 

원인은 이랬습니다. 지형 그림을 만들 때 "여기까지가 육지"라는 마스크를 만들어서 육지에만 땅 색을 칠하거든요. 그 마스크는 육지 모양 데이터를 하나씩 받아 칠하는 방식인데, 이 데이터에는 바깥 테두리 말고 안쪽 구멍도 같이 들어 있습니다. 대륙 한가운데 뚫린 내해(內海)가 그 구멍이에요.

 

바깥 테두리만 칠하고 구멍을 무시하면 어떻게 되냐면, 카스피해가 아시아 대륙 한복판이니까 그냥 육지로 메워집니다. 그리고 그 자리 표고는 해수면보다 낮으니 땅 색표에서 엉뚱한 색이 나와요. 그래서 각진 얼룩이 됩니다.

 

고친 코드는 세 줄입니다. 지금 파일에 주석까지 그대로 남아 있어요.

 

# 구멍(예: 카스피해)은 바다로 파낸다 — 안 그러면 육지로 칠해져 깨진 네모로 보임.
for hole in poly[1:]:
    h = proj(hole)
    if len(h) >= 3:
        dr.polygon(h, fill=0)

 

여기서 중요한 건 고친 방법이 아니라 어떻게 발견됐느냐입니다.

 

데이터는 멀쩡했어요. 육지 모양 파일에 카스피해 구멍은 처음부터 정확하게 들어 있었습니다. 코드도 안 죽었고, 검사기도 통과했고, 빌드는 성공했습니다. 로그 어디에도 경고 한 줄 없어요.

 

이건 화면을 눈으로 봐야만 보이는 문제였습니다.

 

자료가 맞는 것과 화면이 맞아 보이는 것은 다른 문제였습니다

 

지난 편은 성경 66권을 열 개 시대 칸으로 나눈 이야기였어요. 오늘은 그 위에 무엇을 어떻게 그렸는가 입니다.

 

그리고 오늘 이야기는 대부분 fix: 로 시작하는 커밋에서 나옵니다.

 

7월 19일 오후 2시 25분에 시작한 이 도구는, 다음 날인 20일 오전 8시 43분에 66권짜리로 넓혀졌습니다. 그때부터 낮 12시 36분까지 약 네 시간이 오늘 이야기의 전부예요. 그 네 시간 커밋 목록이 이렇습니다.

 

07-20 09:37  창세기 시작 · 깃발 아이콘 · 강 라벨 · 영향력 애니 · 미리보기
07-20 09:44  레반트 고해상 지형 인셋(DEM 기반)
07-20 09:53  fix: 지형 이미지를 인라인 → 외부 파일로 분리 (배포 깨짐)
07-20 10:07  지형 전체를 통일 DEM으로 재생성
07-20 10:15  style: 지형을 채도↓·밝기↑로 눌러 배경화
07-20 10:19  perf: 배경화를 CSS 필터 → 이미지에 구워넣기
07-20 10:29  perf: rAF 스로틀 + 드래그 중 라벨 생략 + 지오메트리 솎기
07-20 10:36  fix: 카스피해가 깨진 네모로 보이던 문제
07-20 12:09  우상단 오류 신고·제안 폼
07-20 12:17  fix: 얕은 바다(대륙붕)가 흰색으로 뜨던 문제
07-20 12:24  fix: 바다 배경화 제외 + 이미지 캐시 버전 붙이기
07-20 12:29  fix: 신고 메일 한글 항목 이름 깨짐

 

 

목록을 보시면 fix 가 다섯 개인데, 다섯 개가 전부 "화면에 이상하게 보였다" 입니다. 값이 틀린 게 하나도 없어요. 계산이 잘못된 것도 없고요.

 

앞 회차들에서 나온 버그는 성격이 달랐습니다. 계산기는 금액이 틀렸고, 카드 도구는 한도 숫자가 틀렸고, 지분 도구는 지분율이 틀렸어요. 전부 이 틀린 거라 값을 확인하면 잡힙니다.

 

지도는 안 그래요. 값이 다 맞는데 그림이 이상합니다. 그리고 그림이 이상한 건 사람이 보기 전까지 아무도 모릅니다.

 

3000년 전 지도에 국경선을 그으면 안 됩니다

 

여기부터가 진짜 어려운 문제였어요.

 

시대를 열 개로 나눴으니 각 시대마다 "그때 여기엔 어느 나라가 있었나"를 그려야 합니다. 그런데 그때 그 땅에 '나라'가 있었느냐부터가 애매해요.

 

실제 데이터를 열어보면 이게 바로 보입니다. 분열 왕국 시대(BC 930–586년경) 칸에 들어 있는 스물네 개 영역 중 일부예요.

 

할슈타트 철기 문화권
카르타고와 서지중해
서방 그리스 식민지(남이탈리아·시칠리아)
그리스 도시국가와 이오니아
리디아 왕국
프리기아
우라르투
킴메르족
스키타이 스텝
사카(동부 스텝)
메디아
엘람
신바빌로니아

 

"킴메르족", "스키타이 스텝", "할슈타트 철기 문화권". 이게 나라입니까? 국경이 있었을까요? 없죠. 유목 집단이고 문화권이에요. 초대교회 시대 칸에는 "게르만 부족", "아라비아 유목민", "중앙아시아 스텝 유목민" 같은 게 들어 있습니다.

 

그런데 지도에 뭘 그리긴 그려야 합니다. 안 그리면 지중해 바깥이 텅 빈 채로 남아요.

 

 

설계 문서에 이 고민의 흔적이 한 줄 남아 있습니다. 원래는 위치 표시를 깃발 모양으로 만들면서 깃발 안에 국기를 넣을까 검토했었는데, 이렇게 적고 접었어요.

 

국가별 실제 국기 렌더링은 하지 않는다(1세기 갈릴리/유대에 해당 개념이 없음) — 깃발 자리에는 사건 아이콘만 넣는다.

 

깃발 안에 국기 대신 사건 아이콘이 들어간 게 그래서입니다. 지금 그 아이콘은 열네 개예요. 가르침·기적·식사·치유·갈등·이동·수난·언약·전투·심판·예배·유배·탄생·죽음. 이모지를 쓰다가 나중에 직접 그린 선 그림으로 바꿨습니다.

 

같은 고민이 나라 그리는 방식에도 그대로 들어갔어요. 결론은 이렇습니다.

 

선을 긋지 말고 면만 옅게 칠한다.

 

지금 화면 규칙이 이래요.

 

/* 시대별 국가: 4색 이하로 채우고, 경계선은 회색계열·초박형으로
   거의 인식되지 않게. 지형이 비쳐 땅색과 구분. */
.sphere-polity { fill-opacity: 0.40; stroke: #6f6a60; stroke-width: 0.5; stroke-opacity: 0.6; }

 

테두리 두께가 0.5픽셀이고 그마저도 60%만 진하게, 색은 회색입니다. 사실상 안 보이라고 넣은 선이에요. 면은 40%만 비치게 칠해서 밑에 있는 지형이 그대로 올라옵니다.

 

이렇게 하면 "여기부터 여기까지가 앗수르"라는 단정이 안 됩니다. 색이 있는 쪽과 없는 쪽이 서서히 갈릴 뿐이에요. 모르는 걸 모르는 것처럼 그린 겁니다.

 

그런데 색이 스물네 개면 그건 지도가 아니라 색종이입니다

 

면을 칠하기로 하고 나니 바로 다음 문제가 나왔어요.

 

분열 왕국 시대만 영역이 스물네 개입니다. 복음서 시대에는 더 많고요. 여기에 각각 다른 색을 주면 화면이 색종이가 됩니다. 어느 색이 어느 나라인지 아무도 못 외워요.

 

그래서 색을 네 개로 못 박았습니다.

 

// 4색 정리: 지도를 4색 이하로 유지해 혼란을 줄인다. 붉은 영향력 오버레이와
// 겹치지 않도록 빨강은 제외(녹색·파랑·보라·황갈).
var POLITY_COLORS = ["#5a9e57", "#4276bd", "#9160b0", "#b98a3c"];

 

지도는 네 가지 색이면 인접한 나라끼리 안 겹치게 칠할 수 있다는 게 오래된 정리인데, 그걸 그대로 썼어요. 다만 실제로 색을 배정하는 방법은 아주 미련합니다.

 

// 인접 판정 = lon/lat 경계상자가 겹침(약간의 여유). 각 국가에 이웃이 가장 적게
// 쓴 색을 골라 4색 안에서 충돌을 최소화한다.

 

두 나라가 이웃인지 아닌지를, 각 나라를 감싸는 네모 상자가 겹치는지로 판단합니다. 여유는 0.2도. 진짜 다각형끼리 맞닿았는지 계산하는 게 아니라 네모끼리 겹쳤으면 이웃으로 칩니다. 그리고 앞에서부터 하나씩 보면서 이웃이 제일 적게 쓴 색을 골라 줘요.

 

정확한 방법이 아닙니다. 네 색으로 완벽하게 안 나뉠 수도 있어요. 그런데 지도가 목적이지 정리 증명이 목적이 아니잖아요. 비슷한 색 두 개가 붙어 보이는 것만 막으면 됩니다.

 

 

빨강을 뺀 이유가 중요한데, 그건 다음 이야기입니다.

 

영향력을 한 겹으로 그리면 그게 거짓말이 됩니다

 

나라를 그렸으면 이 지도의 진짜 주인공을 그려야 합니다. 이 도구에서 제일 하고 싶었던 게 그거였어요.

 

하나님의 영향이 어디까지 미쳤는가.

 

이건 국경이 아닙니다. 나라 경계랑 아무 상관이 없어요. 그리고 여기가 정말 어려운 지점입니다. 한 겹으로 그리면 무조건 거짓말이 되거든요.

 

예를 들어 요셉이 이집트 총리가 된 시기를 생각해봅시다. 언약을 받은 가족은 가나안에 몇십 명 규모로 있었어요. 그런데 그 일의 영향은 이집트 전체에 미쳤습니다. 이 둘을 한 덩어리로 칠하면 "이집트 전체가 언약 공동체였다"가 되고, 가나안만 칠하면 "이집트엔 아무 일도 없었다"가 됩니다. 둘 다 틀렸어요.

 

그래서 두 겹으로 그렸습니다. 설계 문서에 정의가 이렇게 적혀 있어요.

 

- 진한 핵심: 그 시대 하나님을 예배·따르는 언약 공동체가 실제로 있던 지리.

 

- 옅은 확산: 하나님의 손길·영광이 더 넓게 도달·영향을 준 범위. 요셉으로 인한 이집트, 요나로 인한 니느웨, 다니엘로 인한 바벨론·페르시아 궁정, 바울로 인한 로마 속주 전역. 핵심을 포함하는 더 큰 영역.

 

실제 데이터에 시대마다 두 겹의 이름이 하나씩 붙어 있습니다. 이걸 나란히 놓고 보면 이 지도가 하려는 말이 그대로 보여요.

 

시대진한 핵심옅은 확산
태초에덴과 경건한 계보온 땅
족장 시대언약의 족장들복이 미친 땅
출애굽과 광야이스라엘 진영과 성막하나님의 권능이 드러난 땅
정복과 사사약속의 땅에 정착한 이스라엘언약이 선포된 가나안과 요단동편
통일 왕국다윗과 솔로몬의 이스라엘솔로몬의 영광이 미친 땅
분열 왕국과 예언자이스라엘과 유다예언이 선포되고 심판이 미친 열국
포로와 귀환포로와 귀환의 언약 공동체이방 제국 속에서 하나님을 증거한 범위
복음서예수의 사역복음이 전해진 땅
초대교회와 바울세워진 교회들복음이 전파된 로마 세계
계시록과 일곱 교회아시아의 일곱 교회온 땅에 임할 하나님 나라

 

 

첫 줄이 재밌습니다. 태초 시대에 그려진 나라는 딱 하나예요. "초기 인류 문명(메소포타미아)", 좌표 여덟 개짜리 다각형 하나. 그런데 옅은 확산 쪽 이름은 "온 땅" 입니다.

 

나라는 하나인데 영향력은 온 땅. 한 겹으로 그렸으면 이 대비가 통째로 사라졌을 거예요.

 

화면에서는 이렇게 구분됩니다.

 

.influence-reach { fill: #e8342a; fill-opacity: 0.20; stroke-dasharray: 6 5; }  /* 옅은 확산 */
.influence-core  { fill: #e01818; fill-opacity: 0.36; }                          /* 진한 핵심 */

 

바깥 겹은 20%만 비치고 테두리가 점선입니다. 안쪽 겹은 36%에 테두리가 실선이고요. 점선으로 한 게 의도한 거예요. "여기가 경계다"가 아니라 "이쯤까지"라는 뜻이니까요.

 

그리고 이 두 겹을 다른 색이 아니라 같은 빨강 계열의 진하기 차이로 뒀습니다. 다른 색으로 하면 서로 다른 두 가지처럼 보이는데, 사실 같은 하나가 진했다 옅었다 하는 거니까요. 나라 색에서 빨강을 뺀 게 이래서입니다. 빨강은 이 두 겹 몫으로 통째로 비워뒀어요.

 

화면 왼쪽 아래 범례에 딱 두 줄만 있습니다.

 

■ 언약 공동체
▨ 영향이 미친 땅

 

시대 탭을 누르면 이 두 겹이 중심에서 0.9초에 걸쳐 자라나는 연출이 붙어 있어요. 시대가 넘어갈 때마다 영역이 커지는 게 눈에 보이라고 넣은 겁니다.

 

솔직히 말하면 이 두 겹의 좌표는 전부 추정입니다. 근거가 딱 떨어지는 게 아니에요. 그래서 설계 문서에 원칙을 박아뒀습니다.

 

모든 연대·경계는 추정치이며 화면이 "추정" 맥락을 유지(정확한 사실로 오인 방지).

 

옅은 쪽 테두리를 점선으로 한 것도, 나라 테두리를 0.5픽셀 회색으로 죽인 것도 다 같은 이야기예요. 정확하지 않은 걸 정확해 보이게 그리지 않는다.

 

잘 만든 지형을 일부러 죽였습니다

 

이제 배경 이야기입니다.

 

이 지도의 바닥에는 진짜 지형 그림이 깔려 있어요. 표고 데이터를 타일로 받아서 음영기복(빛을 북서쪽 45도에서 비췄을 때 생기는 그림자)을 계산하고, 높이별로 색을 입힌 그림입니다. 낮은 땅은 녹색, 올라가면 갈색, 더 올라가면 흰색.

 

LAND_STOPS = [(-250, 녹회색), (0, 연녹), (250, 황록), (700, 베이지),
              (1400, 갈색), (2400, 회갈), (3800, 설산 흰색)]

 

넓은 쪽 그림은 서쪽 -13도부터 동쪽 92도까지, 남쪽 8도부터 북쪽 66도까지를 덮습니다. 유럽 서쪽 끝부터 인도까지예요. 픽셀로는 7350×4060. 잘 나왔습니다. 산맥이 다 보여요.

 

그런데 그 위에 나라 색과 영향력을 얹으니까 아무것도 안 보였습니다.

 

지형이 너무 잘 만들어져서요. 산 그림자와 고도 색이 화려하니까 그 위에 40% 비치는 나라 색을 얹어봐야 묻힙니다. 영향력 빨강도 지형 갈색에 섞여서 어디까지가 영향력인지 구분이 안 갔어요.

 

7월 20일 오전 10시 15분 커밋이 그래서 나옵니다.

 

style: 지형을 채도↓·밝기↑로 눌러 배경화 + 나라/영향력 색 대비 강화

 

지형의 채도를 절반으로 깎고 밝기를 16% 올렸습니다. 잘 만든 걸 일부러 흐리게 만든 거예요.

 

 

이게 이번 편에서 제가 제일 오래 망설인 결정입니다. 지형 그림은 표고 타일을 몇천 장 받아서 만든 거고, 그 자체로 볼 만하거든요. 그걸 흐리게 만드는 건 아깝습니다.

 

그런데 이 화면의 주인공이 지형이 아니잖아요. 지형은 "여기가 어디쯤인지" 알려주는 배경이고, 봐야 하는 건 나라와 영향력입니다. 주인공이 둘이면 주인공이 없는 것과 같아요.

 

지금 파일에 주석으로 남아 있는 이유가 이겁니다.

 

# 배경화(채도↓·밝기↑·대비↓)는 '육지에만' 적용

 

'육지에만'이라고 적힌 이유는 조금 뒤에 나옵니다. 그것도 눈으로 잡힌 거예요.

 

이스라엘만 선명하고 나머지가 흐렸습니다

 

지형 이야기가 하나 더 있어요.

 

처음에는 성경 무대 한복판인 레반트 지역만 고해상도로 따로 만들어서 넓은 지형 위에 겹쳤습니다. 확대했을 때 요단강 골짜기가 또렷하게 보이라고요. 7월 20일 오전 9시 44분 커밋이 그겁니다.

 

그런데 겹쳐놓고 보니 이음새가 보였습니다.

 

가운데 네모만 선명하고 그 바깥이 흐릿하니까, 확대하면 사각형 경계가 딱 드러나요. 정보로는 맞는데 그림으로는 이상합니다.

 

23분 뒤인 10시 07분에 전체를 다시 만들었습니다. 지금 그 파일 맨 위 설명이 이래요.

 

이스라엘만 상세하고 나머지는 저해상이던 문제를 없애기 위해, 보이는 지도 전체와 레반트 인셋을 '같은' 표고 파이프라인으로 만든다. 두 이미지가 동일 스타일이라 인셋이 이음새 없이 더 선명하게만 겹친다.

 

해상도를 통일한 게 아니라 만드는 방식을 통일한 겁니다. 넓은 쪽은 성기게, 레반트는 촘촘하게 뽑되 색표·음영·바다 처리를 완전히 똑같이 맞췄어요. 그러니까 겹쳐도 "더 선명해질 뿐" 다른 그림이 되지 않습니다.

 

레반트 인셋은 확대 배율이 1.2배를 넘을 때만 나타납니다. 넓게 보고 있을 땐 어차피 안 보이는 해상도라 아예 안 그려요.

 

 

그림을 HTML 안에 통째로 넣었더니 배포가 깨졌습니다

 

이 도구는 결과물이 HTML 파일 딱 한 장입니다. 데이터도 스크립트도 다 그 안에 들어가 있어요. 지분 도구에서 했던 방식 그대로입니다.

 

그래서 지형 그림도 그 안에 넣었습니다. 그림을 글자로 바꿔서 HTML 문서 안에 통째로 박아넣는 방식이 있거든요. 그러면 파일이 진짜로 한 장이 됩니다.

 

배포가 깨졌습니다.

 

넓은 쪽 지형 그림이 5.28메가바이트예요. 이걸 글자로 바꾸면 7메가가 넘습니다. 그 덩어리가 HTML 한 파일 안에 들어가면 배포하는 쪽에서 그걸 통째로 못 내보내요.

 

9시 53분 커밋으로 분리했습니다. 지금 코드에 이유가 그대로 적혀 있어요.

 

"""지형 이미지를 output 옆에 별도 파일로 복사하고 상대 주소를 돌려준다.
거대 base64 인라인은 CDN이 잘라 서빙하므로 외부 파일로 분리한다."""

 

HTML 한 장 원칙이 여기서 깨진 겁니다. 지금 배포되는 건 HTML 한 장(436KB) + 지형 그림 두 장이에요.

 

그런데 파일을 분리하니까 새 문제가 생겼습니다. 파일 이름이 항상 같으니까 그림을 새로 만들어도 브라우저가 옛날 그림을 계속 씁니다. 지형을 배경화하고 바다 색을 고쳐도 화면이 안 바뀌어요.

 

12시 24분에 이걸 붙였습니다.

 

# 내용 해시를 버전 쿼리로 붙여 캐시 우회(같은 파일명이라도 새 이미지를 받도록).
ver = hashlib.md5(data).hexdigest()[:8]
return stem + ".jpg?v=" + ver

 

그림 내용에서 뽑은 여덟 자리 값을 주소 뒤에 붙입니다. 그림이 바뀌면 그 값이 바뀌고, 값이 바뀌면 브라우저가 새로 받아요. 그림이 안 바뀌면 값도 그대로라 계속 캐시를 씁니다.

 

이것도 자료로는 안 잡히는 문제였어요. 파일은 정상적으로 새로 만들어졌고 배포도 성공했는데, 화면만 옛날 그림이었습니다.

 

 

손가락으로 밀었는데 지도가 안 따라왔습니다

 

지형을 흐리게 누르는 방법이 원래 두 가지였어요.

 

첫 번째는 화면에서 실시간으로 누르기. 원본 그림을 그대로 두고 브라우저에게 "이 그림은 채도를 반으로, 밝기를 16% 올려서 보여줘"라고 시키는 겁니다. 코드 한 줄이면 되고, 나중에 값을 바꾸기도 쉬워요. 그래서 처음엔 이걸로 했습니다.

 

그리고 지도를 손가락으로 밀어봤는데, 안 따라왔습니다.

 

당연하죠. 7350×4060짜리 그림을 화면에 그릴 때마다 매번 채도·밝기 계산을 새로 하는 거니까요. 밀 때마다 그 계산이 초당 몇십 번씩 돕니다.

 

10시 19분에 두 번째 방법으로 바꿨습니다. 그림 파일 자체를 흐리게 만들어서 저장하기.

 

perf: 지형 배경화를 CSS 필터→이미지에 구워넣기(팬/줌 속도 개선)

 

이제 브라우저는 아무 계산도 안 합니다. 이미 흐린 그림을 그냥 그리기만 해요. 대신 값을 조정하려면 그림을 다시 만들어야 하는데, 그건 한 번만 하면 되는 일이니까요.

 

지금 파일에 그 흔적이 남아 있습니다.

 

/* 지형은 채도·밝기 조정을 이미지에 구워넣어 '배경'화
   (런타임 필터는 팬/줌 때 느려서 제거). */

 

10분 뒤인 10시 29분에 또 한 번 손봤어요. 이번엔 지도 위에 얹히는 것들이 문제였습니다.

 

perf: 팬/줌 속도 개선 — rAF 스로틀 + 드래그 중 라벨 생략 + 지오메트리 솎기

 

용어를 풀면 이렇습니다.

 

하나. 미는 만큼 다 그리지 않는다. 손가락은 초당 수백 번 움직이는데 화면은 초당 60번밖에 안 바뀝니다. 그래서 "다음 그릴 차례에 한 번만 그린다"고 예약해두고, 그 사이 들어온 요청은 전부 무시해요.

 

둘. 미는 동안엔 글씨를 안 그린다. 지명과 나라 이름을 화면에 뿌릴 때 겹치는 걸 골라내야 하는데, 그게 서로 다 비교하는 계산이라 개수가 늘면 확 무거워집니다. 그래서 미는 동안엔 아예 지웠다가 손을 떼면 다시 그려요.

 

if (dragging) {
  // 드래그/핀치 중엔 라벨(충돌계산 O(n²))을 건너뛰어 프레임을 가볍게.
  placeLayer.innerHTML = "";
  riverLabelLayer.innerHTML = "";
}

 

셋. 점을 솎아낸다. 강줄기와 육지 모양은 점을 이어 만든 선인데, 점이 수만 개입니다. 이걸 매번 다 계산할 필요가 없어요. 강은 두 점 중 하나, 육지 마스크는 세 점 중 하나만 씁니다. 육지 마스크는 눈에 안 보이는 선(영향력이 바다로 넘치지 않게 가두는 용도)이라 크게 솎아도 티가 안 나거든요.

 

# 육지 마스크는 보이지 않는 클리핑 경계라 크게 솎아도 무방(재투영 비용↓).
land_mask_rings = _decimate(basemap.polygon_clip_rings(land, LAND_MASK_BBOX), 3)

 

 

성능 이야기를 이렇게 길게 쓴 이유가 있어요. 이건 "최적화를 했습니다"가 아니라 "손가락으로 밀었는데 안 따라왔습니다" 에서 시작한 일이거든요. 숫자를 재서 시작한 게 아닙니다. 손으로 밀어보고 답답해서 시작했어요.

 

그리고 이건 자동으로 안 잡힙니다. 테스트는 전부 통과하고 있었어요. 느린 건 오류가 아니니까요.

 

얕은 바다가 흰색으로 떴습니다

 

카스피해를 고치고 한 시간 반쯤 지나서 또 하나 나왔습니다.

 

해안선을 따라 흰 테두리가 둘러져 있었어요. 페르시아만, 아드리아해 쪽처럼 물이 얕은 데가 특히 심했습니다.

 

12시 17분 커밋입니다.

 

fix: 얕은 바다(대륙붕)가 흰색으로 뜨던 문제 — 바다 색을 진한 파랑으로

 

원인이 두 개가 겹쳐 있었어요.

 

첫째, 바다 색을 수심에 따라 정하는데 수심 0미터 근처 색이 너무 옅었습니다. 육지에 붙은 얕은 바다가 거의 흰색으로 나왔어요.

 

둘째, 이게 더 큰데 — 앞에서 지형을 배경화한 그 처리가 바다에도 걸려 있었습니다. 밝기를 16% 올리는 처리요. 안 그래도 옅은 얕은 바다에 밝기를 더 올리니까 완전히 하얘진 겁니다.

 

두 개를 다 고쳤어요. 바다 색표를 다시 잡고,

 

# 바다(수심별 파랑). 얕은 대륙붕도 또렷한 파랑이 되도록(흰색 방지).
SEA_STOPS = [(0, 파랑), (-150, 진한파랑), (-1200, 더진한파랑), (-4500, 남색)]

 

배경화를 육지에만 걸었습니다.

 

# 배경화(채도↓·밝기↑·대비↓)는 '육지에만' 적용 — 바다는 진한 파랑을 그대로 유지해야
# 얕은 대륙붕이 흰색으로 뜨지 않는다.

 

아까 '육지에만'이 여기서 나온 겁니다. 배경화를 넣은 게 10시 15분이고, 그게 바다를 망친다는 걸 안 게 12시 17분이에요. 두 시간 동안 몰랐습니다.

 

왜 몰랐냐면, 그 두 시간 동안 저는 나라 색과 영향력을 보고 있었거든요. 화면 한복판의 레반트만 보고 있었어요. 바다는 그냥 배경이라 안 봤습니다.

 

 

이게 눈으로 잡는 방식의 한계이기도 합니다. 눈은 보고 있는 데만 봐요. 검사기는 안 보는 데를 못 잡고, 눈은 안 보고 있는 데를 못 잡습니다. 종류가 다를 뿐이지 둘 다 구멍이 있어요.

 

틀린 걸 알려줄 길을 냈는데, 그 길도 깨져 있었습니다

 

여기까지 오면서 확실해진 게 하나 있습니다. 저 혼자서는 다 못 맞춥니다.

 

이 지도에 들어간 좌표가 몇천 개고, 연대는 전부 추정이고, 어떤 나라 영역은 제가 근사로 그린 다각형이에요. 성경 지리를 전공한 사람이 보면 틀린 데가 분명히 있을 겁니다.

 

그래서 12시 09분에 화면 오른쪽 위에 버튼을 하나 달았습니다.

 

⚠ 신고·제안

 

누르면 창이 뜨는데, 항목이 이렇습니다.

 

  • 유형 — 오류·오탐 신고(틀린 위치/연대/내용) / 개선 제안 / 기타
  • 내용 — 어떤 오류인지, 또는 어떤 제안인지
  • 회신 이메일 — 선택. 안 적어도 보내집니다.

 

로그인 없이 씁니다. 이름도 안 받아요. 홈페이지 댓글을 로그인 없이 열어둔 거랑 같은 판단입니다. 틀린 걸 알려주려고 회원가입까지 할 사람은 없어요.

 

여기에 하나 더 넣었습니다. 보낼 때 지금 보고 있는 시대와 사건, 장절을 같이 보냅니다.

 

return currentEra.title + " · " + ev.order + ". " + ev.title + " (" + citationText(ev) + ")";

 

"위치가 틀렸어요"라고만 오면 저는 어느 시대 어느 사건인지 알 길이 없거든요. 어차피 화면이 알고 있는 정보니까 같이 붙여 보냅니다.

 

그리고 이것도 깨져 있었습니다.

 

첫 신고를 테스트로 보내봤더니 메일은 왔는데, 항목 이름이 전부 깨져 있었어요. 유형·내용·회신 이메일 같은 한글 항목 이름이 알아볼 수 없는 글자로 왔습니다. 값은 멀쩡한데 이름만요.

 

12시 29분 커밋입니다.

 

fix: 신고 메일 한글 필드 라벨 깨짐 — 영문 키 + message 값에 한글 통합

 

고친 방법은 단순합니다. 항목 이름을 전부 영문으로 바꾸고, 한글은 본문 값 하나에 다 몰아넣었어요.

 

// 한글 '필드 키'는 메일에서 깨지므로(값은 정상), 영문 키만 쓰고 한글은
// message 값 하나에 담는다.
var body = "■ 사이트: 성경지도\n"
  + "■ 유형: " + typeS.value + "\n\n"
  + "■ 내용:\n" + msg + "\n\n"
  + "■ 회신 이메일: " + (reply || "(미기재)") + "\n"
  + "■ 현재 위치: " + context();

 

깔끔한 해결이 아니에요. 원래는 항목이 나뉘어서 오는 게 보기 좋습니다. 그런데 남의 서비스가 한글 항목 이름을 못 받는 건 제가 고칠 수 있는 게 아니거든요. 제가 바꿀 수 있는 쪽을 바꿨습니다.

 

 

여기서 재밌는 게 있는데, 이 버그도 눈으로만 잡히는 종류였어요. 보내는 쪽은 성공 응답을 받았습니다. 화면에도 "잘 전달됐어요"가 떴고요. 코드 입장에서는 아무 문제가 없었습니다. 메일함을 직접 열어봐야 알 수 있는 거였어요.

 

그래서 사람은 어디에 남았나

 

이번 편에서 사람이 한 일을 정리하면 이렇습니다.

 

첫째, 화면을 눈으로 본 것. 오늘 나온 다섯 개 버그 — 카스피해, 얕은 바다, 배포 깨짐, 캐시, 메일 깨짐 — 이 중에 자동으로 잡힌 게 하나도 없습니다. 테스트는 전부 통과했고, 빌드는 전부 성공했고, 데이터는 전부 유효했어요. 값이 맞는 것과 그림이 맞는 것은 완전히 다른 문제입니다. 그리고 그림이 맞는지는 아직 사람 눈밖에 못 봅니다.

 

둘째, 잘 만든 걸 일부러 죽인 것. 지형 그림은 이 도구에서 제일 공들인 결과물인데, 채도를 절반으로 깎았습니다. 기계에게 "지형을 잘 만들어줘"라고 하면 잘 만들어줍니다. 그런데 "이건 배경이니까 흐려야 한다"는 판단은 안 해줘요. 화면에 주인공이 몇 명인지는 만든 사람이 정하는 겁니다.

 

셋째, 국경선을 안 그은 것. 그때 그 땅에 국경이 없었다는 걸 알면서 굵은 선을 긋는 건 그리기는 쉽고 보기도 좋습니다. 대신 거짓말이 돼요. 0.5픽셀 회색 선으로 죽여놓은 건 "이건 확정이 아니다"를 그림으로 말한 겁니다.

 

넷째, 영향력을 한 겹이 아니라 두 겹으로 그린 것. 한 겹이면 무조건 "여기까지가 전부"라는 말이 됩니다. 진한 핵심과 옅은 확산을 나눠야 "여긴 확실하고 여기는 미쳤을 뿐"이 그려져요. 그리고 바깥 겹 테두리를 점선으로 한 것도요.

 

다섯째, 틀릴 수 있다고 인정하고 길을 낸 것. 신고 폼은 기능이 아니라 태도에 가깝습니다. 이 지도에 오류가 있다는 걸 전제로 만든 버튼이거든요.

 

 

기계가 잘한 건 확실합니다. 표고 타일을 몇천 장 받아서 음영기복을 계산하고, 강줄기 7메가짜리 데이터를 잘라내고, 스물네 개 나라에 네 가지 색을 겹치지 않게 배정하는 건 손으로는 못 합니다. 지도를 미는 게 느릴 때 무엇을 줄여야 하는지도 정확하게 짚었어요.

 

그런데 기계는 카스피해가 이상하다고 말해주지 않았습니다. 얕은 바다가 하얗다고도, 이스라엘만 선명해서 이음새가 보인다고도 말해주지 않았어요. 그건 전부 화면을 열어놓고 "어, 저건 좀 이상한데" 했을 때 나온 겁니다.

 

그러니까 이번 편의 결론은 좀 시시해요. 지도는 눈으로 봐야 합니다. 그것도 만든 다음이 아니라 만드는 내내요. 7월 20일 그 네 시간 동안 제가 한 일의 절반은 브라우저를 열고 닫는 거였습니다.

 

다음 편은 이 지도 이야기의 마지막입니다. 지도를 다 그려놓고 나서 알게 된 게 하나 있는데, 이 지도는 검색에 아예 안 잡힙니다. 화면을 자바스크립트로 그리니까 검색 엔진이 볼 게 없어요. 잘 만든 게 아무도 못 찾는 자리에 있는 상태였습니다.

 

#성경지도 #성경아틀라스 #바이블맵 #성경66권 #성경시대 #성경공부 #성경통독 #구약성경 #신약성경 #성경지리 #지형도 #음영기복 #DEM #지도만들기 #데이터시각화 #SVG #자바스크립트 #파이썬 #4색정리 #웹개발 #프론트엔드 #성능개선 #버그수정 #정적사이트 #개인프로젝트 #사이드프로젝트 #도구만들기 #AI개발 #클로드 #휴먼인더루프

댓글

    로그인 없이 쓰는 대신, 등록한 댓글은 직접 지울 수 없습니다. 지워야 할 댓글은 옆의 신고를 눌러주세요.
    네이버 블로그글 원문 보러가기 →유튜브 쇼츠만드는 장면 20초로 보기 →
    관리자 Victor · 문의는 우상단 신고·제안으로 남겨주세요.
    글과 화면은 정적 파일로 만듭니다. 댓글과 조회수만 외부 데이터베이스에 저장합니다 — 개인정보처리방침

    오류 신고 · 제안

    관리자 Victor에게 전달됩니다