Skip to content
Genom
API reference

@genomdev/pptx

PowerPoint presentations (.pptx and .ppt) — parser, model, content adapter and viewer

98 exported symbols across 2 entry points

@genomdev/pptx

Classes

Environment
class Environment

The document-wide `Environment`: fonts, and the styles a text box inherits. The presentation's own defaults live here rather than on a master, which is the opposite of where the modern format puts them — `p:defaultTextStyle` is on the presentation part and `p:txStyles` on the master, and a `.ppt` has it the other way round for the pair that matter.

fonts
FontCollection
defaults
MasterStyles
`TxSIStyleAtom`/`TxPFStyleAtom`: what a shape with no placeholder gets.
scheme
ColorScheme | undefined
FontCollection
class FontCollection

The document's shared tables: the fonts, and the masters' typography. A run of text in a `.ppt` names its typeface by number. The number is a position in this collection and means nothing without it — "font 3" is Verdana in one presentation and 宋体 in the next — so the collection has to be read before any slide can say what it is set in.

name
(index: number) => string | undefined
size
number
first
string | undefined
The first font in the collection, which is a deck's usual body face.
PptMedia
class PptMedia
size
number
part
(index: number) => MediaPart | undefined
The part a shape's one-based picture index stands for.
bytes
(partName: string) => Promise<Uint8Array | undefined>
The bytes behind a part name, decoded once. Asynchronous because a metafile is usually deflated and is translated to SVG once it is not — a picture shared by twelve slides is one decode.
contentType
(partName: string) => Promise<string | undefined>
The content type as decoded, which is not the one stored for a metafile.
url
(partName: string) => Promise<string | undefined>
A URL a browser can show the picture from. An object URL where the host has them and a data URL otherwise, so the same presentation renders in a tab and on a server.
svg
(partName: string) => Promise<string | undefined>
The SVG source of a translated metafile, for inlining rather than embedding. An SVG handed to an `<img>` seals its words out of the document: they cannot be selected, copied, found or read aloud, and no instrument measuring the page can see them either. A metafile with text in it is therefore returned as source so the viewer can put it in the DOM. The size cap is there because a recorded drawing can run to megabytes of paths, and inlining one of those buys nothing a reader would notice.
dispose
() => void

Functions

child
function child(record: PptRecord | undefined, type: number): PptRecord | undefined

The first child of a type.

childrenOf
function childrenOf(record: PptRecord | undefined, type: number): readonly PptRecord[]

Every child of a type, immediate children only.

colorFromIndexStruct
function colorFromIndexStruct(value: number, scheme: ColorScheme | undefined): ResolvedColor | undefined

A four-byte colour field, which is two different things told apart by a byte. The high byte is not part of the colour. `0xFE` means the three below it are a literal `RGB`; `0x00`–`0x07` mean they are to be ignored and the byte is an index into the colour scheme; `0xFF` means the field says nothing at all. Reading the whole word as a colour gives a deck whose every text run is one of eight shades of near-black, which looks plausible enough to ship.

currentEditOffset
function currentEditOffset(currentUser: Uint8Array | undefined): number | undefined

The offset the `Current User` stream points at, if it can be believed. The stream *is* the atom — its eight-byte record header is the first thing in it, with no length in front — and the four bytes after that header are the atom's own stated size rather than anything to read. Both of those are easy to get wrong by one field, and being wrong by one field here reads the header token as a version number, fails the check, and silently falls back to scanning for the last save.

currentUserSaysEncrypted
function currentUserSaysEncrypted(currentUser: Uint8Array | undefined): boolean

Whether the `Current User` stream says the presentation is enciphered.

descendants
function descendants(record: PptRecord, type: number): Generator<PptRecord>

Every record of a type at any depth, the record itself included.

extractPptx
function extractPptx(input: ByteSourceInput | PptxDocument, options?: ExtractOptions): Promise<ContentDocument>

Содержимое презентации — без зонтика и без чужих форматов в графе. Для того, кто знает, какой у него файл. Принимает и уже открытый документ: вьюверу незачем разбирать файл второй раз, чтобы поискать в нём.

find
function find(record: PptRecord | undefined, type: number): PptRecord | undefined

The first record of a type at any depth.

flag
function flag(props: TextProps | undefined, field: string, bit: number): boolean | undefined

A flag out of a bit-mask property, distinguishing "off" from "not stated". The whole subtlety of the format is in this function. `bold` is bit 0 of the `flags` field, and that field is *itself* selected by bits 0-15 of the mask — so a run whose mask has bit 0 set and whose flags have bit 0 clear says "not bold" and overrides the master, while a run whose mask lacks bit 0 says nothing and inherits. Collapsing the two makes every inherited bold run plain, which on a template that bolds its titles is the whole deck.

levelsForKind
function levelsForKind(styles: MasterStyles, kind: number): readonly StyleLevel[]

The levels stated for a kind of text, falling back the way PowerPoint does. A master states the kinds its design uses and no others, so asking for the centred body of a deck that has none must give the body rather than nothing: nothing means the browser's default face at the browser's default size, which is never what the deck looks like.

levelStyleOf
function levelStyleOf(styles: MasterStyles, placeholderType: string | undefined, level: number, context: { scheme: ColorScheme | undefined; fonts: FontCollection; }): TextLevelStyle | undefined

The master's typography for one role at one outline level. The `.ppt` half of the ladder a paragraph climbs. In the modern format the rungs are the run, the shape's list style, the layout's and the master's; in this one there is no layout, so the ladder is shorter — the run's own properties over the master's level style — but the master's rung carries exactly the same information and matters exactly as much. A title in a deck of this age states nothing about itself at all: not its size, not its colour, not its face. All of that is here, and a reader that skips it renders every presentation ever made in Times New Roman at twelve points.

openPpt
function openPpt(source: ByteSource, options?: OpenPptOptions): Promise<PptxDocument>
openPptx
function openPptx(source: ByteSource, options?: OpenOptions): Promise<PptxDocument>

Opens a PowerPoint presentation. Reads the table of contents: slide order and canvas size. Each slide is a separate package part and is therefore parsed on demand: showing the first slide need not touch the other ninety-nine.

parseBackground
function parseBackground(root: XmlElement): DiagramFill | undefined

Reads `p:cSld/p:bg`: what the slide, layout or master is drawn on. Two spellings. `p:bgPr` states the fill outright; `p:bgRef` names an entry of the theme's background list and the colour to fill its placeholder with, exactly as a shape's `a:fillRef` does — so the same resolution serves both, and the reference is returned as a solid fill of the referenced colour when the theme is not at hand.

parseDiagramShapes
function parseDiagramShapes(root: XmlElement): Shape[]

The shapes of a SmartArt drawing, as slide shapes. A `dsp:sp` is a `p:sp` under another namespace — same transform, same geometry, same text body — so a deck needs no second renderer for SmartArt: the shapes go through the one that draws everything else, and inherit its text layout and its effects with them. That is why this is not `parseDiagramDrawing` from `@genomdev/office-core`, which reads the same part into a model of its own. A document and a workbook have no general shape renderer to hand the result to; a deck does, and using it draws more rather than less.

parseGraphicFrame
function parseGraphicFrame(element: XmlElement, ns?: string): Shape | undefined

Reads `p:graphicFrame`: a chart, a table or a diagram on a slide. Only the chart is followed further, because only the chart has a renderer already — the frame itself is read whatever it holds, so that the space it takes is not silently lost. Exported because a `.ppt` needs it and has no slide to reach it through. PowerPoint 2007 and later hide the modern form of a table or a diagram inside a binary presentation as a small package of their own, whose one part holds a `p:E2oFrame` — a graphic frame under another name, with the same children in the same namespace. `@genomdev/pptx` opens the package and hands the element here, so the table it holds is the same `SlideTable` a `.pptx` would have produced and everything above is unchanged.

parseListStyle
function parseListStyle(container: XmlElement | undefined): TextLevelStyle[]

Reads nine `a:lvlNpPr` out of a list style. The same nine levels appear in four places — the master's `p:txStyles`, a layout placeholder's `a:lstStyle`, the shape's own, and the presentation's default — and a paragraph takes the first answer it finds walking outwards. One reader serves all four.

parseRecords
function parseRecords(bytes: Uint8Array, from: number, to: number): PptRecord[]

Reads a sequence of records filling a range. Stops at the first header that cannot be believed. Continuing past one is worse than stopping: the reader would be somewhere inside a payload, where every eight bytes look like a header and the records it invents are indexed by the same code that indexes real ones.

parseSlide
function parseSlide(root: XmlElement): Shape[]

Parses a slide part (`ppt/slides/slideN.xml`). Shapes nest inside groups (`p:grpSp`), so the walk is recursive. Inheritance from the layout and master is deliberately not resolved here: that is a separate layer which needs access to the whole package, and it belongs to rendering rather than to parsing.

parseTableStyles
function parseTableStyles(root: XmlElement): Map<string, TableStyle>

Reads the part into a lookup by style id, braces and all.

parseTextBody
function parseTextBody(textBody: XmlElement): TextParagraph[]
placeholderOfKind
function placeholderOfKind(kind: number): string | undefined

The placeholder name a story's kind stands for, `title` and friends.

propValue
function propValue(props: TextProps | undefined, name: string): number | undefined
readColorScheme
function readColorScheme(data: Uint8Array): ColorScheme | undefined

Reads a `ColorSchemeAtom`. Eight four-byte values, each `red, green, blue, unused` — so the bytes are in the opposite order from the hex a person writes, and a reader that takes the low three bytes as `RGB` renders every deck in its own complement.

readCoreRecords
function readCoreRecords(stream: Uint8Array, directory: PersistDirectory): Map<number, PptRecord>

The records the directory names, read once and indexed by persist identifier. Reading them eagerly rather than on demand is deliberate and cheap: a presentation is a few megabytes at most, the records are already in memory, and the alternative — parsing a slide the first time somebody looks at it — would have to keep the stream alive anyway. What *is* deferred is the work above a record: turning it into shapes and paragraphs, which is where the time actually goes.

readDrawing
function readDrawing(drawing: PptRecord | undefined, context: DrawingContext): Shape[]

Reads a slide's drawing into shapes. The top of the tree is one group holding everything, and its own shape is the slide's canvas rather than something drawn — it is skipped, or the deck gets one full-slide rectangle in front of every slide.

readMasterStyleAtom
function readMasterStyleAtom(data: Uint8Array, instance: number): { paragraph: TextProps; character: TextProps; }[]

`TxMasterStyleAtom`: the deck's typography, one entry per outline level. The master's answer to `p:txStyles`, and the same information — but written as pairs, a paragraph exception and a character exception per level, and with one quirk that has to be got right. The record's instance number says which kind of text these levels describe, and the styles for a *centred* body and everything numbered above it write the level number before each pair, while a title's and a plain body's do not. Read the wrong way the two bytes are taken for the top half of the next mask, and the whole master comes out unformatted.

readMasterStyles
function readMasterStyles(master: PptRecord | undefined): MasterStyles

Reads the `TxMasterStyleAtom`s a master carries. Which kind an atom describes comes from its instance number and from nothing else: the atoms sit side by side in the master with no marker between them, so taking the first as the title and the second as the body by position happens to work for most files and fails for exactly those whose master states only one of the two.

readOutline
function readOutline(document: PptRecord | undefined, codePage: number): Outline
readPersistDirectory
function readPersistDirectory(stream: Uint8Array, startOffset: number | undefined): PersistDirectory

Reads the persist directory by walking the chain of saves. Each `UserEditAtom` is visited once. The guard matters more than it looks: a file whose chain loops — and fuzzers produce them, as do a few real files whose last save was interrupted — would otherwise be read until memory ran out, and the presentation is perfectly readable from the part of the chain that came before the loop.

readRecordAt
function readRecordAt(bytes: Uint8Array, at: number): PptRecord | undefined

Reads the record at an offset, and its children if it has any. A length running past the end of the stream is clamped rather than refused: a `.ppt` truncated by whatever copied it is common enough that losing the whole presentation over the last record would be the wrong trade. What is not clamped is a *nested* length — see {@link parseRecords}.

readStories
function readStories(records: readonly PptRecord[], codePage: number): TextStory[]

Splits a run of records into stories. Driven by the headers rather than by container structure, because there is no container: `[header][chars][styles][header][chars][styles]` is one list, and a reader that groups by anything else pairs the second story's characters with the first story's styles.

readStyleAtom
function readStyleAtom(data: Uint8Array, textLength: number): { paragraphs: StyleRun[]; characters: StyleRun[]; }

`StyleTextPropAtom`: the paragraph runs, then the character runs. Both lists cover the same text and neither states where it starts — each run says only how many characters it covers, so position is the running sum. The two lists are read one after the other out of one payload, which is why the character list cannot be read without the paragraph list being read correctly first: there is no offset to seek to. The text length is passed in because the atom does not carry it. The stated lengths are checked against it — a run claiming more characters than the story holds is a corrupt file, and believing it walks the reader off the end of a list that has no terminator.

recordHeaderAt
function recordHeaderAt(bytes: Uint8Array, at: number): { type: number; version: number; instance: number; length: number; } | undefined

The header at an offset, without reading the payload.

schemeReference
function schemeReference(index: number): DiagramColor

A scheme slot as a theme reference, for the places that state an index.

shapesToText
function shapesToText(shapes: readonly Shape[]): string

Collects all shape text of a slide, for search and previews.

showsMasterShapes
function showsMasterShapes(root: XmlElement): boolean

Whether a part draws the master's own shapes. `showMasterSp="0"` on a layout or a slide means "my design, not the one behind me" — 88 parts of the corpus say so, and drawing the master's logo over a layout that turned it off is worse than not drawing it at all.

storyToParagraphs
function storyToParagraphs(story: TextStory, context: TextContext): TextParagraph[]

Turns a story into the paragraphs the modern model uses. Three lists have to be walked at once and none of them is indexed: the characters, the paragraph runs and the character runs each say only how long they are. The walk below keeps one cursor over the text and consumes from the other two as it passes them, which is the only way to pair them — and it is why a single wrong length earlier in the file misformats everything after it rather than one run.

textStyleListFor
function textStyleListFor(styles: TextStyleDefaults, placeholderType: string | undefined): readonly TextLevelStyle[]

Which of the master's three lists describes a placeholder's text. Only three kinds of text exist as far as `p:txStyles` is concerned: a title, the body of a slide, and everything else.

themeOfScheme
function themeOfScheme(scheme: ColorScheme | undefined, fonts: { major: string | undefined; minor: string | undefined; }): Theme

The scheme as a theme, so that everything above this line stays unchanged. The renderer resolves `accent1` through a `Theme`, and a presentation that cannot hand it one is a presentation drawn without colours. The twelve slots are filled from the eight: the four the scheme has no opinion about take the value of the slot they are nearest to, which is what PowerPoint does when it converts a deck of this age.

topLevelRecords
function topLevelRecords(stream: Uint8Array): PptRecord[]

Every top-level record of the stream, for the tools rather than the reader. The reader has no use for this — a record not named by the directory is by definition not part of the presentation — but a person looking at a file that disagrees with PowerPoint does, and so does the dump tool.

walkPptx
function walkPptx(document: PptxDocument, hash: string, options: ResolvedOptions): Promise<{ blocks: Block[]; annotations: Annotation[]; }>

Reading a deck as content. Simpler than a document in one way and harder in another. A slide *is* a page, so there is no pagination to be honest about and the section structure is given. But a slide has no reading order: it is a bag of shapes at coordinates, and the order they appear in the file is the order they were drawn, which is z-order and not the order anybody reads them in. So shapes are sorted before they are walked — title first because it is the title, then top to bottom and left to right. A deck extracted in file order routinely puts the page number before the heading, and every chunk from it starts with "4".

Interfaces

ColorScheme
interface ColorScheme
colors
readonly string[]
The eight colours as `RRGGBB`, by slot.
DrawingContext
interface DrawingContext

A slide's drawing, read into the shapes the modern model uses. This is the part of a `.ppt` that is *not* peculiar to it. Everything a slide shows is an Office Art tree — the same tree a `.doc` anchors to its text and an `.xls` floats over its grid — so the walk below is the third of three, and the record layer under it is shared. What is peculiar is where the words are, and there are two answers rather than one. A text box carries its own story inside the shape, in a record that Office Art treats as opaque bytes and that turns out to hold PowerPoint records. A *placeholder* — the title and the bullets, which is most of the text in most decks — carries nothing at all: its words are in the document's outline list, and the shape names them by number. A reader that handles only the first shows every deck as its pictures and its captions with the title and the body missing, which is a plausible-looking presentation of nothing.

scheme
ColorScheme | undefined
text
TextContext
media
PptMedia | undefined
outline
readonly TextStory[]
The stories the outline list holds for this slide, in order.
partName
string
The part name shapes of this drawing are addressed against.
codePage
number
The code page eight-bit text in this presentation is written in.
claimed
Set<number>
Which outline stories this slide has already given to a shape. A slide's stories belong to its shapes one apiece, and the only rule that can hand the same one out twice is the fallback below — matching a placeholder to a story by *kind*, where a slide with six body placeholders matches all six to the first body story. `poi/datetime` is the extreme case: thirteen date placeholders, one story, and the same word thirteen times on the slide.
metro
Map<string, Uint8Array<ArrayBufferLike>>
The metro blobs met along the way, by shape id. Collected rather than read here because reading one means unzipping it, and this walk is synchronous by design — a slide's geometry should not have to wait on a decompressor. What comes out is applied in `document.ts`, where there is already a promise to hang it on.
metroMembers
Map<string, string[]>
The members a metro group would otherwise contribute, by the group's id. A table's blob sits on the *group* — the grid as a whole — and the group's members are the cells drawn the old way. Both are emitted, because whether the blob can be read is not known until it has been unzipped, and losing a grid to an unreadable blob would be worse than showing it twice. Whichever of the two survives is decided in `document.ts`, once the answer is in.
MasterStyles
interface MasterStyles

A master's typography, by kind of text and outline level. The `.ppt` counterpart of `p:txStyles`, and it is finer-grained than the modern format's three lists: a master carries one `TxMasterStyleAtom` per *text kind*, and there are nine of them. The title and the body are the two everyone knows about; the interesting one is the fifth, the centred body, which is what a subtitle on a title slide is. Collapsing the nine into three was worth exactly one visible bug and it is the kind to remember: a subtitle taking the body's style is a subtitle with a bullet in front of it, on the first slide of every deck built from the shipped template. Nothing about the number was wrong — the size, the face and the colour were all the body's, and the body's are nearly the subtitle's.

byKind
ReadonlyMap<number, readonly StyleLevel[]>
By `TextHeaderAtom` kind: 0 a title, 1 a body, 5 a centred body, and so on.
MediaPart
interface MediaPart

The presentation's picture store. The same Office Art store the other two binary formats keep, found in a different place and pointing somewhere else again. A `.ppt` puts the store in the document's `PPDrawingGroup` record and the *bytes* in a stream of their own, called `Pictures`, which each entry names by offset. So the store looks empty on inspection and the pictures are in a stream nothing else refers to — the same shape of trap Word sets by keeping them among its text, and it costs the whole deck's imagery when missed. Names are invented rather than read. The model addresses a picture by package part name and relationship id, because that is what the modern format gives it; a binary presentation has neither. `ppt/media/image3.png` is therefore a name this module makes up and answers to, which is what keeps the renderer, the extractor and the addressing scheme identical for both generations.

partName
string
contentType
string
OpenPptOptions
interface OpenPptOptions extends OpenOptions
password?
string | undefined
Accepted for symmetry with the other readers; encryption is not supported.
Outline
interface Outline
masters
readonly SlideEntry[]
slides
readonly SlideEntry[]
notes
readonly SlideEntry[]
PersistDirectory
interface PersistDirectory

Finding out which bytes of the stream are the presentation. This is the one structure a `.ppt` has that neither of its siblings does, and it exists because PowerPoint saved incrementally. Editing a slide appended a new copy of it to the end of the stream and left the old one where it was; a file of forty slides may hold four hundred, most of them superseded. Nothing in the stream marks a record as dead. What decides is a chain, and it is read backwards: `Current User`, a stream of its own, points at the *last* `UserEditAtom`. A `UserEditAtom` points at the persist directory of its own save, and at the `UserEditAtom` of the save before it. A persist directory maps *persist identifiers* — small numbers a slide is named by — to byte offsets. Walking the chain from the last save to the first, and letting each earlier directory fill only the identifiers no later one claimed, gives the current offset for every object. A reader that instead takes the first match walking forwards shows the presentation as it was when it was created.

offsets
ReadonlyMap<number, number>
Persist identifier to the offset of the record it currently names.
documentPersistId
number
Which persist identifier the `Document` record has, per the last save.
encrypted
boolean
True when a `DocumentEncryptionAtom` was found along the way.
PptRecord
interface PptRecord
type
number
version
number
instance
number
offset
number
Where the record's header begins in the stream that holds it.
data
Uint8Array<ArrayBufferLike>
The payload, always — a container's included. A view rather than a copy, so keeping it for records that also have children costs nothing, and it is the only way to read the two records whose children are in another language.
children
readonly PptRecord[]
PptxDocument
interface PptxDocument extends GenomDocument, PresentationTheme
format
"pptx" | "ppt"
Which generation of the format the deck was read from. Both readers produce this one model — `@genomdev/pptx` reads the binary record stream into it rather than converting — so the field is the only place the difference survives, and it is kept because a caller reporting what it opened should be able to say the truth.
kind
"presentation"
metadata
DocumentMetadata
slides
readonly Slide[]
pageCount
number
Slide count.
slideSize
{ width: number; height: number; }
Slide size in EMUs, from `p:sldSz`.
loadImage
(slide: Slide, relationshipId: string) => Promise<{ bytes: Uint8Array; contentType: string; } | undefined>
imageUrl
(slide: Slide, relationshipId: string) => Promise<string | undefined>
A URL for a slide's picture, metafiles translated.
imageUrlFrom
(partName: string, relationshipId: string) => Promise<string | undefined>
The same, for a picture belonging to any part: a layout's background.
imageSvgFrom
(partName: string, relationshipId: string) => Promise<string | undefined>
A translated metafile's SVG source, when its text is worth inlining.
oleImageUrl
(partName: string, shapeId: string) => Promise<string | undefined>
The picture an older embedded object keeps in the slide's VML drawing.
oleImageSvg
(partName: string, shapeId: string) => Promise<string | undefined>
The same, as SVG source, when that picture is a metafile worth inlining.
hyperlink
(slide: Slide, relationshipId: string) => Promise<string | undefined>
Where a run's `a:hlinkClick` points, when it points outside the deck.
Rect
interface Rect

A rectangle in EMUs, the DrawingML coordinate system.

x
number
y
number
width
number
height
number
Shape
interface Shape

A shape holding text or a picture.

id
string
name
string
frame
Rect | undefined
Position and size; `undefined` when inherited from the layout.
paragraphs
readonly TextParagraph[]
placeholderType
string | undefined
The shape role in the layout (`ph type`): `title`, `body`, `ctrTitle`. It tells the renderer that a shape is a title even when the styling lives in the slide layout rather than in the shape itself.
placeholderIndex
number | undefined
`p:ph/@idx`: which placeholder of its kind this is. PowerPoint matches a slide's placeholder to its layout's, and a layout's to its master's, on the type **and** this number — a template numbers its body 1, its date 2, its footer 3, and every placeholder a designer adds from ten up. Without it a subtitle and a content box are indistinguishable, and the chain hands one the other's anchor.
imageRelationshipId
string | undefined
Image relationship id when the shape is a picture (`p:pic`).
oleShapeId?
string | undefined
The `spid` of an embedded object whose picture is not beside it. Older files keep the picture of an embedded worksheet or document as a VML shape of this id, in a drawing part related to the slide, rather than in the `mc:Fallback` where a modern file puts it. Set only when there is no {@link imageRelationshipId} to use instead.
sourcePart
string | undefined
The part the shape was read from, when that is not the slide. A logo in the master is drawn on every slide of the deck, but the picture it points at is the master's: the relationship has to be resolved against the part that stated it, or the image is simply not found.
listStyle
readonly TextLevelStyle[] | undefined
`p:txBody/a:lstStyle`: what this shape sets for each outline level. The third rung of the ladder a paragraph climbs — its own properties, then its shape's list style, then the one its placeholder inherits from the layout and the master, then the master's `p:txStyles`. Layouts state 7 561 non-empty list styles across the corpus, and every one of them was ignored.
inheritedListStyle
readonly TextLevelStyle[] | undefined
The list style of the layout or master placeholder this shape matches.
inheritedListStyles
readonly (readonly TextLevelStyle[] | undefined)[] | undefined
The rest of the chain behind it: the master's placeholder, then anything behind that, outermost last. The layout and the master are rungs of one ladder and each states only what it changes, so taking the first that states *anything* discards the rest. A Google Slides export is the clearest case: its layout's title placeholder states a bullet size and an empty `a:defRPr`, which is enough to count as stating something, and the master's twenty-five points behind it were never read — `13928819-02_20241010_Vos_Code-and-software` drew its titles at the renderer's own fourteen.
geometry
DiagramGeometry | undefined
How the shape is painted, `p:spPr`. The same three things a shape has in a workbook and in a document — geometry, fill, outline — read into the same types, so that the renderer that draws an Excel shape draws this one.
fill
DiagramColor | undefined
filled
boolean
paint
DiagramFill | undefined
The fill as stated, when it is not a flat colour. A gradient panel, a hatched box and a shape filled with a photograph were all drawn as nothing, because only `a:solidFill` was read.
outline
DiagramOutline | undefined
style
ShapeStyleReference | undefined
`p:style`: how the deck's theme paints this shape. Most shapes state no colour at all — they name an entry of the theme's format scheme and the colour to fill its placeholder with. Ignored, they are drawn unpainted, with their labels in the default colour on the default background: which is white on white for a third of the corpus's slides.
shadow
DiagramShadow | undefined
`a:effectLst/a:outerShdw`: the shadow the shape casts, if any.
rotation
number
`a:xfrm/@rot`, in degrees clockwise; a slide states sixtieths of one.
flipHorizontal
boolean
`a:xfrm/@flipH` and `@flipV`: the shape drawn mirrored.
flipVertical
boolean
verticalAlignment
"center" | "top" | "bottom" | undefined
`a:bodyPr`: where the text sits inside the shape. A shape is a box and its text is placed in it: `@anchor` says against which edge, `@lIns` and friends say how far from it. Both have defaults that are not zero and not centre — PowerPoint anchors to the top and insets by a tenth of an inch — so a reader that ignores them puts every caption in a different place from the one the deck was designed with.
insets
TextInsets | undefined
statesBody
boolean | undefined
Whether the shape carried an `a:bodyPr` of its own at all. `@wrap` and `@vert` have defaults that are indistinguishable from silence once read — `wrap` is `square` and `vert` is `horz` — so the only way to tell a shape that asked for wrapping from one that said nothing is to record that the element was there. Without it a slide placeholder with an empty `<a:bodyPr/>` would override a layout that turns wrapping off.
wrap
boolean
`a:bodyPr/@wrap`: `none` lets a long line run past the shape.
spaceFirstLastParagraph
boolean | undefined
`a:bodyPr/@spcFirstLastPara`: the space before the first paragraph counts. Off by default, and the probes say so: `paragraph-spacing` and `placeholder-spacing` both put the first line of three boxes stating nothing, twelve points and twenty per cent on one baseline. On, the space is drawn — `13683066-Bijloke_AnatomicalTheatre` states ten points and PowerPoint sets the whole block 13.33 px lower, which is those ten points. **7979 shapes of the corpus state it**, in 160 decks: everything Google Slides exports, which writes the attribute on every box it makes.
textDirection
"horizontal" | "vertical" | "vertical270" | "eastAsian"
`a:bodyPr/@vert`: text set on its side. A side caption, a table's rotated header, the spine of a poster: the file turns the text rather than the shape. Drawn horizontally it overflows the narrow box it was given and covers whatever is beside it.
textRotation?
number | undefined
`a:bodyPr/@rot`: the text's own turn inside the shape, in 60000ths of a degree, on top of whatever the shape itself is turned by.
textFrame?
Rect | undefined
`dsp:txXfrm`: the rectangle a SmartArt label is set in, in the diagram's space. Shares its centre with the shape's own frame.
fontScale
number | undefined
`a:normAutofit/@fontScale`: how far PowerPoint shrank the text to fit. A stated number rather than a guess — the application worked it out when the deck was saved and wrote it down, so a reader that ignores it draws text at a size the author never saw, overflowing the box it was shrunk to fit.
lineSpacingReduction
number | undefined
`a:normAutofit/@lnSpcReduction`, as a fraction.
table
SlideTable | undefined
`a:tbl` inside a graphic frame: the rows, in reading order.
chartRelationshipId
string | undefined
`p:graphicFrame` pointing at a chart part, by relationship id.
diagram
readonly Shape[] | undefined
A SmartArt diagram, once the drawing PowerPoint saved with it is read. The diagram itself is a data model and a layout algorithm — laying it out is a program, not a parse — but every deck written since 2010 also carries the shapes the application produced, in ordinary DrawingML. Those are what is drawn: 54 decks of the corpus have one, and without it a SmartArt frame is an empty rectangle in the middle of the slide.
diagramData
string | undefined
`dgm:relIds/@r:dm`: the data part, which names the drawing beside it.
chart
ChartDefinition | undefined
The chart itself, once the slide has read the part it points at. Parsed rather than referenced: `c:chartSpace` is the same part on a slide as in a workbook, and the renderer that draws it is the same too.
Slide
interface Slide
index
number
Zero-based position in the presentation.
partName
string
load
() => Promise<SlideContent>
SlideBackground
interface SlideBackground

A background, and the part whose relationships resolve its picture.

styleIndex?
number | undefined
`p:bgRef/@idx`, zero-based: the entry of the theme's background list. Present only when the part named one. The fill beside it is the colour that entry is filled *with*; the entry itself may be a picture, and only the theme knows.
fill
DiagramFill
partName
string
The part the fill was found in: a slide, a layout or a master.
SlideContent
interface SlideContent
shapes
readonly Shape[]
themePart?
string | undefined
The theme part this slide inherits, reached through its layout and master. A deck has one theme per master and a notes theme besides, and the document's own `theme` can only be one of them. A slide knows which is its own, and it is the only thing that does.
masterPart?
string | undefined
The slide master this slide's layout belongs to. A deck may carry several, and 114 of the corpus's 1775 do — every merged presentation and every template with two designs. The master is where the default size, colour, bullet and paragraph gap of every placeholder come from, so reading the *first* master in the package described those slides with another design's typography.
colorMap?
Readonly<Record<string, string>> | undefined
`p:clrMap`, as this slide inherits it: which theme colour each role uses. Per slide because a layout may override it and the layouts of one deck differ — a dark section in a light deck is exactly this and nothing else.
notes
string | undefined
Speaker notes, when the package contains that part.
background
SlideBackground | undefined
What the slide is drawn on: its own background, or the one it inherits. Slides state a background 41 times in the corpus and masters 505 — a deck's background is a property of its design, not of its slides — so a reader that looks only at the slide draws every designed deck on white.
SlideEntry
interface SlideEntry

The document's outline: which slides there are, in which order, and what their placeholders say. `SlideListWithText` is two things at once and that is the whole of its awkwardness. It is the presentation's table of contents — a `SlidePersistAtom` per slide, naming the record that holds it — and it is *also* where the text of every outline placeholder lives, as stories following the atom they belong to. So a slide's title is not in the slide; it is here, and the slide's title shape merely points back at it by number. There are three of these lists and they are told apart by the record's instance number, not by their position among the document's children: the masters, the slides, the notes. Taking them by position puts the masters' text on the slides for any file whose lists are not all present.

reference
number
The persist identifier of the record holding the slide.
slideId
number
The slide's own identifier, which the notes refer to it by.
stories
readonly TextStory[]
The stories this slide's placeholders hold, in the order they appear.
SlideTable
interface SlideTable

A table on a slide: column widths and rows of cells.

columns
readonly number[]
Column widths in EMUs, from `a:gridCol`.
rows
readonly SlideTableRow[]
styleId
string | undefined
`a:tableStyleId`: the GUID of the style in `ppt/tableStyles.xml`. A table states almost nothing about its own look; it names a style and sets the flags below, and the part says what those mean. Without it every table in every deck is drawn as the same grey grid.
firstRow
boolean
`a:tblPr` flags: which special parts of the style apply.
lastRow
boolean
firstColumn
boolean
lastColumn
boolean
bandRow
boolean
bandColumn
boolean
SlideTableCell
interface SlideTableCell
paragraphs
readonly TextParagraph[]
merged
boolean
Cells a merge swallowed carry no content and are not drawn.
columnSpan
number
rowSpan
number
fill
DiagramColor | undefined
insets
{ left: number; top: number; right: number; bottom: number; }
`a:tcPr/@marL`, `@marR`, `@marT`, `@marB`: the cell's own insets, in EMUs. Defaulted here rather than left unstated, because DrawingML defaults them and a table states them only to depart: a tenth of an inch left and right, a twentieth top and bottom. They were not read at all until now and the renderer padded cells by a percentage of the table's width instead — which is neither the right distance nor the same distance twice, since a percentage padding resolves against the width on all four sides.
verticalAlignment
"center" | "top" | "bottom"
`a:tcPr/@anchor`: which edge of the cell the text sits against.
SlideTableRow
interface SlideTableRow
height
number
Row height in EMUs, from `a:tr/@h`; Word calls this a minimum.
cells
readonly SlideTableCell[]
StyleRun
interface StyleRun

One run of a style atom: how many characters it covers, and what it says.

length
number
props
TextProps
level
number
Outline level, paragraph runs only.
TableBorder
interface TableBorder

A rule, stated outright or as a reference into the theme's line list.

outline
DiagramOutline | undefined
reference
StyleReference | undefined
TableBorders
interface TableBorders
left
TableBorder | undefined
right
TableBorder | undefined
top
TableBorder | undefined
bottom
TableBorder | undefined
insideHorizontal
TableBorder | undefined
insideVertical
TableBorder | undefined
TablePartStyle
interface TablePartStyle

One part of a table style: the whole table, a band, a header row.

fill
DiagramFill | undefined
`a:tcStyle/a:fill`, stated outright.
fillReference
StyleReference | undefined
`a:tcStyle/a:fillRef`: the theme entry the part is filled from.
bold
boolean | undefined
italic
boolean | undefined
textColor
DiagramColor | undefined
textReference
StyleReference | undefined
borders
TableBorders
TableStyle
interface TableStyle

A whole table style: the parts, in the order they override each other. PowerPoint applies them from the least specific to the most: the whole table, then the banding, then the first and last rows and columns. A cell in the header row of a banded table is painted by three of them in turn.

wholeTable
TablePartStyle | undefined
band1Horizontal
TablePartStyle | undefined
band2Horizontal
TablePartStyle | undefined
band1Vertical
TablePartStyle | undefined
band2Vertical
TablePartStyle | undefined
firstRow
TablePartStyle | undefined
lastRow
TablePartStyle | undefined
firstColumn
TablePartStyle | undefined
lastColumn
TablePartStyle | undefined
TextContext
interface TextContext

What a story needs from the deck to become paragraphs. The colour scheme because a run's colour is usually an index into it, and the font collection because a run's typeface is an index too — a `.ppt` states "font seven", and only the document knows that font seven is Verdana.

scheme
ColorScheme | undefined
fonts
FontCollection
slideNumber?
number | undefined
Which slide this is, one-based, for a story that holds a page number. The number is nowhere in the file — a `.ppt` marks the position and leaves the arithmetic to whatever draws the slide, which is the same arrangement the modern format has and the same reason a renderer has to be told.
TextLevelStyle
interface TextLevelStyle

What the master sets for one outline level of one kind of placeholder. `p:txStyles` is the deck's typography: it says a title is 40pt, bold, and coloured `tx2`, and a first-level bullet 20pt in `tx1`. Reading only the size out of it — which is where this started — gives every deck the right scale in the wrong colour.

sizePoints
number | undefined
color
DiagramColor | undefined
bold
boolean | undefined
italic
boolean | undefined
typeface
string | undefined
caps
"all" | "none" | "small" | undefined
`a:defRPr/@cap`: a level set in capitals, which a run need not repeat.
alignment
"left" | "center" | "right" | "justify" | undefined
lineSpacing
TextSpacing | undefined
The spacing and the bullet the level carries. The master is where a deck's list looks like a list: the step between lines, the gap above an item, how far it is indented, and which glyph marks it. A slide states these only when it departs from them, so a reader that takes them from the paragraph alone renders most decks unbulleted and unspaced.
spaceBefore
TextSpacing | undefined
spaceAfter
TextSpacing | undefined
marginLeft
number | undefined
indent
number | undefined
tabSize
number | undefined
`a:lvlNpPr/@defTabSz`; see {@link TextParagraph.tabSize}.
rightToLeft
boolean | undefined
`a:lvlNpPr/@rtl`: the level runs right to left; see {@link TextParagraph.rightToLeft}.
bulletChar
string | undefined
bulletPicture
boolean | undefined
`a:buBlip`; see {@link TextParagraph.bulletPicture}.
bulletStated?
boolean | undefined
Whether the level *said* whether it is bulleted, as against leaving it unsaid. PowerPoint 97-2003 only: the binary format writes the marker's character and the flag that turns it on as two independent fields, and a master states the character far more often than the flag.
bulletNone
boolean
bulletColor
DiagramColor | undefined
bulletSizePercent
number | undefined
bulletSizePoints
number | undefined
`a:buSzPts`: the marker's size in points; see {@link TextParagraph.bulletSizePoints}.
bulletFont
string | undefined
kerningFrom
number | undefined
`a:defRPr/@kern`: the size from which text at this level is kerned. The masters state it and the runs almost never do — the shipped template writes `kern="1200"` on every level of every style — so a rule that read the run alone kerned nothing at all. `45541_Footer` shows the cost on its title: 711 pixels in PowerPoint and 743 in ours, four and a half per cent of a line that has to wrap in the same place.
TextParagraph
interface TextParagraph

A paragraph of a text body (`a:p`).

runs
readonly TextRun[]
level
number
List nesting level; 0 is the top level.
alignment
"left" | "center" | "right" | "justify" | undefined
bulletChar
string | undefined
Bullet glyph, when the paragraph is bulleted.
bulletNumbering
{ readonly scheme: string; readonly startAt: number; } | undefined
`a:buAutoNum`: the paragraph is numbered rather than bulleted. The scheme names the shape of the number — `arabicPeriod` is `1.`, `alphaLcParenR` is `a)` — and `startAt` restarts the count. The number itself is not in the file: it is the paragraph's position among its neighbours at the same level, which only the renderer knows.
bulletPicture
boolean
`a:buBlip`: the marker is a picture rather than a character. The image itself is a relationship of the part the bullet was written in — usually a master — and is not drawn yet. What matters for the text is that a marker is *there*: it occupies the hanging indent, so the words start at `marL` like any other bulleted paragraph rather than at the hang. `19944360-Lecture-4` sets every second-level bullet this way, and without it the whole block sits 36 px left of PowerPoint's.
bulletNone
boolean
`a:buNone`: the paragraph states that it has no bullet at all.
bulletColor
DiagramColor | undefined
`a:buClr`, `a:buSzPct`, `a:buFont`: how the marker itself is set.
bulletSizePercent
number | undefined
bulletSizePoints
number | undefined
`a:buSzPts`: the marker's size in points, stated outright. The commoner of the two forms by a distance — **167 decks and 65132 occurrences against 4937 of `a:buSzPct`** — and it was not read at all, so every such marker was drawn at the text's size instead of its own. It is not only the marker that moves: a bullet is the widest thing on the first line of its paragraph as often as not, and its box is what holds the hang open, so the whole text column starts somewhere else. A length, and therefore not autofit's to shrink; see `autofitSize`.
bulletFont
string | undefined
lineSpacing
TextSpacing | undefined
The spacing a paragraph asks for, which nothing used to read. `a:lnSpc` is the step between its lines and `a:spcBef`/`a:spcAft` the gaps around it, each stated either as a percentage of the type size or as a number of points. Ignored, every list in every deck comes out at the browser's own line height with no space between items: the commonest thing in a presentation, set wrong.
spaceBefore
TextSpacing | undefined
spaceAfter
TextSpacing | undefined
marginLeft
number | undefined
`a:pPr/@marL` and `@indent`, in EMUs: the list's own indentation.
tabSize
number | undefined
`a:pPr/@defTabSz`: how far apart this paragraph's tab stops are, in EMUs. An inch unless the file says otherwise — and the file says it *here*, or on the level style behind it, and not on `a:bodyPr`: the probe `tab-grid` states half an inch in both places and PowerPoint honours only the paragraph's. A deck converted from `.ppt` carries the value on every level of its master.
indent
number | undefined
rightToLeft
boolean | undefined
`a:pPr/@rtl`: the paragraph runs right to left. Arabic, Hebrew and Persian decks state it on every paragraph, and it decides three things at once — which edge the text starts from, which end the bullet sits at, and the order the words of a mixed line come out in. Unread, such a deck is drawn left-aligned with its runs in file order, and the corpus shows what that costs: the nine decks that state it produce 37.6% of their lines against 73.8% for the rest, and place 7.7% against 25.2%. It is the widest gap any construct in the census shows.
endProperties
TextRunProperties | undefined
`a:endParaRPr`: the properties of the paragraph mark itself. Only interesting when the paragraph holds nothing else — and then it is the whole of it. PowerPoint gives an empty paragraph a line box of *this* type, not of the level's: `poi/alterman_security` separates two bullets with an empty paragraph whose mark states 28 points where its level says 32, and a reader that takes the level puts everything below it six pixels low.
TextProps
interface TextProps

The values a mask named, by property name, and which bits were set.

mask
number
values
ReadonlyMap<string, number>
TextRun
interface TextRun
field?
string | undefined
`a:fld/@type` where the run is a field: `slidenum`, `datetime1`… The text beside it is what the application last cached, which for a slide number inherited from a layout is a placeholder rather than a number.
math?
readonly MathNode[] | undefined
An equation, where the run is one. `m:oMath` sits among a paragraph's runs and holds a tree rather than a string — a fraction, a root, a sum with its limits. It is text: PowerPoint draws it as letters and its export writes every one of them into the PDF. The run's `text` is the same letters in reading order, so anything that only wants the words still gets them.
text
string
properties
TextRunProperties
TextRunProperties
interface TextRunProperties

Formatting of a text fragment (`a:rPr`).

bold?
boolean | undefined
italic?
boolean | undefined
underline?
boolean | undefined
fontSize?
number | undefined
Size in points; the file stores hundredths of a point.
fontFamily?
string | undefined
color?
string | undefined
Colour as `RRGGBB`, when given literally.
colorReference?
DiagramColor | undefined
The colour as the file states it, theme slots and all. Most templates colour their text by theme (`a:schemeClr val="tx1"`) rather than literally, and a reader that only takes `a:srgbClr` renders those runs in whatever the stylesheet happens to inherit.
hyperlinkId?
string | undefined
`a:hlinkClick`: the relationship the run links through.
shadow?
DiagramShadow | undefined
`a:rPr/a:effectLst/a:outerShdw`: the shadow behind the letters. The commonest effect in the corpus by a distance — 514 runs of 1 044 effect lists — because a title over a photograph is unreadable without one.
textOutline?
DiagramOutline | undefined
`a:rPr/a:ln`: the line drawn around the letters. A title outlined in white over a photograph is the commonest use, and fourteen decks of the corpus draw one on their first slide alone. Without it such a title is the fill alone, which over a busy picture is nothing.
textPicture?
string | undefined
`a:rPr/a:blipFill`: the picture the letters are filled with. Twenty-two decks of the corpus do it — a heading cut out of a photograph or a pattern — and drawn as flat text it is the wrong colour entirely. The relationship belongs to the part the shape came from.
baseline?
number | undefined
`@baseline`: the run is raised or lowered, as a share of the type size. How a presentation writes a superscript — 522 runs of the corpus do — and drawn on the baseline they read as ordinary digits: "m2" for "m²".
letterSpacing?
number | undefined
`@spc`: letter spacing in points, positive to open the line up.
caps?
"all" | "none" | "small" | undefined
`@cap`: `all` for capitals, `small` for small ones, `none` for neither. `none` is recorded rather than dropped because the level style above the run may state `all`, and a run departing from it has to be able to say so.
strike?
"single" | "double" | undefined
`@strike`: `sngStrike` or `dblStrike`.
kerningFrom?
number | undefined
`@kern`: the size, in points, from which the run is kerned. A *threshold*, not a switch, and its absence means no kerning at all — which is not the browser's default and never was. The probe `kerning` measures the difference: the same line of Times New Roman at 44 points comes out 694 pixels wide when the file states `kern="1200"` and **743** when it states nothing, and a line seven per cent wide wraps a word early — after which neither side has the same lines at all.
eastAsianFont?
string | undefined
`a:ea`: the typeface for East Asian text, when it differs from the Latin.
complexScriptFont?
string | undefined
`a:cs`: the face for Arabic, Hebrew and the other complex scripts.
TextSpacing
interface TextSpacing

A spacing, as a share of the type size or as an absolute measure.

percent
number | undefined
`a:spcPct/@val`, as a fraction: 1.5 for one and a half lines.
points
number | undefined
`a:spcPts/@val`, in points.
TextStory
interface TextStory

A text story, and turning one into paragraphs. A story is a run of records rather than a container: a `TextHeaderAtom` saying what kind of text follows, then the characters — as bytes or as UTF-16, never both — then the styles that cover them. They sit side by side in whatever holds them, a slide's drawing or the document's outline list, and a story ends where the next header begins. The characters are one string with `\r` between paragraphs. Nothing marks a paragraph otherwise; the styles are stated as runs over that string, so a paragraph's formatting is found by counting characters, not by looking it up.

kind
number
`TextHeaderAtom`'s kind: title, body, notes, other.
index
number
Position among the stories of the list this one came from.
text
string
paragraphStyles
readonly StyleRun[]
characterStyles
readonly StyleRun[]
indents
readonly { length: number; level: number; }[]
`MasterTextPropAtom`: the outline level of each run, when stated apart.
fields
readonly { position: number; kind: "slideNumber" | "date" | "footer"; }[]
Where the story holds a field rather than a character. A slide number, a date and a footer are not text in a `.ppt`: the story holds one placeholder character and a *metacharacter atom* beside it saying which position that character stands at and what it stands for. The character itself is usually `*`, which is why a reader that ignores these draws an asterisk where PowerPoint draws the page number — thirteen of them on the first slide of `poi/datetime`.
ruler
TextRuler | undefined
`TextRulerAtom`: the story's own tab grid, where it states one.

Type aliases

StyleLevel
type StyleLevel = { paragraph: TextProps; character: TextProps }

One outline level's typography: the paragraph's and the run's.

Values

BulletFlag
BulletFlag: { readonly Bulleted: 1; readonly HardFont: 2; readonly HardColor: 4; readonly HardSize: 8; }

Bits of the paragraph `bulletFlags` field.

CharFlag
CharFlag: { readonly Bold: 1; readonly Italic: 2; readonly Underline: 4; readonly Shadow: 16; readonly Strike: 256; readonly Emboss: 512; }

Bits of the character `flags` field.

CURRENT_USER_STREAM
CURRENT_USER_STREAM: "Current User"

Where the pointer to the most recent edit is kept, outside the document.

DEFAULT_PPT_SLIDE_SIZE
DEFAULT_PPT_SLIDE_SIZE: { readonly width: number; readonly height: number; }

Slide size when a document states none: the 10 by 7.5 inch default of 1997.

DEFAULT_SLIDE_SIZE
DEFAULT_SLIDE_SIZE: { readonly width: 12192000; readonly height: 6858000; }

Default slide size: widescreen 16:9, 13.333 by 7.5 inches.

DEFAULT_TEXT_INSETS
DEFAULT_TEXT_INSETS: { readonly left: 91440; readonly top: 45720; readonly right: 91440; readonly bottom: 45720; }

`a:bodyPr` insets when the file states none, in EMUs. A tenth of an inch left and right, a twentieth top and bottom — PowerPoint's defaults, and not zero, so text never touches the edge of its shape.

DOCUMENT_STREAMS
DOCUMENT_STREAMS: readonly ["PowerPoint Document", "PP97_DUALSTORAGE"]

The streams a presentation may live in. `PowerPoint Document` is the one every version since 97 writes. The second is a curiosity worth handling: a file saved by PowerPoint 95 for compatibility keeps *both* generations side by side, and the modern stream is the one to read — but some tools keep only the old name.

EMPTY_OUTLINE
EMPTY_OUTLINE: Outline
EMU_PER_MASTER_UNIT
EMU_PER_MASTER_UNIT: number

Master units to EMUs. A `.ppt` measures in 576ths of an inch and a `.pptx` in 914 400ths; the ratio is exact, which is the only reason the two models can share a rectangle type without either side rounding.

PLACEHOLDER_OF_ID
PLACEHOLDER_OF_ID: Readonly<Record<number, string>>

`OEPlaceholderAtom`'s identifier as the placeholder name `.pptx` uses.

PLACEHOLDER_OF_TEXT_KIND
PLACEHOLDER_OF_TEXT_KIND: Readonly<Record<number, string>>

The text kind translated into the placeholder name the modern format uses. The whole point of the exercise: once a story says `ctrTitle` rather than `6`, the typography ladder, the extractor and the renderer built for `.pptx` treat it as the title it is, with no code anywhere that knows the deck came out of PowerPoint 97.

PlaceholderId
PlaceholderId: { readonly None: 0; readonly MasterTitle: 1; readonly MasterBody: 2; readonly MasterCenteredTitle: 3; readonly MasterSubTitle: 4; readonly MasterNotesSlideImage: 5; readonly MasterNotesBody: 6; readonly MasterDate: 7; readonly MasterSlideNumber: 8; readonly MasterFooter: 9; readonly MasterHeader: 10; readonly NotesSlideImage: 11; readonly NotesBody: 12; readonly Title: 13; readonly Body: 14; readonly CenteredTitle: 15; readonly SubTitle: 16; readonly VerticalTextTitle: 17; readonly VerticalTextBody: 18; readonly Object: 19; readonly Graph: 20; readonly Table: 21; readonly ClipArt: 22; readonly OrganisationChart: 23; readonly MediaClip: 24; }

`OEPlaceholderAtom`'s placeholder identifiers. A superset of the text kinds above: it also names the three things that are placeholders but hold no outline text — the date, the footer and the slide number — which is exactly the set a renderer must not draw as body text.

pptx
pptx: FormatModule<PptxDocument>

PowerPoint presentations, both generations, as one module. Recognition is stated as data so the registry can pick this module out of six without loading any of them: an OPC package announces its main part's content type, and that is the only thing that tells the three OOXML formats apart. The compound file is the case rules cannot settle — a `.doc`, an `.xls` and a `.ppt` share one signature — so it shortlists itself and `canOpen` reads the directory to be sure. One module rather than two because the binary reader produces the same model: nothing above here has to know which generation it was handed.

Rec
Rec: { readonly Document: 1000; readonly DocumentAtom: 1001; readonly EndDocument: 1002; readonly Slide: 1006; readonly SlideAtom: 1007; readonly Notes: 1008; readonly NotesAtom: 1009; readonly Environment: 1010; readonly SlidePersistAtom: 1011; readonly MainMaster: 1016; readonly SSSlideInfoAtom: 1017; readonly RoundTripHFPlaceholder12: 1056; readonly ExObjList: 1033; readonly PPDrawingGroup: 1035; readonly PPDrawing: 1036; readonly List: 2000; readonly FontCollection: 2005; readonly ColorSchemeAtom: 2032; readonly ExObjRefAtom: 3009; readonly OEPlaceholderAtom: 3011; readonly OutlineTextRefAtom: 3998; readonly TextHeaderAtom: 3999; readonly TextCharsAtom: 4000; readonly StyleTextPropAtom: 4001; readonly MasterTextPropAtom: 4002; readonly TxMasterStyleAtom: 4003; readonly TxCFStyleAtom: 4004; readonly TxPFStyleAtom: 4005; readonly TextRulerAtom: 4006; readonly TextBytesAtom: 4008; readonly TextSpecInfoAtom: 4010; readonly FontEntityAtom: 4023; readonly CString: 4026; readonly ExOleObjAtom: 4035; readonly ExEmbed: 4044; readonly ExHyperlinkAtom: 4051; readonly ExHyperlink: 4055; readonly SlideNumberMCAtom: 4056; readonly HeadersFooters: 4057; readonly HeadersFootersAtom: 4058; readonly TxInteractiveInfoAtom: 4063; readonly SlideListWithText: 4080; readonly InteractiveInfo: 4082; readonly InteractiveInfoAtom: 4083; readonly UserEditAtom: 4085; readonly DateTimeMCAtom: 4087; readonly GenericDateMCAtom: 4088; readonly FooterMCAtom: 4090; readonly ExOleObjStg: 4113; readonly ProgTags: 5000; readonly ProgStringTag: 5001; readonly ProgBinaryTag: 5002; readonly PersistPtrFullBlock: 6001; readonly PersistPtrIncrementalBlock: 6002; readonly Comment2000: 12000; readonly Comment2000Atom: 12001; readonly DocumentEncryptionAtom: 12052; }

The record types a PowerPoint 97-2003 stream is made of. Numbered rather than named — a `.ppt` has no XML and no vocabulary, only these numbers — and grouped the way the format groups them: the document and its slides in the 1000s, the collections in the 2000s, text in the 4000s. Only the types this reader acts on are listed; everything else is stepped over by its stated length, which is what lets a reader written against PowerPoint 97 walk a file PowerPoint 2003 saved.

SchemeSlot
SchemeSlot: { readonly Background: 0; readonly TextAndLines: 1; readonly Shadows: 2; readonly TitleText: 3; readonly Fills: 4; readonly Accent: 5; readonly AccentAndHyperlink: 6; readonly AccentAndFollowedHyperlink: 7; }

The eight slots, in the order the atom writes them.

SlideListRole
SlideListRole: { readonly Slides: 0; readonly Masters: 1; readonly Notes: 2; }

Which of a `SlideListWithText`'s three roles this one holds. The instance number of the record says it, and the three are not interchangeable: the first lists the masters, the second the slides in their presentation order, the third the notes pages. A reader that takes them by position among the document's children gets the masters and the slides the right way round only by luck.

TextKind
TextKind: { readonly Title: 0; readonly Body: 1; readonly Notes: 2; readonly Outline: 3; readonly Other: 4; readonly CenterBody: 5; readonly CenterTitle: 6; readonly HalfBody: 7; readonly QuarterBody: 8; }

What kind of text a story holds, from `TextHeaderAtom`. The nearest thing the binary format has to `p:ph/@type`, and it is what turns a box of words into a title: the outline placeholders are numbered here and the renderer asks the master for a title's typography by this number.

@genomdev/pptx/view

Classes

PptxView
class PptxView extends BaseDocumentView<PptxDocument>

Renders a presentation: one slide on screen plus navigation. A slide is built by positioning shapes absolutely from their EMU coordinates, scaled to the actual canvas size. That preserves the original composition, which flow layout cannot reproduce. Inheritance from the layout and master is not implemented yet: a shape with no explicit parameters is drawn with defaults. It shows mostly in the size and colour of title fonts.

currentSlideIndex
number
pageOfLocator
(locator: string) => number | undefined
Which slide an address is on. A deck shows one slide at a time, so a highlight on slide forty is in the same position as a highlight on page four hundred of a document: it will never appear by scrolling, because the slide is not drawn. The flow of the address says which slide, and that is the whole answer — no layout is involved, because a slide is a page by construction.
goTo
(index: number) => void
next
() => void
previous
() => void
renderContent
() => Promise<void>
Renders the content into {@link root}. Called on every update.
initialize
() => Promise<void>
The theme is read before the first slide is drawn, once per document.
destroy
() => void
Tear the view down and release resources. The container is left empty.

Interfaces

PptxViewOptions
interface PptxViewOptions extends ViewOptions

What the host may ask of the presentation view beyond the common options. The built-in toolbar exists so that the view is usable on its own — dropped into a page with nothing around it, it must still be possible to reach slide seven. An application that has its own navigator (the playground's toolbar counts slides for every format alike) turns it off and drives `goTo` itself, and then wants to be told when the slide changes so its counter agrees.

toolbar?
boolean | undefined
Draw the previous/next strip under the slide. Default: yes.
notes?
boolean | undefined
Show the speaker notes under the slide. Default: yes.
onSlideChange?
((index: number) => void) | undefined
Called whenever the shown slide changes, with its zero-based index.
locators?
boolean | { hash: string; } | undefined
Stamp shapes and paragraphs with the address extraction gave them. Off by default: a viewer that never highlights anything should pay nothing for the attributes. On, it is what lets a passage found by a retrieval system be scrolled to and highlighted in the deck it came from.

Values

PPTX_VIEW_CSS
PPTX_VIEW_CSS: "\n.genom-pptx {\n --genom-canvas-background: #2b2b2f;\n --genom-slide-background: #ffffff;\n --genom-slide-text: #1a1a1a;\n --genom-chrome-text: #d0d0d4;\n\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--genom-canvas-background);\n font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;\n /*\n * Off, because PowerPoint's own default is off.\n *\n * The a:rPr/@kern attribute is a threshold — the run is kerned from that\n * size up — and a file that states none is not kerned at any size. The\n * browser kerns everything, which made every unkerned line narrower than\n * PowerPoint draws it: seven per cent on a 44-point title, and a word\n * wrapped earlier than it should be. Runs that state a threshold turn it\n * back on.\n */\n font-kerning: none;\n}\n\n/*\n * The slide, centred on the stage — but never at the cost of its own edges.\n *\n * Plain `center` centres an item wider than its container too, which puts the\n * overflow on both sides, and a scroll container cannot reach what hangs off\n * its start. A slide zoomed past the window lost its top and its left with no\n * way to scroll to them. `safe` centres while it fits and aligns to the start\n * when it does not.\n */\n.genom-pptx__stage {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n align-items: safe center;\n justify-content: safe center;\n padding: 24px;\n overflow: auto;\n}\n\n/*\n * The slide's place on the stage, at the size the reader is looking at it.\n *\n * The drawing inside is at the size the file states and is scaled by a\n * transform, which does not affect layout — so this is what the stage lays out,\n * what the shadow is drawn around, and what a scrollbar measures.\n */\n.genom-pptx__stage-slide {\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);\n flex: 0 0 auto;\n}\n\n/* The slide itself, always at its natural size. */\n\n.genom-pptx__slide {\n background: var(--genom-slide-background);\n color: var(--genom-slide-text);\n overflow: hidden;\n}\n\n/* The shape's own outline, drawn under its text and never intercepting it. */\n\n.genom-pptx__outline {\n position: absolute;\n inset: 0;\n overflow: visible;\n pointer-events: none;\n}\n\n/* Shapes are positioned absolutely: PresentationML gives explicit coordinates. */\n/*\n * Text sits at the top of its shape unless the shape says otherwise.\n *\n * PresentationML's default anchor is `t`, and centring by default put every\n * unanchored caption half a box lower than the deck was designed with. The\n * shape's own declarations override this when `a:bodyPr/@anchor` states one.\n */\n.genom-pptx__shape {\n position: absolute;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n overflow: visible;\n}\n\n/*\n * A tab is a stop on an inch grid, not eight spaces.\n *\n * CSS measures a tab in *space widths* by default — eight of them, about five\n * ems of the running type — while PowerPoint advances to the next multiple of\n * a:bodyPr/@defTabSz, which is one inch unless a deck says otherwise. Old decks\n * set their tables with tabs: 15686698-Takahashi-IMFP05 writes three columns in\n * one paragraph, and on the browser's grid the three ran together into a line\n * that pairs with none of PowerPoint's three.\n */\n.genom-pptx__paragraph {\n margin: 0;\n white-space: pre-wrap;\n word-wrap: break-word;\n tab-size: 96px;\n}\n\n/*\n * `a:bodyPr/@wrap=\"none\"`: the line runs past the box rather than folding.\n *\n * A rule rather than an inline style because the declaration belongs to the\n * paragraphs and the property belongs to the shape, and threading it down\n * would put a tenth argument on the paragraph renderer for a boolean. The\n * clipping has to come off with it: a box that does not wrap has text outside\n * itself by definition, and PowerPoint draws it there.\n */\n.genom-pptx__shape--nowrap {\n overflow: visible;\n}\n\n.genom-pptx__shape--nowrap .genom-pptx__paragraph {\n white-space: pre;\n word-wrap: normal;\n}\n\n/*\n * A picture's box. What is inside it is either an image element or, for a\n * metafile whose words are worth having in the document, the drawing itself —\n * and the box is what carries the frame so that the two are placed identically.\n */\n.genom-pptx__image {\n position: absolute;\n overflow: hidden;\n}\n\n/*\n * Filled, not contained: DrawingML sizes a picture by its frame.\n *\n * a:stretch with an empty a:fillRect is what a p:blipFill states, and it means\n * the shape's rectangle exactly, whatever the picture's own proportions are.\n * Where the two agree the difference is invisible, which is most photos; where\n * they do not, contain letterboxes the picture inside a box PowerPoint fills.\n *\n * Worth 133 placed lines of the corpus's 134389 — the largest single gain the\n * presentation loop has had, and it is a one-word change. That is what a\n * default costs when it is the wrong default: nothing was reported as broken,\n * every picture whose frame disagreed with its own proportions was simply a\n * little smaller and a little off, and every word drawn inside one was out of\n * place by a share of its own position.\n */\n.genom-pptx__image-source {\n width: 100%;\n height: 100%;\n object-fit: fill;\n}\n\n.genom-pptx__toolbar {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 10px;\n color: var(--genom-chrome-text);\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n font-size: 13px;\n}\n\n.genom-pptx__button {\n appearance: none;\n border: 1px solid rgba(255, 255, 255, 0.18);\n border-radius: 6px;\n background: transparent;\n color: inherit;\n padding: 5px 12px;\n cursor: pointer;\n font: inherit;\n}\n\n.genom-pptx__button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.genom-pptx__button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.genom-pptx__counter {\n font-variant-numeric: tabular-nums;\n min-width: 84px;\n text-align: center;\n}\n\n.genom-pptx__notes {\n flex: 0 0 auto;\n max-height: 25%;\n overflow: auto;\n padding: 10px 16px;\n color: var(--genom-chrome-text);\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n font-size: 13px;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n/* The bullet hangs in the indent its paragraph reserved for it. */\n\n.genom-pptx__bullet {\n white-space: pre;\n}\n\n.genom-pptx__link {\n color: inherit;\n text-decoration: underline;\n cursor: pointer;\n}\n\n.genom-pptx__table {\n position: absolute;\n table-layout: fixed;\n border-collapse: collapse;\n}\n\n/*\n * No padding here: `a:tcPr` states all four insets and the renderer writes\n * them. The percentage that used to be here resolved against the table's width\n * on all four sides, so a cell's top inset grew with the table.\n */\n.genom-pptx__cell {\n /*\n * `a:gridCol/@w` is the column, insets and rule included.\n *\n * Under `table-layout: fixed` the first row's stated widths *are* the grid,\n * and a content-box cell adds its padding and border to them — so a table\n * whose insets had just become real (a tenth of an inch a side instead of a\n * fraction of a per cent) grew by twenty pixels a column, and every column\n * after the first started somewhere PowerPoint did not put it.\n */\n box-sizing: border-box;\n border: 1px solid rgba(0, 0, 0, 0.25);\n vertical-align: top;\n overflow: hidden;\n}\n"
pptxView
pptxView: ViewModule<PptxDocument>

PowerPoint presentations with its renderer attached. What `@genomdev/pptx/view` exports and what an application passes to the viewer. The universal half is the same object — the renderer is a field on it, not a second registration — so a format either brings a way to draw itself or it does not, and nothing has to pair them up by hand.