Skip to content

Development

This page covers everything you need to work on the pptx-viewer monorepo: how to set up your environment, the workspace command reference, the build order and why it matters, the repository layout, the tech stack, and the conventions the codebase follows.

For the bigger picture of how the packages fit together, see Architecture.

Getting set up

Prerequisites

  • Bun - package manager and runtime. The repo uses Bun workspaces and workspace:* linking.
  • Node.js 18+ - required for TypeScript compilation and tooling.

TIP

The repository is built and tested with Bun. While many scripts will run under other package managers, the bun run --filter workspace targeting used by the build and typecheck scripts relies on Bun, so install Bun before you begin.

Clone and install

bash
git clone https://github.com/ChristopherVR/pptx-viewer.git
cd pptx-viewer

# Install all workspace dependencies (packages/* and demo)
bun install

A single bun install at the root installs dependencies for every workspace package and wires up the internal workspace:* links between them.

Workspace command reference

Run these from the repository root. They operate across all workspace packages.

CommandWhat it does
bun installInstall all workspace dependencies.
bun run buildBuild every package in dependency order (see Build order).
bun run devWatch-mode build - run per package from its directory (see Per-package commands).
bun run testRun the full test suite via scripts/test-all.sh (Vitest across all packages).
bun run typecheckType-check every package (bun run --filter '*' typecheck).
bun run fmtFormat all files with oxfmt.
bun run fmt:checkCheck formatting without writing - CI-safe.
bun run lintLint with oxlint.
bun run lint:fixAuto-fix lint issues with oxlint.
bun run demoStart the Vite demo dev server.
bun run e2eRun the Playwright end-to-end tests.
bun run e2e:installInstall the Playwright browser (chromium, with system deps).
bun run e2e:uiOpen the Playwright test runner in interactive UI mode.

INFO

bun run test runs through scripts/test-all.sh, which drives Vitest across the workspace rather than invoking vitest directly. The end-to-end commands use Playwright; run bun run e2e:install once before your first bun run e2e to fetch the browser binary.

Per-package commands

Each package exposes its own scripts. Run them from inside the package directory:

bash
cd packages/core && bun run build      # Build a specific package (tsup)
cd packages/core && bun run dev        # Watch mode
cd packages/core && bun run test       # Run this package's tests
cd packages/core && bun run typecheck  # Type-check this package

Build order and why it matters

bun run build compiles packages in dependency order:

core → shared → react / vue / angular

WARNING

The order is not arbitrary. The dependency graph is { react, vue, angular } → shared → core. Each package consumes the built output of the packages below it, so a downstream package must be built before anything that imports it. Building out of order (for example, building a binding before core) will fail or pick up stale artifacts. (emf-converter and mtx-decompressor are external npm dependencies of core, not built in this repo.)

The root build script chains the per-package builds with Bun's --filter so the order is enforced for you - you normally just run bun run build at the root.

Monorepo structure

packages/
  core/             pptx-viewer-core     – Parse, create, edit, serialize PPTX (framework-agnostic)
  shared/           pptx-viewer-shared   – Framework-agnostic viewer logic (internal, bundled into each binding)
  react/            pptx-viewer          – React viewer/editor/presenter component
  vue/              pptx-vue-viewer      – Vue 3 viewer/editor component
  angular/          pptx-angular-viewer  – Angular viewer/editor component
  tools/            pptx-viewer-mcp      – Supporting tooling / MCP server
demos/
  demo-react/                            – Vite + React demo app
  demo-vue/                              – Vite + Vue 3 demo app
  demo-angular/                          – Vite + Angular demo app

Packages link to one another with the workspace:* protocol, and the Bun workspaces are declared at the repository root (packages/* and demos/*).

Tech stack

CategoryTechnologies
LanguageTypeScript (strict mode)
RuntimeBun (package manager), Node.js 18+
UIReact 19, Framer Motion, Tailwind CSS 4, Lucide React
ParsingJSZip (ZIP), fast-xml-parser (XML)
Exporthtml2canvas + jsPDF (PDF), custom GIF encoder, MediaRecorder (video)
3DThree.js (optional)
CollaborationYjs (CRDT), y-websocket (optional)
CryptoWeb Crypto API (AES-128/256 for PPTX encryption)
TestingVitest (unit/integration), Playwright (end-to-end)
Formattingoxfmt (from the oxc toolchain)
Lintingoxlint (from the oxc toolchain)
Bundlertsup (ESM + CJS with .d.ts declarations)

Code conventions

These conventions keep the codebase consistent and are enforced (where possible) by oxfmt and oxlint.

Mixin pattern

The core runtime is composed from 50+ focused mixin modules. Each PptxHandlerRuntime*.ts file adds one concern (parsing, saving, theme resolution, element processing, etc.) to PptxHandlerRuntime. Add new capabilities as new mixins rather than growing existing modules. See Concepts for the mixin composition model.

Barrel exports

Every directory has an index.ts barrel. Import from the barrel, not from individual files:

ts
// Good
import { PptxHandler } from '../core';

// Avoid
import { PptxHandler } from '../core/core/PptxHandler';

Type narrowing via the type discriminant

PptxElement is a discriminated union. Always narrow on the type field - never cast:

ts
if (element.type === 'image') {
	// element is now typed as the image element variant
	console.log(element.src);
}

See Data model for the full element union.

EMU units

PowerPoint stores geometry in English Metric Units (EMU). Conversion constants live in packages/core/src/core/constants.ts:

ts
EMU_PER_INCH = 914400;
EMU_PER_POINT = 12700;
EMU_PER_PIXEL = 9525;

Use these constants instead of hard-coding conversion factors.

File naming

  • kebab-case for utility files (type-guards.ts, clip-path.ts).
  • PascalCase for classes and class files (PptxHandlerRuntime.ts).

Colocated tests

Tests live next to the source they cover, using the .test.ts suffix (for example, geometry.tsgeometry.test.ts).

No any

Never introduce any. Use concrete types, unknown plus narrowing, or the XmlObject alias for parsed fast-xml-parser output.

Packing for npm distribution

Each publishable package has a pack script, surfaced at the root for convenience:

bash
bun run pack:core    # packages/core
bun run pack:shared  # packages/shared
bun run pack:react   # packages/react
bun run pack:vue     # packages/vue
bun run pack:angular # packages/angular

TIP

Run bun run build before packing so the tarball contains freshly built dist/ output and up-to-date .d.ts declarations.

Released under the Apache-2.0 License.