Folio 02 · 오픈소스 프로젝트
NotePane
Notion처럼 쓰는 편집기를 가진, 가벼운 메모·스티키 앱
- 기간
- 2026.07.24 — 현재
- 역할
- 데스크톱 앱 · 제품 개발
- 라이선스
- MIT
Notion의 편집기는 좋은데 메모 하나 적자고 띄우기엔 무겁고, 가벼운 메모·스티키 앱은 많은데 편집기가 전부 일반 텍스트거나 Markdown 소스 수준이었음. 슬래시 메뉴, 블록 드래그, 토글, 표가 되는 편집기를 가진 가벼운 메모 앱이 없어서 직접 만든 프로젝트. 편집기는 BlockNote 위에서 시작했지만 Notion다운 동작은 거의 손으로 구현했고, 같은 문서를 탭 세션과 스티키 창으로 오가며 쓰는 로컬 우선 데스크톱 앱이 됨. 계정도 서버도 없음.
Electron · React · BlockNote · Vite · Playwright · JSON
화면
01 왜 새로 만들었나: Notion 편집기를 가진 스티키 메모 2026.07
회의 중에 떠오른 것을 바로 적어 두고 다른 창 위에 띄워 두고 싶은데, 그 메모가 체크리스트와 표와 접히는 토글을 가졌으면 했음. Notion은 그 편집기를 갖고 있지만 메모 하나에 쓰기엔 무겁고 창 위에 띄울 수도 없음. 가벼운 메모·스티키 앱은 열 개 넘게 써 봤지만 편집기가 전부 일반 텍스트 아니면 Markdown 소스였음. 두 조건을 함께 가진 앱이 없어 직접 만들기로 하고, 같은 노트를 모아 쓰기도 펼쳐 두기도 할 수 있도록 창 모델부터 구성.
요구사항
- 두 가지 배치
- 탭 세션과 독립 메모 창 사이에서 같은 노트를 이어서 편집
- 빠른 전환
- 단축키와 드래그로 노트를 전환·분리·결합
- 작업 유지
- 노트별 위치·크기·고정 상태를 저장
구현
-
노트와 창의 역할 분리: 창은 노트를 "보여 주는" 것이지 "소유하는" 것이 아니다 설계 판단
- 첫 설계에서는 스티키 창 하나가 곧 노트 하나였음. BrowserWindow를 만들 때 노트를 같이 만들고, 창을 닫으면 노트도 지웠음. 메모장 앱이라면 그걸로 충분한데, 같은 노트를 탭으로도 보고 싶어진 순간 모델이 깨짐. 창이 노트를 소유하면 "탭에서 열어 둔 노트를 스티키로도 띄우기"가 복제가 되어 버림
- 그래서 노트는 store.cjs가 가진 데이터이고, 창은 그 노트 ID를 쿼리스트링으로 받아 그리는 뷰로 다시 정의. 메인 프로세스는 windows 맵에 창 ID와 노트 ID의 쌍만 들고, 렌더러는 자기가 어느 노트인지 URL로 알 뿐 창이 몇 개인지 모름. 모드 전환은 창을 다 닫고 같은 노트 ID들로 다시 열면 끝이라, 문서를 복제하거나 직렬화하는 경로가 아예 없음
- 탭 창의 핀과 위치는 노트가 아니라 앱의 것으로 분리. 처음엔 탭 창을 고정(always on top)하면 그때 열려 있던 노트에 핀이 붙어서, 스티키로 바꾸면 엉뚱한 메모 하나만 떠 있었음. 탭 창 레코드(tabsWindow)를 따로 두고, 옛 데이터는 읽을 때 한 번 옮기는 마이그레이션을 넣어 해결
- 저장은 임시 파일에 쓰고 rename으로 바꿔치기. Windows에서는 백신이나 OneDrive가 파일을 잠깐 잡고 있어 rename이 EPERM·EBUSY로 실패하는데, 10·30·90ms 세 번만 재시도하면 체감상 거의 사라짐. 그 이상 기다리면 저장이 느리다고 느껴져서 세 번에서 끊음
-
분리와 복귀가 가능한 작업 공간
- 사이드바 탭을 밖으로 끌어 독립 창으로 분리하고 다시 탭 창으로 결합
- 세션별 색상과 투명도를 탭과 스티키 창에서 공유
- 항상 위에 표시하기와 창 위치 저장으로 참고할 노트를 작업 화면에 유지
까다로웠던 지점
닫은 창과 삭제한 노트의 구분
스티키 창의 X를 누르는 것은 "지금은 치워 둬"이지 "지워"가 아님. 그런데 창을 뷰로 분리하고 나니 반대 문제가 생김. 창을 닫아도 노트는 살아 있으니, 다른 노트를 새로 만들거나 모드를 다시 맞추는 순간 syncWindows가 "열려 있어야 할 노트"를 계산해 방금 닫은 창을 도로 띄움. 닫은 지 1초 만에 다시 나타나는 메모는 사용자 입장에서 버그로 보임.
해결메인 프로세스에 manuallyClosedStickyNoteIds라는 Set 하나를 둠. 창의 closed 이벤트에서 (1) 앱 종료 중이 아니고 (2) 스티키 모드이고 (3) 프로그램이 닫은 게 아닐 때만 노트 ID를 넣고, 창을 다시 배치할 때 이 집합에 든 노트는 건너뜀. 세 조건 중 하나라도 빠지면 틀림. 종료 중에 기록하면 다음 실행에서 노트가 안 보이고, 모드 전환으로 프로그램이 닫은 창을 기록하면 탭에서 돌아왔을 때 메모가 사라짐. 집합을 비우는 시점도 셋으로 못 박음. 마지막 스티키 창이 닫혀 탭 모드로 복귀할 때, 스티키 모드에 다시 들어갈 때, 검색으로 그 노트를 찾아 열 때. 마지막 것이 "검색은 손으로 닫은 창도 드러낸다"는 Electron 테스트로 고정되어 있음. 이 Set은 일부러 디스크에 저장하지 않음. 재시작하면 모두 다시 보이는 쪽이 "어디 갔지"보다 낫다는 판단.
남긴 것
- 문서를 정리하는 작업과 옆에 띄워 두고 참고하는 작업을 하나의 앱에서 연결
- macOS와 Windows용 패키징, WSL에서 Windows 앱을 실행하는 개발 경로 마련
02 메모 창 안에 Notion 편집기를 2026.08
이 프로젝트의 존재 이유가 편집기라서, 짧은 메모에서도 제목·체크리스트·표·코드가 되고 길어진 기록은 접거나 다시 정리할 수 있어야 했음. BlockNote를 뼈대로 삼되 Notion처럼 느껴지는 동작은 하나씩 직접 만들어 감.
요구사항
- 문서 구조
- 슬래시 메뉴, 중첩 블록, 토글, 표, 코드 블록 지원
- 입력 일관성
- 텍스트 선택과 블록 드래그가 창 이동과 충돌하지 않을 것
- 결과물 전달
- Markdown 가져오기와 PNG·PDF 내보내기 제공
구현
-
BlockNote로 시작해, Notion다운 부분은 직접 쓴다 설계 판단
- 편집기 엔진을 직접 쓸 것인가부터 정해야 했음. ProseMirror 위에서 블록 모델을 처음부터 만들면 Notion과 똑같이 할 수 있지만 혼자서 몇 달이 걸리고, 그 몇 달 동안 앱은 없음. 반대로 TipTap이나 BlockNote 같은 완성형을 쓰면 첫 주에 메모가 됨. BlockNote를 고른 이유는 블록 단위 문서 모델과 슬래시 메뉴라는 "Notion의 뼈대"를 이미 갖고 있고, 그 아래가 ProseMirror라 막히면 한 층 내려가 직접 고칠 수 있어서
- 기본 상태의 BlockNote는 Notion과 닮았지만 같지는 않았음. 블록을 드래그하면 한 블록만 잡히고, Shift+클릭으로 블록 여러 개를 고를 수 없고, 토글 안에서 Enter·Tab이 Notion과 다르게 움직이고, 표의 셀 선택과 열 너비 조절이 없고, 콜아웃 블록이 없고, 붙여 넣은 Markdown이 블록으로 풀리지 않았음. 하나하나는 사소한데 합치면 "Notion 같다"는 느낌이 사라지는 것들
- 그래서 메뉴·사이드 메뉴·슬래시 메뉴는 BlockNote 것을 버리고 다시 그렸고, 블록 다중 선택과 드래그 선택, 토글 키보드, 표 열 크기, 콜아웃과 아이콘 선택기, Markdown 단축 입력, 클립보드 변환, 노트 안 찾기를 ProseMirror 플러그인과 DOM 처리로 직접 구현. 지금 src/editor 아래가 약 5,800줄인데 BlockNote 설정은 그중 몇 백 줄이고 나머지가 이 작업. 엔진을 바꾼 게 아니라 엔진 위에 Notion의 손맛을 다시 쌓은 것
- 편집기와 데스크톱 창의 경계도 여기서 정함. 창 이동은 헤더만 담당하고 편집 표면과 버튼은 no-drag로 두어 마우스 입력이 전부 편집기로 가게. 블록 드래그가 창 드래그로 새는 순간 편집기가 "웹 페이지 같다"고 느껴지기 때문. 어디까지 BlockNote를 믿고 어디서부터 직접 쓸지는 기준 하나로 정했음. 사용자가 Notion에서 손에 익힌 동작이 다르게 움직이면 직접 쓴다
-
읽기와 내보내기
- 노트별 글꼴·크기 설정과 목차, 코드 구문 강조, 이미지 자르기·다운로드 제공
- Electron의 화면 캡처와 PDF 인쇄 기능으로 PNG·PDF 생성
- 내보낼 때 앱의 조작부와 메모 배경을 제외해 문서 내용만 전달
남긴 것
- 스티키 메모 창 안에서 Notion과 같은 손맛으로 표·토글·콜아웃·이미지가 포함된 기록을 쓸 수 있게 됨
- 앱 안의 기록을 이미지와 PDF로 꺼내 다른 작업에 활용할 수 있는 경로 확보
03 로컬 저장과 유지보수 경계 정리 2026.09
창과 편집 동작이 늘어나면서 저장, 키보드 입력, 테마 처리가 하나의 화면 코드에 모이는 상황. 로컬 저장 구조를 문서화하고 렌더러를 책임별로 분리해 수정할 위치와 검증 범위를 명확하게 정리.
요구사항
- 로컬 소유
- 로그인과 동기화 서버 없이 노트와 설정을 컴퓨터에 보관
- 복원 가능성
- 구조화된 문서와 창 상태 저장, 전체 백업 가져오기·내보내기 지원
- 검증 범위
- 저장소 단위 테스트와 렌더러·데스크톱 실행 검증을 분리
구현
-
문서 저장 흐름
- BlockNote 문서 JSON과 Markdown 보조 표현을 IPC로 전달하고 notes.json에 원자적으로 기록
- 노트 내용·창 배치·색상·글꼴과 앱 전체 테마·레이아웃 설정을 로컬에 보관
- 환경설정에서 전체 백업을 내보내거나 가져오는 경로 제공
-
기능별 코드와 테스트
- 편집기, 저장 데이터 정규화, 색상 계산, UI, 상태 훅을 각자의 모듈로 분리
- 저장 동작을 단위 테스트로, 화면 입력과 Electron 창 동작을 별도 Playwright 테스트로 검증
- 정의되지 않은 참조 검사·빌드·테스트를 반복 실행 가능한 명령으로 묶고 코드 맵 작성
남긴 것
- 계정이나 서버 없이 사용할 수 있는 로컬 우선 노트 앱으로 범위 정립
- 기능별 코드 맵과 검증 명령을 갖춘 MIT 라이선스 오픈소스 프로젝트로 공개