This guide demonstrates the pptx flow, first with pptx-large (animations, transitions, layouts), then with pptx-full (custom-geometry shapes).

Prerequisites: @awacloud/ooxml and @awacloud/fw installed and the install and runtime registration of Getting started; the bundles come from @awacloud/ooxml/bundles/pptx-large and @awacloud/ooxml/bundles/pptx-full.

Bootstrapping with ModuleRuntime

register() takes one descriptor per call — use registerAll(array) for a batch. The extras are not re-exported by name from the @awacloud/ooxml root; import the whole extras array instead:

import fw from '@awacloud/fw';
import { fw_require, modules, extras } from '@awacloud/ooxml';
import { pptxLargeBundle } from '@awacloud/ooxml/bundles/pptx-large';

fw.runtime.registerAll(fw_require);
fw.runtime.registerAll(modules);
fw.runtime.registerAll(extras);   // every opt-in extra; a bundle only
                                   // resolves the ones it declares
fw.runtime.register(pptxLargeBundle);

const pp = fw.runtime.resolve('pptxLargeBundle'); // enriched pptx instance

Reading

const bytes  = await fetch('/sample.pptx')
    .then(r => r.arrayBuffer())
    .then(b => new Uint8Array(b));
const result = pp.read(bytes);   // → { presentation, package, unmodelledParts }

The typed presentation lives under result.presentation:

{
    type: 'presentation',
    slides: [{
        title?, body?,                 // high-level shorthand
        paragraphs?,                   // body-only shorthand
        shapes?                        // fully-typed form (see below)
    }],
    slideLayouts?: [...],   // auto-generated on write when absent
    slideMasters?: [...],   // auto-generated on write when absent
    theme?: { /* clrScheme, fontScheme, fmtScheme */ },
    sldSize?: { cx, cy, type? }
}

Slide model

A parsed slide has no cSld/spTree level — <p:cSld> is flattened directly into the slide object:

{
    type: 'slide',
    name?, bg?,
    shapes: [
        { type: 'shape',  placeholder?, spPr?, txBody? },   // text shape
        { type: 'picture', /* … */ },                        // <p:pic>
        { type: 'table',   /* … */ },                         // <p:graphicFrame> table
        { type: 'chart',   /* … */ }                          // <p:graphicFrame> chart
    ],
    spTreeExtras?: [xmlNode],
    clrMap?, clrMapOvr?,
    _extras?: [xmlNode]     // <p:timing>, <p:transition>, … — NOT auto-typed
}

See pptxSlide for the full shape union and pptx for the top-level orchestrator.

Layouts (with pptx-large)

result.presentation.slideLayouts?.length;

pmlLayoutsTyped types the layout descriptors; see pmlLayoutsTyped.

Concrete input → parsed object

Input ppt/slides/slide1.xml excerpt:

<p:sld xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
  <p:cSld>
    <p:spTree>
      <p:sp><p:spPr/><p:txBody><a:p><a:r><a:t>Title</a:t></a:r></a:p></p:txBody></p:sp>
    </p:spTree>
  </p:cSld>
</p:sld>

After read():

{
    type: 'slide',
    shapes: [{ type: 'shape', txBody: { paragraphs: [{ runs: [{ value: 'Title' }] }] } }]
}

Transitions and animations

pmlTransitions and pmlAnimations are parse*/render* extras — they expose no hydrate* hook, so pptxWalker never invokes them automatically. <p:transition> and <p:timing> stay as raw elements on the slide's _extras until you decode them explicitly:

const transitions = fw.runtime.resolve('pmlTransitions');
const transEl = (result.presentation.slides[0]._extras || [])
    .find(e => e.name === 'p:transition');
if (transEl) {
    const t = transitions.parseTransition(transEl);
    t.effect;   // { kind: 'fade', attrs: {} }
}

const animations = fw.runtime.resolve('pmlAnimations');
const timingEl = (result.presentation.slides[0]._extras || [])
    .find(e => e.name === 'p:timing');
if (timingEl) animations.parseTiming(timingEl);

See pmlTransitions and pmlAnimations.

Mutating + writing

// Add a new slide.
result.presentation.slides.push(
    pp.fromTitleBody({ title: 'New slide', body: ['First point'] })
);

// `write` takes the PRESENTATION, not the whole read() result.
const out = pp.write(result.presentation);
const blob = new Blob([out], {
    type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
});

write() produces the parts its model carries; a part read() did not model (speaker notes, the notes master, the layouts no slide uses, presentation and view properties, document properties, …) is not written back — read() lists it in result.unmodelledParts.

Advanced shapes (with pptx-full)

import { pptxFullBundle } from '@awacloud/ooxml/bundles/pptx-full';

// `extras` (registered above) already covers pptx-full's own extras
// (dmlShapesAdvanced, transitional, legacyVml, pmlMisc, dmlChartMisc,
// dmlMainMisc, mathMisc) — `pptxLargeBundle` is already registered too
// (a declared dependency of pptxFullBundle):
fw.runtime.register(pptxFullBundle);

const ppFull = fw.runtime.resolve('pptxFullBundle');
const result = ppFull.read(bytes);

// Custom-geometry shapes: the raw `p:spPr` element is kept on each shape.
const shapesExt = fw.runtime.resolve('dmlShapesAdvanced');
const slide = result.presentation.slides[0];
const geomEl = slide.shapes
    .map(s => s.spPr && s.spPr.children.find(c => c.name === 'a:custGeom'))
    .find(Boolean);
const custGeom = geomEl && shapesExt.parseCustGeom(geomEl);
// → { avLst?, gdLst?, pathLst, … }

See dmlShapesAdvanced.

See also