If you've ever had to turn a PowerPoint to HTML on a server, you know the usual options are grim. You either shell out to LibreOffice in headless mode (a 400 MB dependency that forks a process per file and occasionally hangs), spin up a headless browser, or ship the deck off to some cloud conversion API and pray about the privacy implications. For something that's just a file format, that's a lot of moving parts.
deck-ir takes a different route. It does pptx to html in pure JavaScript — without LibreOffice, without a headless browser, without native binaries, and without a single network call. It reads the OOXML inside the .pptx directly and emits an HTML fragment per slide. It runs in Node.js, and because it has zero native dependencies, it also runs client-side in the browser.
It's the open-source rendering core extracted from the PPTX→HTML pipeline of a commercial product, flashdeck.cn. The whole thing leans on exactly two runtime dependencies: jszip and fast-xml-parser. No Chromium, no LLM, no storage layer.
Try it right now
Before any of the explanation — here's the live demo. Drop a .pptx onto the page and it renders in your browser. There's no upload; the parsing and rendering happen 100% client-side in JavaScript. That demo is the library, which is the most honest proof I can offer that it doesn't secretly need a server.
Why "no LibreOffice" actually matters
The LibreOffice-in-a-container approach works, but it costs you:
- A huge image and a heavyweight process you have to babysit, rate-limit, and restart.
- Nondeterminism — subprocess timeouts, font fallbacks that drift, the occasional zombie.
- All-or-nothing output. You get a rendered file, not a structured model you can post-process.
deck-ir is deterministic: the same .pptx always produces the same HTML. And the output is self-contained — media is inlined as data: URLs by default, so each slide's HTML fragment stands alone with no asset directory to manage. (If you'd rather host media yourself, pass a mediaResolver and deck-ir hands you the bytes instead.)
How it works: a .pptx is just a ZIP of XML
The trick to convert pptx without an office suite is realizing there's no magic in the format. A .pptx is a ZIP archive of XML files (the OOXML spec). deck-ir unzips it with jszip, parses the XML with fast-xml-parser, and walks the tree itself.
The pipeline has three stages:
-
parsePptxToRawIR— builds a faithful, low-level model of the OOXML. No interpretation yet, just structure. -
transformToSemanticIR— this is where the real work happens. It resolves the things PowerPoint leaves implicit:- The 3-layer background merge (master → layout → slide), so each slide gets the background it actually displays.
-
Color schemes, including
lumMod/lumOffmodulation resolved down to concrete hex values. - EMU → px conversion for absolute positioning (PowerPoint measures in English Metric Units; the browser doesn't).
- Text runs, geometry, groups, z-order, and SmartArt reconstructed from its cached drawing.
- An HTML/SVG emitter — turns the semantic model into a standalone HTML fragment per slide.
Because each stage is a clean transform over a data structure, you can tap in at any level instead of accepting whatever a black box hands you.
How to convert a .pptx to HTML in Node.js
The common path is one call:
import { parsePptx } from "deck-ir";
import { readFile } from "node:fs/promises";
const buffer = await readFile("deck.pptx");
const { slideSize, slides, media } = await parsePptx(buffer);
// slides: Array<{ html: string; warnings: string[] }>
// one faithful HTML fragment per slide
// slideSize: the deck's dimensions
// media: the inlined assets (when you opt out of data: URLs)
for (const [i, slide] of slides.entries()) {
console.log(`Slide ${i + 1}:`, slide.warnings);
// slide.html is ready to drop into a page
}
That buffer works the same in the browser — feed it the ArrayBuffer from a File and you get the same fragments, no server round-trip.
If you want finer control, the lower-level pieces are exported too: parsePptxToRawIR, transformToSemanticIR, and emitSlideHtml. Parse once, inspect or mutate the intermediate representation (hence the name — deck IR), then emit. That's the seam most "render my slides" tools never give you.
What it renders
deck-ir aims for faithful layout, not a loose approximation:
- Shapes — rectangles, ellipses, lines, and arbitrary custom geometry.
- Fills — solid, gradient, and image fills.
- Outlines — stroke color/width, plus border-radius.
- Text — font family, size, color, bold/italic/underline, alignment, and bullets.
-
Images — including
srcRectcropping. - Backgrounds — the full 3-layer master/layout/slide merge.
- Color — theme color schemes resolved to hex.
- Structure — z-order, groups, and SmartArt (from its cached drawing).
- Positioning — EMU→px absolute layout so things land where the author put them.
Honest limitations
No converter is lossless, and pretending otherwise just wastes your afternoon. Here's what deck-ir does not do:
- Charts and tables without a cached drawing fall back to a placeholder. (When PowerPoint has cached a drawing for them, they render; when it hasn't, there's nothing static to draw.)
- Animations, transitions, audio, and video are ignored. The output is static HTML — a faithful snapshot of each slide, not a player.
-
Fonts are not embedded. Slides emit
font-familynames only. That keeps the output small, but it means CJK text needs CJK fonts installed on the viewer's machine to render correctly. Plan for that if your decks are Chinese, Japanese, or Korean.
None of these are secret asterisks — they're the natural edges of "static, deterministic, dependency-free." If you need animations or pixel-perfect chart rendering, you genuinely do want a heavier tool.
A sibling for templating: deck-ir-vlm
If you want to go beyond rendering, there's a companion library, deck-ir-vlm, that adds a VLM layer on top of deck-ir to classify and cluster a deck's slides into editable HTML template layouts — text becomes {{token}} slots you can fill programmatically. That's a different job (and it does pull in a model), so it's a separate package: github.com/darksun113/deck-ir-vlm.
Try it, install it, star it
If you do anything with slide decks on the server — thumbnails, previews, search indexing, content extraction — deck-ir is worth ten minutes:
-
Live demo (client-side, drop a
.pptx): https://darksun113.github.io/deck-ir/ -
Install:
npm i deck-ir - GitHub (a star helps it reach the next person fighting LibreOffice): https://github.com/darksun113/deck-ir
- License: AGPL-3.0, with a commercial dual-license available if AGPL doesn't fit your stack.
And if you'd rather not build the rest of the slide pipeline yourself — AI one-line → full deck, an editor, export to editable PPTX, mermaid support — that whole product lives at flashdeck.cn. deck-ir is the rendering core it's built on, now open for you to use directly.

Top comments (0)