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, aurora gradients, organic blobs, glassmorphism, halftones, 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.5)
Native primitives — editable in PowerPoint
| Primitive | What it does |
|---|---|
addText |
Editable text (fontFace, charSpacing, shadow, glow, outline) |
addRect, addShape, addLine |
Standard shapes + radius + border + shadow |
addImage |
URL / base64 / dataURL |
addChart |
Editorial-styled bar/line/pie/area/doughnut |
addTable |
Native PPT table (4 presets: editorial, minimal, grid, striped) |
addQuote |
Blockquote with 3 styles (classic, pullquote, minimal) |
addDivider |
Section break (line, double, labeled, dots) |
addAvatar |
Circular avatar (initials or image) + optional name/role |
addBadge |
Pill (rounded rect + centered text) |
addProgressBar |
Horizontal progress bar + % label |
addTimeline |
Horizontal timeline with dot milestones |
addConnector |
Arrow between two points (auto-oriented head) |
addStatCard |
Large value + label + delta ▲▼ + optional sparkline |
addKPIGrid |
Row of 2/3/4 stat cards |
addCallout |
Colored callout box (info / success / warning / danger) |
addFeatureCard |
Lucide icon + title + body card |
addStepFlow |
Numbered steps 1→2→3… with connecting lines |
addComparisonTable |
✓/✗ feature comparison with highlighted column |
addLogoCloud |
Auto-grid of logo images ("trusted by") |
addTeamCard |
Avatar + name + role + bio |
Raster primitives — SVG→PNG, pixel-perfect (await required)
| Primitive | What it does |
|---|---|
addBackground |
Linear / radial / mesh gradient full-slide fill |
addAuroraGradient |
Organic multi-blob aurora mesh gradient |
addHalftone |
Dot halftone (horizontal / vertical / radial fade) |
addGridPaper |
Fine grid with major lines (Notion / Figma style) |
addCheckerPattern |
2-color checkerboard |
addRadialBurst |
Retro sun-burst rays from configurable center |
addNoiseTexture |
Colored film grain via SVG feTurbulence |
addGradientText |
Text with multi-stop gradient fill |
addBlob |
Organic seeded blob shapes |
addGlassCard |
Glassmorphism card (tint + border + highlight) |
addGrain |
Cinema grain texture |
addNoiseGradient |
Risograph-style noise gradient |
addIsometricGrid |
Isometric grid (3 axes) |
addDotGrid |
Notion/Linear-style dot grid |
addStripes |
Diagonal stripe pattern |
addWaveDivider |
Sinusoidal section divider |
addProgressRing |
Circular progress ring + center label |
addSparkline |
Mini inline line chart (smoothed) |
addBarRace |
Horizontal ranked bar chart with labels & values |
addRadarChart |
Multi-series spider/radar polygon chart |
addHeatmap |
Grid colored by value (lerp low→high) |
addFunnel |
Conversion funnel with trapezoid stages |
addCodeBlock |
Syntax-highlighted code (js/ts/py/json/sh) |
addIcon |
SVG / Lucide icon by name / raw paths |
native = XML PPT (editable in PowerPoint) · raster = SVG→PNG (pixel-perfect,
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: 'My deck' })
pres.setTheme({ primary: '#7C3AED', fontBody: 'Inter, system-ui, sans-serif' })
const s = pres.addSlide()
// Aurora gradient background
await s.addAuroraGradient({
x: 0, y: 0, w: 13.333, h: 7.5,
bg: '#0B0B0F',
blobs: [
{ x: 0.2, y: 0.3, r: 0.45, color: '#7C3AED' },
{ x: 0.75, y: 0.25, r: 0.4, color: '#EC4899' },
{ x: 0.55, y: 0.75, r: 0.5, color: '#06B6D4' },
],
})
// Cover title (native — editable in PowerPoint)
s.addText('Build slides\nthat actually\nlook designed.', {
x: 0.8, y: 1.5, w: 11, h: 4,
fontFace: 'Fraunces, Georgia, serif',
fontSize: 90, bold: true, color: '#FFFFFF',
})
// KPI row
s.addKPIGrid({
x: 0.8, y: 5.8, w: 11.7, h: 1.4, gap: 0.25,
items: [
{ label: 'REVENUE', value: '$4.2M', delta: 28 },
{ label: 'USERS', value: '128k', delta: 14 },
{ label: 'NPS', value: '72', delta: 6 },
{ label: 'CHURN', value: '2.1%', delta: -18 },
],
bg: 'rgba(255,255,255,0.1)', color: '#FFFFFF',
})
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.
Backgrounds & textures
await s.addBackground({ color: '#fafaf7' })
await s.addBackground({ gradient: { type: 'mesh', colors: ['#6366f1', '#ec4899'], base: '#0b0b0f', blur: 80 } })
await s.addAuroraGradient({ x, y, w, h, bg: '#0B0B0F', blobs: [{ x:0.2, y:0.3, r:0.4, color:'#7C3AED' }], blur: 120 })
await s.addHalftone({ x, y, w, h, direction: 'radial', cellSize: 20, color: '#7C3AED', opacity: 0.4 })
await s.addGridPaper({ x, y, w, h, cellSize: 32, majorEvery: 5, opacity: 0.08 })
await s.addCheckerPattern({ x, y, w, h, cellSize: 40, colorA: '#fff', colorB: '#0b0b0f' })
await s.addRadialBurst({ x, y, w, h, rays: 24, color: '#FBBF24', opacity: 0.3 })
await s.addNoiseTexture({ x, y, w, h, opacity: 0.15, tint: '#FFFFFF' })
await s.addDotGrid({ x, y, w, h, cellSize: 24, dotRadius: 1.2, color: '#fff', opacity: 0.25 })
await s.addStripes({ x, y, w, h, angle: 45, stripeWidth: 16, color: '#fff', opacity: 0.15 })
await s.addGrain({ x, y, w, h, opacity: 0.08 })
await s.addNoiseGradient({ x, y, w, h })
await s.addBlob({ x, y, w, h, seed: 42, points: 8, fillGradient: ['#ec4899', '#f59e0b'] })
await s.addGlassCard({ x, y, w, h, tint: '#fff', tintOpacity: 0.12, highlight: true })
await s.addIsometricGrid({ x, y, w, h })Text effects
await s.addGradientText('Hello', {
x, y, w, h,
fontFamily: 'Fraunces, serif', fontSize: 140, fontWeight: 500,
gradient: ['#6366f1', '#ec4899'], angle: 135,
})Data visualisation
await s.addBarRace({
x, y, w, h,
data: [{ label: 'EU', value: 4200, color: '#7C3AED' }, ...],
})
await s.addRadarChart({
x, y, w, h,
axes: ['Speed', 'Quality', 'Price', 'Support', 'DX'],
values: [[0.9, 0.8, 0.7, 0.85, 0.95], [0.6, 0.7, 0.9, 0.5, 0.4]],
fillColor: ['#7C3AED', '#9CA3AF'],
})
await s.addHeatmap({
x, y, w, h,
data: [[3,5,8,6], [2,7,4,9]],
rowLabels: ['A', 'B'], colLabels: ['Q1','Q2','Q3','Q4'],
colorLow: '#F3E8FF', colorHigh: '#7C3AED',
})
await s.addFunnel({
x, y, w, h,
stages: [{ label: 'Visitors', value: 100000 }, { label: 'Paying', value: 7200 }],
})
await s.addProgressRing({ x, y, w, h, value: 0.72, sublabel: 'NPS' })
await s.addSparkline({ x, y, w, h, values: [10, 14, 12, 18, 22, 28] })
await s.addCodeBlock({ x, y, w, h, code: 'const x = 1', language: 'js', theme: 'dark' })
await s.addIcon({ x, y, w, h, name: 'Zap', color: '#7C3AED' })Layout composites (native — editable in PowerPoint)
// Stat card with delta + sparkline
s.addStatCard({ x, y, w, h, value: '$4.2M', label: 'REVENUE', delta: 28,
sparkline: [12,15,18,22,28,38,42] })
// Grid of KPI cards
s.addKPIGrid({ x, y, w, h, gap: 0.25,
items: [{ label: 'MRR', value: '$84k', delta: 12 }, ...] })
// Callout box
s.addCallout({ x, y, w, h, variant: 'success',
title: 'Production-ready', body: 'Used in 200+ companies.' })
// Feature card
s.addFeatureCard({ x, y, w, h, icon: 'Zap', title: 'Fast', body: '100 slides/s' })
// Step flow 1→2→3
s.addStepFlow({ x, y, w, h,
steps: [{ title: 'Install' }, { title: 'Write' }, { title: 'Export' }] })
// Comparison table ✓/✗
s.addComparisonTable({ x, y, w, h,
columns: ['Free', 'Pro'], highlightCol: 1,
rows: [{ label: 'Unlimited slides', values: [false, true] }] })
// Team card
s.addTeamCard({ x, y, w, h, name: 'Claude N.', role: 'FOUNDER',
initials: 'CN', bio: 'Obsessed with editorial typography.' })
// Logo cloud
s.addLogoCloud({ x, y, w, h, logos: ['https://...logo.png', ...], cols: 4 })Low-level escape hatch
Nothing from pptxgenjs is hidden:
const rawSlide = slide.raw()
rawSlide.addChart(pres._pptx.ChartType.bar, data, chartOpts)
pres._pptx.defineSlideMaster({ ... })Theme system
const pres = new Pres({ theme: { primary: '#7C3AED', fontBody: 'Inter, sans-serif' } })
// or later:
pres.setTheme({ primary: '#FF0000' })All primitives fall back to theme values when an option is omitted. Override explicitly to take priority.
| Key | Default | Used by |
|---|---|---|
primary |
#7C3AED |
badges, avatars, accents |
text |
#FAFAFA |
addText, addTable |
textDim |
#A1A1AB |
captions, roles |
surface |
#1E1E3F |
card backgrounds |
fontBody |
Inter, system-ui |
all text primitives |
fontDisplay |
Fraunces, Georgia |
display headings |
fontMono |
JetBrains Mono |
code blocks |
Exposed utilities
For advanced usage — build your own primitives:
import {
// SVG helpers
blobSvg, halftoneSvg, auroraGradientSvg, radarChartSvg, funnelSvg,
gradientSvg, gradientTextSvg, glassSvg, barRaceSvg, heatmapSvg,
// Raster
svgToPngDataUrl, generateGrainPng,
// Colors
normalizeHex, hexToRgb, rgbToHex, mix,
// Cache
cachedRaster, clearRasterCache, rasterCacheStats, setRasterCacheMax,
// Validation
validateRect, validateColor, safeRun, setStrict,
} 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
- Node-compatible rasterizer (via
@napi-rs/canvas) for SSR / CI use - Monaco editor in the playground
addAnimatedGif— export animated sequences- TypeScript types for all v0.5 new methods
- Official LLM system-prompt snippet
License
MIT © 2026 Claude Ndanda