Read, edit, and write presentation files in TypeScript

Open any .pptx or start from an empty deck. Change slides, charts, and tables through typed functions, then save a file that Keynote, Google Slides, LibreOffice Impress and other common presentation apps all open cleanly. It runs in Node and in the browser.

Create slides with AI Open the playground

A slide and the code that built it

hero-deck.ts
export function buildHeroDeck(): PresentationData {
  const pres = createPresentation();
  const slide = addBlankSlide(pres);

  const bar = addSlideShape(slide, {
    preset: 'rect',
    x: inches(0.6),
    y: inches(0.62),
    w: inches(0.12),
    h: inches(0.95),
  });
  setShapeFill(bar, '#D6336C');
  setShapeNoStroke(bar);

  const title = addSlideTextBox(slide, {
    x: inches(0.85),
    y: inches(0.5),
    w: inches(9),
    h: inches(0.7),
    text: 'Revenue grew 2.5× in four quarters',
  });
  setShapeTextFormat(title, { size: 30, bold: true, color: '#15171C' });

  const subtitle = addSlideTextBox(slide, {
    x: inches(0.85),
    y: inches(1.15),
    w: inches(9),
    h: inches(0.45),
    text: 'FY26 plan, USD thousands',
  });
  setShapeTextFormat(subtitle, { size: 16, color: '#5B616E' });

  addSlideChart(slide, {
    x: inches(0.6),
    y: inches(1.9),
    w: inches(12.1),
    h: inches(5),
    spec: {
      kind: 'column',
      categories: ['Q1', 'Q2', 'Q3', 'Q4'],
      series: [
        { name: 'Revenue', values: [120, 180, 240, 300], color: '#D6336C' },
        { name: 'Cost', values: [80, 90, 130, 160], color: '#C9CDD6' },
      ],
      legend: { position: 'b', textStyle: { sizePt: 14, color: '#5B616E' } },
      categoryAxisLabelStyle: { sizePt: 14, color: '#5B616E' },
      valueAxisLabelStyle: { sizePt: 14, color: '#5B616E' },
      valueAxisMajorGridlines: true,
      valueAxisMajorGridlineColor: '#E2E4E9',
      gapWidthPct: 80,
    },
  });

  return pres;
}

That slide is real output. The code shown with it built the deck, and @office-kit/pptx-preview drew it as SVG. Download it and open it in your presentation app: the chart is editable, data and all.

  • loadPresentation(bytes)

    Edit a file you already have

    Any .pptx made in a desktop presentation app, Keynote, or Google Slides is a template. Fill {{tokens}}, swap a picture and keep its crop, add slides from the deck’s own layouts. Parts the library does not model, such as SmartArt, OLE objects, and video, are carried through unchanged.

    Read the template guide
  • deck.tsx → preview → deck.pptx

    Create slides with AI

    Install the Claude Code skill and describe your presentation. Claude handles setup, TSX authoring, live preview, and .pptx export. Review the slides and ask for changes.

    Create your first presentation
  • renderSlideToSvg(pres, slide)

    See the slide before you send it

    The companion @office-kit/pptx-preview package draws a slide as SVG in the browser and as PNG in Node, with no headless office suite. It also reports text that overflows its box, which is how an automated pipeline catches a broken slide.

    Try it in the playground

A designer makes the template. Your code fills it in.

Most decks that matter already exist as a .pptx someone cares about: the brand template, last quarter’s review, the certificate with the right fonts. Load it, replace what changes, and everything else stays exactly as it was designed.

Every write has a matching read, so the same API that fills a template can also audit one: list the layouts, find every hyperlink, or check which slides still have an empty title.

template-fill.ts
import { readFile, writeFile } from 'node:fs/promises';
import { loadPresentation, replaceTokensInPresentation, savePresentation } from '@office-kit/pptx';

const pres = await loadPresentation(await readFile('template.pptx'));
replaceTokensInPresentation(pres, {
  name: 'Yamashita',
  event: 'Re:Invent',
  date: '2026-12-01',
});
await writeFile('out.pptx', await savePresentation(pres));

Valid files, checked by machines

A deck that opens in one desktop presentation app but breaks Keynote is a bug here. So is one that opens everywhere and still fails schema validation.

Every sample deck passes the Open XML SDK validator.
A CI job runs OpenXmlValidator over the generated samples and fails the build on the first error. Emitted XML is also checked against the ECMA-376 schemas.
What the library does not understand, it does not touch.
Unknown parts and extensions are preserved on load → save, so a deck that went in with SmartArt comes out with SmartArt.
You ship only the functions you import.
Side-effect-free exports let bundlers remove unused functions. CI checks tree-shaking and bundle-size limits.
One runtime dependency.
fflate, for ZIP. XML reading and writing is hand-rolled, and nothing on the hot path touches fs, Buffer, or zlib.

How it differs from PptxGenJS

PptxGenJS is the established way to generate a deck in JavaScript, and it is good at that. The difference is direction: PptxGenJS writes new files, while this library reads, edits, and writes. Compared against PptxGenJS 4.0.

Capability@office-kit/pptxPptxGenJS
Open and edit an existing .pptxYes. Load, change, save; unknown parts are preservedNo. It creates new files only
TemplatesAny .pptx a designer made in a desktop presentation appSlide masters defined in code
Read back what is in a deckEvery setter has a getter, plus deck-wide queriesNo. The API is write-only
API shapeTree-shakeable functions, ESM onlyOne class with methods; ESM, CommonJS, and a script-tag bundle
Transitions and animationsSlide transitions; four entrance and exit presetsNo
CommentsYesNo (speaker notes only)
Chart types you can authorEvery ECMA-376 plot type, 3-D, stock and surface included; combos, error bars, data table, date axisBar, line, area, pie, doughnut, scatter, bubble, radar, 3-D bar
Audio, video, YouTube embedsYes, from bytes in Node and the browser, with read-backYes (write-only)
HTML table to slidesNoYes, with automatic paging
Render a slide to an imageSVG and PNG, via the companion preview packageNo

Pick PptxGenJS if you only ever generate new decks and need HTML-table import, CommonJS, or a script-tag build. Pick this library if a template, an existing deck, or a validation requirement is involved.

What you can build today

The library is pre-1.0 and says so. This is what works now, and what does not yet. The API reference lists every function.

Slides
Add, remove, move, duplicate, hide. Layouts, sections, sizes, backgrounds.
Text
Paragraphs, runs, bullets, spacing, autofit. Latin, East Asian, and complex-script fonts.
Shapes
180+ presets, lines, groups, fills (solid, gradient, pattern, picture), strokes, shadows, glows, z-order.
Tables
Rows, columns, merges, borders, fills, per-cell text, margins, and direction.
Charts
All 16 plot types, 3-D, stock and surface included, plus combos, secondary axis, data labels, trendlines, error bars, data table. The workbook behind “Edit data” is generated for you.
Pictures
PNG, JPEG, GIF, BMP, TIFF, WebP, SVG. Crop, opacity, brightness, contrast, in-place swap.
Review
Speaker notes, comments, hyperlinks, click actions, with deck-wide find and replace.
Deck
Theme colors and fonts, document properties, thumbnail, package inspection, validatePresentation().

Not yet

  • New themes, masters, and layouts from scratch
  • SmartArt and OLE authoring (both are preserved on round trip)
  • Encrypted files

Written to be driven by AI agents too

Decks are increasingly written by agents, so the docs are built for them as well as for you. The Claude Code skill handles project setup, TSX authoring, preview and export. Install it once, then describe the presentation you want.

  • /llms.txt An index of every docs page, for a model to pick from.
  • /llms-full.txt The whole documentation in one file.
  • any-docs-page.md Add .md to a docs URL to get the raw Markdown.
  • skill/SKILL.md The installable Claude Code skill, with bundled TSX and core references.