Skip to content

Core Engine Overview

pptx-viewer-core is a framework-agnostic TypeScript engine for working with PowerPoint (.pptx) files. It parses, creates, edits, serializes, and converts presentations entirely in memory on the OpenXML ZIP archive - no native dependencies, no browser DOM required.

A .pptx file is a ZIP archive of XML documents conforming to the Office Open XML (OOXML) specification. This package gives you a complete, typed SDK over that format. It has four runtime dependencies: jszip (ZIP handling), fast-xml-parser (XML parse/build), and the extracted emf-converter and mtx-decompressor binary-format packages.

Where this fits

The viewer bindings (pptx-react-viewer, pptx-vue-viewer, pptx-angular-viewer) render the data model this engine produces. The MCP tools package wraps it for AI agents. See /react/ and /packages/mcp.

Install

bash
bun add pptx-viewer-core
# or: npm install pptx-viewer-core

Capability map

CapabilityEntry pointDescription
Parsehandler.load(buffer, options?)Unzip, parse XML, and extract slides, elements, themes, masters, layouts, media, charts, SmartArt, comments, animations, transitions, and document properties.
CreatePptxHandler.create() / PresentationBuild presentations from scratch with a fluent builder API (/core/builder).
Editmutate data.slides / PptxXmlBuilderAdd/remove/reorder slides, insert elements, modify text, change styles, update themes (/core/editing).
Savehandler.save(slides, options?)Serialize the data model back into a valid .pptx (or .ppsx / .pptm) ZIP archive with full round-trip fidelity (/core/saving).
ConvertPptxMarkdownConverterTransform parsed PPTX into Markdown with media extraction, notes, and metadata (/core/converter).
ExportSvgExporterHeadless SVG rendering of slides, one <svg> string per slide, no browser needed (/core/svg-export).
Encrypt/Decryptload({ password }) / handler.saveEncrypted()Read password-protected PPTX (standard and agile schemes) and write agile AES-128/AES-256 output (/core/encryption).
Theme opshandler.switchTheme() / switchThemePreset()Swap colour/font schemes live; 8 built-in presets in THEME_PRESETS.
Text opsfindText / replaceText / mergePresentationDeck-wide search, replace, and slide merging (also exposed via the CLI).
Validatesignature and conformance utilitiesDigital-signature detection, OOXML Strict handling, accessibility and validator helpers.

Runtime support

The engine builds XML and SVG by string/object manipulation, so it has no DOM dependency anywhere in the load/edit/save path.

RuntimeParse / Edit / SaveSVG exportMarkdown convertEncryptionCLI
BrowserYesYesYes (in-memory)Yes (crypto.subtle)No
Node 18+YesYesYes (+ disk adapter)Yes (19+, or flag on 18)Yes
BunYesYesYes (+ disk adapter)YesYes
Deno / Workers / serverlessYesYesYes (custom adapter)YesNo

The only platform-conditional pieces are:

  • Encryption needs Web Crypto on globalThis.crypto (crypto.subtle and crypto.getRandomValues). That is native in browsers, Bun, Deno, Workers, and Node 19+; on Node 18 launch with --experimental-global-webcrypto.
  • Writing files (extracted media, exported SVGs) is your side of the contract: the engine returns strings/Uint8Arrays, and the converter accepts a pluggable FileSystemAdapter.
  • The CLI binary uses node:fs and runs under Node or Bun.

Lifecycle

                 new PptxHandler()
                        |
        ArrayBuffer --> load(buffer, { password? })
                        |        (detect OLE2 -> decrypt -> unzip -> parse XML
                        |         -> resolve theme/master/layout inheritance)
                        v
                    PptxData  { slides, theme, width, height, ... }
                        |
          mutate slides/elements in place  (or via PptxXmlBuilder)
                        |
        +---------------+----------------------+
        |                                      |
   save(slides, options?)          saveEncrypted(slides, password, options?)
        |                                      |
    Uint8Array (.pptx/.ppsx/.pptm)      Uint8Array (encrypted OLE2)
                        |
                  handler.dispose()   (free Blob URLs, caches, ZIP)

The handler instance holds the in-memory ZIP archive of the loaded (or created) file. Everything you do not touch - media, masters, custom XML, VBA - passes through it verbatim on save, which is why you must call save() on the same handler that produced the data. Call dispose() when you are done to release memory immediately.

Quick example

ts
import { PptxHandler } from 'pptx-viewer-core';
import { readFile, writeFile } from 'node:fs/promises';

const file = await readFile('deck.pptx');
const buffer = file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength);

const handler = new PptxHandler();
const data = await handler.load(buffer as ArrayBuffer);

console.log(`${data.slides.length} slides, ${data.width}x${data.height}px`);

// Walk the typed element model (discriminated union, narrow on `type`)
for (const el of data.slides[0].elements) {
	if (el.type === 'text') {
		console.log('text box:', el.text);
	}
}

// Edit in place
const title = data.slides[0].elements.find((el) => el.type === 'text');
if (title && title.type === 'text') {
	title.text = 'Updated title';
}

const bytes = await handler.save(data.slides); // => Uint8Array
await writeFile('out.pptx', bytes);
handler.dispose();
ts
import { PptxHandler, inchesToEmu } from 'pptx-viewer-core';

const { handler, data, createSlide } = await PptxHandler.create({
	title: 'Q4 Report',
	creator: 'Sales Team',
	width: inchesToEmu(13.333), // EMU; defaults to 16:9 widescreen
	height: inchesToEmu(7.5),
	initialSlideCount: 0,
	theme: { colors: { accent1: '#FF6B6B' }, fonts: { majorFont: 'Montserrat' } },
});

data.slides.push(createSlide('Title Slide').addText('Hello', { fontSize: 36 }).build());

const bytes = await handler.save(data.slides);

PptxHandler.create(options) and its alias PptxHandler.createBlank(options) both accept a PresentationOptions object (width/height in EMU, theme, title, creator, initialSlideCount) and return { handler, data, createSlide }. See /core/builder for the fluent API and /core/loading for the load pipeline and its options (password, eagerDecodeImages, maxUncompressedBytes, allowExternalImages).

Hardened loading

load() enforces a zip-bomb budget (500 MiB uncompressed by default, 65,536 entry cap; violation throws ZipBombError) and drops external http(s) image references unless you opt in with allowExternalImages: true.

Main public exports

Everything is re-exported from the package root (pptx-viewer-core). Import from the barrel, not individual files. There are also subpath exports: pptx-viewer-core/converter, pptx-viewer-core/cli, and pptx-viewer-core/signature-node (Node-only signing/PKI helpers).

ExportKindPurpose
PptxHandlerclassLoad, edit, save, encrypt. The facade.
PresentationclassHighest-level fluent presentation builder.
TextBuilder, ShapeBuilder, ImageBuilder, TableBuilder, ChartBuilder, ConnectorBuilder, MediaBuilder, GroupBuilderclassesTier-2 element builders (/core/builder).
PptxXmlBuilderclassLow-level fluent in-place mutation of PptxData.
ThemePresets, THEME_PRESETS, SlideSizesconsts8 builder theme presets; 8 switchable viewer presets; 7 standard slide dimensions (EMU).
inches, cm, mm, pt (to pixels); inchesToEmu, cmToEmu, pixelsToEmu (to EMU)functionsUnit-conversion helpers.
PptxMarkdownConverterclassPPTX to Markdown converter (/core/converter).
SvgExporterclassHeadless SVG export (/core/svg-export).
decryptPptx, encryptPptx, verifyPassword, detectFileFormatfunctionsLow-level crypto (/core/encryption).
findText, replaceText, mergePresentationfunctionsDeck-wide text search/replace and merge.
PptxData, PptxSlide, PptxElement, TextStyle, ShapeStyle, TableData, PptxChartData, PptxTheme, ...typesThe type system - see /guide/data-model.
getShapeClipPath, evaluateGuides, evaluatePresetShape, getConnectorPathGeometry, getElementTransform, ...functionsGeometry helpers (/core/geometry).
parseDrawingColor and colour utilitiesfunctionsOOXML colour parsing and transforms.

Architecture at a glance

  • PptxHandler wraps PptxHandlerCore, which delegates to an injectable IPptxHandlerRuntime (you can pass your own via new PptxHandler({ runtime }) for testing).
  • The runtime is assembled from 50+ focused mixin modules (theme loading, element parsing, save pipeline, etc.).
  • The type system centres on PptxElement, a discriminated union of 16 variants (text, shape, connector, image, picture, table, chart, smartArt, ole, media, group, ink, contentPart, zoom, model3d, unknown) narrowed by element.type. See /guide/data-model.
  • EMU (English Metric Units) is the native OOXML coordinate system: 1 inch = 914,400 EMU, 1 point = 12,700 EMU, 1 pixel = 9,525 EMU at 96 DPI. The parsed model exposes pixel values (data.width/data.height) alongside raw EMU (widthEmu/heightEmu).

Next steps

Released under the Apache-2.0 License.