Loss-aware by design
Content the semantic model does not yet represent is preserved and reproduced verbatim, or reported — never silently discarded.
OpenDoc is a deterministic, embeddable Word-document engine written in
Rust. It reads and writes .docx, holds the document in a
normalized editable model, and lays it out and renders it to pixels — for native,
WebAssembly, and headless hosts that need real DOCX fidelity
without a browser, a server, or a UI framework. It is the
ground-up successor to Casual Docs, which treats the
DOM as its canvas; OpenDoc owns the layout itself.
Apache-2.0. Pre-release — OpenDoc will take semantic versioning when its public package line begins. Rust 1.96 pinned, 1.88 MSRV; every pull request runs build, test, lint, docs and WASM gates.
Type with formatting, apply styles, fonts, sizes and colours, build lists and
tables, then save back to .docx. Nothing is uploaded — everything runs
client-side. To start from your own file instead, open the
blank editor.
.docxThe usual options are a full office suite you cannot embed, a converter that silently drops what it does not understand, or a browser editor that treats the DOM as the source of truth. OpenDoc is built the other way around.
Content the semantic model does not yet represent is preserved and reproduced verbatim, or reported — never silently discarded.
The same input, fonts, and engine version produce the same model, layout, and bytes, every time — which is what makes rendering regression-testable at all.
No mandatory DOM, server, React, or collaboration provider. The core targets
Rust hosts, wasm32-unknown-unknown, desktop, and headless services
alike.
Packages are parsed under explicit entry, path, size, expansion, and resource
limits — a hostile .docx is an input, not an exploit.
Into a normalized, editable model: paragraphs and runs with the full property
tail, styles (basedOn chains) and theme, numbering, sections and
page geometry, tables (merged cells, nested tables, borders, shading, cell
margins), images and drawings, hyperlinks, fields, text boxes, footnotes and
endnotes, headers and footers, comments, tracked changes, bookmarks, and
content controls.
Byte-identical reconstruction of an unedited package, or a semantic
writer that re-emits an edited model as a valid .docx that opens
cleanly in LibreOffice.
Grapheme-aware inserts and deletes, paragraph split/join, atomic transactions with semantic inverses, position mapping, revision-checked undo/redo, directed caret and range selection, and bounded ordered events.
Text shaping and line breaking via parley, an effective-property
style cascade, pagination with break control, a backend-neutral display list,
and a CPU raster backend that renders real pages and tables to PNG via
tiny-skia with glyph outlines from skrifa.
The engine compiled to wasm32-unknown-unknown drives a live
editor: hit-testing, an engine-drawn caret and selection, incremental
per-page repaint (sub-10 ms on a large document), run and paragraph
formatting with type-in-format, lists, tables, pictures, drawings, comments and
tracked changes — all through a closed operation set with group undo/redo.
The page body, headers, footers, footnote and endnote bodies, text boxes, and objects nested inside a shape group each accept typing, selection, formatting, clipboard, find and replace, comments, and tracked changes — held to that by an operation × surface matrix in CI, not by spot-checks.
Import, export, the editing model, layout, raster rendering, and the WebAssembly editor above all run. The engine is the document core for Casual Docs and an SDK others can embed.
There is no published package line yet, so there is no stable version to pin — semantic versioning starts when one does. Build from source in the meantime.
Casual Docs is the shipping ProseMirror web editor
and is what docs.casualoffice.org runs today. OpenDoc is its
successor and is not yet a drop-in replacement — it is where the
document engine work now happens.
.docx; the blank editor takes one of your own. Everything runs
client-side, so nothing you open leaves the browser.