카톡 대화 분석기는 대화 파일을 서버로 보내지 않습니다. 이 구조는 대화 파일을 서버로 보내지 않는 구조를 만들고 확인한 방법에 정리해 두었습니다. 그런데 서버가 없으면 결과를 링크로 공유할 수 없습니다. 링크를 만들려면 결과를 어딘가에 저장해야 하기 때문입니다.
그래서 공유는 이미지 한 장으로 하기로 했습니다. 결과 화면 아래에 있는 “결과 카드로 공유하기”가 그 이미지를 만드는 곳입니다. 이 글은 그 카드 한 장이 어떻게 만들어지는지에 대한 기록입니다.
1. 카드에 들어가는 것과 빠지는 것
처음에 정한 원칙은 하나였습니다. 카드에는 대화 원문을 넣지 않는다. 카드는 단톡방이나 SNS에 올라가는 것이 목적이라, 거기에 실제 대화 문장이 찍혀 있으면 안 됩니다.
카드에 들어가는 것은 숫자와 짧은 꼬리표뿐입니다.
- 머리: 방 이름(가리기를 켜면 일반 제목), 대화 기간과 일수
- 수치 세 칸: 메시지 수, 참여자 수, 가장 활발한 시간
- 본문: 대화 종류에 따라 다릅니다.
- 단톡방은 “이 방의 칭호”를 최대 5개까지 넣습니다. 수다왕처럼 칭호 이름, 받은 사람, “메시지 4개” 같은 근거 수치가 한 줄씩 들어갑니다. 결과 화면에는 칭호가 더 나올 수 있지만, 다 넣으면 카드가 넘쳐서 5개로 잘랐습니다.
- 1:1 대화는 “둘의 대화”입니다. 두 사람의 메시지 비율 막대와, 메시지 수·답장 시간·먼저 말 건 횟수 같은 비교 항목 4개를 넣습니다. 결과 화면보다 항목을 줄였습니다.
- 메시지를 보낸 사람이 한 명뿐이면 비교할 것이 없으니 시간대별 대화 막대그래프만 넣습니다.
- 바닥:
talk.lalalab.kr주소와 “브라우저에서만 분석 · 서버 전송 없음”이라는 문구
바닥의 주소는 카드를 본 사람이 도구를 찾아올 수 있는 유일한 길입니다. 링크 공유가 안 되는 대신 이미지 안에 주소를 넣어 둔 것입니다.
카드에 넣을 내용을 정하는 코드(card-model.ts)와 실제로 그리는 코드(card.ts)는 나눠 두었습니다. 내용을 정하는 쪽은 그림 없이도 테스트할 수 있어서, “1:1이면 비교 항목이 4개인지”, “가리기를 켜면 방 이름이 사라지는지” 같은 것을 자동 테스트로 확인합니다.
2. 이름 가리기
카드에는 기본으로 이름이 나옵니다. 친구끼리 단톡방에 다시 올릴 때는 누가 수다왕인지 보여야 재미있기 때문입니다. 하지만 공개 SNS에 올릴 때는 이야기가 다릅니다. 그래서 “이름 가리기” 옵션을 두었습니다.
가리는 규칙은 단순합니다. 첫 글자만 남기고 나머지를 별표로 바꿉니다.
| 원래 이름 | 가린 뒤 |
|---|---|
| 하늘 | 하* |
| 박서준 | 박** |
| 한 글자 이름 | ** |
| 영문 닉네임 Christopher | C*** |
별표는 최대 3개까지만 붙여서 긴 닉네임이라도 길이가 그대로 드러나지 않게 했습니다. 닉네임 맨 앞에 이모지가 있는 경우도 생각했습니다. 이모지는 컴퓨터 안에서 문자 두 개로 저장되는 경우가 있어서, 그냥 자르면 깨진 글자가 나옵니다. 그래서 글자를 셀 때 이모지 하나를 한 글자로 세도록 했습니다.
고민이 하나 더 있었습니다. 1:1 대화에서 두 사람이 “김하늘”과 “김하람”이면 둘 다 “김**“이 되어 카드에서 누가 누구인지 알 수 없습니다. 이럴 때는 겹치는 이름에 순서대로 번호를 붙여 “김**(1)”, “김**(2)“로 구분합니다.
가리기를 켜면 방 이름도 함께 숨깁니다. 카톡 1:1 대화를 내보내면 방 이름이 곧 상대방 이름이라, 사람 이름만 가리고 방 이름을 남기면 소용이 없기 때문입니다. 대신 “둘의 대화”, “우리 단톡방” 같은 일반 제목을 넣습니다.
3. 정사각형과 스토리, 그리고 기본값
카드 크기는 두 가지입니다.
- 정사각형: 1080×1080 픽셀. 단톡방이나 피드에 올리기 좋은 크기
- 스토리: 1080×1920 픽셀. 인스타그램 스토리처럼 세로로 긴 화면용
스토리 형식은 세로 공간이 넉넉해서, 칭호나 둘의 비교 아래에 시간대별 대화 그래프를 하나 더 넣습니다.
이름 가리기의 기본값은 형식에 따라 달라집니다. 정사각형은 꺼진 상태, 스토리를 고르면 자동으로 켜집니다. 스토리는 보통 공개 SNS에 올라가는 형식이라, 개인정보를 다루는 도구라면 기본으로 가려 두는 쪽이 맞다고 봤습니다. 사이트를 점검하면서 남긴 개선 목록에 있던 항목을 반영한 것입니다.
다만 사용자가 가리기 체크를 한 번이라도 직접 바꾸면, 그 뒤로는 형식을 바꿔도 자동으로 건드리지 않습니다. 일부러 끈 것을 도구가 다시 켜면 곤란하기 때문입니다. 분석 기간(전체, 최근 1년, 최근 3개월)을 바꿔 결과를 다시 그릴 때도 고른 형식과 가리기 설정은 그대로 이어집니다.
4. 카드는 캔버스에 직접 그린다
웹 페이지의 일부를 이미지로 바꾸는 방법은 여러 가지가 있지만, 카드는 캔버스(Canvas)에 직접 그립니다. 캔버스는 브라우저가 제공하는 그림판 같은 것으로, 자바스크립트로 “여기에 사각형, 저기에 글자”를 하나씩 찍어 그림을 만듭니다.
카드의 모양은 “실험 리포트” 종이입니다. 옅은 모눈이 깔린 종이에 테두리를 두르고, 맨 위에 LALALAB / EXP-01, TALK REPORT 머리줄을 넣습니다. 본문 영역에는 FIG. 01처럼 그림 번호를 붙입니다. 사이트를 어두운 테마로 보고 있어도 카드는 항상 밝은 종이 색으로 그립니다. 이미지는 어디로 갈지 모르니 한 가지 모습으로 고정하는 편이 낫습니다.
캔버스에 직접 그리면서 신경 쓴 부분이 몇 가지 있습니다.
- 긴 이름 자르기: 이름이 칸보다 길면 한 글자씩 줄여 가며 폭을 재고, 들어가는 데까지만 쓰고 “…“을 붙입니다.
- 칭호 줄 높이: 칭호가 적어 줄 높이가 넉넉하면 칭호 이름을 위에, 받은 사람을 아래에 두 줄로 쌓고, 칭호가 많으면 한 줄에 나란히 놓습니다.
- 아이콘: 칭호 옆 아이콘은 결과 화면에서 쓰는 것과 같은 SVG를 이미지로 바꿔 그립니다. 외부에서 받아 오지 않고 코드 안에 있는 SVG를 그 자리에서 이미지로 만듭니다.
- 고정폭 글꼴과 한글: 숫자는 고정폭 글꼴로 쓰는데, 이 글꼴은 공백이 넓어 “밤 9시” 같은 글자가 벌어져 보였습니다. 그래서 한글과 공백이 섞인 글자는 본문 글꼴로 바꿔 그립니다.
5. 글꼴을 먼저 받아 두는 이유
카드에는 Pretendard(한글 본문)와 JetBrains Mono(숫자·라벨) 두 글꼴을 씁니다. 사이트를 점검할 때 “글꼴을 지정만 하고 불러오지 않아, 공유 카드 이미지도 기기마다 달라진다”는 문제가 나왔고, 그 뒤로 글꼴을 사이트에 직접 올려 쓰고 있습니다.
한글 글꼴은 파일이 큽니다. 그래서 글자 범위별로 잘게 나눈 조각(서브셋, woff2 파일) 형태로 두고, 브라우저가 화면에 실제로 쓰이는 글자의 조각만 받게 했습니다. 또 첫 화면이 늦게 뜨지 않도록, 글꼴이 늦게 도착하면 그 페이지에서는 기본 글꼴로 두게 설정했습니다.
이 방식은 웹 페이지에는 좋지만 캔버스에는 문제가 됩니다. 캔버스는 그리는 그 순간에 준비된 글꼴로 그리기 때문에, 아직 받지 않은 글자가 있으면 첫 카드가 기본 글꼴로 나옵니다. 그래서 카드를 그리기 전에 카드에 들어갈 글자들을 모아 해당 글꼴 조각을 먼저 불러온 뒤 그립니다. 방 이름, 칭호, 숫자, 고정 문구까지 카드에 찍힐 글자를 미리 한데 모아 브라우저에 “이 글자들을 쓸 테니 준비해 달라”고 요청하는 방식입니다.
이때 받는 것은 사이트에 올려 둔 글꼴 파일뿐입니다. 어떤 글자 조각이 필요한지는 브라우저가 스스로 판단하고, 요청에는 대화 내용이 들어가지 않습니다. 개인정보 처리방침에도 “결과 화면과 카드를 그릴 때 필요한 글꼴 조각 파일을 이 사이트에서 추가로 받아올 수 있다”고 적어 두었습니다. 사이트의 보안 정책도 글꼴은 사이트 자신에서만 받도록 막혀 있습니다. 인터넷이 끊긴 상태라면 글꼴이 기본 글꼴로 바뀔 뿐, 카드는 그대로 만들어집니다.
글꼴을 기다리는 사이에 사용자가 형식이나 가리기를 바꾸는 경우도 있습니다. 이때 늦게 끝난 옛 그림이 새 그림을 덮어쓰면, 가리기를 켰는데 이름이 보이는 카드가 나올 수 있습니다. 그래서 그리기 요청마다 번호를 붙이고, 기다림이 끝났을 때 자기가 가장 최근 요청이 아니면 캔버스를 건드리지 않고 그만둡니다.
6. 저장과 공유
카드 아래에는 버튼이 두 개 있습니다.
- 이미지 저장: 캔버스 그림을 PNG 파일로 만들어 기기에 내려받습니다. 파일 이름은
talk-lalalab-square.png처럼 형식만 들어가고, 방 이름이나 사람 이름은 넣지 않습니다. - 공유하기: 휴대폰의 공유 창을 띄워 카카오톡, 인스타그램 같은 앱으로 바로 보냅니다.
공유하기는 브라우저의 Web Share API를 씁니다. 웹 페이지가 기기의 기본 공유 창을 열 수 있게 해 주는 기능입니다. 다만 모든 브라우저가 파일 공유를 지원하지는 않습니다. 그래서 페이지를 열 때 “이 브라우저가 이미지 파일을 공유할 수 있는지”를 먼저 물어보고, 안 되면 공유하기 버튼을 아예 숨겨 이미지 저장만 보여 줍니다. 공유를 시도했다가 막히거나 실패해도 이미지 저장으로 대신합니다. 사용자가 공유 창을 그냥 닫은 경우만 아무것도 하지 않습니다.
아이폰 사파리에서 생긴 문제도 있었습니다. 사파리는 사용자가 버튼을 누른 직후에만 공유 창을 열도록 허용합니다. 버튼을 누른 뒤에 이미지를 만들기 시작하면 그 시간 때문에 공유가 막힐 수 있습니다. 그래서 카드를 그릴 때마다 PNG 파일을 미리 만들어 둡니다. 버튼을 누르면 이미 준비된 파일을 바로 넘깁니다. 파일이 준비되기 전에는 두 버튼을 잠가서, 눌러도 아무 일이 없는 상황을 막았습니다.
이 모든 과정, 즉 캔버스에 그리기, PNG로 바꾸기, 저장과 공유는 브라우저 안에서 끝납니다. 이미지가 서버를 거치는 단계가 없습니다. 이미지 저장도 서버 주소가 아니라 브라우저 메모리 안에 잠깐 만든 주소로 내려받고, 그 주소는 잠시 뒤 지웁니다.
7. 통계에는 무엇이 남나
카드를 저장하거나 공유하면 방문 통계에 기록이 하나 남습니다. 들어가는 것은 저장인지 공유인지, 카드 형식(정사각형·스토리), 이름 가리기를 켰는지 세 가지뿐입니다. 카드 이미지나 이름, 방 이름은 보내지 않습니다. 이 기록으로 사람들이 어떤 형식을 더 많이 쓰는지, 가리기를 켜고 공유하는지 정도를 볼 수 있습니다.
정리
링크 공유를 포기한 대신 이미지 한 장에 필요한 것을 담기로 했고, 그 이미지도 서버 없이 만들었습니다. 카드에는 대화 원문을 넣지 않고, 공개 SNS용 형식에서는 이름을 기본으로 가리고, 이름을 가릴 때는 방 이름까지 함께 숨깁니다. 이미지가 기기 밖으로 나가는 때는 사용자가 직접 저장하거나 공유 버튼을 눌렀을 때뿐입니다.
카톡 대화 분석기에서 예시 대화로 결과를 띄우면, 대화 파일 없이도 카드를 직접 만들어 볼 수 있습니다.