1. 개발 배경
앱 안에서 자라던 뷰어를 뗐다
@ohah/pdf 는 2026년 8월 30일에 저장소가 열렸지만, 첫 커밋이 이미 300개 파일에 36,526줄이었다. 첫 커밋 본문이 사정을 그대로 적어 두고 있다.
[비공개 PoC 저장소] 안에서 자라던 PDF 뷰어를 라이브러리로 뗐다. 엔진(
c/*.zig)과 브라우저 쪽(src/*.ts)만 가져오고, 화면 갈래를 넷 낸다 — 바닐라·React·Vue·Svelte.
개인 PoC 저장소(비공개)에서 만들던 것이 저장소보다 커졌고, 그래서 라이브러리로 나왔다. 인용문의 저장소 이름은 비공개라 가렸다. 같은 커밋에서 /Length 가 4294967295 인 문서가 메모리 밖을 짚던 것을 고쳤다 — wasm32 에서 usize 는 32비트라 data + length 가 도로 작아져 검사가 뚫렸고, 무작위 퍼저가 찾아냈다.
무엇을 하려는가
9월 26일 확인한 README의 첫 줄이 목표다.
브라우저에서 PDF 를 읽고, 그리고, 고친다. 엔진은 Zig 로 짜 wasm 하나(328KB)로 굽고 웹 워커에서 돌린다.
세 동사가 각각 범위다.
- 읽기 — 쪽 그리기, 글자 뽑기(읽는 차례로 줄 세우기), Markdown·블록 JSON 출력, 링크·목차·문서 속성, 레이어 켜고 끄기, 딸린 파일, 전자 서명 확인, 암호 문서(RC4·AES-128·AES-256).
- 그리기 — 박힌 TrueType·CFF·Type1·Type3 와 CID 글꼴, 세로쓰기, DCT·JPX(JPEG 2000)·JBIG2·CCITT 그림, 투명 그룹과 혼합 모드, ICC 색.
- 고치기 — 쪽 고르기·회전·이어붙이기, 워터마크, 주석, 양식 칸 채우기와 새 칸 만들기, 암호 걸기.
pdf.js 가 이미 있는데 왜 만드는가에 대한 답은 저장소가 직접 하지 않는다. 대신 docs/compare.md 에 pdf.js 와 화소를 맞댄 표를 두고, 크게 다른 것과 그 까닭을 tests/pdfjs-known.json 에 하나씩 적는다. 기능 지원은 실행 가능한 시험으로 확인한다. 9월 26일 확인한 검증 스크립트는 기능 단언 수가 최소 434개인지 검사한다. 이는 스크립트의 기준이며, 이번 글 갱신에서 직접 시험을 실행한 결과는 아니다.
도구 사슬이 전부 자기 것이다
이 프로젝트가 재미있는 지점은 만든 사람의 다른 프로젝트가 전부 부품으로 들어와 있다는 것이다.
zntc 는 --outdir 로 주면 --sourcemap 을 무시하고, 한 줄짜리 } catch { /* 주석 */ } 를 세 줄로 펴면서 생성 줄 셈을 놓쳐 그 뒤 매핑이 밀렸다. 이 두 결함을 pdf 쪽에서 찾아 zntc 에 고친 것이 8월 31일 v0.1.5·v0.1.6 이다.
지금
이 문서는 저장소의 커밋 이력과 README·docs/support.md·docs/compare.md 를 근거로 정리했다. 작업 세션 기록은 남아 있지 않다.