SlideCanvas
v2.4.0 Stable

SlideCanvas Docs

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

Enterprise-Grade Parsing

Deep internal processing of XML-based PPTX structures.

Professional Ribbon UI

A high-density, Microsoft Office-style toolbar layout (120px height).

Slash Commands (/)

A fast, context-aware command menu triggered by typing / anywhere.

AI Image Generation

Integrated flow for generating design assets via optional onGenerateImage hook.

Infographic Generation

Advanced workflow to refine selected slide text into visual prompts.

Smart Actions Group

Prominent buttons for Present, Export (PPTX), and Delete.

Installation

Install SlideCanvas via your preferred package manager. We support npm, yarn, and pnpm.

npm install slidecanvas

Internal Flow Architecture

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

1

Ingestion Layer

Decomposes binary .pptx uploads or remote URLs.

2

Normalization Engine

Converts complex XML structures into standardized JSON.

3

Virtual Canvas Sync

Bridges state to a high-performance Fabric.js canvas.

4

Serialization Pipe

Reconstructs state back into OpenXML for export.

NoteAll parsing and state transformations occur within a secure, sandboxed internal context to ensure document integrity.

Getting Started

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

MyEditor.tsx
import { PptEditor } from 'slidecanvas';

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

Remote Loading

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

App.tsx
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" />;
}

S3 Integration

Setup a proxy route to bypass CORS restrictions when loading files from S3.

api/proxy/route.ts
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' }
  });
}
ImportantTo use the custom proxy above, pass its path to the proxyUrl prop in the PptEditor component.

Large Files

To bypass server payload limits, implement a custom client-side fetcher using the fetchPresentation prop.

<PptEditor
  fetchPresentation={async (url) => {
    // Logic to fetch directly from client
    const response = await fetch(url);
    if (!response.ok) throw new Error("Fetch failed");
    return await response.blob();
  }}
/>

Slash Commands

Type / at any time to trigger context-aware actions.

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

AI Image Generation

Integrate your own AI image provider via 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
  }}
/>
TipWhen an image is generated, SlideCanvas provides a professional Preview Modal.

Custom AI Handlers

Bypass internal Gemini logic with your own backend for custom AI workflows.

<PptEditor
  onAiEdit={async (text, prompt) => myApi.customEdit(text, prompt)}
  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)}
/>

Infographics

Two-step workflow for creating visual assets from slide content.

<PptEditor 
  isTwoStepInfographicGeneration={true}
  onRefineInfographicPrompt={async (text) => await myAiRefine(text)}
  onGenerateInfographic={async (prompt) => 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
/>
NoteWhen 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.

7-Second S3 Auto-Save

Generate a Blob and save to S3 after a 7-second debounce.

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

export function S3Editor({ s3Key }) {
  const timerRef = useRef(null);

  const handleAutoSave = (presentation) => {
    if (timerRef.current) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(async () => {
      const exporter = new PptxBlobExporter();
      const blob = await exporter.exportToBlob(presentation);
      const formData = new FormData();
      formData.append('file', blob, 'update.pptx');
      formData.append('key', s3Key);
      await fetch('/api/save-to-s3', { method: 'POST', body: formData });
    }, 7000);
  };

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

Programmatic Creation

Build a presentation state manually to generate slides on the fly.

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

Headless Processing

Extract text content without rendering the UI.

import { PptxParser } from 'slidecanvas';

async function extractCaptions(fileBuffer: ArrayBuffer) {
  const parser = new PptxParser();
  const presentation = await parser.parse(fileBuffer);
  return presentation.slides.flatMap(s => s.elements.map(e => e.content));
}

API Reference

<PptEditor /> Properties

PropertyTypeDefaultDescription
widthnumber | stringRequiredThe width of the editor container.
heightnumber | stringRequiredThe height of the editor container.
initialPresentationPresentationundefinedInitial presentation data to load.
urlstringundefinedURL of a public .pptx file to load on mount.
initialSource'scratch' | 'uploaded' | 'url'undefinedSets the initial UI source state and badge.
appNamestring"SlideCanvas"Brand name shown in the ribbon.
appBgColorstring"#B7472A"Primary brand color for the UI.
geminiApiKeystringundefinedAPI key for built-in AI text actions.
onGenerateImage(prompt: string) => Promise<string>undefinedCustom hook to handle AI image generation.
isTwoStepInfographicGenerationbooleanfalseEnables Step 1: Prompt Refinement modal for infographics.
onRefineInfographicPrompt(text: string) => Promise<string>undefinedHook to transform text into a visual prompt (Step 1).
onGenerateInfographic(prompt: string) => Promise<string>undefinedHook to generate the infographic image (Step 2).
proxyUrlstringundefinedBase path for the proxy API (used for PPTX loading and image previews).
showHomeOnEmptybooleanfalseShows a "New / Upload" splash if no data provided.
onChange(pres: Presentation) => voidundefinedFired on any change to the deck.
onSourceChange(src, url?) => voidundefinedFired when the deck origin changes (useful for routing).
onAiRewrite(text: string) => Promise<string>undefinedOptional hook to override default Gemini rewrite logic.
onAiGrammar(text: string) => Promise<string>undefinedOptional hook to override default Gemini grammar logic.
onAiShorten(text: string) => Promise<string>undefinedOptional hook to override default Gemini shorten logic.
onAiLengthen(text: string) => Promise<string>undefinedOptional hook to override default Gemini lengthen logic.
onAiContinue(text: string) => Promise<string>undefinedOptional hook to override default Gemini continue-writing logic.
onRefineShorten(text: string) => Promise<string>undefinedOverride loop for Toolbar "Shorten" button.
onRefineReframe(text: string) => Promise<string>undefinedOverride loop for Toolbar "Reframe" button.
onRefineLengthen(text: string) => Promise<string>undefinedOverride loop for Toolbar "Lengthen" button.
fetchPresentation(url: string) => Promise<ArrayBuffer | Blob>undefinedCustom 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>
  );
}

Advanced Features

Custom Image Generation

SlideCanvas provides a hook to integrate any image generation API.

<PptEditor
  onGenerateImage={async (prompt) => {
    const response = await fetch('/api/generate', {
      method: 'POST',
      body: JSON.stringify({ prompt })
    });
    const { imageUrl } = await response.json();
    return imageUrl;
  }}
/>

Headless Utilities

SlideCanvas provides a set of utilities for processing PPTX files on the server or in a web worker.

import { PptxParser, PptxBlobExporter } from 'slidecanvas';

// Parse a file
const parser = new PptxParser();
const presentation = await parser.parse(arrayBuffer);

// Modify and export
presentation.slides[0].elements[0].content = "Updated Title";
const exporter = new PptxBlobExporter();
const blob = await exporter.exportToBlob(presentation);

Production Considerations

ImportantAlways ensure your proxy server is configured to handle large binary payloads if you are loading large PPTX files.

For high-traffic applications, we recommend using a CDN for your PPTX assets and configuring SlideCanvas to fetch them directly using the fetchPresentation hook.

License

SlideCanvas is licensed under the Apache License, Version 2.0.