Appearance
PPTX Inspection
The @shbernal/ts-pptx/inspect subpath answers one flat question about a PPTX package (what is on the slides, and where) for tools that examine a deck after generation or manual editing.
ts
import { inspectPptx, loadPptxPackage, listPptxParts } from "@shbernal/ts-pptx/inspect"inspectPptx(input) loads a PPTX package and returns:
slideSize: presentation width and height in inches.slides[]: slides in presentation order (p:sldIdLst), the order PowerPoint shows them, which stops matching part order once a deck is reordered.slides[].elements[]: normalized objects withid,name,kind,zIndex,box,rotation,flipH,flipV,parentZIndex,childZIndices,text,textRuns,paragraphs,fontSizes,colors,fill,line,shapeType,textWrap,autofit,autofitFontScale, andbodyInsets.
Its relationship to ts-pptx/read
This is a shallow projection over the read model, not a second reader. ts-pptx/read gives a navigable, mutable model shaped like the OOXML tree; this flattens it to one array per slide, which is the shape an overlap check, a layout linter, or a deck diff wants. Both reach the same package through OpcPackage and the same parser, so they cannot disagree about what a deck says.
Reach for read instead when you need to change anything, or to reach what this surface flattens away: table cells, chart series, speaker notes, comments, animations, or the layout/master a placeholder inherits from.
Two things this surface deliberately does not report, both because it describes what a slide states rather than what PowerPoint would render:
- A shape with no transform of its own is omitted, not resolved. A placeholder that inherits its box from the layout has no box here;
Shape.resolvedFrameon the read model is where inheritance is resolved. p:graphicFrame(tables, charts, SmartArt) is skipped entirely. It is a structure rather than a box with text, and it does not consume azIndex.
loadPptxPackage() returns an OpcPackage, so a tool that starts here can hand the result straight to Presentation.fromPackage() without re-reading the bytes. Its input must be a real OPC package: a zip that merely contains slide XML but no [Content_Types].xml is rejected with a PackageReadError.
Geometry, groups, and z-order
box is slide-absolute inches, composing every enclosing group transform, so boxes are directly comparable whether or not an element is grouped. A group (<p:grpSp>) authors its children in a private coordinate space (a:chOff/a:chExt) that need not match its slide frame (PowerPoint makes it non-identity as soon as a user resizes a group), so a child's raw a:xfrm is not placeable on the slide and is never what you get here.
For a rotated element, box is the unrotated placement box (what PowerPoint writes after Ungroup) and rotation (degrees, [0, 360)) / flipH / flipV report its effective orientation after group composition. This is Shape.absoluteFrame from the read API, converted to inches.
An element whose position cannot be resolved, because an enclosing group has a degenerate (zero) a:chExt, is omitted with a warning rather than reported at a wrong position.
zIndex is 0-based paint order: a depth-first walk of the shape tree in document order, so higher draws on top. Elements are linked by it:
kind: 'group'is a group container. It has an id, name, box, and fill, but no text of its own.parentZIndexis the enclosing group'szIndex, ornullat slide level.childZIndiceslists a group's direct children in document order; empty for every other kind.
A group's box overlaps its children by construction, so tools that reason about layout (overlap, coverage) usually want the leaves only: filter out kind === 'group', or keep elements with childZIndices.length === 0.
autofit and bodyInsets describe the text frame's a:bodyPr so a consumer can tell a bounded text box from an auto-growing one and compute its inner box:
autofit:'none'(fixed height, a genuine overflow candidate),'normAutofit'(shrink text to fit, ts-pptxfit: 'shrink'), or'spAutoFit'(resize shape to fit text,fit: 'resize'; the authored height is an output, so it cannot overflow).nullfor elements without a text frame (e.g. images).bodyInsets:{ left, top, right, bottom }in inches, with PowerPoint defaults applied when absent (0.1in left/right, 0.05in top/bottom). Subtract fromboxto get the inner text box.nullfor elements without a text frame.
textRuns[].text is the run's a:t verbatim, including the leading or trailing whitespace an xml:space="preserve" run carries: that space widens a line, and dropping it also welds adjacent runs together. The element's own text is the opposite: runs joined, whitespace collapsed, trimmed, for matching and word counts.
The subpath also exports package helpers (loadPptxPackage(), listPptxParts(), readPptxTextPart(), and readPptxBinaryPart()) plus geometry helpers boxAnchor() and overlapArea().
Downstream tools should keep policy decisions outside this package. For example, ts-pptx can report object boxes and overlap area, while a deck production tool decides which margins, overlaps, colors, or semantic relationships are acceptable for its workflow.