neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
翻譯準備中
在瀏覽器中開啟 .docx 檔案,呈現與 Word 相符的版面。根據未見過文件的凍結盲測試,以像素比對 Microsoft Word(SSIM 0.80 日文 / 0.90 英文)。開源,Rust。
AI 翻譯
Open .docx files in the browser with Word-faithful layout. Pixel-measured against Microsoft Word on frozen blind benchmarks of never-seen documents (SSIM 0.80 Japanese / 0.90 English). Open source, Ru
開發工具Python · RustGitHub @Ryujiyasu上線中營運者未確認
試用過了嗎? 點一下就好,不需要登入。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證在瀏覽器中開啟 .docx 檔案,呈現與 Word 相符的版面。以像素為單位對 Microsoft Word 進行凍結盲測,測試從未見過的文件(SSIM 0.80 日文 / 0.90 英文)。開源,使用 Rust + WebAssembly,100% 客戶端。
AI 翻譯
Open .docx files in the browser with Word-faithful layout. Pixel-measured against Microsoft Word on frozen blind benchmarks of never-seen documents (SSIM 0.80 Japanese / 0.90 English). Open source, Rust + WebAssembly, 100% client-side.
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A browser-native Office document engine — Rust + WebAssembly, no server.
Word (.docx) layout is scored against Microsoft Word page by page, PowerPoint (.pptx) against PowerPoint slide by slide, on frozen blind benchmarks of documents the engine has never been tuned against — and Excel (.xlsx) ships a formula engine and a browser VBA host verified against Excel itself.
Canonical repository: GitHub — Ryujiyasu/oxi (issues, pull requests, CI, releases).
The GitLab repository receives main from GitHub and exists to run the Pages job that serves the live demo.檢視完整 README ↗Oxi = Opensource Xplatform Interoperability
A browser-native Office document engine — Rust + WebAssembly, no server. Word (.docx) layout is scored against Microsoft Word page by page, PowerPoint (.pptx) against PowerPoint slide by slide, on frozen blind benchmarks of documents the engine has never been tuned against — and Excel (.xlsx) ships a formula engine and a browser VBA host verified against Excel itself.
Live Demo · Layout Accuracy · Contributing
Canonical repository: GitHub — Ryujiyasu/oxi (issues, pull requests, CI, releases). The GitLab repository receives
mainfrom GitHub and exists to run the Pages job that serves the live demo.
Three editors over one engine, recorded from the assembled desktop build — the same files the installer ships. Nothing is staged: each clip opens a real file and the numbers on screen are the engine's own.
Oxidocs — .docx
Oxicells — .xlsx
Oxislides — .pptx
Europe is actively dismantling its Microsoft Office dependency in 2026:
Every one of these transitions is missing the same piece: a rendering engine that opens existing .docx files identically to Microsoft Word, so that "migration" stops being a project and becomes indistinguishable from switching applications. LibreOffice's long struggle in public-sector rollouts is well documented — not because its features are weak, but because per-document visual divergence forces every organization into a per-file audit it cannot staff.
Oxi's answer is a measurement loop, not a promise: Word is the ground truth, the gate is external, and the headline numbers come from documents the engine has never been allowed to fix.
An accuracy number is only as honest as the corpus it comes from. Oxi's documents are split into three roles, per language, and only one of them is allowed to be a headline:
| Role | What it is | May be a fix target? |
|---|---|---|
| dev | The tuned corpus: 96 documents under per-paragraph pagination gates + a 369-document (1113-page) pixel-SSIM sentinel + synthetic probes, plus every blind set retired by rotation | Yes — this is where bugs are root-caused |
| validation | Previously blind sets, demoted after rotation | Yes, after demotion |
| blind | 50 documents per language, frozen before measurement, never anatomized; re-measured per binary revision, not tuned against | No |
The blind sets are drawn from the public superdoc-dev/docx-corpus (ODC-BY, 736K real .docx from Common Crawl) by a deterministic rule declared before fetching: 10 document types × the next 5 documents in SHA-256-ascending manifest order, with a purely mechanical quarantine (valid zip, has word/document.xml, no macros, ≤ 4 MB). No quality-based selection, no post-hoc swaps. When a newer blind set is frozen, the old one is demoted to validation and only then becomes fixable.
Everything below is measured against Microsoft Word's own render of the same file (Microsoft 365 16.0.20430.20182, 150 DPI, resize-to-match, structural similarity; one fresh Word process per document). Nobody grades their own homework.
One measurement note, because it would otherwise flatter a competitor: OfficeCLI is measured with --render html, its own layout engine. Its default --render auto is documented as "native on Windows w/ Word", and on a host with Word installed that path hands the rendering to Word itself — 0.996 SSIM against Word, because it is Word. Its own engine scores 0.972 on that same page. Only the second is a comparison.
Frozen 2026-10-25 (pipeline_data/FROZEN_BLIND_I.md) as the next unclaimed SHA-256 ranks per type, before any measurement. Every engine renders the same 50 documents; where one produced nothing for a document, its row says how many it managed. Word opened and exported all 100 documents of the two sets, so no quarantine replacement was needed this time.
Why a new set. Blind-H (2026-10-02) was spent the day its numbers were written down and has since been a fix target, so it can no longer say how the engine generalizes. The sets are different documents and are not comparable: Oxi scored 0.874 on H50 and 0.903 here.
Every engine is at its latest public release on the measurement day (2026-10-25): LibreOffice and ONLYOFFICE installed fresh, the npm-distributed engines at @latest, GenOffice pulled to its newest commit, and two engines that appeared since the last rotation added — WordCraft and ibisOffice, both exporting a PDF from their own command line.
| Engine | mean SSIM (common pages) | penalized | page count matches Word | documents scored |
|---|---|---|---|---|
| ONLYOFFICE 10.0.0 | 0.909 | 0.888 | 42 / 50 | 49 |
| Oxi 0.8.9 | 0.903 | 0.883 | 47 / 50 | 50 |
| WordCraft 0.10.0 | 0.885 | 0.857 | 41 / 50 | 50 |
| LibreOffice 26.8.1.1 | 0.864 | 0.828 | 39 / 50 | 50 |
| SILURUS @silurus/ooxml 0.89.4 | 0.842 | 0.806 | 41 / 50 | 50 |
| Polaris Office 11.115 | 0.830 | 0.813 | 35 / 50 | 44 |
| GenOffice 28cee5ca | 0.815 | 0.747 | 35 / 50 | 49 |
| ibisOffice 0.8.4 | 0.783 | 0.706 | 33 / 50 | 50 |
OfficeCLI 1.0.158 (--render html) | 0.770 | 0.443 | 14 / 50 | 50 |
| BetterOffice @betteroffice/docx 0.4.3 | 0.767 | 0.636 | 26 / 50 | 50 |
| eigenpal @eigenpal/docx-editor-react 1.9.0 | 0.756 | 0.704 | 33 / 50 | 50 |
Oxi is second in English, 0.006 behind ONLYOFFICE — inside the ±0.02 one sample carries — and places page breaks best (47 / 50). The mean hides a split worth stating: document by document, ONLYOFFICE is closer to Word on 37 of 50 and WordCraft on 34 of 50, while Oxi beats LibreOffice on 30 of 50. Oxi's mean holds up because its bad documents are less bad, not because it wins the typical one. The worst Oxi document is at 0.542 — a defect, since ONLYOFFICE scores it 0.924.
Frozen 2026-10-25 by the same rule, before any measurement. The Japanese technical type is exhausted in the public manifest, so its five slots were filled by the pre-declared top-up rule (the next unclaimed entries across the other types in SHA order — all five came from forms).
| Engine | mean SSIM (common pages) | penalized | page count matches Word | documents scored |
|---|---|---|---|---|
| Oxi 0.8.9 | 0.905 | 0.899 | 47 / 50 | 50 |
| Polaris Office 11.115 | 0.848 | 0.826 | 46 / 50 | 50 |
| LibreOffice 26.8.1.1 | 0.831 | 0.789 | 41 / 50 | 50 |
| WordCraft 0.10.0 | 0.827 | 0.749 | 37 / 50 | 50 |
| GenOffice 28cee5ca | 0.825 | 0.737 | 34 / 50 | 50 |
| SILURUS @silurus/ooxml 0.89.4 | 0.821 | 0.719 | 31 / 50 | 48 |
| ibisOffice 0.8.4 | 0.819 | 0.776 | 41 / 50 | 50 |
OfficeCLI 1.0.158 (--render html) | 0.810 | 0.629 | 32 / 50 | 50 |
| ONLYOFFICE 10.0.0 | 0.790 | 0.734 | 38 / 50 | 50 |
| BetterOffice @betteroffice/docx 0.4.3 | 0.785 | 0.675 | 34 / 50 | 50 |
| eigenpal @eigenpal/docx-editor-react 1.9.0 | 0.768 | 0.694 | 36 / 50 | 50 |
Oxi is first in Japanese by 0.057 over Polaris Office and 0.074 over LibreOffice, closer to Word than Polaris Office on 40 of 50 documents, than LibreOffice on 43, than WordCraft on 43 and than ONLYOFFICE on 48. Polaris Office comes within one document of Oxi on Japanese page breaks (46 / 50 against 47). The worst document (0.670) is hard for every engine — the others score it between 0.58 and 0.71, BetterOffice the one engine above Oxi on it.
Rankings do not transfer between languages. ONLYOFFICE is first in English and ninth in Japanese; Oxi is second in English and first in Japanese. That is the whole reason for keeping a blind set per language, and for keeping both numbers on this page rather than the flattering one.
Every engine was measured against the same Word ground truth (Microsoft 365 16.0.20430.20182, 150 DPI). Versions are recorded in _engine_versions_blindI50.json beside each result. Three measurement notes, each written down before any number was compared: (1) GenOffice's newest build hands its renderer the file as a one-shot URL instead of bytes; the harness first fed it bytes, every document opened as a blank page, and that run was discarded and redone — the numbers above are the redone run. (2) OfficeCLI's low page-count match is its own pagination: the harness takes the page count from OfficeCLI's own view and captures every page it reports. (3) Polaris Office has no command line, so its export is driven through its own window; the first run timed out on every document (the save dialog had moved and a leftover window took the next document's keystrokes), the driver was fixed before any Polaris number was read, and the six English documents Polaris still would not export on two attempts are counted as not rendered.
Three independently frozen Japanese blind sets, each measured once against the binary of its day:
| Japanese blind set | Oxi mean SSIM | page count matches Word |
|---|---|---|
| blind-B50 (ranks 11-15, 2026-08-31) | 0.842 | 45 / 50 |
| blind-C50 (ranks 16-20, 2026-08-31) | 0.802 | 35 / 50 |
| blind-D50 (ranks 21-25, 2026-09-11) | 0.802 | 40 / 50 |
| blind-H50 (next unclaimed ranks, 2026-10-02) | 0.857 | 41 / 50 |
| blind-I50 (next unclaimed ranks, 2026-10-25) | 0.905 | 47 / 50 |
B50 and C50 were measured the same day on the same binary, so the 0.040 between them is set difficulty and nothing else. Roughly a quarter of that is a known defect — 19 of the 50 blind-C documents contain an anchored floating text box whose text Oxi drops, and those documents average 0.06-0.10 lower than the rest — and the remainder is simply that one sample of fifty wild documents is harder than another. A single blind number carries about ±0.02, and a page-count rate can move 90% → 70% between samples.
D50, cut eleven days and one engine revision later, landed on 0.802 again. Two independent samples agreeing to four decimal places is the strongest evidence on this page that the Japanese number is a property of the engine rather than of the corpus.
H50, three weeks and one engine generation later, is the first Japanese set to leave 0.80: 0.857. Two rotations (E, F, G) of pagination-only blind measurement were tuned against in between, so that step is engine, not sampling — but it is one sample, and the ±0.02 above still applies to it.
I50, three weeks and 219 commits later (145 of them layout fixes derived from Word measurements), is the first to pass 0.90: 0.905, with page breaks matching Word on 47 of 50. Again one sample, and the ±0.02 above applies.
The English sets moved too — 0.903 on C50, 0.837 on D50, 0.874 on H50, 0.903 on I50 — but C50 had been rotated into the development corpus by then, so set difficulty and tuning cannot be separated there and the C50 English number is retired rather than quoted.
Two honest caveats about the two engine tables together: (1) the English and Japanese sets are different documents, so the numbers are not comparable across languages — each is only comparable within its table; (2) engine rankings do not transfer between corpora (ONLYOFFICE leads English and comes ninth in Japanese), which is exactly why blind sets per language exist.
What the differences look like: the same Japanese government research-application form (rotated table-cell labels), rendered by Word, Oxi, LibreOffice and @silurus/ooxml. This document is from the development corpus and is shown for illustration only — the numbers above come from the blind sets.
The same measurement discipline, applied to real-world .pptx files. 50 files are sampled at random (seed 20260809) from noxneural/pptx_collection_templates before any measurement, and each is scored against Microsoft PowerPoint's own render (Microsoft 365 16.0.20131.20154, 150 DPI, resize-to-match, structural similarity — the same pipeline as the Word tables above).
| Engine | mean SSIM vs PowerPoint (per doc) | page count matches PowerPoint |
|---|---|---|
| Oxi (2026-08-20, re-measured) | 0.953 | 48 / 48 |
| LibreOffice 26.2.1.2 | 0.913 | 48 / 48 |
| ONLYOFFICE 9.3.1.8 | 0.908 | 48 / 48 |
Two of the 50 sampled files (corrupt zip containers, unopenable by every engine — PowerPoint COM, LibreOffice, ONLYOFFICE's x2t and Oxi all reject them) are excluded, leaving 48 measured documents — every engine matches PowerPoint's slide count on all 48. Oxi now leads both suites on this frozen set (paired difference vs LibreOffice +0.040 ± 0.005, |t| = 8.7, ahead on 44 of the 48 documents; LibreOffice and ONLYOFFICE remain statistically tied with each other). The set was first measured at 0.679 (2026-08-13, the renderer's first PPTX measurement) — the week of renderer work since (slide-master placeholder inheritance, group transforms under mirroring, embedded fonts, color emoji, mixed-face line boxes) moved it to 0.953, with every one of the 48 documents improving and none regressing; the worst document now scores 0.880. As with the Word tables, the set is frozen, never anatomized, and re-measured as the engine improves. One operational note: ONLYOFFICE's x2t emits unusually large intermediate PDFs (up to 65 MB for a single deck), which dominates its pipeline cost. Per-document scores, the paired statistics and the full method: docs/benchmarks/pptx-hf50.md; raw scores as JSON: docs/benchmarks/pptx-hf50-results.json.
The blind sets are the published claim; the development corpus is how regressions are caught before a change is committed. Every layout change must pass, in order:
tools/measure_vba_*_com.ps1).cargo test.These numbers are tuned — every document in them has been individually root-caused — so they belong in a gate, not in a headline. The date-by-date development history is in docs/layout_accuracy.md; the derivation log is RESEARCH_LOG.md.
When Word saves a .docx it writes <w:lastRenderedPageBreak/> wherever its own render started a new page. That marker is part of the answer every number on this page is scored against, and Oxi's parser reads it by default: several layout rules use it as a hint. The blind-set numbers above were measured that way. Whether the other engines in the tables read the marker has not been checked, so the page-count column may favour Oxi.
From now on the benchmarks run blind: OXI_IGNORE_LRPB=1 makes the parser drop the marker, so no layout rule can see it, and tools/metrics/bench_env.py sets it for benchmark scripts unless OXI_BENCH_WITH_LRPB=1 asks for the hinted mode. Re-measured blind (2026-10-28). The published blind-I numbers were re-run with the frozen engine (77605bde) on copies of the same 100 documents with every <w:lastRenderedPageBreak/> removed, against the same Word PDFs:
| with the marker (published) | blind | |
|---|---|---|
| EN mean SSIM / penalized / page count | 0.9028 / 0.8829 / 47 of 50 | 0.9031 / 0.8831 / 47 of 50 |
| JA mean SSIM / penalized / page count | 0.9050 / 0.8985 / 47 of 50 | 0.9050 / 0.8985 / 47 of 50 |
The tables above stand: the marker did not contribute to them. The current engine also scores identically in both modes on blind-I. Benchmarks keep running blind by default regardless.
The same marker also makes a Word-free pagination check that anyone can run on their own files. tools/oxi-lrpb-bench derives the page every paragraph and table row starts on from the markers, checks that derivation against the page count Word wrote in docProps/app.xml, then scores Oxi blind and hinted:
cd tools/oxi-lrpb-bench && cargo build --release
./target/release/oxi-lrpb-bench <file.docx | folder>... [--json out.json]
First run, on the Word-saved files of docling's public tests/data/docx (2026-10-28; English only, so a smoke test rather than a claim):
| blind | hinted | |
|---|---|---|
| paragraphs and table rows on Word's page | 286 / 304 | 286 / 304 |
| page count matches Word | 8 / 10 | 8 / 10 |
| Word's page breaks placed at the same spot | 16 / 17 |
The derived page counts matched docProps/app.xml on all 10 files. The marker cannot replace Oxi: it gives a page number but no position on the page, files saved by anything other than Word do not carry it, and it goes stale as soon as the document is edited.
tools/metrics/fetch_docx_corpus.py # fetch the public corpus (deterministic, SHA-ordered)
tools/metrics/ssim_now.py # Oxi absolute SSIM re-measure vs stored Word renders
tools/metrics/ssim_ab.py <VAR> # A/B a single rule against the whole corpus
tools/metrics/render_libra.py # LibreOffice headless → PDF → PNG
tools/metrics/render_onlyoffice.py # ONLYOFFICE x2t headless → PDF → PNG
tools/metrics/browser_oracle.py # @silurus/ooxml via Playwright (tools/browser-oracle/)
tools/metrics/compare_renderers_3way.py # cross-renderer scoring on identical inputs
tools/oxi-lrpb-bench # Word-free page-break check against Word's saved markers
Oxi's rendering engine was built without any disassembly, decompilation, or binary analysis of proprietary software. All layout specifications come from two sources only:
AI (Claude) was used throughout specification derivation — root-cause analysis, COM measurement, pattern confirmation, fix implementation — with every specification decision grounded in measured values and confirmed by human review. Under Microsoft's Open Specification Promise, no patents are asserted against implementations of the OOXML specification.
Word's layout is built on GDI, which rounds character widths to integer pixels and computes line heights by rounding ascent and descent separately before adding them. These roundings cascade: a 0.18pt/character difference at Calibri 11pt becomes 10.8pt of accumulated error over 60 characters — enough to change where lines break and pages split. Reproducing Word therefore requires reproducing GDI exactly; for formats without a GDI heritage, it requires not inheriting those constraints.
| Format | Engine | Reason |
|---|---|---|
| .docx (Word compatible) | GDI | Word uses GDI text metrics — integer-pixel rounding, tmHeight line heights, hinting-dependent widths |
| .odt / .pdf | DirectWrite | ODF has no single canonical engine; DirectWrite's floating-point metrics give cross-platform consistency, variable-font and modern OpenType support, without GDI's legacy rounding |
Both engines implement a shared FontEngine trait, so the layout engine switches with a one-line configuration change per document.
Oxi bundles no proprietary fonts. Open-licensed fonts are metric-matched to their Microsoft counterparts (advance width, line height, kerning — verified by automated tests). For documents authored with Microsoft Fonts, a font divergence score — a per-glyph pixel-diff table generated once on a licensed system, combined with the document's character frequency — quantifies visual fidelity without shipping proprietary fonts at runtime.
Tested against 504 real-world government documents (Japanese ministries) + generated files:
| Oxi | LibreOffice | |
|---|---|---|
| Overall | 100.0% | 99.2% |
| DOCX | 100.0% | 100.0% |
| XLSX | 100.0% | 98.6% |
| PPTX | 100.0% | 100.0% |
LibreOffice timed out (>45s) on 4 large government xlsx files. Oxi parsed all instantly.
Most Word-compatible renderers treat Japanese layout as an afterthought. For Oxi it is a measured target:
| Solution | Approach | Limitation |
|---|---|---|
| LibreOffice / Collabora Online | C++ server-side rendering | Requires server infrastructure. No pixel-fidelity goal against Word |
| ZetaOffice | LibreOffice compiled to WASM | 100MB+ download. Layout accuracy = LibreOffice quality. Not a rewrite, just a port |
| ONLYOFFICE | JavaScript canvas rendering | Strong Word fidelity, but AGPL — not embeddable in proprietary products — and server-oriented |
| @silurus/ooxml | Rust/WASM + canvas | Same stack as Oxi, but a self-referential Canvas2D oracle — no external Word ground truth (measured above) |
| Apryse (PDFTron) | C++ → WASM viewer | Proprietary. Converts to internal format — not native OOXML rendering |
| Google Docs | Server-rendered | Proprietary. Requires server. Intentionally diverges from Word layout |
| docx-rs / rdocx | Rust DOCX libraries | Read/write and export only — no layout engine for browser rendering |
Oxi's unique combination: OSS (MPL-2.0 core + permissive bindings — embeddable in proprietary products, unlike AGPL) + Rust/WASM client-side + a format-agnostic IR (no proprietary "Oxi format") + externally-gated Word fidelity + zero server cost. No other project occupies this intersection.
The comparative claims are measured, not asserted — see the blind-set tables above, where ONLYOFFICE still beats Oxi on English pixel similarity and LibreOffice is a statistical tie there (Oxi leads both on English page-count accuracy, and leads outright on the Japanese and PowerPoint sets).
LibreOffice treats ODF as native and OOXML as an import (round-trip degrades). Microsoft Word inverts that. Oxi's IR is format-agnostic from the start — neither format owns it, so neither degrades on round-trip.
Beyond .docx rendering (the core mission), Oxi also ships:
These share the IR and the font engines, but they are not where Oxi's measured differentiation lives — the rendering fidelity above is.
crates/
oxidocs-common/ Shared OOXML utilities (ZIP, XML, relationships)
oxidocs-core/ .docx engine — parser, IR, layout, font metrics, editor
oxicells-core/ .xlsx engine — parser, IR, editor
oxislides-core/ .pptx engine — parser, IR, editor
oxipdf-core/ PDF 1.7 engine — parser, text extraction, generator
oxihanko/ Japanese digital stamp (hanko) generator + PAdES signer
oxidocs-wasm/ WebAssembly bindings (wasm-bindgen)
web/ Web demo (vanilla JS + Canvas)
tools/
font-metrics-gen/ Standalone tool to extract font metrics from system fonts
font-glyph-diff-gen/ Per-glyph pixel-diff table for Microsoft Font divergence scoring
metrics/ Measurement, comparison and SSIM scripts
oxi-gdi-renderer/ Native GDI verification renderer
oxi-dwrite-renderer/ Native DirectWrite verification renderer
tests/fixtures/ Test .docx / .xlsx / .pptx files
The Intermediate Representation is language-agnostic and does not depend on Word/Excel/PowerPoint internals:
Document → Page → Block (Paragraph | Table | Image) → Run
All processing is exposed via wasm-bindgen and can be called directly from JavaScript:
import init, {
parse_document, // .docx → IR (JSON)
parse_spreadsheet, // .xlsx → IR (JSON)
parse_presentation, // .pptx → IR (JSON)
layout_document, // .docx → positioned layout with coordinates
edit_docx, // apply text edits → new .docx bytes
edit_xlsx, // apply cell edits → new .xlsx bytes
edit_pptx, // apply slide edits → new .pptx bytes
create_blank_docx, // generate empty .docx
parse_pdf, // PDF → structure (JSON)
pdf_extract_text, // PDF → plain text
create_pdf, // generate PDF from scratch
pdf_verify_signatures, // verify PDF signatures
generate_hanko_svg, // generate stamp SVG with custom config
preview_hanko, // quick stamp preview by name
} from "./oxidocs_wasm.js";
await init();
const bytes = new Uint8Array(await (await fetch("sample.docx")).arrayBuffer());
const layout = layout_document(bytes); // positioned elements for canvas rendering
npm install @oxidocs/wasm # the engine, for a browser
cargo install oxidocs-cli # the command-line tool
Or download a desktop installer for Windows, macOS or Linux from Releases. Installed apps update themselves from that feed.
The engine crates are on crates.io under the oxidocs- prefix: oxidocs (the
facade), oxidocs-core, oxicells-core, oxislides-core, oxipdf-core,
oxihanko, oxivba-core.
Prerequisites: Rust 1.93+ and wasm-pack 0.14+.
Build and test:
cargo build # Build all crates
cargo test # Run tests
cargo clippy # Lint
Build the wasm and serve the demo:
cd crates/oxidocs-wasm
wasm-pack build --target web # Build .wasm + JS bindings
cd ../../web
python3 -m http.server 8080 # Serve at http://localhost:8080
| Layer | Technology |
|---|---|
| Core engines | Rust (memory-safe, zero-cost abstractions) |
| XML parsing | quick-xml |
| ZIP handling | zip crate |
| Serialization | serde / serde_json |
| Browser bindings | wasm-bindgen + wasm-pack |
| Font metrics | Generated at build time from the local system fonts via tools/font-metrics-gen |
| Web demo | Vanilla JS + Canvas (no framework dependencies) |
Oxi treats every document as untrusted input. A hostile file can render wrong — it cannot run code, exfiltrate data, or escape the sandbox. See SECURITY.md for the reporting policy.
unsafe in the WASM-facing crates — memory safety end-to-end in the engine; platform unsafe exists only in the optional native GDI/DirectWrite verification renderersvbaProject.bin), OLE objects and embedded scripts are never executed; they are preserved as opaque bytes for round-trip. Field codes are never evaluated (only PAGE/NUMPAGES are computed, from the engine's own layout state)quick-xml; external entities and DTDs are never fetched or expandedThe version number is the mean pixel similarity to Word on the current frozen blind
sets, with every page Oxi gets wrong counted against it: 0.8.9 means that on the
never-seen English and Japanese benchmarks above, Oxi's documents average penalized SSIM
0.89 against Word's own render of the same files (0.883 and 0.899; a page Oxi adds or
drops scores zero; two-decimal truncation of the two-language mean). The number is
measured, not tuned — a blind set is spent once its number is written down and a new one
is frozen before the next release — and 1.0 is the project's stop condition rather than
its finish line. Per-release detail: CHANGELOG.md.
The measurement loop (deterministic reference output, falsifiable hypotheses, external merge gate, blind holdout) transfers to ODF unchanged — only the reference renderer changes.
Contributions are welcome. Oxi has a simple acceptance criterion:
Every merged PR must improve the pixel accuracy of at least one document — without regressing the gates.
Features that go beyond pixel-accurate rendering — collaboration, AI integration, purpose-specific workflows — belong in a separate extension or downstream project, not in Oxi core.
The desktop app is not one of those: oxi-desktop is the same engine in a window rather than a tab, so it ships in core under the same license as the rest of it.
git checkout -b feature/amazing-feature)cargo test && cargo clippy)git commit -s) — Oxi uses the Developer Certificate of Origin (DCO). No CLA, no copyright assignment: your code stays yoursSee CONTRIBUTING.md for details.
Oxi is licensed in three layers, chosen to maximize both adoption and the flow of improvements back into the canonical tree:
| Layer | License | Why |
|---|---|---|
Core engine (oxidocs, oxidocs-common, oxidocs-core, oxicells-core, oxislides-core, oxipdf-core, oxihanko, oxidocs-cli, oxi-desktop) | MPL-2.0 | File-level copyleft: modifications to engine files must be published, so layout-fidelity improvements converge into one tree. Embedding Oxi in proprietary or commercial products is fully permitted — only changes to Oxi's own files must be shared. Same license as LibreOffice and Firefox |
Bindings (oxidocs-wasm, oxidocs-python) | MIT OR Apache-2.0 | Standard Rust dual license — zero friction for embedding in any stack |
Conformance corpus (self-authored repro documents under tools/golden-test/repros/) | CC BY-SA 4.0 | The Word-compatibility test suite is a shared public asset; improvements to it must stay shared |
Contributions are accepted under the Developer Certificate of Origin (git commit -s). There is no CLA — contributors keep their copyright, and the project cannot relicense your work out from under you.
All third-party dependencies must be MPL-2.0-compatible (MIT, Apache-2.0, BSD, etc.).