Package Exports
- slidewave
- slidewave/package.json
Readme
Slidewave
Low-level JS library for generating beautiful
.pptxfiles. pptxgenjs-compatible API, but with designer-grade primitives that LLMs can't uniformize.
What is Slidewave?
Slidewave is a JavaScript library that generates .pptx files by code — openable in PowerPoint, Keynote and Google Slides. It's a thin layer on top of pptxgenjs: same low-level API (inches, addText, addShape…) but with extra designer-grade primitives that are impossible to click in PowerPoint.
Why
- Programmatic generation — 100 slides in 1 second, dynamic templates, real-time data.
- Modern visuals — mesh gradients, organic blobs, glassmorphism, editorial charts, syntax-highlighted code, Lucide icons.
- Still editable — text, shapes and charts remain native PPT objects, modifiable inside PowerPoint.
- Zero lock-in — standard
.pptxoutput. Works everywhere. - Live SVG preview — see the result in-browser without opening PowerPoint.
- LLM-friendly — Claude / GPT / Gemini emit editorial-grade slides instead of the usual rectangles.
Feature catalogue (v0.3)
| Primitive | Mode | What it does |
|---|---|---|
addText |
native | Editable text (fontFace, charSpacing, shadow) |
addRect, addShape, addLine |
native | Standard shapes + radius + border + shadow |
addImage |
native | URL / base64 / dataURL |
addChart |
native | Editorial-styled bar/line/pie/area/doughnut |
addBadge |
native | Pill (rounded rect + centered text) |
addProgressBar |
native | Horizontal progress bar (+ % label) |
addTimeline |
native | Horizontal timeline with dot milestones |
addConnector |
native | Arrow between two points (auto-oriented head) |
addBackground |
raster | Linear / radial / mesh gradient fill |
addGradientText |
raster | Text with multi-stop gradient |
addBlob |
raster | Organic seeded blob shapes |
addGlassCard |
raster | Glassmorphism card (tint + border + highlight) |
addGrain |
raster | Cinema grain texture |
addNoiseGradient |
raster | Risograph-style noise gradient |
addIsometricGrid |
raster | Isometric grid (3 axes) |
addDotGrid |
raster | Notion/Linear-style dot grid background |
addStripes |
raster | Diagonal stripe pattern |
addWaveDivider |
raster | Sinusoidal section divider |
addProgressRing |
raster | Circular progress ring + center label |
addSparkline |
raster | Mini inline line chart (smoothed) |
addCodeBlock |
raster | Syntax-highlighted code (js/ts/py/json/sh) |
addIcon |
raster | SVG / Lucide / raw paths |
native = XML PPT (editable) · raster = SVG→PNG (pixel-perfect visuals,
awaitrequired)
Architecture
Your code (recipe.js)
│
▼
┌──────┐
│ Pres │ ← layout, title, save()
└──┬───┘
│ addSlide()
▼
┌───────┐
│ Slide │ ← fluent API + ops[]
└──┬─┬──┘
│ │
┌──────┘ └──────┐
▼ ▼
NATIVE RASTERISED
(PPT XML) (SVG → PNG)
addText addBlob
addRect addGradientText
addChart addGlassCard
addShape addCodeBlock …
│ │
└───────┬───────┘
▼
┌──────────┐
│ pptxgenjs│ serialises → .zip → .pptx
└────┬─────┘
▼
hello.pptxEach Slide method is also recorded in slide._ops so pres.renderAllSvg() can reproduce the slide as an SVG — that's the live preview, 100% offline, no PowerPoint needed.
Install
npm install slidewave pptxgenjspptxgenjs is a peer dependency so you control its version.
Browser-only. Slidewave uses
Canvas,ImageandBlobto 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' },
})
charSpacingis in POINTS. Typical values:2to6. Negative tightens. Setting it to300will 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 slideSlide — 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
#RRGGBBorRRGGBB pptxgenjsis 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 contentsRoadmap
- 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