Architecture¶
One file, on purpose¶
The entire application — UI, diff engine, and OOXML parsing — lives in a single self-contained file: src/pptxdiff/index.html (template + logic). This is a deliberate constraint, not an accident of growth:
- Zero build step. Clone the repo, open the file, done. No bundler, no transpile step, no
node_modulesneeded to run it. - Zero server-side component. Everything — parsing, rendering, diffing, exporting — happens in the browser, against files that never leave your machine.
- Trivially distributable. The same file is what
npx pptxdiff, the global npm install, the VS Code extension, and a plaingit clone+ double-click all ultimately serve. There's exactly one artifact to keep correct.
support.js is the runtime the app is authored against — pinned intentionally, not casually upgraded — and sample-pptx.js is a plain ES module that builds the in-browser sample/test-fixture .pptx files used by "Reset to sample" and the self-test suite.
No backend, by design¶
There is no server component beyond the CLI's static file server (see CLI reference), which serves files unchanged and contains no application logic. This shapes several features directly:
- Exports are files or best-effort direct network calls from the browser, never routed through a backend you'd have to trust or host — see Exports & live push for exactly which services this makes reliable (Slack) vs. CORS-limited (Notion, Confluence).
- "Shareable link" is a self-contained
data:URL, not a hosted short link — there's no server to host one on. - Review state lives in
localStorage, not a shared database — a review session is local to one browser unless you explicitly export/import a JSON report.
Runtime dependencies, vendored locally¶
React, ReactDOM, Babel-standalone, @aiden0z/pptx-renderer, JSZip, and the Spectral font are all vendored under src/pptxdiff/vendor/ and loaded from disk — not from a CDN. pptx-renderer in particular ships as a single self-contained esbuild bundle (its own jszip runtime dependency inlined) rather than the dynamic esm.sh import it originally used. This means the app runs fully offline/air-gapped: no runtime dependency needs internet access, on top of your .pptx files already never leaving your machine. See docs/.scrolls/SPEC.md §24 in the repository for the full vendoring breakdown.
Each vendored file's upstream package/version/source URL/hash/license is tracked in a machine-checkable src/pptxdiff/vendor/manifest.json and its human-readable counterpart PROVENANCE.md, both re-verifiable via scripts/verify_vendor.mjs. See the repo-root SECURITY.md for the security rationale.
This is the default, not a hard requirement — PPTXDIFF_LITE_MODE is a documented, opt-in escape hatch back to CDN sourcing for all five, if you ever want that. See the CLI reference and the in-app toggle.
Packaging layers¶
src/pptxdiff/index.html (the app: template + logic + diff engine)
├── opened directly ──────────────► Option C: git clone + open the file
└── served unchanged by bin/cli.js (static file server, no app logic)
├── npx pptxdiff
├── npm install -g pptxdiff
├── VS Code extension (sugatoray.pptxdiff-vscode)
└── Homebrew formula (brew install --formula ...)
All five surfaces above serve the identical app — none of them modify or rebuild it. Fixing a bug or shipping a feature happens exactly once, in index.html. The Homebrew formula is a thin packaging layer on top of the already-published npm tarball, not a separate build.
Testing philosophy¶
Because there's no build step and no separate test runner wired into CI, correctness is verified by the app's own in-browser self-test suite, run against the app's real parsing/rendering/diffing code in a real browser — not a mocked unit-test harness. New logic is written pure-function-first (a testable decision/builder function, with a Red/Green test) before the impure DOM/network/localStorage shell is wired around it.