npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

slidewave

v0.6.1

Published

Low-level JS library for generating beautiful .pptx files — pptxgenjs-compatible API with designer-grade primitives (global theme, parallel raster pipeline, LRU cache, addTable/Quote/Divider/Avatar, Lucide icons, Prism syntax highlighting, blobs, mesh gra

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

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

  1. Programmatic generation — 100 slides in 1 second, dynamic templates, real-time data.
  2. Modern visuals — mesh gradients, aurora gradients, organic blobs, glassmorphism, halftones, editorial charts, syntax-highlighted code, Lucide icons.
  3. Still editable — text, shapes and charts remain native PPT objects, modifiable inside PowerPoint.
  4. Zero lock-in — standard .pptx output. Works everywhere.
  5. Live SVG preview — see the result in-browser without opening PowerPoint.
  6. 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, await required)

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.pptx

Each 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 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: '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' },
})

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.

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 #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

  • 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