gamma-migration-deep-dive
Deep dive into migrating to Gamma from other presentation platforms. Use when migrating from PowerPoint, Google Slides, Canva, or other presentation tools to Gamma. Trigger with phrases like "gamma migration", "migrate to gamma", "gamma import", "gamma from powerpoint", "gamma from google slides". allowed-tools: Read, Write, Edit, Bash(node:*) version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>
Allowed Tools
No tools specified
Provided by Plugin
gamma-pack
Claude Code skill pack for Gamma (24 skills)
Installation
This skill is included in the gamma-pack plugin:
/plugin install gamma-pack@claude-code-plugins-plus
Click to copy
Instructions
# Gamma Migration Deep Dive
## Overview
Comprehensive guide for migrating presentations and workflows from other platforms to Gamma.
## Prerequisites
- Gamma API access
- Source platform export capabilities
- Node.js 18+ for migration scripts
- Sufficient Gamma storage quota
## Supported Migration Paths
| Source | Format | Fidelity | Notes |
|--------|--------|----------|-------|
| PowerPoint | .pptx | High | Native import |
| Google Slides | .pptx export | High | Export first |
| Canva | .pdf/.pptx | Medium | Limited animations |
| Keynote | .pptx export | High | Export first |
| PDF | .pdf | Medium | Static only |
| Markdown | .md | High | Structure preserved |
## Instructions
### Step 1: Inventory Source Presentations
```typescript
// scripts/migration-inventory.ts
interface SourcePresentation {
id: string;
title: string;
source: 'powerpoint' | 'google' | 'canva' | 'other';
path: string;
size: number;
lastModified: Date;
slideCount?: number;
}
async function inventoryPresentations(sourceDir: string): Promise {
const files = await glob('**/*.{pptx,pdf,key}', { cwd: sourceDir });
const inventory: SourcePresentation[] = [];
for (const file of files) {
const stats = await fs.stat(path.join(sourceDir, file));
const ext = path.extname(file).toLowerCase();
inventory.push({
id: crypto.randomUUID(),
title: path.basename(file, ext),
source: detectSource(file),
path: file,
size: stats.size,
lastModified: stats.mtime,
});
}
// Save inventory
await fs.writeFile(
'migration-inventory.json',
JSON.stringify(inventory, null, 2)
);
console.log(`Found ${inventory.length} presentations to migrate`);
return inventory;
}
```
### Step 2: Migration Engine
```typescript
// lib/migration-engine.ts
import { GammaClient } from '@gamma/sdk';
interface MigrationResult {
sourceId: string;
gammaId?: string;
success: boolean;
error?: string;
duration: number;
}
class MigrationEngine {
private gamma: GammaClient;
private results: MigrationResult[] = [];
constructor() {
this.gamma = new GammaClient({
apiKey: process.env.GAMMA_API_KEY,
timeout: 120000, // Long timeout for imports
});
}
async migrateFile(source: SourcePresentation): Promise {
const start = Date.now();
try {
// Read file
const fileBuffer = await fs.readFile(source.path);
// Upload to Gamma
const presentation = await this.gamma.presentations.import({
file: fileBuffer,
filename: path.basename(source.path),
title: source.title,
preserveFormatting: true,
convertToGammaStyle: false,
});
const result: MigrationResult = {
sourceId: source.id,
gammaId: presentation.id,
success: true,
duration: Date.now() - start,
};
this.results.push(result);
return result;
} catch (error) {
const result: MigrationResult = {
sourceId: source.id,
success: false,
error: error.message,
duration: Date.now() - start,
};
this.results.push(result);
return result;
}
}
async migrateAll(
sources: SourcePresentation[],
options = { concurrency: 3, retries: 2 }
) {
const queue = new PQueue({ concurrency: options.concurrency });
const tasks = sources.map(source =>
queue.add(async () => {
for (let attempt = 0; attempt < options.retries; attempt++) {
const result = await this.migrateFile(source);
if (result.success) return result;
console.log(`Retry ${attempt + 1} for ${source.title}`);
await delay(5000 * (attempt + 1));
}
})
);
await Promise.all(tasks);
return this.getReport();
}
getReport() {
const successful = this.results.filter(r => r.success);
const failed = this.results.filter(r => !r.success);
return {
total: this.results.length,
successful: successful.length,
failed: failed.length,
successRate: (successful.length / this.results.length * 100).toFixed(1),
averageDuration: successful.reduce((a, b) => a + b.duration, 0) / successful.length,
failures: failed.map(f => ({ id: f.sourceId, error: f.error })),
};
}
}
```
### Step 3: Platform-Specific Handlers
#### Google Slides Migration
```typescript
// lib/google-slides-migrator.ts
import { google } from 'googleapis';
async function migrateFromGoogleSlides(
driveFileId: string,
gamma: GammaClient
) {
const drive = google.drive('v3');
// Export as PowerPoint
const exportResponse = await drive.files.export({
fileId: driveFileId,
mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
}, { responseType: 'arraybuffer' });
// Import to Gamma
const presentation = await gamma.presentations.import({
file: Buffer.from(exportResponse.data as ArrayBuffer),
filename: 'exported.pptx',
source: 'google_slides',
});
return presentation;
}
```
#### PowerPoint Migration with Metadata
```typescript
// lib/powerpoint-migrator.ts
import JSZip from 'jszip';
import { parseStringPromise } from 'xml2js';
async function extractPowerPointMetadata(filePath: string) {
const fileBuffer = await fs.readFile(filePath);
const zip = await JSZip.loadAsync(fileBuffer);
// Extract core properties
const coreXml = await zip.file('docProps/core.xml')?.async('string');
if (!coreXml) return {};
const core = await parseStringPromise(coreXml);
return {
title: core['cp:coreProperties']?.['dc:title']?.[0],
creator: core['cp:coreProperties']?.['dc:creator']?.[0],
created: core['cp:coreProperties']?.['dcterms:created']?.[0],
modified: core['cp:coreProperties']?.['dcterms:modified']?.[0],
};
}
async function migrateWithMetadata(source: SourcePresentation, gamma: GammaClient) {
const metadata = await extractPowerPointMetadata(source.path);
const fileBuffer = await fs.readFile(source.path);
const presentation = await gamma.presentations.import({
file: fileBuffer,
filename: path.basename(source.path),
title: metadata.title || source.title,
metadata: {
originalCreator: metadata.creator,
originalCreated: metadata.created,
migratedAt: new Date().toISOString(),
},
});
return presentation;
}
```
### Step 4: Post-Migration Validation
```typescript
// scripts/validate-migration.ts
async function validateMigration(sourceId: string, gammaId: string) {
const gamma = new GammaClient({ apiKey: process.env.GAMMA_API_KEY });
const presentation = await gamma.presentations.get(gammaId, {
include: ['slides', 'assets'],
});
const validations = {
exists: !!presentation,
hasSlides: presentation.slides?.length > 0,
allAssetsLoaded: presentation.assets?.every(a => a.status === 'loaded'),
canExport: false,
};
// Test export capability
try {
const exportTest = await gamma.exports.create(gammaId, {
format: 'pdf',
dryRun: true,
});
validations.canExport = exportTest.valid;
} catch {
validations.canExport = false;
}
return {
sourceId,
gammaId,
validations,
passed: Object.values(validations).every(v => v),
};
}
```
### Step 5: Rollback Plan
```typescript
// lib/rollback.ts
interface MigrationSnapshot {
timestamp: Date;
mappings: Array<{ sourceId: string; gammaId: string }>;
}
async function createSnapshot(results: MigrationResult[]): Promise {
const snapshot: MigrationSnapshot = {
timestamp: new Date(),
mappings: results
.filter(r => r.success && r.gammaId)
.map(r => ({ sourceId: r.sourceId, gammaId: r.gammaId! })),
};
const snapshotPath = `migration-snapshot-${Date.now()}.json`;
await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2));
return snapshotPath;
}
async function rollbackMigration(snapshotPath: string) {
const snapshot: MigrationSnapshot = JSON.parse(
await fs.readFile(snapshotPath, 'utf-8')
);
const gamma = new GammaClient({ apiKey: process.env.GAMMA_API_KEY });
console.log(`Rolling back ${snapshot.mappings.length} presentations...`);
for (const mapping of snapshot.mappings) {
try {
await gamma.presentations.delete(mapping.gammaId);
console.log(`Deleted: ${mapping.gammaId}`);
} catch (error) {
console.error(`Failed to delete ${mapping.gammaId}: ${error.message}`);
}
}
console.log('Rollback complete');
}
```
## Migration Checklist
### Pre-Migration
- [ ] Inventory all source presentations
- [ ] Verify Gamma storage quota
- [ ] Test import with sample files
- [ ] Set up monitoring for migration
- [ ] Create rollback plan
- [ ] Notify stakeholders
### During Migration
- [ ] Run migration in batches
- [ ] Monitor error rates
- [ ] Validate each batch
- [ ] Take snapshots for rollback
### Post-Migration
- [ ] Validate all presentations
- [ ] Update links and references
- [ ] Train users on Gamma
- [ ] Archive source files
- [ ] Document lessons learned
## Resources
- [Gamma Import Formats](https://gamma.app/docs/import)
- [Migration Best Practices](https://gamma.app/docs/migration)
- [Gamma Support](https://gamma.app/support)
## Summary
This skill pack provides comprehensive coverage for Gamma integration from initial setup through enterprise deployment and migration. Start with `gamma-install-auth` and progress through the skills as needed for your integration complexity.