agentsclimarketplace

Gamma migration deep dive

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/gamma-pack/skills/gamma-migration-deep-dive

'Deep dive into migrating to Gamma from other presentation platforms.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill gamma-migration-deep-dive

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.8 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it

Gamma Migration Deep Dive

Current State

!npm list 2>/dev/null | head -10

Overview

Migrate presentation workflows from PowerPoint, Google Slides, Canva, or other platforms to Gamma's AI-powered generation. Gamma takes a fundamentally different approach -- instead of manually placing slides, you provide content and Gamma generates the presentation. Migration is about converting your content pipeline, not your slide files.

Prerequisites

  • Gamma API access (Pro+ plan)
  • Source presentations accessible for content extraction
  • Node.js 18+ for migration scripts
  • Completed gamma-install-auth setup

Migration Approaches

ApproachWhen to UseEffort
Content extraction + regenerationLots of text-heavy presentationsMedium
Import via Gamma UIOne-off migration of key decksLow
Template recreationRepeatable presentation formatsMedium
Parallel operationGradual transition over timeLow

Key insight: You don't "import" slides into Gamma. You extract content from old presentations and regenerate them using Gamma's AI. This often produces better results than the originals.

Instructions

Step 1: Inventory Source Presentations

// scripts/inventory-presentations.ts
import { readdir, stat } from "node:fs/promises";
import { join, extname } from "node:path";

interface PresentationInfo {
  path: string;
  format: string;
  sizeMB: number;
  lastModified: Date;
}

async function inventoryPresentations(dir: string): Promise<PresentationInfo[]> {
  const entries = await readdir(dir, { recursive: true });
  const presentations: PresentationInfo[] = [];

  for (const entry of entries) {
    const ext = extname(entry).toLowerCase();
    if ([".pptx", ".ppt", ".key", ".pdf", ".md"].includes(ext)) {
      const fullPath = join(dir, entry);
      const info = await stat(fullPath);
      presentations.push({
        path: fullPath,
        format: ext,
        sizeMB: info.size / (1024 * 1024),
        lastModified: info.mtime,
      });
    }
  }

  console.log(`Found ${presentations.length} presentations:`);
  const byFormat = presentations.reduce((acc, p) => {
    acc[p.format] = (acc[p.format] || 0) + 1;
    return acc;
  }, {} as Record<string, number>);
  console.log("By format:", byFormat);

  return presentations;
}

Step 2: Extract Content from PowerPoint

// scripts/extract-pptx.ts
// Use 'pptx-parser' or 'officegen' to extract text content

import JSZip from "jszip";
import { readFile } from "node:fs/promises";
import { DOMParser } from "xmldom";

async function extractPptxContent(pptxPath: string): Promise<string[]> {
  const buffer = await readFile(pptxPath);
  const zip = await JSZip.loadAsync(buffer);

  const slides: string[] = [];
  const slideFiles = Object.keys(zip.files)
    .filter((f) => f.match(/ppt\/slides\/slide\d+\.xml$/))
    .sort();

  for (const slideFile of slideFiles) {
    const xml = await zip.file(slideFile)!.async("string");
    const doc = new DOMParser().parseFromString(xml);
    // Extract all text elements
    const textNodes = doc.getElementsByTagName("a:t");
    const texts: string[] = [];
    for (let i = 0; i < textNodes.length; i++) {
      const text = textNodes[i].textContent?.trim();
      if (text) texts.push(text);
    }
    slides.push(texts.join("\n"));
  }

  return slides;
}

// Convert extracted content to Gamma prompt
function slidesToGammaPrompt(slides: string[], title: string): string {
  let prompt = `${title}\n\n`;
  slides.forEach((content, i) => {
    prompt += `Slide ${i + 1}:\n${content}\n\n`;
  });
  return prompt;
}

Step 3: Batch Migration Script

// scripts/migrate-to-gamma.ts
import { createGammaClient } from "../src/client";
import { pollUntilDone } from "../src/poll";
import pLimit from "p-limit";

const gamma = createGammaClient({ apiKey: process.env.GAMMA_API_KEY! });
const limit = pLimit(2); // Max 2 concurrent generations

interface MigrationItem {
  title: string;
  content: string;
  sourceFile: string;
}

async function migrateBatch(items: MigrationItem[]) {
  const results = await Promise.allSettled(
    items.map((item) =>
      limit(async () => {
        console.log(`Migrating: ${item.title}`);
        const { generationId } = await gamma.generate({
          content: item.content,
          outputFormat: "presentation",
          textMode: "condense", // AI condenses extracted text
          exportAs: "pptx",    // Get PPTX for comparison
        });

        const result = await pollUntilDone(gamma, generationId);
        return {
          title: item.title,
          sourceFile: item.sourceFile,
          gammaUrl: result.gammaUrl,
          exportUrl: result.exportUrl,
          creditsUsed: result.creditsUsed,
        };
      })
    )
  );

  // Report
  const succeeded = results.filter((r) => r.status === "fulfilled");
  const failed = results.filter((r) => r.status === "rejected");
  console.log(`\nMigration complete: ${succeeded.length} succeeded, ${failed.length} failed`);

  for (const r of results) {
    if (r.status === "fulfilled") {
      console.log(`  OK: ${r.value.title} → ${r.value.gammaUrl}`);
    } else {
      console.log(`  FAIL: ${r.reason}`);
    }
  }
}

Step 4: Template Recreation

For recurring presentation types (weekly reports, proposals, etc.), create Gamma templates:

Migration steps for templates:
1. Identify repeating presentation formats in your org
2. Create a one-page template gamma in the Gamma app:
   - gamma.app → Create → design a single representative page
3. Note the template gamma ID from the URL
4. Use POST /v1.0/generations/from-template with the gammaId
5. Update your automation scripts to use generateFromTemplate()
// After template creation in Gamma UI
const MIGRATED_TEMPLATES: Record<string, string> = {
  "weekly-report": "gamma_template_weekly_abc123",
  "sales-proposal": "gamma_template_proposal_def456",
  "team-update": "gamma_template_update_ghi789",
};

async function generateFromMigratedTemplate(
  templateKey: string,
  content: string
) {
  const gammaId = MIGRATED_TEMPLATES[templateKey];
  if (!gammaId) throw new Error(`Unknown template: ${templateKey}`);

  const { generationId } = await gamma.generateFromTemplate({
    gammaId,
    prompt: content,
    exportAs: "pdf",
  });

  return pollUntilDone(gamma, generationId);
}

Step 5: Validation Checklist

After migrating each presentation:

- [ ] Content accuracy: AI-generated text matches source intent
- [ ] Slide count: reasonable for the content volume
- [ ] Theme/branding: workspace theme applied correctly
- [ ] Export quality: PDF/PPTX downloads successfully
- [ ] Links preserved: any URLs from original are in the content
- [ ] Stakeholder review: key presentations reviewed by owners

Supported Migration Paths

SourceMethodFidelityNotes
PowerPoint (.pptx)Extract text → regenerateContent-high, design-newAI redesigns slides
Google SlidesExport as .pptx → extractContent-high, design-newExport first
CanvaExport as .pdf → extract textMediumLimited text extraction
Keynote (.key)Export as .pptx → extractContent-high, design-newExport first
Markdown (.md)Direct use as contentHighBest migration path
Notion pagesExport as .md → use directlyHighClean text extraction

Error Handling

IssueCauseSolution
Content too longExceeds 100K token limitSplit into multiple presentations
Credit budget exceededToo many migrations at onceBatch over multiple days
Poor output qualityContent too unstructuredAdd structure (headings, bullets) to extracted content
Missing imagesImages in source not extractedGamma generates new images; reference image concepts in text

Resources

Next Steps

Review gamma-core-workflow-a for ongoing content generation after migration.

What ships with it: 1 file

5.6 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.