npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rhwp/editor

v0.8.7

Published

HWP 에디터 웹 컴포넌트 — iframe 기반 임베드

Readme

@rhwp/editor

알(R), 모두의 한글 — 3줄로 HWP 에디터를 웹 페이지에 임베드

npm License: MIT

웹 페이지에 HWP 에디터를 통째로 임베드합니다. 메뉴, 툴바, 서식, 표 편집 — rhwp-studio의 모든 기능을 그대로 사용할 수 있습니다.

SDK는 지원되는 Studio와 MessageChannel v1을 협상해 binary를 transferable로 전송합니다. 구버전 Studio에는 기존 postMessage protocol로 자동 전환되며 기존 공개 API는 유지됩니다. getRendererDiagnostics()는 renderer-diagnostics-v1 capability를 협상한 Studio에서만 사용할 수 있습니다. getFontDecisionTrace()는 font-decision-trace-v1 capability를 협상한 Studio에서만 사용할 수 있으며, 현재 snapshot을 읽을 뿐 font load, 권한 요청, repaint 또는 backend 변경을 시작하지 않습니다. 호스트와 studioUrl은 HTTP(S) origin만 지원합니다. file:, data:, 브라우저 확장처럼 origin이 null이거나 불투명한 환경의 연결은 SDK와 Studio 양쪽에서 거부합니다.

온라인 데모 에서 먼저 체험해보세요.

설치

npm install @rhwp/editor

빠른 시작 — 3줄이면 충분합니다

<!DOCTYPE html>
<html>
<head>
  <title>내 HWP 에디터</title>
  <style>
    #editor { width: 100%; height: 100vh; }
  </style>
</head>
<body>
  <div id="editor"></div>
  <script type="module">
    import { createEditor } from '@rhwp/editor';

    const editor = await createEditor('#editor');
  </script>
</body>
</html>

이것만으로 메뉴바, 툴바, 편집 영역, 상태 표시줄이 포함된 완전한 HWP 에디터가 표시됩니다.

웹페이지에서 JavaScript 로 제어하기 — createStudio

createEditor 의 상위 집합입니다. 같은 것을 만들고, studio 의 메뉴·커맨드를 조종하고 문서를 HwpCtrl API 로 편집할 수 있습니다.

import { createStudio } from '@rhwp/editor';

const studio = await createStudio('#app', {
  plugins: ['hwpctrl'],            // HwpCtrl API 사용
  chrome: { statusbar: false },    // 메뉴·툴바·상태표시줄 표시
});

await studio.loadFile(buffer, 'doc.hwp');

// studio 커맨드 — 메뉴·툴바·키보드와 같은 경로를 탑니다
await studio.commands.execute('edit:copy');
const commands = await studio.commands.list();   // {id, label, enabled, opensDialog}

// 문서 편집 — 여러 호출을 한 메시지·한 트랜잭션으로
await studio.hwpctrl.batch(h => {
  h.PutFieldText('기안자', '홍길동');
  h.PutFieldText('기안일', '2026-08-12');
});
const bytes = await studio.hwpctrl.exportBytes();

await studio.hwpctrl.undo();       // 위 배치 전체가 undo 1스텝
studio.destroy();

알아 둘 것 셋.

  • 배치를 쓰세요. 실측상 100회 호출이 배치면 postMessage 1회·11ms, 개별이면 100회·583ms 입니다 (약 45배). 배치 하나가 트랜잭션 하나이고 undo 도 1스텝입니다.
  • 대화상자를 여는 커맨드는 기본 거절됩니다({ok:false, reason:'needs-dialog'}). 자동화가 그것을 열면 사람이 누를 때까지 응답이 멈춥니다. 사용자가 앞에 있는 통합에서는 studio.commands.execute(id, params, { allowDialog: true }) 로 풉니다.
  • 컨테이너 이동은 지원하지 않습니다. iframe 을 다른 요소로 옮기면 브라우저가 문서를 재로드해 편집 상태가 사라집니다. 화면상의 이동·숨김은 컨테이너 CSS 로 하고(display:none 은 상태를 보존합니다), 정말 옮겨야 하면 destroy() 후 다시 만듭니다.

chrome:{ menu:false } 로 메뉴를 숨겨도 커맨드 레지스트리는 살아 있어 commands.execute 가 계속 동작합니다 — "UI 없는 편집기" 구성이 이것으로 섭니다.

검증

브리지 전 계약(자동화·플러그인·hwpctrl·성능)을 한 번에 확인하려면 저장소에서:

cd rhwp-studio && npm run gate:bridge

HWP 파일 로드

import { createEditor } from '@rhwp/editor';

const editor = await createEditor('#editor');

// 파일 선택 또는 fetch로 HWP 데이터 가져오기
const response = await fetch('document.hwp');
const buffer = await response.arrayBuffer();

// 에디터에 로드
const result = await editor.loadFile(buffer, 'document.hwp');
console.log(`${result.pageCount}페이지 로드 완료`);

API

createEditor(container, options?)

에디터를 생성하고 컨테이너에 마운트합니다.

const editor = await createEditor('#editor');
// 또는
const editor = await createEditor(document.getElementById('editor'));

옵션:

| 옵션 | 기본값 | 설명 | |------|--------|------| | studioUrl | https://edwardkim.github.io/rhwp/ | rhwp-studio HTTP(S) URL. opaque origin은 지원하지 않음 | | width | '100%' | iframe 너비 | | height | '100%' | iframe 높이 | | renderer | 'canvas2d' | 문서 단위 renderer 요청. auto, canvas2d, canvaskit 중 하나 | | requestTimeoutMs | method별 기본값 | 모든 method 제한 시간 override(ms). 일반 10초, load/export 60초 | | handshakeTimeoutMs | 1000 | v1 협상 후 legacy 전환까지의 제한 시간(ms) |

editor.loadFile(data, fileName?, options?)

HWP 파일을 로드합니다.

const result = await editor.loadFile(buffer, 'sample.hwp');
// result = { pageCount: 5 }

// 안내창에서 사용자가 직접 선택하도록 열기
await editor.loadFile(buffer, 'sample.hwpx', { suppressDialogs: false });

options:

| 옵션 | 기본값 | 설명 | |------|--------|------| | skipUnsavedGuard | false | 미저장 변경 확인 없이 문서 교체 | | suppressDialogs | true | 로드 후 안내창(HWPX 검증, 로컬 글꼴 감지) 없이 열기 |

suppressDialogs를 생략하면 검증 경고는 '그대로 열기'로 처리하고 글꼴은 웹 대체 글꼴로 표시하여 loadFile 응답을 즉시 반환합니다. 안내창(HWPX 비표준 lineseg 검증, 로컬 글꼴 감지)에서 사용자가 직접 선택해야 하는 대화형 흐름이 필요하면 suppressDialogs: false를 명시하세요.

editor.pageCount()

현재 문서의 페이지 수를 반환합니다.

const count = await editor.pageCount();

문서 에이전트 exact command

서버가 만든 HWP/HWPX 문단 교체 후보는 현재 문서의 epoch, change sequence, 전체 문서 SHA, target 원문·서식·인접 문맥 SHA를 모두 결속한 뒤 한 snapshot transaction으로 적용할 수 있습니다.

const state = await editor.getDocumentState();
const selection = await editor.getSelectionContext();
if (!selection.editable || !selection.target) throw new Error('편집할 수 없는 target');

const receipt = await editor.applyTextCommand({
  schemaVersion: 1,
  commandId: crypto.randomUUID(),
  expectedDocumentEpoch: state.documentEpoch,
  expectedChangeSeq: state.changeSeq,
  expectedDocumentSha256: state.documentSha256,
  target: selection.target,
  expectedBeforeSha256: candidate.beforeSha256,
  expectedFormatSha256: candidate.formatSha256,
  expectedAdjacentContextSha256: candidate.adjacentContextSha256,
  replacement: candidate.replacement,
});

await editor.focusTarget(receipt.target);
const off = editor.onDocumentChanged(event => console.log(event.reason, event.changeSeq));

await editor.revertTextCommand({
  schemaVersion: 1,
  commandId: receipt.commandId,
  expectedDocumentEpoch: receipt.documentEpoch,
  expectedChangeSeq: receipt.afterChangeSeq,
  expectedAfterDocumentSha256: receipt.afterDocumentSha256,
  expectedAfterSha256: receipt.afterTextSha256,
});
off();

v1 target은 control·field·혼합 글자 서식이 없는 본문 문단 전체(최대 4,000 Unicode code point)로 제한됩니다. apply 뒤 다른 편집이 있으면 agent revert는 실패합니다. TRANSACTION_FAILED와 RENDER_FAILED에는 snapshot 복구 여부인 error.recovered가 포함됩니다. SHA 정규형과 오류 계약은 document_agent_command.md를 참조하세요.

editor.getPageSvg(page?)

특정 페이지를 SVG 문자열로 렌더링합니다.

const svg = await editor.getPageSvg(0); // 첫 페이지

editor.getRendererDiagnostics(page?)

선택된 renderer와 0부터 시작하는 페이지별 readiness 진단을 반환합니다. Studio가 renderer-diagnostics-v1 capability를 제공하지 않으면 명시적으로 실패합니다. auto에서는 문서 capability preflight, 실제 선택 이유, fallback 이유, 문서 revision과 resource generation을 selection에서 확인할 수 있습니다. 현재 Studio는 selection을 반환하지만, 같은 v1 capability를 제공하는 이전 Studio와의 additive 호환을 위해 이 필드는 없을 수도 있습니다. selectionError는 preflight/리소스/replay 실패를, top-level initializationError는 Studio 앱 초기화 실패를 나타냅니다. preflight의 requiredFontFamilies는 자동 선택에서 첫 replay 전에 준비해야 하는 문서 폰트 목록입니다. 기존 v1 소비자 호환을 위해 top-level request.backend.backend는 계속 canvas2d 또는 canvaskit만 반환하며, auto 요청과 실제 선택 과정은 additive selection에서 확인합니다.

const diagnostics = await editor.getRendererDiagnostics(0);
console.log(diagnostics.schemaVersion, diagnostics.effectiveBackend);

editor.getFontDecisionTrace(page?, options?)

문자가 document face에서 layout metric과 backend paint 후보까지 도달한 계보를 반환합니다. page는 0부터 시작하고 maxCharacters는 1..4096만 허용합니다. 기본값은 1024이며, 상한에 도달하면 조용히 자르지 않고 status: 'truncated', recordsOmitted와 reason을 반환합니다. Studio가 font-decision-trace-v1 capability를 제공하지 않거나 입력이 범위를 벗어나면 명시적으로 실패합니다.

const trace = await editor.getFontDecisionTrace(0, { maxCharacters: 256 });
console.log(trace.schemaVersion, trace.status, trace.layoutHash.value);
for (const record of trace.records) {
  console.log(
    record.source.character,
    record.document.face,
    record.layoutMetric.widthSource,
    record.paint.canvas2d.certainty,
    record.paint.canvaskit.certainty,
  );
}

layoutHash는 backend 환경과 무관한 portable layout 계보를, normalizedHash는 현재 backend capability snapshot까지 포함한 결과를 고정합니다. Canvas2D가 실제 glyph face를 공개하지 않으면 CSS chain만 기록하고 certainty: 'notObserved'로 남깁니다. trace는 font 선택 authority나 fallback 교정 API가 아닙니다.

editor.exportHwp()

현재 편집 중인 문서를 HWP 바이너리로 내보냅니다.

const bytes = await editor.exportHwp();
const blob = new Blob([bytes], { type: 'application/x-hwp' });

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.hwp';
a.click();
URL.revokeObjectURL(url);

editor.exportHwpx()

현재 편집 중인 문서를 HWPX(ZIP+XML) 바이너리로 내보냅니다.

const bytes = await editor.exportHwpx();
const blob = new Blob([bytes], { type: 'application/vnd.hancom.hwpx' });

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.hwpx';
a.click();
URL.revokeObjectURL(url);

editor.exportHwpVerify()

HWP 직렬화 + 자기 재로드 검증 메타데이터를 반환합니다 (#178). 검증 메타데이터만 반환하며, 실제 HWP bytes 가 필요하면 exportHwp() 를 별도 호출하세요.

const verify = await editor.exportHwpVerify();
// {
//   bytesLen: 678912,
//   pageCountBefore: 9,
//   pageCountAfter: 9,
//   recovered: true
// }
if (!verify.recovered || verify.pageCountBefore !== verify.pageCountAfter) {
  console.warn('HWP 직렬화 검증 실패', verify);
}

editor.exportHml()

현재 편집 중인 문서를 HML(XML) 바이너리로 내보냅니다.

const bytes = await editor.exportHml();
const blob = new Blob([bytes], { type: 'application/xml' });

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.hml';
a.click();
URL.revokeObjectURL(url);

editor.getHmlSaveState()

현재 문서의 HML 저장 가능 여부와 blocker 목록을 반환합니다. 저장 가능 여부는 hmlSavable로 판정하고, 실패 원인은 blockers 배열로 표시하세요. exportHml()의 오류 문자열을 파싱하지 마세요.

const state = await editor.getHmlSaveState();
// {
//   sourceFormat: 'hwp',
//   hmlSavable: false,
//   blockers: [
//     {
//       code: 'HML_SOURCE_REQUIRED',
//       xmlPath: '/HWPML',
//       message: 'HML source metadata is required',
//       preserved: false
//     }
//   ]
// }

if (state.hmlSavable) {
  const bytes = await editor.exportHml();
  // ... 저장 진행
} else {
  for (const item of state.blockers) {
    console.warn(`HML 저장 불가 [${item.code}] ${item.xmlPath} — ${item.message}`);
  }
}

반환값:

| 필드 | 타입 | 설명 | |------|------|------| | sourceFormat | string | 현재 문서의 원본 형식 — 'hwp', 'hwpx', 'hml' | | hmlSavable | boolean | HML로 저장 가능하면 true | | blockers | HmlSaveBlocker[] | 저장을 막는 요소 목록. hmlSavable이 true이면 빈 배열 |

HmlSaveBlocker:

| 필드 | 타입 | 설명 | |------|------|------| | code | string | blocker 종류 코드 | | xmlPath | string | 해당 요소의 XML 경로 | | message | string | 사람이 읽을 수 있는 사유 | | preserved | false | 항상 false — 해당 요소가 HML로 보존되지 않음을 뜻함 |

editor.notifySaved(fileName?)

내보내기 바이트의 영속화(서버 업로드 또는 호스트 핸드오프) 완료를 스튜디오에 통지합니다 (#2660). 통지 시 스튜디오는 미저장(dirty) 상태를 해제하고 자동복구 draft(IndexedDB)를 삭제합니다. draft 삭제가 완료된 뒤 resolve되므로, resolve 이후 창을 닫아도 안전합니다.

const bytes = await editor.exportHwp();
await uploadToServer(bytes);        // 호스트 저장
await editor.notifySaved();         // 저장 완료 통지 — dirty 해제 + 복구 draft 삭제
  • fileName (선택): 호스트가 저장에 사용한 파일 이름. 전달하면 스튜디오의 현재 파일 이름이 갱신됩니다.
  • 반환: { ok: true, wasDirty: boolean } — wasDirty는 통지 시점에 미저장 변경이 있었는지 여부(멱등 호출 관찰용).
  • 스튜디오가 notify-saved-v1 capability를 광고하지 않으면(구버전 스튜디오 또는 legacy 폴백 연결) 요청을 보내지 않고 예외를 던집니다.

editor.destroy()

에디터를 제거합니다.

editor.destroy();

저장 계약 — 내보내기와 저장 완료 통지

exportHwp()/exportHwpx()/exportHml()은 직렬화 바이트만 반환하며 문서를 "저장됨"으로 표시하지 않습니다. 호스트 저장(업로드)이 실패할 수 있으므로, 스튜디오는 호스트가 notifySaved()로 확정하기 전까지 자동복구 draft를 보존합니다. 통지 없이 종료하면 다음 실행 시 "문서 복구" 안내가 표시됩니다.

iframe 임베드 (업로드 확정 후 통지):

const bytes = await editor.exportHwp();
try {
  await uploadToServer(bytes);
  await editor.notifySaved();       // 업로드 "성공 시에만" 호출
} catch (error) {
  // 통지하지 않음 — 복구 draft가 보존되어 재시도/복구 가능
}

팝업 통합 (핸드오프 즉시 통지 후 닫기):

스튜디오를 window.open으로 띄우고 window.opener.postMessage로 바이트를 넘기는 통합에서는, 핸드오프 시점에 통지하고 닫습니다. 바이트를 수신한 호스트가 이후 영속화(재시도 포함)를 책임집니다.

window.opener?.postMessage(
  { action: 'documentExported', content: base64, format: 'hwp' },
  HOST_ORIGIN,                       // '*' 대신 반드시 명시적 오리진 사용 (문서 유출 방지)
);
await editor.notifySaved();          // draft 삭제 완료까지 대기
window.close();

SDK 없이 스튜디오 페이지 안에서 직접 통합(포크/주입)하는 경우에는 같은 동작의 window.rhwpStudio.notifySaved(fileName?)를 사용할 수 있습니다.

디버깅 도구 — rhwpDev

iframe 안의 rhwp-studio에는 개발 모드 전용 디버깅 헬퍼 rhwpDev가 내장되어 있습니다. 검색, 커서 이동, 문단 ID 점검 등을 콘솔에서 직접 호출할 수 있습니다.

접근 방법

rhwpDev는 iframe 내부 window에 등록됩니다. 브라우저 DevTools의 콘솔 컨텍스트를 iframe으로 전환한 후 호출하세요.

Chrome / Edge: DevTools 콘솔 좌측 상단의 컨텍스트 드롭다운(top ▾)에서 rhwp-studio iframe 선택

Firefox: 콘솔 우측 상단의 iframe 버튼 → iframe URL 선택

// iframe 컨텍스트로 전환 후
rhwpDev.help();   // 사용법 안내

주의: rhwp-studio가 DEV 모드(vite dev server)로 빌드된 경우에만 rhwpDev가 등록됩니다. 프로덕션 빌드(기본 호스팅 URL https://edwardkim.github.io/rhwp/)에는 포함되지 않습니다. 디버깅 도구가 필요하면 셀프 호스팅 환경에서 vite dev 모드로 실행하세요.

주요 메서드

rhwpDev.search(text, includeCells?)

문서 영역에서 모든 매치를 일괄 검색합니다. 반환: SearchHit[]

const hits = rhwpDev.search("사업계획");
// → 9 match(es), console.table 자동 표시
//
// [{sec: 0, para: 2, charOffset: 0, length: 13}, ...]

// 표 셀/글상자 내부 포함
const allHits = rhwpDev.search("사업계획", true);

rhwpDev.goto(hit, options?)

SearchHit으로 커서를 이동하고 화면을 스크롤합니다. 반환: boolean

const hits = rhwpDev.search("사업계획");

// 3번째 매치로 이동 + 선택 (인덱스 2)
rhwpDev.goto(hits[2]);

// 캐럿만 이동 (선택 없음)
rhwpDev.goto(hits[2], { select: false });

// 한 줄 패턴
rhwpDev.goto(rhwpDev.search("text")[0]);

rhwpDev.showAllIds(pageNum?)

페이지의 모든 문단 ID를 console.table로 표시합니다.

rhwpDev.showAllIds(0);    // 첫 페이지만
rhwpDev.showAllIds();     // 전체 페이지

rhwpDev.findNearest(targetId, pageNum?)

가장 가까운 paragraph 인덱스를 검색합니다.

rhwpDev.findNearest(618);
// → { paraIdx: 0, distance: 618, text: "...", container: "cell[p0,c2,i0]" }

rhwpDev.help()

전체 사용법과 예시를 콘솔에 출력합니다.

SearchHit 구조

interface SearchHit {
  sec: number;          // 구역 인덱스
  para: number;         // 본문: 문단 인덱스 / 셀: parentPara
  charOffset: number;   // 문단 내 글자 오프셋
  length: number;       // 매치 길이
  cellContext?: {       // 셀/글상자 매치 시
    parentPara: number;
    ctrlIdx: number;
    cellIdx: number;
    cellPara: number;
  };
}

활용 예시 — 매치 일괄 강조

// 모든 "회사" 매치를 순차적으로 보여주기
const hits = rhwpDev.search("회사");
let i = 0;
setInterval(() => {
  if (i >= hits.length) return;
  rhwpDev.goto(hits[i++]);
}, 1500);

폰트 안내

기본 동작 — 별도 설정 없이 사용 가능

@rhwp/editor가 기본으로 연결하는 rhwp-studio 배포본은 오픈소스 폰트를 포함하므로 별도 폰트 설정 없이 바로 사용할 수 있습니다. @rhwp/editor 패키지 자체에는 폰트 파일이나 UI runtime dependency가 포함되지 않습니다.

HWP 문서에서 사용된 한컴 전용 폰트(한컴바탕, HY명조 등)는 자동으로 오픈소스 폰트로 폴백됩니다.

내장 폴백 폰트

| HWP 원본 폰트 | 자동 폴백 | |--------------|----------| | 한컴바탕, HY명조, 바탕, 궁서 | Noto Serif KR → 나눔명조 → serif | | 한컴돋움, HY고딕, 돋움, 굴림 | Noto Sans KR → 나눔고딕 → sans-serif | | 함초롬바탕 | Noto Serif KR → 나눔명조 → serif | | 함초롬돋움, 맑은 고딕 | Pretendard → Noto Sans KR → sans-serif | | Arial, Calibri, Verdana | Pretendard → sans-serif | | Times New Roman | Noto Serif KR → serif | | Courier New | D2Coding → monospace |

폰트 품질

  • 내장 폰트만으로 대부분의 HWP 문서를 원본에 가깝게 렌더링할 수 있습니다
  • 글자 간격이 원본과 미세하게 다를 수 있으나, 문서 내용 열람에는 지장이 없습니다
  • 한컴 전용 폰트가 설치된 PC에서는 원본과 동일하게 표시됩니다

셀프 호스팅 시 폰트

저장소의 canonical source는 assets/fonts/이고, rhwp-studio build는 이를 배포본의 runtime fonts/ 경로로 노출합니다. 셀프 호스팅 서버에서는 이 runtime 경로가 함께 배포되므로 별도 설정 없이 오픈소스 폰트를 사용합니다. 추가 폰트는 assets/fonts/에 WOFF2를 추가하고 rhwp-studio/src/core/font-loader.ts에 @font-face와 로딩 정책을 등록해야 합니다.

셀프 호스팅

기본적으로 https://edwardkim.github.io/rhwp/에 호스팅된 에디터를 사용합니다. 자체 서버에서 호스팅하려면:

# rhwp-studio 빌드
cd rhwp-studio
npm install
npx vite build --base=/your-path/

# 빌드 결과물(dist/)을 서버에 배포

외부(CDN) 웹폰트를 사용할 수 없는 환경 — 함초롬체 CDN은 비상업적 사용 조건이므로 상업 환경, 또는 오프라인/폐쇄망 — 에서는 빌드 시점 스위치로 CDN 로드를 끕니다. 조판(줄바꿈·페이지 분할)은 내장 폰트 메트릭 기준이라 변하지 않고, 화면 표시만 번들/시스템 글꼴로 대체됩니다:

RHWP_DISABLE_EXTERNAL_WEBFONTS=1 npx vite build --base=/your-path/

브라우저 확장 storage에 저장된 disableExternalWebFonts 설정이 있으면 그 값이 빌드 스위치보다 우선합니다.

const editor = await createEditor('#editor', {
  studioUrl: 'https://your-domain.com/your-path/'
});

패키지 비교

| 패키지 | 용도 | |--------|------| | @rhwp/core | WASM 파서/렌더러 (직접 API 호출) | | @rhwp/editor | 완전한 에디터 UI (iframe 임베드) |

  • 뷰어만 필요하면 → @rhwp/core
  • 편집 기능이 필요하면 → @rhwp/editor

Third-Party Licenses

이 패키지는 iframe을 통해 rhwp-studio를 임베드하며, 내부적으로 @rhwp/core WASM 엔진을 사용합니다.

Rust 크레이트 (WASM 엔진)

| 크레이트 | 라이선스 | |---------|---------| | wasm-bindgen / web-sys / js-sys | MIT OR Apache-2.0 | | quick-xml | MIT | | cfb | MIT | | flate2 | MIT OR Apache-2.0 | | encoding_rs | (Apache-2.0 OR MIT) AND BSD-3-Clause | | usvg / svg2pdf | Apache-2.0 OR MIT | | pdf-writer | MIT OR Apache-2.0 | | unicode-segmentation / unicode-width | MIT OR Apache-2.0 | | image | MIT OR Apache-2.0 |

내장 웹 폰트

| 폰트 | 라이선스 | |------|---------| | Pretendard (Regular, Bold) | SIL Open Font License 1.1 | | Noto Sans KR (Regular, Bold) | SIL Open Font License 1.1 | | Noto Serif KR (Regular, Bold) | SIL Open Font License 1.1 | | 나눔고딕 | SIL Open Font License 1.1 | | 나눔명조 | SIL Open Font License 1.1 | | 고운바탕 | SIL Open Font License 1.1 | | 고운돋움 | SIL Open Font License 1.1 | | D2Coding | SIL Open Font License 1.1 |

프론트엔드

| 패키지 | 라이선스 | |--------|---------| | TypeScript | Apache-2.0 | | Vite | MIT |

전체 목록: THIRD_PARTY_LICENSES.md

모든 의존성은 MIT 라이선스와 호환됩니다.

Notice

본 제품은 한글과컴퓨터의 한글 문서 파일(.hwp) 공개 문서를 참고하여 개발하였습니다.

Trademark

"한글", "한컴", "HWP", "HWPX"는 주식회사 한글과컴퓨터의 등록 상표입니다. 본 패키지는 한글과컴퓨터와 제휴, 후원, 승인 관계가 없는 독립적인 오픈소스 프로젝트입니다.

License

MIT