Sign in

    office-viewer

    A read-only DOCX, XLSX, and PDF viewer with structured selections.

    Download zip
    Author
    Version
    0.1.3
    License
    Apache-2.0
    Last updated
    16 hours ago
    Downloads
    591

    #Office Viewer

    A read-only document viewer built with MoonBit and Rabbita. Office Viewer provides standalone DOCX, XLSX, and PDF previews and a reusable browser surface with structured selections for host applications and agents.

    #Supported formats

    FormatRenderingSelection
    DOCXoffice.mbt PageModel and paginated SVGNative text selection with validated paragraph/run references where available
    XLSXoffice.mbt workbook reader and HTML rendererCells and rectangular ranges with worksheet names and canonical selectors
    PDFPDF.js canvas, text, and annotation layersNative text selection with page/item ranges, document identity, geometry, and available tagged structure

    The viewer supports zoom and search. PDF previews also provide page navigation, fit to width, rotation, and password prompts. Files are read locally in the browser; the standalone demo uses a mock file path in its selection metadata. Excel previews preserve workbook styles, merged cells, images, charts, and formula results. Supported uncached formulas are evaluated by office.mbt; unsupported formulas remain visibly marked as pending.

    #Run locally

    Dependencies are resolved from Mooncakes using the versions in moon.mod. Use the official MoonBit toolchain 0.10.14+7d59c7ec9 (moon 0.1.20260920) and Node.js 24. From office-viewer:

    moon update moon install moonbit-community/warren@0.4.0 npm ci --ignore-scripts moon run tools/prepare-browser-assets.mbtx moon check --target js moon test --target js -p Lampese/office-viewer/viewer moon test --target js -p Lampese/office-viewer/cmd/browser npm run test:pdf-runtime

    Start the development server from office-viewer:

    warren dev --direct --browser-entry cmd/browser --server-entry "" --port 4311

    Open http://127.0.0.1:4311/. To build the same release artifact as CI, install Terser in a temporary directory and put it on PATH:

    minifier="$(mktemp -d)" npm install --prefix "$minifier" --ignore-scripts --no-audit --no-fund terser@5.51.2 PATH="$minifier/node_modules/.bin:$PATH" bash scripts/build-pages.sh

    The generated dist/ is ignored by Git; an optional first argument selects a different output directory inside the repository (required by Warren). The script uses Warren to compile/minify the browser entry and copy public/, including the existing bundled fonts. It fingerprints JS/CSS filenames and writes build-info.json with the source revision and full asset SHA-256 hashes. It does not regenerate fonts. Run moon run tools/prepare-browser-assets.mbtx after updating npm dependencies; the generated PDF.js worker, CMaps, fonts, codecs, and icon assets are copied from public/vendor/ into the release artifact.

    #Continuous deployment

    The Pages workflow checks, tests, and builds on pull requests and every push to main. PRs never deploy. After a successful main build (or a manual run on main), it uploads the generated temporary artifact and deploys it with GitHub Pages. Build output is not committed to the repository. The workflow uses the Mooncakes dependencies in moon.mod and pins Warren, the official compiler/core archives and their checksums, Terser, and npm browser dependencies. Update these pins together after compatibility checks. The deployed build-info.json identifies the exact source commit and asset contents. PDF.js and icon assets are generated before the source build; they are served locally from the deployed directory, including under subpaths.

    #Structured selections and annotations

    The current selection layer is deliberately read-only: Word uses browser text selection inside positioned page SVG, and Excel uses rectangle selection over cells. Word's source metadata is built in the viewer by reading the same bytes through office.mbt's annotated DOCX reader and joining its paragraph/run projection with the PageModel text. The join is fail-closed, so an uncertain paragraph remains physical-only instead of receiving a guessed selector. Both formats produce the versioned office.selection.v1 JSON envelope shown in docs/selection-model.md; the inspector displays that envelope and can copy it through the browser clipboard for the later host application's Agent conversation.

    Hosts can choose @viewer.materialize_selection_full, @viewer.materialize_selection_preview, or @viewer.materialize_selection_deferred to control how much selected content enters an Agent context. The APIs preserve the existing office.mbt file and selector fields and make UTF-16 omission counts explicit; see docs/embedding.md.

    PDF selections use office.pdf.text-range.v1 references rather than office.mbt selectors. Agent materializations keep the selected text and a single reference with the file path, SHA-256, parser version, and text-item endpoints. Hosts can resolve that reference against the same file bytes using resolve_pdf_selection; the raw selection and resolver result retain detailed geometry and tagged metadata. The demo's Selection panel exposes Full, Preview, and Deferred output and PDF reference resolution. See PDF preview for the PDF contract and browser tests.

    Existing DOCX comments/w15 replies and Excel traditional Notes are available in a document gutter and the optional Comments overview, and through @viewer.read_annotations or RenderedDocument.annotations. The office.annotations.v1 contract preserves missing metadata and explicit support limits. Word navigation shows only proven paragraph context; Notes beyond preview bounds remain in the list and JSON. The gutter opens alongside the document when space permits and collapses on narrow surfaces; use its Comments or Notes heading or a document marker to open it. Quote a whole comment or highlight any body text to capture an office.selection.v1 annotation-body selection, including source identity and UTF-16 offsets. Preview/deferred modes retain the reference without leaking the unselected body. See docs/annotations-model.md for the API, unsupported modern-comment formats, and dependency versions.

    The reusable surface lives in viewer/. Its renderer and Rabbita surface are host-neutral: a standalone host can provide browser file bytes, while OpenSeek can provide bytes and the real office.mbt file path from its native backend. The intended OpenSeek integration mounts this same JS/Rabbita surface inside the desktop frontend; it does not open a second webpage or iframe.

    The layout engines still have documented OOXML gaps, including some nested tables, content controls, tab-stop cases, and paragraph-level section breaks. Those need to be surfaced as structured provenance before claiming complete Word compatibility.

    #Font policy

    The document surface uses the same bundled glyphs and metrics as pagelayout. The PDF font programs from pagelayout/fontoutlines omit the naming table a browser requires. scripts/prepare-fonts.mjs adds that metadata and updates the font directory and checksums in public/fonts, preserving every glyph, character map and metric table. These browser-ready fonts are loaded with @font-face. The bundled Carlito, Liberation, and Noto Sans SC files are distributed under the license notices in public/fonts/LICENSES. The modified font families use distinct internal names (Office Viewer Sans, Office Viewer Sans Alt, Office Viewer Serif, Office Viewer Mono, and Office Viewer CJK) to respect Reserved Font Names. Copyright and OFL metadata are included in each font. The renderer's CSS substitution keys and asset filenames stay compatible; public/fonts/LICENSES/MODIFICATIONS.md records the original-to-modified naming map and changes.

    System fonts remain an explicit local enhancement. The Aa button switches the browser's glyph source to installed Calibri/Arial/Times New Roman/Courier New or common CJK equivalents when available, while keeping the page model's bundled coordinates and pagination unchanged. Missing local faces fall back to the bundled files. The default mode never silently changes with the host machine; the browser runtime records both bundled loading and the selected font mode.

    After exporting changed upstream font programs into public/fonts, prepare the browser assets and verify them:

    npm run prepare:fonts npm run test:fonts npm run test:package

    The corrected TTF files and their license notices are committed in public/fonts and included in the Mooncakes package. test:package checks the actual moon package ZIP for all 17 fonts, the 3 licenses and the matching stylesheet. Embedded hosts such as OpenSeek copy these resources from the resolved .mooncakes/Lampese/office-viewer/public/fonts directory. Consumers use the published assets directly; the preparation script runs when font programs are exported, not during application startup. Pages builds check font validity before copying the assets.

    PDF fonts, CMaps, and images are handled by PDF.js. Embedded fonts come from the opened document; standard fonts and CMaps are included with the PDF.js assets and their upstream license notices. Image-only PDFs display normally; OCR and inferred paragraph/table extraction are not included.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io