EDITORCLASSBLOGLOGINimg default descriptionimg default descriptionimg default description표현한다는 것의무한한 가능성,새로운 형태로
담아내다.
img default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default description새로운 형태의 콘텐츠Opkle은 코드 없이 웹을 마음껏 만들고, 누구나 자기 화면을 그릴 수 있도록 에디터를 만들고, 그 결과물을 어디서나 즐길 수 있게 돕는 팀입니다.텍스트와 화면과의 조화를 통해, 웹을 짓는다는 것이 그저 단순한 코딩이 아닌, 상상을 펼치고 감각을 깨우는 과정이 될 수 있도록 좋은 도구를 만들어 냅니다.
옵클 에디터 개발기: 첫 번째 구현은 코드 편집기였습니다dev2옵클 에디터 개발기: 미리보기는 곧 또 하나의 편집기였습니다dev3옵클 에디터 개발기: 미디어쿼리까지 편집하는 EPUB 에디터dev4옵클 에디터 개발기: CSS 애니메이션으로 영상을 흡수하는 방식dev5옵클 에디터 개발기: 책을 만들기 위한 LLM을 설계하다dev6678910...2 옵클 에디터 개발기: 첫 번째 구현은 코드 편집기였습니다EPUB 에디터를 만들겠다고 마음먹은 뒤에는 바로 구현으로 들어갔습니다. 그때의 판단은 지금 생각하면 꽤 직선적이었습니다. EPUB은 결국 압축된 웹문서 묶음이고, 본문은 XHTML, 스타일은 CSS, 패키지 정보는 OPF와 NCX 또는 nav 문서로 구성됩니다. 그러니 웹 개발자가 EPUB 에디터를 만든다면 TypeScript와 Node.js를 기반으로 파일 트리, 패키징, 코드 편집, 미리보기, 저장 구조를 직접 통제하는 쪽이 가장 자연스럽다고 생각했습니다.처음 프로젝트는 Node.js + TypeScript 구조로 잡았습니다. 서버 쪽에서는 EPUB 프로젝트를 하나의 작업 디렉터리처럼 다루고, 프론트에서는 각 XHTML/CSS 리소스를 독립된 편집 단위로 열 수 있게 만들었습니다. 에디터의 중심에는 CodeMirror 6를 붙였습니다. CM6는 확장 구조가 좋고, language package와 transaction/update listener를 통해 입력 상태를 세밀하게 감지할 수 있었기 때문에, 단순 textarea보다 훨씬 안정적으로 코드 편집 경험을 만들 수 있었습니다.그때 제가 만들려던 것은 사실상 “Sigil보다 자동화된 웹 기반 EPUB IDE”에 가까웠습니다. EPUB의 `META-INF/container.xml`, `OEBPS/content.opf`, 본문 XHTML, CSS, 이미지, 폰트 리소스를 프로젝트 트리로 만들고, 파일을 열 때마다 해당 리소스에 대응하는 CodeMirror 인스턴스를 생성했습니다. 사용자가 본문을 입력하면 update listener가 변경 내용을 감지하고, 내부 상태에 반영한 뒤, 필요한 경우 HTML fragment를 다시 정리하는 방식이었습니다. 지금 돌아보면 첫 구현은 창작자용 에디터라기보다 EPUB 패키지를 다루는 개발 도구에 가까웠습니다.EPUB 프로젝트를 먼저 파일 시스템처럼처음에는 EPUB을 창작자의 화면보다 패키지 구조에서 바라봤습니다. 새 책을 만들면 기본 폴더 트리를 생성하고, OPF 파일에는 metadata, manifest, spine을 세팅했습니다. 본문 파일을 추가하면 manifest에 XHTML item을 넣고, spine에도 읽기 순서를 반영하는 식이었습니다. CSS 파일은 별도의 리소스로 등록하고, 본문 XHTML에서 link 태그로 연결되게 했습니다.이 접근은 개발자로서는 명확했습니다. EPUB은 결국 reading system이 읽어야 하는 규칙을 가진 파일 묶음이기 때문에, 에디터가 그 규칙을 일관되게 관리하면 됩니다. 어떤 파일이 manifest에 빠져 있으면 안 되고, spine에 없는 본문은 읽기 순서에서 사라지며, 이미지나 폰트도 OPF에 등록되지 않으면 패키지 안에서 고아 리소스가 됩니다. 그래서 처음 구현에서는 프로젝트 트리와 OPF 상태를 강하게 연결하려고 했습니다.파일 하나를 추가하는 행위도 단순히 UI 목록에 항목을 추가하는 문제가 아니었습니다. 내부적으로는 리소스 path, media-type, manifest id, spine 포함 여부, 본문에서 참조되는 상대 경로까지 함께 맞아야 했습니다. 특히 EPUB은 ZIP으로 묶인 뒤에도 내부 경로가 유지되어야 하므로, 프론트에서 보이는 이름과 실제 패키지 경로를 분리해서 관리할 필요가 있었습니다.당시에는 이 구조를 자동으로 잘 처리해 주면 사용자가 훨씬 편해질 것이라고 생각했습니다. 사용자는 폴더 트리를 직접 만들지 않아도 되고, OPF를 손으로 수정하지 않아도 되며, 리소스를 추가하면 manifest가 알아서 갱신됩니다. 그러나 이 판단에는 전제가 있었습니다. 사용자가 최소한 “EPUB은 이런 파일들의 묶음”이라는 사실을 받아들이고, 그 파일들을 편집하는 작업 방식에 익숙해져야 한다는 전제였습니다.CodeMirror6 와 HTML 편집본문 편집은 CodeMirror 6를 중심으로 만들었습니다. 각 XHTML 파일마다 독립된 CM6 EditorView를 만들고, 문서 상태는 EditorState로 관리했습니다. 입력이 들어오면 update listener에서 transaction을 받아 변경 여부를 확인하고, 바뀐 문자열을 내부 document model에 반영했습니다. 저장 시점에는 이 문자열을 다시 XHTML 파일 내용으로 직렬화하는 방식이었습니다.처음에는 사용자가 완전히 손으로 HTML을 작성하지 않아도 되게 만들고 싶었습니다. 예를 들어 일반 텍스트를 입력하면 문단 단위로 `

` 태그를 씌우고, 특정 영역을 선택한 뒤 더블 클릭하거나 우클릭하면 태그 이름을 바꾸거나 속성을 추가할 수 있게 했습니다. 선택한 영역에 class를 붙이고, 그 class를 CSS 쪽에서 선택자로 연결하는 흐름도 생각했습니다. 코드 편집기 위에 창작자용 조작 레이어를 얹는 방식이었습니다.

기술적으로는 꽤 재미있는 작업이었습니다. CM6에서 selection range를 읽고, 해당 range가 HTML 문자열의 어느 태그 내부에 있는지 추적하고, context menu에서 tagName이나 attribute를 바꾸면 원본 문자열을 수정해야 했습니다. 단순 텍스트 편집이 아니라, 문자열 안의 HTML 구조와 사용자의 selection을 계속 맞춰야 했습니다. 잘못하면 커서 위치가 틀어지고, 태그가 깨지고, undo stack과 내부 상태가 어긋납니다.이 문제를 다루면서 저는 꽤 많은 시간을 “코드를 덜 보이게 하는 코드 편집기”에 썼습니다. 사용자가 직접 `
`를 치지 않아도 되게 하고, 속성 편집 UI를 붙이고, 우클릭으로 태그를 바꾸게 만들었습니다. 하지만 핵심 구조는 여전히 HTML 문자열이었습니다. 사용자는 결국 태그와 속성, class와 selector의 세계 안에서 작업해야 했습니다.
리소스 드롭과 OPF manifest 자동 갱신이미지와 폰트는 EPUB 제작에서 자주 막히는 부분이었습니다. 파일을 프로젝트 안에 넣는 것만으로는 끝나지 않습니다. OPF manifest에 item을 추가해야 하고, media-type을 맞춰야 하며, 본문이나 CSS에서 참조할 경로도 안정적으로 만들어야 합니다. 폰트라면 CSS의 `@font-face`까지 연결될 수 있고, 이미지는 XHTML의 `img src`나 CSS background에서 참조될 수 있습니다.그래서 CodeMirror 6 영역에 drag and drop 이벤트를 붙였습니다. 사용자가 이미지나 폰트 파일을 끌어다 놓으면, 파일을 내부 리소스 저장소에 추가하고, 파일 확장자와 MIME type을 기준으로 OPF manifest item을 생성했습니다. 같은 이름이 이미 있으면 충돌을 피하기 위해 path를 다시 만들고, 본문 에디터에 드롭한 경우에는 해당 위치에 `img` 태그나 참조 코드를 삽입하는 흐름을 만들었습니다.이 기능은 그 당시의 제 기준에서는 꽤 중요한 진전이었습니다. EPUB 패키지에서 리소스 누락은 흔한 오류이고, manifest와 실제 파일 목록이 어긋나면 유통 단계에서 문제가 됩니다. 에디터가 드롭 이벤트를 받아 리소스 등록과 참조 삽입을 한 번에 처리하면, 사용자가 OPF를 직접 열어 보는 일을 줄일 수 있었습니다.하지만 여기에도 같은 한계가 있었습니다. 개발자인 저는 “manifest를 자동 갱신한다”는 사실에 큰 의미를 두었지만, 사용자는 manifest가 무엇인지 모르는 상태였습니다. 사용자가 원하는 것은 “이 이미지를 여기에 넣고 싶다”였지, “이 리소스를 manifest에 등록하고 XHTML에서 참조하고 싶다”가 아니었습니다. 제가 자동화한 것은 EPUB 내부 규칙이었고, 사용자가 느끼는 작업 단위는 여전히 책의 장면과 문단이었습니다.저장은 IndexedDB에저장 구조는 처음부터 중요하게 봤습니다. 웹 기반 에디터에서 원고가 날아가는 경험은 치명적입니다. 특히 책 작업은 한 번에 끝나는 작업이 아니라 며칠, 몇 주, 몇 달 동안 이어집니다. 서버에만 의존하는 저장 구조는 네트워크 상태와 로그인 상태, 서버 장애에 영향을 받을 수 있고, 원고를 항상 외부로 보내는 것에 대한 부담도 있었습니다.그래서 브라우저의 IndexedDB를 적극적으로 사용했습니다. 프로젝트 단위로 본문 XHTML, CSS, 이미지, 폰트, OPF 메타데이터, 작업 상태를 로컬에 저장하고, 편집 중에는 변경된 리소스만 갱신하는 식으로 설계했습니다. localStorage로는 용량과 구조화 측면에서 부족했고, 파일과 큰 문자열, blob을 함께 다루려면 IndexedDB가 더 맞았습니다.자동 저장은 단순히 일정 시간마다 전체 프로젝트를 덮어쓰는 방식으로 만들 수 없었습니다. 리소스 수가 늘어나면 전체 직렬화 비용이 커지고, 이미지와 폰트까지 매번 다시 쓰는 것은 비효율적입니다. 그래서 내부적으로는 변경된 문서 상태와 리소스 상태를 분리해서 다루려 했습니다. 편집 중인 XHTML/CSS 문자열은 빠르게 저장하고, blob 리소스는 추가되거나 교체될 때만 갱신하는 식의 방향이었습니다.이 결정은 이후 옵클 에디터의 큰 뼈대가 되었습니다. 로컬 우선 저장, 자동 저장, 작업 복원, 브라우저 안에서의 프로젝트 관리 같은 개념은 이때부터 중요해졌습니다. 다만 이 역시 1차 구현에서는 기술적으로는 의미가 있었지만, 사용자의 작업 경험을 근본적으로 바꾸지는 못했습니다. 저장이 안정적이어도, 편집 화면이 여전히 코드 중심이면 사용자는 계속 어렵다고 느꼈습니다.1차 구현 뒤 바로 만난 한계1차 구현본을 만든 뒤, 아는 작가님들께 보여 드렸습니다. 저는 어느 정도 자신이 있었습니다. EPUB 프로젝트 생성, OPF 세팅, XHTML/CSS 편집, 리소스 드롭, manifest 자동 갱신, IndexedDB 자동 저장까지 붙였으니 기존 도구보다 훨씬 쉬워졌다고 생각했습니다. 개발자로서는 분명 많은 마찰을 줄인 상태였습니다.그런데 작가님들의 반응은 달랐습니다. 여전히 어렵다고 했습니다. 더 정확히는, 제가 줄였다고 생각한 어려움이 사용자의 핵심 어려움이 아니었습니다. HTML과 CSS의 문법을 자세히 모르면, 화면에 보이는 여러 코드 영역이 왜 나뉘어 있는지 이해하기 어려웠습니다. 본문 에디터와 스타일 에디터가 따로 있고, 태그에는 class가 붙고, CSS에서는 그 class를 선택자로 다시 불러와야 했습니다.저는 태그를 자동으로 씌워 주면 쉬워질 거라고 생각했지만, 사용자에게는 자동으로 씌워진 태그 자체가 낯설었습니다. 더블 클릭이나 우클릭으로 태그를 바꿀 수 있게 해도, 왜 태그를 바꿔야 하는지 모르면 그 기능은 편의가 아니라 새로운 부담이 됩니다. CSS를 따로 편집할 수 있게 해도, selector와 declaration의 관계를 모르면 자유도가 아니라 복잡함으로 느껴집니다.그때 조금 부끄러운 마음이 들었습니다. 저는 창작자를 위한 도구를 만들겠다고 해 놓고, 여전히 HTML과 CSS를 아는 사람의 시선으로 쉬움을 설계하고 있었습니다. 코드를 덜 치게 만든 것이지, 코드를 몰라도 책을 만들 수 있게 만든 것은 아니었습니다. 사용자는 EPUB 내부 구조를 배우고 싶은 것이 아니라, 자기 책을 만들고 싶었던 것입니다.코드 편집기를 넘어가야 한다는 결론그 1차 구현은 실패라기보다 필요한 통과점이었습니다. EPUB 프로젝트 구조를 자동으로 만들고, OPF manifest를 갱신하고, IndexedDB에 저장하며, CodeMirror 6 위에서 HTML과 CSS를 다루는 시스템은 분명 이후에도 중요한 기반이 되었습니다. 에디터의 저장 구조, 리소스 관리, 패키징 감각은 이때 만들어졌습니다.하지만 그 구현은 제가 정말 풀어야 할 문제가 무엇인지도 보여 주었습니다. EPUB 제작의 어려움은 단순히 태그를 많이 입력해야 한다는 데 있지 않았습니다. 창작자가 자기 책을 만들 때 계속 HTML과 CSS의 개념으로 생각해야 한다는 데 있었습니다. 문단을 고치고 싶은 사람에게 태그를 보여 주고, 이미지의 느낌을 조정하고 싶은 사람에게 선택자를 보여 주면, 작업의 언어가 자꾸 바뀝니다.그때부터 에디터를 더 깊게 바꿔야겠다고 생각했습니다. 코드 편집기를 조금 더 친절하게 만드는 것으로는 충분하지 않았습니다. 창작자가 보는 화면 자체가 책의 구조와 가까워져야 했고, 조작 방식도 코드의 단위가 아니라 문단, 이미지, 장면, 스타일의 단위로 바뀌어야 했습니다. HTML과 CSS는 사라지는 것이 아니라, 에디터 뒤에서 조용히 일해야 했습니다.첫 번째 구현은 저에게 아주 중요한 사실을 알려 주었습니다. 개발자가 생각하는 쉬움과 창작자가 느끼는 쉬움은 다를 수 있습니다. 이 차이를 인정하지 않으면, 아무리 많은 기능을 넣어도 도구는 계속 어려운 얼굴을 하게 됩니다. 옵클 에디터는 그때부터 단순한 EPUB 코드 편집기가 아니라, 창작자가 자기 책을 직접 만지는 편집 환경으로 가야 했습니다.
이전글목록으로다음글
저작권 고시Copyright Notice본 웹사이트의 모든 디자인 결과물 및 영상에 대한 저작권은 Abstract Cloud에 있으며, 저작권법 및 관련 법령에 의해 보호받습니다. 웹, 영상, 본문, 표지, 내지 디자인을 포함한 모든 콘텐츠는 저작권자의 자산으로, 사전 동의 없이 무단 복제, 배포, 2차 저작물 제작, 온라인 공유 등을 금지합니다. 이를 위반할 시, 저작권법에 따라 민형사상 책임을 질 수 있습니다. 정당한 구매와 저작권 보호는 창작자의 권리를 지키며, 더 나은 작품으로 보답할 힘이 됩니다.저작권자: Abstract Cloud | 대표자: 배창규(uragen)
© Abstract Cloud. All Rights Reserved.
HOMEFAQ이용 약관개인정보 이용방침help@opkle.app
010-2747-3403
상호 :추상적 형상 디자인(Abstract cloud)  |  대표자 :배창규사업자등록번호 :249-74-00533통신판매업 신고번호 :2025-의정부송산-0634주소 :경기도 의정부시 부용로 49, 108동 402호웹의 모든 콘텐츠, 디자인, 소스 코드에 대한
저작권은 Opkle에게 있습니다.
img default description