Deno library for generating PPTX files with a JSX-first layout DSL that lowers to layout, scene, and OOXML.
deno add @pixel/pptxConfigure Deno to use @pixel/pptx as the JSX import source:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@pixel/pptx"
}
}/** @jsxImportSource @pixel/pptx */
import {
Align,
clr,
generate,
Presentation,
Slide,
Text,
u,
} from "@pixel/pptx";
const heroStyle = {
fill: { kind: "solid", color: clr.hex("1F4E79") },
verticalAlign: "middle",
padding: u.in(0.18),
fontSize: u.font(28),
fontColor: clr.hex("FFFFFF"),
bold: true,
};
const deck = (
<Presentation title="Hello deck">
<Slide background={{ kind: "solid", color: clr.hex("F7F4EE") }}>
<Align x="center" y="center" w={u.in(6)} h={u.in(1.2)}>
<Text.P style={heroStyle}>Hello, world!</Text.P>
</Align>
</Slide>
</Presentation>
);
Deno.writeFileSync("hello.pptx", generate(deck));Preview rendered from examples/minimal.tsx.
Full source: examples/quarterly-review.tsx
generate(<Presentation>...</Presentation>)u.*for units:in,cm,pt,emu,font,pctclr.hex(...)for validated OOXML colors- Inherited layout defaults through
presentation layout={...}andslide layout={...}
<Presentation><Slide><Row><Row.Start><Row.End><Column><Column.Start><Column.End><Stack><Align><Positioned>
<Text>— multi-paragraph text body (gapfor paragraph spacing)<Text.P>— single paragraph; auto-creates a text body at the top level<Shape preset="..."><Image ... /><Table cols=[...]><Table.Row height={...}><Table.Cell><Chart.Bar ... /><Chart.Line ... /><Chart.Pie ... /><Chart.Donut ... />
- Raw string and number children create text directly inside
<Text.P> <Text.Span>is optional — bare strings inside<Text.P>work directlygap={...}on<Text>,<Shape>, and<Table.Cell>inserts paragraph-block spacing- Inline components:
<Text.Span>,<Text.Link href="...">,<Text.Bold>,<Text.Italic>,<Text.Underline>
- Style props are plain typed objects, not special builder tokens
styleaccepts either one style object or an array of style objects- Later style entries win, with nested objects merged structurally
- Backgrounds, fills, lines, shadows, bullets, and image options are plain data
- Charts use
data,category, andseries=[...], with one or more series for bar/line and exactly one series for pie/donut
basis,grow,alignSelf,aspectRatio,w, andhapply directly to children inside<Row>and<Column><Row.Start>/<Row.End>and<Column.Start>/<Column.End>express split layouts without spacer or push props<Positioned x y w h>is the explicit parent-relative absolute placement wrapper<Positioned>children inside<Row>and<Column>do not consume flow space<Align>remains the explicit single-child alignment wrapperpresentation layout={...}andslide layout={...}provide inherited defaults for slide padding, row/column gap, stack padding, and text gap
Run the full local checks before committing:
deno check mod.ts
deno lint
deno fmt --check
deno test
deno publish --dry-run
