2P by GN⁺ | ★ favorite | 댓글 1개
  • Wordgard 0.1은 ProseMirror 안정화 이후 9년간의 경험과 CodeMirror 6의 설계를 반영해 새로 만든 JavaScript 리치 텍스트 편집기 라이브러리임
  • 기존 ProseMirror를 2.0으로 바꾸거나 1.x에 덧붙이지 않고, 호환성 부담 없는 새 API와 별도 이름으로 다시 설계함
  • 핵심 설계는 steps 대신 변경 섹션 기반 모델을 쓰고, 독립적인 노드·마크 타입과 CodeMirror식 facet 확장 시스템을 결합함
  • 브라우저 선택 동작 의존을 줄여 포인터·키보드 선택을 직접 처리하지만, 터치 선택은 네이티브 컨텍스트 메뉴 문제 때문에 브라우저 구현을 유지함
  • npm의 wordgard로 설치할 수 있고 문서와 참조 매뉴얼도 공개됐지만, 피드백과 버그 수정을 거치며 한동안 0.x 버전에 머물 예정임

Wordgard의 성격과 배포 상태

  • Wordgard는 ProseMirror 스타일 리치 텍스트 편집기 시스템을 새로 반복한 프로젝트임
  • ProseMirror 안정화 이후 9년 동안 배운 점과 CodeMirror 버전 6 재설계에서 많은 영향을 받음
  • 브라우저 DOM으로 편집기 인터페이스를 표시하는 JavaScript 라이브러리이며, 라이선스는 MIT
  • 코드는 Forgejo 서버에 공개되어 있음
  • npm 레지스트리에서 wordgard로 설치할 수 있고, 사용법은 웹사이트에서 확인 가능함

ProseMirror를 바꾸지 않고 새 시스템을 만든 이유

  • ProseMirror는 계속 유지보수되지만, 일부 설계는 지금 기준에서 다르게 만들었어야 했던 부분으로 남아 있음
  • 비호환 인터페이스의 ProseMirror 2.0을 내면 사람들이 “ProseMirror”라고 부를 때 무엇을 뜻하는지 모호해질 수 있음
  • ProseMirror 1.x에 하위 호환 방식으로 새 아이디어를 붙이면 구조가 타협적으로 흐를 수 있음
  • Wordgard는 ProseMirror의 많은 아이디어를 가져오되, 프로그래밍 인터페이스는 호환성을 고려하지 않고 처음부터 다시 설계함

변경 표현: steps 대신 섹션 기반 모델

  • ProseMirror의 steps는 변경을 여러 원자적 작업으로 나누고, 각 step이 이전 step으로 만들어진 문서에 적용되는 방식임
  • 이 방식은 동작하지만 여러 step의 위치 보정과 변경 범위 추적이 복잡해 다루기 어색함
  • Wordgard는 CodeMirror의 변경 표현과 ShareJS의 “delta” 형식에서 온 방식을 바탕으로 더 단순한 모델을 사용함
    • 문서 길이가 10일 때 위치 4에 L을 삽입하면 [keep 4] [replace 0 with "L"] [keep 6]으로 표현함
    • 처음 두 문자를 삭제하면 [replace 2 with ""] [keep 8]로 표현함
  • 리치 텍스트 처리를 위해 변경 섹션을 추가해, 구조를 유지한 채 강조·링크 스타일·이미지 대체 텍스트 같은 마크를 추가하거나 제거할 수 있음
    • 3부터 6까지의 단어를 굵게 만들면 [keep 3] [update 3 +bold] [keep 4]로 표현함
  • Wordgard는 ProseMirror와 같은 토큰 카운팅 인덱스를 사용해 노드 열기·닫기 토큰과 리프 토큰의 평평한 시퀀스로 문서 위치를 다룸
  • 단일 트랜잭션은 항상 하나의 변경을 가지므로, 변경 합성과 검사·추론이 쉬워짐
  • 제한적인 운영 변환을 지원해 같은 시작 문서를 기준으로 표현된 여러 변경을 병합할 수 있음
    • 여러 변경을 가진 트랜잭션을 더 편하게 표현할 수 있음
    • 협업 편집과 일부 변경만 되돌리는 undo history 구현에 활용 가능함

유효한 문서 구조를 유지하는 방식

  • Wordgard 문서는 단순한 토큰 시퀀스가 아니라 균형 잡힌 트리 구조여야 함
  • 예를 들어 노드 닫기 토큰을 삭제하면 토큰 균형이 깨져 적용할 수 없는 변경이 만들어질 수 있음
  • 변경 집합 생성 코드는 결과가 유효한 문서 구조가 되도록 변경을 검사하고 보정해야 함
  • 운영 변환에서도 변환된 변경이 문서를 무효화하지 않아야 함
  • Wordgard의 변경 모델은 변환 중 결합 결과를 보정하는 fix-up change를 도출함
    • A-over-B와 B-over-A에 대해 같은 보정을 만들도록 입력을 조심해서 사용함
    • 보정이 없으면 두 순서는 같은, 그러나 무효할 수 있는 문서를 만들 수 있음
    • 같은 보정을 합성하면 두 순서 모두 같은 유효 문서로 수렴함
  • 대부분의 변경은 보정이 필요 없지만, 필요한 경우에도 수렴성을 유지하도록 설계됨

스키마 조합과 마크 일반화

  • ProseMirror의 문서 스키마는 노드 간 관계를 직접 지정하므로 보통 손으로 설정해야 함
  • ProseMirror의 노드와 마크 타입은 특정 스키마 안에서만 존재하며, 스키마 사이에서 공유할 수 있는 노드 정체성이 없음
  • Wordgard에서는 노드·마크 타입이 독립 객체이며 여러 문서 스키마에 포함될 수 있음
  • 이 객체들은 타입 지정과 자동완성을 지원하는 핸들처럼 동작해, 필요한 요소를 조합해 스키마를 만들기 쉬움
  • 스키마는 기존 요소의 관계를 오버라이드할 수 있음
    • 노드나 마크 정의는 기본 콘텐츠나 대상 타입을 지정함
    • 같은 요소를 다르게 쓰고 싶을 때 스키마가 그 관계를 바꿀 수 있음
  • 기본 내장 노드를 더 풍부하게 제공할 수 있어, 편집 지원 확장이나 메뉴 버튼 같은 시스템 통합을 해당 노드에 직접 붙이기 쉬움
  • 텍스트 정렬이나 대체 텍스트처럼 특정 노드 속성으로 묶였던 기능은 마크 일반화를 통해 더 모듈식으로 추가할 수 있음
  • 노드 타입 자체는 어떤 마크가 자신을 대상으로 하는지 알 필요가 없음

콘텐츠 제약을 완화한 이유

  • ProseMirror의 대표 기능인 정규식 기반 허용 콘텐츠 지정은 Wordgard에서 지원하지 않음
  • Wordgard의 노드 콘텐츠 설명은 어떤 자식 타입을 지원하는지만 제한하고, 그 순서는 제한하지 않음
  • 정규식 기반 제약은 범용 문서 조작 코드를 작성하기 어렵게 만듦
    • 특정 스키마에 맞춰 작성하지 않은 코드는 어떤 변환이 유효한지 거의 가정할 수 없음
    • 모든 작업을 콘텐츠 제약과 대조해야 하며, 이 과정이 미묘하고 부담스러움
  • 문서 형태를 강하게 잠그는 제약은 사용자가 의도한 형태로 가는 중간 편집 단계를 막아 사용자 경험을 해칠 수 있음
  • Wordgard는 더 느슨한 문서 형태 접근을 장려함
  • 스키마 규칙을 넘어서는 불변 조건이 필요할 때는 correction 추상화를 제공함
    • 허용하고 싶지 않은 문서 형태를 프로그램으로 보정함
    • 콘텐츠 표현식 강제보다 더 지능적이고 문맥을 반영한 보정이 가능함
    • ProseMirror 제약으로도 표현할 수 없던 직사각형 테이블 보장 같은 조건에도 사용할 수 있음

확장 시스템: CodeMirror 6식 facet

  • ProseMirror의 확장 시스템은 플러그인이 여러 일을 맡고, 배열 순서가 우선순위에 영향을 주는 방식임
  • 한 플러그인이 어떤 훅에서는 낮은 우선순위가 필요하고 다른 훅에서는 높은 우선순위가 필요한 상황이 생길 수 있음
  • CodeMirror의 facets 기반 시스템은 확장을 더 세밀하게 만들고, 각 확장 값이 자체 우선순위 범주를 설정할 수 있게 함
  • Facet은 타입이 지정된 확장 지점이며, 라이브러리 자체뿐 아니라 어떤 코드든 정의할 수 있음
  • Wordgard는 이 부분에서 CodeMirror의 시스템을 거의 그대로 가져오며, 상태 업데이트와 재구성 메커니즘도 포함함
  • 구성은 플러그인 배열이 아니라 확장 트리
    • 이벤트 핸들러 정의
    • 편집기 속성 설정
    • 새 편집기 상태 추가
  • 기능 구현은 보통 함께 동작하는 확장 묶음으로 구성됨
  • 확장 번들은 대부분 구성에 넣기만 해도 잘 조합되도록 원시 요소가 설계됨

브라우저 의존성 축소와 선택 처리

  • ProseMirror의 많은 문제는 브라우저 네이티브 선택 동작에 의존하는 방식과 관련됨
  • 기존 접근은 브라우저가 양방향 텍스트나 특이한 스타일의 콘텐츠에서 커서 이동을 처리하게 두고, 그 결과를 자체 선택 모델에 반영하는 방식이었음
  • 실제 브라우저는 일부 콘텐츠를 지나 커서를 이동하지 않거나, 커서를 그리지 않거나, 잘못된 위치에 그리거나, 마우스 선택 드래그에서 이상 동작을 보일 수 있음
  • Wordgard는 포인터와 키보드 기반 선택을 거의 모두 직접 처리함
    • 양방향 텍스트 처리를 구현함
    • 콘텐츠 배치 모델을 만듦
    • 커서를 직접 그림
  • 터치 선택은 예외적으로 네이티브 구현을 사용함
    • 다시 구현하면 네이티브 컨텍스트 메뉴가 깨지는 것으로 보임
    • 휴대폰과 태블릿에서는 컨텍스트 메뉴를 대체하기 어려움
    • 터치 선택은 키보드 선택보다 이상 동작이 덜한 편임

입력 이벤트 처리와 DOM 변경 감시 제거

  • 지난 9년 동안 브라우저의 편집 이벤트 지원, 특히 beforeinput 지원은 더 일관돼짐
  • 실제 사용 환경 테스트가 필요하지만, Wordgard는 ProseMirror가 의존한 DOM 변경 감시와 변경 콘텐츠 파싱 트릭 없이 동작할 수 있어 보임
  • Wordgard는 조합 텍스트 입력을 제외한 모든 것에 대해 beforeinput 이벤트를 처리함
  • 이 방식은 여러 지저분한 우회 구현이 필요한 문제군을 피함

안정성, 버전 계획, 라이선스

  • Wordgard는 이전 프로젝트들이 발표 시점에 있던 상태보다 조금 더 진전된 상태임
  • 핵심 인터페이스는 원하는 기능의 거의 전부를 지원하고, 설계가 실용적인지 확인하기 위한 여러 확장도 작성됨
  • 문서는 아직 다소 거칠지만 참조 매뉴얼은 완성되어 사용할 수 있음
  • 실제 작업에 사람들이 사용하기 전까지는 많은 문제가 드러나지 않을 수 있음
  • 앞으로 추가하고 싶은 기능이 있으며, 공개 후 다른 사람들도 살펴보기를 기대함
  • 공개 인터페이스 일부는 더 많은 통찰에 따라 다시 생각해야 할 수 있음
  • 첫 버전은 0.1이며, 피드백 수집·버그 수정·거친 부분 정리를 위해 한동안 0.x 버전에 머물 예정임
    • 기간은 적어도 1년 정도로 예상됨
  • 라이선스는 이전 프로젝트들과 마찬가지로 MIT
  • 더 제한적인 라이선스도 고려했지만, 널리 사용되는 쪽에 더 관심이 있어 허용적 라이선스를 선택함

AI 모델, 코드 생성, 풀 리퀘스트 정책

  • 이 소프트웨어를 만드는 데 언어 모델은 사용되지 않음
  • JavaScript 코드가 웹에 있고 문서가 공개되어야 하므로, 공개된 코드와 아이디어가 대형 언어 모델에 들어가는 것을 막을 신뢰할 만한 방법은 없다고 봄
  • Wordgard에서는 표준 오픈소스 관행과 달리 pull request를 받지 않는 실험을 함
  • 큰 변경을 리뷰하고 기대에 맞도록 조정하는 과정은 직접 구현하는 것보다 더 많은 일이 될 때가 많음
  • 코드 생성 비용이 크게 낮아지면서, 다른 사람이 코드를 던지고 관리자가 리뷰·유지보수하거나 거절 이유를 설명해야 하는 구조가 더 매력적이지 않게 됨

댓글과 토론

Lobste.rs 의견들
  • 작성자로서 질문이나 피드백이 있으면 이 스레드를 가끔 확인하겠음

    • 꽤 놀라워 보임. FAQ에서 못 봤는데, Markdown 편집에 어떻게 쓰거나 설정할 수 있는지 궁금함
      Markdown 렌더러로 HTML을 만들어 Wordgard에서 편집하게 할 수는 있을 텐데, 이후 편집기 내용에서 Markdown을 어떻게 추출할 수 있을까?
    • ProseMirror를 쓰는 사람들이 어떤 전환 경로를 밟게 될지 궁금함
      결국 Wordgard로 옮기게 될까? 새 프로젝트에서 ProseMirror를 쓰려는 사람이 있다면, 언제 Wordgard를 선택해야 할까?
  • Contains 0% AI

    Not having PRs is an effective way to nip the problem of people submitting LLM-generated slop code in the bud.

    그리고 real, human artist가 만든 멋진 아트도 있음
    좋다

  • Marijn의 프로젝트와 발표를 크게 축하함. 멋져 보이고, Kamila Stankiewicz의 아트도 마음에 듦

  • 프로젝트 메인 홈페이지는 https://wordgard.net/

  • As a deviation from standard open-source practice, I'm doing an experiment where I don't take pull requests for Wordgard.

    이 부분, 특히 마지막 문단 전체가 정말 흥미로움
    AI 코드 생성과 더 나은 관계를 맺게 될 때까지, 혹은 아예 관계를 맺지 않는 쪽으로 가게 될 때까지, 이런 방식이 한동안 더 흔해질지도 궁금함
    참고로 코드는 MIT 라이선스임