Skip to content

Repository files navigation

pptx-forge

Compile JavaScript slide files into PowerPoint decks. Author slides as plain .js files using a design-system API — no PowerPoint, no drag-and-drop.

Try it live — no install required.

How it works

Each workspace is a folder under workspaces/. You write slide files in workspaces/<slug>/slides/, optionally define a color scheme in theme.js, and run forge to get a .pptx.

workspaces/my-deck/
├── theme.js          # colors, header text, footer text
├── slides/
│   ├── 01-overview.js
│   └── 02-approach.js
└── out/
    └── my-deck.pptx  # generated

Prerequisites

  • Node.js 18+
  • chromium-headless-shell (only needed for forge --images) — install with npx playwright install chromium-headless-shell

Install

npm install

npm install does not download any browser binaries. forge --images needs chromium-headless-shell installed separately (see above); nothing else in this project requires it.

If you're developing pptx-forge itself and plan to run the e2e test suite (npm run test:e2e, using @playwright/test), npx playwright install (no arguments) installs both full Chromium and chromium-headless-shell in one step — after that, forge --images also works with no further setup.

Create a workspace

npm run create
# Workspace name: my-deck

Copies the starter template into workspaces/my-deck/ and prints next steps.

Forge

npm run forge my-deck
npm run forge workspaces/my-deck   # relative path — useful for tab completion
npm run forge workspaces/my-deck/slides/overview.js   # single slide file — only that slide is included

Aliases: npm run build my-deck, npm run generate my-deck

Output: workspaces/my-deck/out/my-deck.pptx

Pass a path to a single slide .js file instead of a workspace to compile just that slide — the rest of slides/ is skipped, but theme.js and the output path still resolve from the enclosing workspace.

Options

Flag Short Description
--open -o Open the generated file in the default app after compiling
--preview -v Preview the generated file in QuickLook — macOS only
--snapshot -t Write to a timestamped file (my-deck_2026-06-29_14-30-00.pptx) instead of overwriting
--images -i Export every slide as a PNG next to the generated file
--help -h Show usage and exit

Note: Due to how npm parses arguments, flags must be separated from the script name with --.

npm run forge my-deck -- --open            # compile and open
npm run forge my-deck -- --preview         # quick preview via QuickLook (macOS)
npm run forge my-deck -- --snapshot        # timestamped output
npm run forge my-deck -- --open --snapshot # both
npm run forge my-deck -- --images          # export my-deck-01.png, my-deck-02.png, ...
npm run forge my-deck -- --images --snapshot # export my-deck_2026-06-29_14-30-00-01.png, ...
npm run forge -- --help                    # show help

--images writes one PNG per slide to workspaces/<slug>/out/, overwriting any file already at that path. Filenames follow <slug>[_<timestamp>]-NN.png — the timestamp is included only when --snapshot is also passed, using the exact same timestamp as the .pptx written in that run.

Rendering is done in a headless browser (chromium-headless-shell), reusing the same renderer the browser tool's live preview uses. If it isn't installed yet, --images fails with an error telling you to run:

npx playwright install chromium-headless-shell

If you've already run npx playwright install for the e2e test suite (see below), --images works immediately — that command installs chromium-headless-shell alongside full Chromium by default.

Backup

npm run backup my-deck
npm run backup workspaces/my-deck   # relative path — useful for tab completion

Zips slide and theme files into workspaces/my-deck/backups/my-deck_<timestamp>.zip.

Watch

npm run watch -- my-deck                    # quiet rebuild on every change, no flags forced
npm run watch -- my-deck --snapshot         # timestamped file on every change
npm run watch -- my-deck --snapshot --open  # timestamped file, opened after every change
npm run watch -- my-deck --images           # re-export slide PNGs on every change
npm run watch -- workspaces/my-deck --snapshot   # relative path — useful for tab completion

Watches workspace source files and re-runs forge when they change, forwarding whatever forge options you pass — --open, --preview, --snapshot, --images, any combination. Nothing is forced: pass exactly what you'd pass to npm run forge directly.

  • Debounces rapid edit bursts into a single generation cycle.
  • Ignores generated out/ and backups/ paths to prevent feedback loops.
  • Runs until stopped with Ctrl+C.

Browser tool

A no-install alternative to the CLI: pptx-forge.html is a single self-contained HTML file that runs the same compile pipeline entirely client-side. Double-click it to open — no Node, no server, no network access required.

  • Use it online: pptx-forge.html — hosted version of the latest release, opens directly in your browser, nothing to download

Or download a pre-built copy from GitHub Releases — no build step required:

  • Latest version: pptx-forge.html — always resolves to the newest release
  • A specific version: https://github.com/awaragi/pptx-forge/releases/download/<version>/pptx-forge-<version>.html (e.g. 1.1.0)

Or build it yourself from source:

npm run build:browser

This bundles pptxgenjs, jszip, and the src/ rendering library into pptx-forge.html at the repo root (gitignored — rebuild it locally when you need it).

Open the generated pptx-forge.html in a browser and:

  1. Drag and drop, click "Load files…", or click "New slide" to add theme.js (optional — a placeholder is preloaded) and one or more slide .js files.
  2. Click a file in the sidebar to edit it. Dropping a file with a name that already exists replaces its content in place.
  3. Click the filename above the editor (or its pencil icon) to rename it in place — edit the name directly (the .js extension is fixed and shown separately, not editable), Enter to confirm or Escape to cancel. Use the toolbar's Discard/Download icons to remove or download the file, or click "⚡ Forge" to compile everything currently loaded into a downloadable .pptx. Rename and Discard aren't available for theme.js.

A live preview pane sits below the editor, rendering the slide file you're currently editing — it recompiles and re-renders automatically a moment after you stop typing, with no manual refresh needed. While theme.js or masters.js is open instead of a slide, it keeps showing whichever slide you last viewed, updated live with your in-progress theme/master edits. Drag the divider above it to resize, or use the toolbar's collapse button to hide it entirely — both the size and collapsed state are remembered across reloads. The toolbar also has buttons to copy the current preview to the clipboard as a PNG or download it as one.

A slide file can call pptx.addSlide() more than once — the preview pane handles this by showing numbered slide buttons in the toolbar (or, when there isn't room for all of them, compact ‹ N / M › arrows instead), letting you step through every slide the file produces. Left/Right arrow keys also work once the preview has focus. Downloading a multi-slide file's preview names the file after the sub-slide currently shown (e.g. deck-2.png).

Only .js files are accepted, and Forge requires at least one slide file besides theme.js. This tool has no special sandboxing around the code it runs — it's meant for the same trusted, local use case as the CLI, just without requiring Node.

Import/export workspace zips follow a strict layout: theme.js at the root, slide files under slides/. Import requires theme.js at the root or it fails with an error; any other entries in the zip (stray files, .js files outside slides/, nested folders) are silently ignored.

Authoring slides

Each slide file exports a default function:

export default function Slide01_Title(pptx, lib) {
  const { theme, prim, layout, frame } = lib;
  const slide = pptx.addSlide();
  slide.background = { color: theme.color.surface };

  frame.border(slide, undefined, {}, 's01-border');
  frame.slideHeader(slide, undefined, {}, 's01');
  frame.slideFooter(slide, undefined, {}, 's01');

  layout.sectionTitle(slide, null, 'Hello World', {}, 's01-title');
}

For AI-assisted authoring, share INSTRUCTIONS.md and lib.d.ts with your model. These two files contain everything needed to generate correct slide files.

Versioning

pptx-forge makes no backward compatibility guarantees between versions. The tool's purpose is to generate a .pptx and move on — a workspace is a point-in-time artifact, not a long-lived application. When the library changes, existing slide files may need updating. New projects should start from the current version.

License

GPL-3.0-or-later — see LICENSE. You are free to use, modify, and distribute this software under the terms of the GNU General Public License v3 or any later version; you may not incorporate it verbatim into proprietary software without releasing your changes under the same license.

Component library

All components are available via lib.comp. Destructure the ones you need at the top of each slide function.

Cards

Component Content Description
infoCard { title, body } Standard card with title + body
accentCard { title, body } Card with a thin top accent bar
challengeCard { title, body } Card with a left accent bar — for challenges or risks
overlayCard { title, body } Semi-transparent variant for dark backgrounds
fileCard { filename, purpose, step } Named file/artifact with purpose + next step
numberedStep { num, title, body } Circle number badge + title + body
stepBox { label, steps: string[] } Phase/step container; steps joined with ·
imageCard { image?, title, body?, imageH? } Card with an image placeholder band at top
iconBox { icon?, title, body? } Centered large icon + title + optional body
teamCard { name, role, bio? } Circular avatar placeholder + name + role + optional bio

KPI & Stats

Component Content Description
iconStat { value, label, icon? } Large KPI value + label, optional icon above
darkStat { value, label, source? } Dark-background KPI tile with optional citation line

Flow & Process

Component Content Description
flowBox { label, highlight? } Flow diagram box; highlight: true applies accent fill
flowArrow (none) Arrow connector; opts.vertical: true for ↓
stepFlow { label, highlight? }[] Auto-lays out flow boxes + arrows across the box width
phaseLabel label (string) Accent badge + horizontal rule — section divider

Insight & Callout

Component Content Description
calloutQuote { label?, quote } Left accent bar + optional label + insight/quote text

Lists & Tables

Component Content Description
bulletIconList { icon, text }[] Icon-prefixed bullet lines
twoColumnRow { label, content } Left label / right content row — stack to build key-value tables

Indicators & Placeholders

Component Content Description
progressBar { value, label?, showPct? } Horizontal fill bar; value is 0–1
tagBadge { label } Small filled pill badge
imageHolder { icon?, label? } Dashed placeholder box — swap with a real image in PowerPoint

Custom components

If the built-in comp components don't meet your design needs, it is entirely acceptable to build new ones directly in your slide files using prim primitives. There is no requirement to stay within the existing component set.

It is also acceptable to use pptxgenjs directly (e.g. slide.addText(), slide.addShape(), slide.addImage()) when lib doesn't cover what you need. Prefer lib where it applies — fall back to raw pptxgenjs only when necessary. See the pptxgenjs docs for reference.

If you create something reusable and well-tested, sharing it back with the forge is highly appreciated — open a PR with the implementation or file an issue and paste the function code. Contributions help grow the shared component library for everyone.

Backlog

Planned features and improvements:

  • Syntax highlighting — Add JavaScript syntax coloring to the code editor for better readability
  • Version compatibilitytheme.js and slide .js files should export a version number that must match the library version; mismatch causes runtime errors or bad output
  • Version history — Store version numbers with workspaces to display changelog since last compilation
  • Master slide support — Allow defining and using master slides to maintain consistent layout and styling across multiple slides
  • Responsive design — Improve layout adaptability for different screen sizes and resolutions
  • Settings icon — Add a settings icon with options such as including components in AI prompts and generating file names with timestamps
  • Support for other files — Support for other files (.md, .txt) in workspaces but not included in the generated deck and only for complete packaging of workspace zips
  • Update numbering of slides — Update numbering of slides to be increment of 10 to allow insertion of different slides in between existing slides without having to rename all slides after the insertion point
  • Trash can for deleted workspaces — Deleting a workspace should move it to an app-level trash (e.g. a picker reachable from the workspace switcher) so it can be restored later.

About

CLI tool for primarly AI-generated PowerPoint decks — author slides as JavaScript files with a design-system API and compile to .pptx.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages