요약
contentEditable 대신 글자 하나까지 2D 캔버스에 직접 그리는 편집기 Tasfer가 오픈소스로 공개됐습니다.
개발자 함자 쿠스완이 직접 만든 노트·문서 앱 Tasfer의 설계를 소개한 글입니다. 그는 웹 편집기 대부분이 쓰는 contentEditable(브라우저 내장 편집 기능)이 브라우저마다 다르게 동작해 다루기 어렵다고 봤습니다. Tasfer는 웹과 데스크톱, 모바일에서 돌며 LaTeX 수식, 코드 블록, 표, 달력을 갖췄습니다.
왜 중요한가
- 화면을 브라우저가 아니라 편집기가 그리므로, 브라우저와 기기가 달라도 같은 모양과 동작을 내려고 합니다.
- 계정도 클라우드 사본도 없이 협업하는 구조라서 개인 메모를 회사 서버에 맡기지 않아도 됩니다.
- 앱은 AGPL로, 편집기 엔진은 MIT 라이선스로 따로 공개해 다른 상용 제품도 엔진을 가져다 쓸 수 있습니다.
핵심 내용
- 글자, 커서, 선택 영역, 줄바꿈, 오른쪽에서 왼쪽으로 쓰는 아랍어까지 모두 자체 코드로 재고 그립니다.
- 키 입력은 숨겨 둔 작은 입력 요소가 받아서, 자동 고침과 중국어·아랍어 입력기(IME)가 그대로 작동합니다.
- 협업은 CRDT(편집을 어떤 순서로 합쳐도 같은 결과가 나오는 자료 구조)로 처리합니다.
- 암호화한 편집은 WebRTC로 기기끼리 직접 주고받고, 서버는 서로 찾아 주는 일과 막힌 연결의 중계만 맡습니다.
- 처음엔 WebGL·WebGPU로 GPU 렌더링을 시도했지만, 결국 2D 캔버스로도 충분히 빠르다고 결론 내렸습니다.
HN 반응
- iOS 자동 고침과 커서 오류, 안드로이드 밀어서 지우기·커서 이동 제스처 미지원 등 모바일 버그 보고가 잇따랐습니다.
- 일부 이용자는 캔버스로는 모바일 기본 기능을 다 살릴 수 없다며 DOM으로 돌아가라고 했고, VS Code 터미널도 캔버스를 쓴다는 반론이 나왔습니다.
정말 멋지네요. 그런데 저는 CodeMirror가 얼마나 유연한지 보고 감탄한 적이 있습니다. EtherPK( https://app.etherpk.com )를 시작할 때, 아웃라이너 블록과 일반 산문, 풍부한 오버레이·그래픽·임베드를 한 에디터에 합칠 수 있다는 데 CodeMirror로 승부를 걸었습니다. 막다른 길에 부딪힐까 걱정했고(Logseq이 커스텀 HTML과 중첩 div, 렌더링된 텍스트와 실제 입력 사이의 클릭 위치 매핑을 쓰는 데는 이유가 있을 거라고 짐작했거든요), 9개월이 지난 지금은 이 선택에 더없이 만족합니다. 엄청나게 빠르고, 타이핑하는 느낌도 아주 좋고 가볍습니다(라이브 데모: https://app.etherpk.com/demo )
Office 365가 이 글쓴이 같은 사람을 좀 채용했으면 좋겠습니다. 온라인 Word는 데스크톱 소프트웨어와 렌더링 결과가 한 번도 똑같았던 적이 없는데, 이게 중요하거든요. 저는 연구비 신청서를 쓰는데 문서가 그리 복잡하진 않아도 섹션별 분량 제한은 지켜야 해서 레이아웃이 안정적이어야 합니다. 그래서 결국 Windows VM을 켜서 데스크톱 앱으로 작업하게 됩니다.
LaTeX를 권하시려는 분들께 미리 말씀드리면, 압니다, 알아요. 하지만 협업으로 글을 쓰다 보면 플랫폼을 항상 고를 수 있는 건 아닙니다.
마이크로소프트가 어디선가 블로그 글로, 데스크톱 렌더링 코드를 wasm과 캔버스로 가져와서 동일한 수준을 맞추고 있다고 쓴 적이 있습니다.
그 작업이 얼마나 진척됐는지는 저도 모릅니다. 직접 확인해 보진 않았습니다.
구글은 2020년에 캔버스로 바꿨습니다(제 기억이 맞다면요). 다만 이게 모든 문제의 해법이라는 건 아니고, 그냥 선택지 중 하나일 뿐입니다. 눈치챈 분이 있을지 모르겠지만, 모바일에서 Google Docs 문서를 바로 열 수 없었던 이유도 일부는 이것 때문입니다. 그때는 구글에게도 너무 큰 작업이었을 거라고 생각합니다. 어쨌든 Tasfer는 모바일에서도 최대한 그렇게 해 보려고 했습니다.
저는 사실 Typst를 권하려던 참이었습니다.
다국어 줄바꿈은 어떻게 처리했는지 아시는 분 계신가요?
저도 오래전에 이와 비슷한 도구를 만든 적이 있습니다. 내부 문서 모델로 JATS를, 입력에는 contentEditable을 썼는데, 말씀하신 고충이 정말 공감됩니다. 서로 다른 유형의 중첩된 맥락을 가진 텍스트를 나누거나 합칠 때 의미를 제대로 유지하기가 어려웠습니다.
커서가 한쪽 또는 다른 쪽을 가리키게 한 방식이 마음에 듭니다. "일반" 모드인지, 예를 들어 굵은 글씨 영역 안인지를 알려 주잖아요. 이런 건 본 적이 없는데, 직접 생각해 내신 거라면 그것만으로도 멋진 발명입니다.
정말 멋진 발명이네요. 전반적으로 에디터가 마음에 듭니다. 동작 방식이 신선하고 좋은 아이디어가 많아요. 그런데 제대로 동작하지 않는 부분이 있습니다. 예를 들어 굵게 표시를 어떻게 지우나요? Ctrl+B 단축키 말고는 지울 방법이 없던데, 만들 때는 마크다운을 타이핑해서 만들 수 있었거든요. 첫 번째 글머리 기호를 지우고 실행 취소를 하면 복원되지 않습니다. 두 번째를 지우고 실행 취소를 하면 커서가 첫 번째 글머리 기호로 점프했고요. 그러니까 아직 손볼 곳이 있습니다. 그리고 텍스트를 복사하면 정제된 버전이 아니라 마크다운 텍스트를 받았으면 좋겠습니다(정제된 버전이 필요할 때는 Shift+Ctrl+V에 맡기고요).
방금 안드로이드에서 테스트해 봤는데, 밀어서 삭제(glide delete)와 밀어서 커서 이동(glide cursor control)이 안 됩니다.
캔버스로 이걸 지원하는 게 애초에 가능하긴 할까요?
와, 그런 제스처가 있는지도 몰랐어요. 저는 모바일을 잘 안 쓰거든요. 그래도 꼭 살펴보겠습니다.
제가 이 접근법이 나쁘다고 말한 이유가 바로 이겁니다. 현재 단어나 선택 영역 정도만이 아니라 그 이상을 보고 상호작용할 수 있어야 동작하는 네이티브 기능이 끝없이 이어지는데, 그걸 가로막고 있는 겁니다. 그중 상당수는 아예 구현할 수 없고, 다 커버해 보겠다고 공을 들일수록 contenteditable보다 더 해괴한 물건이 되어 갑니다.
포기하세요. 진심으로 부탁드립니다. DOM으로 바꾸세요. 쓸 만한 결과를 내려면 정말로 필수입니다.
데스크톱에서는 많은 사용자가 눈치채지 못할 만큼 근접할 수 있지만, 모바일에서는 참을 만한 수준에도 절대 도달할 수 없습니다.
VSCode의 터미널 창도 캔버스로 만들었다고 하네요.
https://code.visualstudio.com/blogs/2017/10/03/terminal-renderer
우리 이야기 좀 해요(프로필을 확인해 보세요)! 저는 거의 10년째 글쓰기 도구를 만들고 있는데, 이 프로젝트가 도움이 될 수도 있겠어요. 가끔 그 위에 절차적 생성(procgen)을 얹은 포크도 만들고 있고요. 그중에서도 제가 가장 관심 있는 건 더 나은 양방향 텍스트(bidi) 처리입니다.
Enso.sonnet.io가 제가 말하는 그 도구입니다.
(untested.sonnet.io에는 관련 실험과 장난감 프로젝트에 대한 메모가 있습니다.)
멋진 작업이네요, 아이디어가 마음에 듭니다. Tasfer Discord에 오세요, 거기에 하나 있습니다. 랜딩 페이지에 링크도 방금 추가했어요.
맞춤형 리치 텍스트 LaTeX 에디터라니 정말 멋지네요. 다만 태블릿으로 써 보니 텍스트 선택 같은 게 좀 어색합니다(위아래 자동 스크롤이 네이티브와 똑같지 않고 그만큼 정밀하지도 않아요).
그래도 대단한 프로젝트예요!
캔버스에서 IME와 스크린 리더는 어떻게 처리하셨나요? 그리고 레이아웃을 다시 계산하는 단위는 줄인가요, 블록인가요? 제 마크다운 에디터에서는 바뀐 블록만 다시 레이아웃하는 게 타이핑 속도를 가장 크게 끌어올렸습니다.
편집 중인 줄 전체가 들어 있는 "<div contenteditable=true>"가 숨겨져 있어서, 그 덕분에 IME가 동작합니다.
네, 정확합니다. 그게 입력 표면입니다. 안 그러면 캔버스는 이벤트를 받을 수 없어서, IME나 클립보드 같은 이벤트가 모두 거기를 통해 들어옵니다.
이 에디터는 악센트 문자(예: áã, ö, è)를 전부 삼켜 버립니다.
시간 되시면 어디서 이 문제가 생겼는지 알려 주세요. 정말 알고 싶습니다. 어떤 정보든 도움이 됩니다.
저는 안 그런데요. 브라우저와 OS를 적어 주시면 좋겠습니다.
좋은 아이디어네요! 프라이버시를 중시한 설계도 마음에 듭니다. 그런데 iOS에서는 제대로 테스트하지 않으신 것 같아요. 자동 텍스트 수정이 완전히 망가져 있습니다.
그리고 웹사이트도 전부 LLM으로 쓰고 생성한 것처럼 보입니다. 그러면 신뢰가 안 가요.
이런 조언과 피드백은 진지하게 받아들입니다. 의견 주셔서 감사합니다. iOS는 저도 되게 하려고 해 봤는데, iOS가 그 부분에서 정말 까다롭게 굴더군요. 캔버스가 제어하는 숨겨진 contenteditable을 무슨 이유에서인지 싫어하는 것 같습니다. 그래서 App Store에 iOS 앱도 출시한 겁니다.
그리고 LLM이 많은 분들께 거슬릴 수 있다는 것도, 그런 반응이 어디서 나오는지도 이해합니다.
저는 혼자 일하는 개발자인데, AI 덕분에 이런 아이디어를 만들고 구현할 수 있게 됐습니다. 번역도 도와줬고 그 밖에도 많은 일을 해 줬습니다. 불신을 줄 수 있다는 말씀에는 동의하고, AI가 생각을 대신해서는 안 된다고 생각합니다.
iOS가 "이렇게 하면 안 돼, 안 될 거야"라고 말해 주고 있었는데, 그 신호를 무시하고 망가진 걸 내놓은 데다 특정 플랫폼용 앱까지 따로 만드신 거군요.
LLM은 잘못된 걸 구현하는 데도 기꺼이 도와줍니다. "해볼 수는 있지만 결과는 절대 좋지 않을 겁니다"라고 말하는 건 잘 못 하고요.
그럼 사람인 당신의 피드백은 더 가치 있었다고 생각하시나요? iOS가 막아 놓은 거라면 다른 선택지가 뭐가 있겠어요?
테스터를 많이 모으는 데 Show HN만 한 방법이 없죠.
저도 확인해 드립니다. iOS에서 커서 버그가 있어요. 줄바꿈에서도, 자동 수정에서도요.
저는 LLM이 "도와준" 사이트라도 그 과정에 사람이 개입한 흔적이 보이면 더 너그럽게 보는 편입니다. LLM은 독자보다 설계 목표와 아키텍처에 대한 맥락을 더 많이 갖고 있으니, 정보를 주는 페이지라면 저는 개인적으로 개의치 않습니다.
하지만 아마 소수 의견일 겁니다.
앱의 기술적 기능이 사회적 맥락을 공유하는 특정 독자층에게 왜 의미가 있는지는 사람이 보여 줘야 합니다. LLM은 그 사회적 환경의 참여자가 아니고(앞으로도 그래서는 안 되고), 그래서 LLM이 만든 마케팅은 거의 틀림없이 분위기 파악 못 하거나 주제넘게 읽힙니다.
그게 바로 "사람이 개입한다"는 부분이에요. LLM으로 초안을 만들고 사람이 다듬는 거죠.
요즘 성공하는 캠페인이 늘 전부 사람 손으로만 만들어진다고 생각하신다면, 유감이지만 틀리셨습니다.
옛날에 Flash로도 똑같은 걸 했었죠 :)
UI 라이브러리는 뭘 쓰셨나요? 깔끔해 보이네요.