JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 43
  • Score
    100M100P100Q81209F
  • License MIT

Low-level JS library for generating beautiful .pptx files β€” pptxgenjs-compatible API with designer-grade primitives (blobs, mesh gradients, glass-morphism, grain, gradient text).

Package Exports

  • slidewave
  • slidewave/package.json

Readme

Slidewave

Low-level JS library for generating beautiful .pptx files. pptxgenjs-compatible API, but with designer-grade primitives that LLMs can't uniformize.

npm version license

Slidewave is a drop-in replacement for pptxgenjs that keeps its low-level API (inches, addText, addShape...) but adds rich primitives you can't get otherwise:

  • πŸŒ€ Mesh / radial / linear gradient backgrounds
  • 🫧 Organic blob shapes (seeded SVG, deterministic)
  • ✨ Gradient-filled text (magazine-style)
  • πŸͺŸ Glass-morphism cards with tint, border, highlight
  • 🎞️ Film grain textures
  • 🎯 Full pptxgenjs escape hatch β€” nothing is taken from you

Why

LLMs (Claude, GPT, Gemini…) generating slides via pptxgenjs all produce the same thing: rectangles, limited gradients, identifiable-at-a-glance AI slides. Slidewave gives those same LLMs β€” and you β€” richer primitives to output .pptx files that look designed, not templated.

Install

npm install slidewave pptxgenjs

pptxgenjs is a peer dependency so you control its version.

Browser-only. Slidewave uses Canvas, Image and Blob to rasterize SVG primitives. It does not run in Node without a DOM shim.

Quick start

import { Pres } from 'slidewave'

const pres = new Pres({ layout: 'LAYOUT_WIDE', title: 'Demo' })
const slide = pres.addSlide()

// Rich background (mesh / aurora)
await slide.addBackground({
  gradient: {
    type: 'mesh',
    base: '#0b0b0f',
    colors: ['#6366f1', '#8b5cf6', '#ec4899'],
    blur: 80,
  },
})

// Native editable text (stays editable in PowerPoint)
slide.addText('Hello world', {
  x: 1, y: 1, w: 11, h: 2,
  fontFace: 'Fraunces', fontSize: 140,
  color: '#ffffff', italic: true,
  charSpacing: -1,       // POINTS β€” tight spacing
  lineSpacingMultiple: 1.05,
})

// Gradient-filled text (rasterized, non-editable but visually impossible otherwise)
await slide.addGradientText('Redesigned.', {
  x: 1, y: 3.2, w: 11, h: 2,
  fontFamily: 'Fraunces, serif',
  fontSize: 180, fontWeight: 500,
  gradient: ['#ffffff', '#a5b4fc'],
  angle: 180,
})

// Organic blob
await slide.addBlob({
  x: 8.5, y: 0.5, w: 4.5, h: 4.5,
  seed: 7, points: 9, irregularity: 0.35,
  fillGradient: ['#ec4899', '#f59e0b'],
})

await pres.save('demo.pptx')

API

new Pres(options)

new Pres({
  layout?: 'LAYOUT_WIDE' | 'LAYOUT_16x9' | 'LAYOUT_16x10' | 'LAYOUT_4x3',
  title?: string, author?: string, company?: string, subject?: string,
})
Method Returns Description
addSlide(opts?) Slide Adds a new slide
size() { width, height } Slide dimensions in inches
save(filename) Promise<void> Triggers browser download
toBlob() Promise<Blob> Returns the raw .pptx blob
toArrayBuffer() Promise<ArrayBuffer> Returns raw bytes
.ShapeType, .AlignH, .AlignV pptxgenjs constants

Slide β€” native primitives (editable in PowerPoint)

All coordinates are in inches. 16:9 wide = 13.333 Γ— 7.5.

slide.addText(text, opts)

slide.addText('Title', {
  x: 1, y: 1, w: 10, h: 1.2,
  fontFace: 'Fraunces',
  fontSize: 72,
  color: '#0b0b0f',
  bold, italic, underline,
  align: 'left' | 'center' | 'right',
  valign: 'top' | 'middle' | 'bottom',
  charSpacing: 2,                  // POINTS β€” typical 2..6, negative = tighter
  lineSpacingMultiple: 1.1,
  shadow: { type: 'outer', blur: 20, offset: 4, angle: 90, color: '#000', opacity: 0.3 },
  glow:   { size: 8, opacity: 0.5, color: '#6366f1' },
  outline:{ size: 1, color: '#000' },
})

charSpacing is in POINTS. Typical values: 2 to 6. Negative tightens. Setting it to 300 will break your layout.

slide.addRect(opts)

slide.addRect({
  x: 1, y: 3, w: 5, h: 2,
  fill: '#818cf8',                 // or { type: 'solid', color }
  radius: 0.2,                     // inches
  borderColor: '#1e1b4b', borderWidth: 1,
  shadow: { type: 'outer', blur: 40, offset: 20, angle: 90, color: '#000', opacity: 0.15 },
  rotate: 0,
})

Other native methods

slide.addShape('ellipse' | 'triangle' | ..., opts)   // any pptxgenjs shape
slide.addLine({ x1, y1, x2, y2, color, width })
slide.addImage({ x, y, w, h, data, path })
slide.raw()                                          // underlying pptxgenjs slide

Slide β€” rich primitives (rasterized)

These are async because they render SVG β†’ PNG before embedding.

slide.addBackground(opts)

await slide.addBackground({ color: '#fafaf7' })
await slide.addBackground({
  gradient: {
    type: 'mesh' | 'linear' | 'radial',
    colors: ['#6366f1', '#8b5cf6', '#ec4899'],
    base: '#0b0b0f',   // mesh only β€” backdrop
    angle: 135,        // linear only
    blur: 80,          // mesh only
  },
})

slide.addGradientText(text, opts)

await slide.addGradientText('Hello', {
  x, y, w, h,
  fontFamily: 'Fraunces, serif',
  fontSize: 140, fontWeight: 500,
  fontStyle: 'normal' | 'italic',
  letterSpacing: -0.03,      // em units
  lineHeight: 1.1,
  align: 'left' | 'center' | 'right',
  gradient: ['#6366f1', '#ec4899'],
  angle: 135,
})

slide.addBlob(opts)

await slide.addBlob({
  x, y, w, h,
  seed: 42,                  // deterministic PRNG
  points: 8,                 // control points
  irregularity: 0.4,         // 0..1
  fill: '#6366f1',
  fillGradient: ['#ec4899', '#f59e0b'],
  gradientAngle: 135,
})

slide.addGlassCard(opts)

await slide.addGlassCard({
  x, y, w, h,
  tint: '#ffffff', tintOpacity: 0.12,
  borderColor: '#ffffff', borderOpacity: 0.2, borderWidth: 2,
  radius: 24,
  highlight: true,           // inner top reflection
})

slide.addGrain(opts) Β· slide.addGradientRect(opts)

await slide.addGrain({ x, y, w, h, opacity: 0.08, monochrome: true })

await slide.addGradientRect({
  x, y, w, h,
  type: 'linear', colors: ['#0b0b0f', '#1e1b4b'], angle: 135,
})

Low-level escape hatch

Nothing from pptxgenjs is hidden:

const rawSlide = slide.raw()
rawSlide.addChart(pres._pptx.ChartType.bar, data, chartOpts)

pres._pptx.defineSlideMaster({ ... })

Exposed utilities

For advanced usage β€” build your own primitives:

import {
  blobSvg, gradientSvg, gradientTextSvg, glassSvg,
  svgToPngDataUrl, generateGrainPng,
  normalizeHex, hexToRgb, rgbToHex, mix,
} from 'slidewave'

Design rules

  • Sync methods β†’ native PPT XML β†’ text + shapes stay editable
  • Async methods β†’ rasterized PNG β†’ visually impossible effects, non-editable
  • All sizes in inches (pptxgenjs-compatible)
  • All colors as #RRGGBB or RRGGBB
  • pptxgenjs is a peer dep β€” use any compatible version you want

Use with LLMs

Slidewave is designed so agents (Claude, GPT, Gemini, Mistral) can produce richer output than pptxgenjs allows. Give an LLM the API reference above as part of your system prompt, and it will emit code that produces editorial-grade slides.

Development

git clone https://github.com/NdandaClaude/slidewave
cd slidewave
npm install
npm run dev              # demo playground at localhost:5173
npm run build:lib        # build library to dist/
npm run pack:check       # verify npm package contents

Roadmap

  • More primitives: addIsometricGrid, addCodeBlock (syntax-highlighted), addIcon (Lucide)
  • Editorial-grade chart styles
  • Node-compatible rasterizer (via @napi-rs/canvas) for SSR use
  • Monaco-based playground

License

MIT Β© 2026 Claude Ndanda