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

slidecanvas

v1.2.2

Published

SlideCanvas is a high-performance, browser-native toolkit for viewing and editing PowerPoint (.pptx) files directly in the web browser. It provides an enterprise-grade engine for parsing, rendering, and exporting presentations with pixel-perfect accuracy

Readme

SlideCanvas

SlideCanvas is a high-performance, browser-native toolkit for viewing and editing PowerPoint (.pptx) files directly in the web browser. It provides an enterprise-grade engine for parsing, rendering, and exporting presentations with pixel-perfect accuracy and seamless S3 integration.


Key Features

  • Pixel-Perfect Rendering: High-fidelity display of slides using a sophisticated Fabric.js-based canvas.
  • AI-Powered Editing: Integrated Gemini AI for smart text manipulation (Shorten, Reframe, Lengthen, Grammar, Rewrite) with side-by-side controls and custom "Ask AI" input.
  • Enterprise-Grade Parsing: Deep internal processing of XML-based PPTX structures.
  • Professional Ribbon UI: A high-density, Microsoft Office-style toolbar layout (120px height) with optimized visibility for all controls.
  • Slash Commands (/): A fast, context-aware command menu triggered by typing / anywhere on the canvas or in a text box.
  • AI-Powered Image Generation: Integrated flow for generating design assets via optional onGenerateImage hook, with built-in preview and replacement logic.
  • Two-Step Infographic Generation: Advanced workflow to refine selected slide text into visual prompts before generating infographics (via onRefineInfographicPrompt and onGenerateInfographic).
  • AI Suggestion Box: A side-by-side text refinement UI for reviewing Shorten/Reframe/Lengthen suggestions before applying them.
  • Smart Actions Group: Prominent buttons for Present, Export (PPTX), and Delete, with a subtle "Saved" status indicator.
  • Professional Export: High-quality .pptx generation with support for transparency and layout mapping.
  • S3 & Remote Support: Built-in architecture for loading presentations via secure proxy tunnels.

Installation

Install SlideCanvas via your preferred package manager:

npm install slidecanvas
# or
yarn add slidecanvas
# or
pnpm add slidecanvas

Internal Flow Architecture

SlideCanvas operates on a sophisticated Unidirectional Data Flow architecture designed for reliability and scalability:

  1. Ingestion Layer: A multi-stage processing engine that decomposes binary .pptx uploads or remote URLs.
  2. Normalization Engine: Converts complex XML structures into a standardized, lightweight JSON presentation state.
  3. Virtual Canvas Sync: Bridges the presentation state to a high-performance Fabric.js canvas, handling real-time manipulation and absolute positioning.
  4. Serialization Pipe: Reconstructs the internal state back into standard OpenXML structures for high-fidelity export.

[!NOTE] All parsing and state transformations occur within a secure, sandboxed internal context to ensure document integrity.


Getting Started

1. Basic Setup

To build a basic editor, import the PptEditor component into your React/Next.js application:

import { PptEditor } from 'slidecanvas';

export default function MyEditor() {
  return (
    <main className="h-screen">
      <PptEditor appName="My Studio" />
    </main>
  );
}

2. Loading Remote Presentations via URL

SlideCanvas makes it easy to load existing presentations directly via a URL. The component handles the fetching and parsing internally:

import { PptEditor } from 'slidecanvas';

export default function App() {
  const pptxUrl = "https://example.com/presentations/q1-report.pptx";
  
  // Custom proxy endpoint (defaults to undefined, causing direct fetch)
  // If your app has an API route at /api/proxy, specify it here:
  return <PptEditor url={pptxUrl} proxyUrl="/api/proxy" />;
}

3. Handling Remote Files (S3 Integration)

SlideCanvas supports loading files from S3 or public URLs. To bypass CORS restrictions, we recommend setting up a proxy route in your api/proxy/route.ts:

// Next.js API Proxy Example
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const targetUrl = searchParams.get('url');

  const response = await fetch(targetUrl!, { cache: 'no-store' });
  return new NextResponse(response.body, {
    status: 200,
    headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.presentationml.presentation' }
  });
}

[!IMPORTANT] To use the custom proxy above, pass its path to the proxyUrl prop in the PptEditor component (e.g., <PptEditor proxyUrl="/api/proxy" ... />).

4. Handling Large Files (Client-Side Fetch)

To bypass server payload limits (e.g., Vercel's 4.5MB limit) or CORS issues, you can implement a custom client-side fetcher using the fetchPresentation prop. This is ideal for downloading files directly from S3 using pre-signed URLs.

<PptEditor
  fetchPresentation={async (url) => {
    // Logic to fetch directly from client
    // Example: Fetch pre-signed URL then download file
    const response = await fetch(url);
    if (!response.ok) throw new Error("Fetch failed");
    return await response.blob();
  }}
/>

4. Slash Commands & AI design

SlideCanvas features a powerful Slash Command system. Type / at any time to:

  • Insert Elements: Instantly add Text, Images, or Shapes.
  • AI Actions: Trigger text transformations or AI Image Generation directly at your cursor.

5. Custom AI Image Generation

You can integrate your own AI image provider (e.g., DALL-E, Midjourney, or a custom S3-backed service) by passing the onGenerateImage prop:

<PptEditor 
  onGenerateImage={async (prompt) => {
    const response = await fetch('/api/my-ai', { body: JSON.stringify({ prompt }) });
    const data = await response.json();
    return data.s3ImageUrl; // Return a URL string
  }}
/>

[!TIP] When an image is generated, SlideCanvas provides a professional Preview Modal allowing users to Insert as new, Replace a selected image (preserving dimensions), or Discard.

4. Custom AI Handlers (Ask AI & Toolbar)

SlideCanvas now supports a full suite of custom AI handlers, allowing you to bypass the internal Gemini implementation and use your own backend for every AI action.

<PptEditor
  // ... other props
  
  // Toolbar AI Actions (Quick Actions)
  onRefineShorten={async (text) => myApi.shorten(text)}
  onRefineReframe={async (text) => myApi.reframe(text)}
  onRefineLengthen={async (text) => myApi.lengthen(text)}

  // Slash Menu "Ask AI" Actions
  onAiEdit={async (text, prompt) => myApi.customEdit(text, prompt)} // Handles the custom input field
  onAiRewrite={async (text) => myApi.rewrite(text)}
  onAiGrammar={async (text) => myApi.fixGrammar(text)}
  onAiShorten={async (text) => myApi.shorten(text)}
  onAiLengthen={async (text) => myApi.lengthen(text)}
  onAiContinue={async (text) => myApi.continueWriting(text)}
/>

5. AI Image & Infographic Generation

(Two-Step Flow) SlideCanvas supports a sophisticated two-step workflow for creating infographics from slide content. This is enabled via the isTwoStepInfographicGeneration prop.

  1. Step 1: Refinement: The selected text is sent to onRefineInfographicPrompt. The user previews and edits the AI-generated visual prompt.
  2. Step 2: Generation: The refined prompt is then sent to onGenerateInfographic to create the final asset.
<PptEditor 
  isTwoStepInfographicGeneration={true}
  onRefineInfographicPrompt={async (text) => {
     // Use LLM to turn slide text into a visualization prompt
     return await myAiRefine(text); 
  }}
  onGenerateInfographic={async (prompt) => {
     // Generate the actual chart/infographic image
     return await myImageGen(prompt);
  }}
/>

7. Enabling AI Text Refinement

SlideCanvas comes battery-included with Gemini AI support for text.

import { PptEditor } from 'slidecanvas';

export default function MyEditor() {
  const geminiKey = process.env.NEXT_PUBLIC_GEMINI_API_KEY;

  return (
    <PptEditor 
      geminiApiKey={geminiKey}
      appName="AI Design Studio" 
    />
  );
}

8. Custom AI Text Refinement Hooks

While SlideCanvas includes built-in Gemini support, you can override the logic with your own AI providers (OpenAI, Anthropic, or custom internal LLMs) using the following hooks:

<PptEditor 
  onAiRewrite={async (text) => {
    const res = await myAiService.call('rewrite', text);
    return res.output;
  }}
  onAiGrammar={async (text) => {
    return await myAiService.call('fix-grammar', text);
  }}
  onAiShorten={async (text) => {
    return await myAiService.call('summarize', text);
  }}
  // Also supports onAiLengthen and onAiContinue
/>

[!NOTE] When these hooks are provided, the editor will favor them over the default Gemini integration.

9. Toolbar Refine vs Ask AI

The editor separates "Quick Actions" (Toolbar) from "Conversational AI" (Slash Command). You can provide distinct handlers for each:

  • Toolbar (Refine Menu): Uses onRefineShorten, onRefineReframe, onRefineLengthen.
  • Slash Command (Ask AI): Uses onAiShorten, onAiLengthen, onAiRewrite, etc.

This allows you to use lighter/faster models for the toolbar buttons and more capable models for the conversational interface if desired.

Advanced Usage Examples

1. 7-Second S3 Auto-Save (Real-Time Persistence)

To save changes back to S3 after a modifications stop for 7 seconds, use the PptxBlobExporter combined with a debounce pattern. Unlike the regular exporter, this utility returns a Blob directly without triggering a browser download.

import { PptEditor, PptxBlobExporter } from 'slidecanvas';
import { useRef } from 'react';

export function S3Editor({ s3Key }: { s3Key: string }) {
  const timerRef = useRef<NodeJS.Timeout | null>(null);

  const handleAutoSave = (presentation: any) => {
    // 1. Clear previous timer if user keeps editing
    if (timerRef.current) clearTimeout(timerRef.current);

    // 2. Start a new 7-second countdown
    timerRef.current = setTimeout(async () => {
      console.log('User stopped editing. Generating Blob and saving to S3...');
      
      // 3. Generate the .pptx file binary as a Blob
      const exporter = new PptxBlobExporter();
      const blob = await exporter.exportToBlob(presentation);
      
      // 4. Upload to your backend API which talks to S3
      const formData = new FormData();
      formData.append('file', blob, 'update.pptx');
      formData.append('key', s3Key);

      await fetch('/api/save-to-s3', {
        method: 'POST',
        body: formData
          });
      
      console.log('Saved successfully!');
    }, 7000); // 7 seconds
  };

  return <PptEditor onChange={handleAutoSave} />;
}

Sample Backend (Next.js API Route)

// api/save-to-s3/route.ts
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

export async function POST(req: Request) {
  const data = await req.formData();
  const file = data.get('file') as File;
  const key = data.get('key') as string;
  
  const buffer = Buffer.from(await file.arrayBuffer());
  
  const s3 = new S3Client({ region: "ap-south-1" });
  await s3.send(new PutObjectCommand({
    Bucket: "your-bucket-name",
    Key: key,
    Body: buffer,
    ContentType: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
  }));

  return Response.json({ success: true });
}

2. Programmatic Presentation Creation

You can skip the parser and build a presentation state manually to generate slides on the fly:

import { PptEditor, Presentation } from 'slidecanvas';

const myDraft: Presentation = {
  slides: [
    {
      id: 'welcome-slide',
      elements: [
        {
          id: 'title-1',
          type: 'text',
          content: 'Hello World from SlideCanvas!',
          x: 100, y: 100, width: 600, height: 100, fontSize: 48,
          color: '#3b82f6', zIndex: 1
        }
      ]
    }
  ],
  layout: { width: 12192000, height: 6858000 } // Standard 16:9 EMU
};

export default function App() {
  return <PptEditor initialPresentation={myDraft} />;
}

3. Custom Headless Processing (Node.js/Edge)

Extract text content or images without rendering the UI:

import { PptxParser } from 'slidecanvas';

async function extractCaptions(fileBuffer: ArrayBuffer) {
  const parser = new PptxParser();
  const presentation = await parser.parse(fileBuffer);

  const allText = presentation.slides.flatMap(slide => 
    slide.elements
      .filter(el => el.type === 'text')
      .map(el => el.content)
  );
  
  return allText;
}

API Reference

<PptEditor />

Properties

| Property | Type | Default | Description | | :--- | :--- | :--- | :--- | | width | number \| string | Required | The width of the editor container. | | height | number \| string | Required | The height of the editor container. | | initialPresentation | Presentation | undefined | Initial presentation data to load. | | url | string | undefined | URL of a public .pptx file to load on mount. | | initialSource | 'scratch' \| 'uploaded' \| 'url' | undefined | Sets the initial UI source state and badge. | | appName | string | "SlideCanvas" | Brand name shown in the ribbon. | | appBgColor | string | "#B7472A" | Primary brand color for the UI. | | geminiApiKey | string | undefined | API key for built-in AI text actions. | | onGenerateImage | (prompt: string) => Promise<string> | undefined | Custom hook to handle AI image generation. | | isTwoStepInfographicGeneration | boolean | false | Enables Step 1: Prompt Refinement modal for infographics. | | onRefineInfographicPrompt | (text: string) => Promise<string> | undefined | Hook to transform text into a visual prompt (Step 1). | | onGenerateInfographic | (prompt: string) => Promise<string> | undefined | Hook to generate the infographic image (Step 2). | | proxyUrl | string | undefined | Base path for the proxy API (used for PPTX loading and image previews). | | showHomeOnEmpty | boolean | false | Shows a "New / Upload" splash if no data provided. | | onChange | (pres: Presentation) => void | undefined | Fired on any change to the deck. | | onSourceChange | (src, url?) => void | undefined | Fired when the deck origin changes (useful for routing). | | onAiRewrite | (text: string) => Promise<string> | undefined | Optional hook to override default Gemini rewrite logic. | | onAiGrammar | (text: string) => Promise<string> | undefined | Optional hook to override default Gemini grammar logic. | | onAiShorten | (text: string) => Promise<string> | undefined | Optional hook to override default Gemini shorten logic. | | onAiLengthen | (text: string) => Promise<string> | undefined | Optional hook to override default Gemini lengthen logic. | | onAiContinue | (text: string) => Promise<string> | undefined | Optional hook to override default Gemini continue-writing logic. | | onRefineShorten | (text: string) => Promise<string> | undefined | Override loop for Toolbar "Shorten" button. | | onRefineReframe | (text: string) => Promise<string> | undefined | Override loop for Toolbar "Reframe" button. | | onRefineLengthen | (text: string) => Promise<string> | undefined | Override loop for Toolbar "Lengthen" button. | | fetchPresentation | (url: string) => Promise<ArrayBuffer \| Blob> | undefined | Custom fetcher for loading presentations, bypassing the proxy. |

Usage Examples

1. Branded Full-Screen Editor

Perfect for a standalone presentation app.

import { PptEditor } from 'slidecanvas';

export default function MyEditor() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <PptEditor
        width="100%"
        height="100%"
        appName="SkyDeck"
        appBgColor="#0f172a" // Custom dark theme
        showHomeOnEmpty={true} // Show the splash screen if no PPT loaded
      />
    </div>
  );
}

2. AI-Powered Assistant

Enable Gemini-driven text refinements and slide generation.

<PptEditor
  width={1200}
  height={800}
  geminiApiKey={process.env.NEXT_PUBLIC_GEMINI_API_KEY}
  appName="AI Slides"
/>

3. Deep-Linking & URL Sync (Next.js)

Synchronize the editor's source (Scratch, Uploaded, or Remote) with your browser's address bar.

const router = useRouter();
const searchParams = useSearchParams();

<PptEditor
  width="100vw"
  height="100vh"
  url={searchParams.get('url')}
  initialSource={searchParams.get('source')} // 'scratch' | 'uploaded' | 'url'
  onSourceChange={(source, url) => {
    // Dynamically update URL as user switches between 'Create New' and 'Upload'
    const query = url ? `?url=${url}` : `?source=${source}`;
    router.push(`/editor${query}`);
  }}
/>

Advanced Features

Visual Shape Selection

The editor includes a rich selection of 30+ SVG shapes out of the box. The shapes are fully responsive and scale accurately with the editor's dimensions.

Professional Ribbon UI

SlideCanvas features a sophisticated 120px high ribbon layout divided into logical groups:

  • Slides: New slide creation and layout switching (Title, Content, Split).
  • Font: Full-width family and size selectors with comprehensive formatting tools.
  • Drawing: Instant access to Shapes, Text Boxes, and Image uploads.
  • AI Text: Side-by-side buttons for intelligent content transformation.
  • Actions: Large, accessible buttons for primary workflows like Presenting and Exporting.

Intelligent Routing

Use the onSourceChange callback to synchronize the editor state with your application's routing. This allows for deep-linking to specific presentations or maintaining "Upload" vs "New" states in the address bar.

PptxParser, PptxExporter & PptxBlobExporter

For headless workflows, you can use the internal engine directly:

import { PptxParser, PptxExporter, PptxBlobExporter } from 'slidecanvas';

// 1. Load: Parse a .pptx file into JSON
const parser = new PptxParser();
const presentation = await parser.parse(myArrayBuffer);

// 2. Export: Trigger a browser file download
const exporter = new PptxExporter();
await exporter.export(presentation);

// 3. Blob Export: Get file data as a Blob (useful for S3/API uploads)
const blobExporter = new PptxBlobExporter();
const blob = await blobExporter.exportToBlob(presentation);

Building for Production

To build your application for production, run:

npm run build

The slidecanvas library is optimized for tree-shaking and minimizes your final bundle size by lazily loading the Fabric.js engine.


License

This project is licensed under the MIT License. You are free to use, modify, and distribute this software as permitted by the license terms.