+`;
+
+ try {
+ fs.writeFileSync(this.reportHtmlPath, htmlHeader);
+ } catch (error) {
+ this.log(`Failed to initialize HTML report: ${error.message}`, 'warn');
+ }
+ }
+
+ // Copy original file to report directory before optimization
+ copyOriginalToReport(originalPath) {
+ if (!this.reportDir || this.config.dryRun) return null;
+
+ const filename = path.basename(originalPath);
+ const beforePath = path.join(this.reportDir, 'before', filename);
+
+ try {
+ fs.copyFileSync(originalPath, beforePath);
+ this.log(`Copied original ${filename} to report`, 'debug');
+ return beforePath;
+ } catch (error) {
+ this.log(`Failed to copy original ${filename}: ${error.message}`, 'debug');
+ return null;
+ }
+ }
+
+ // Add comparison to HTML report (collect data, don't write HTML yet)
+ addComparisonToReport(originalPath, convertedPath, originalSize, convertedSize, beforeReportPath) {
+ if (!this.reportDir || this.config.dryRun || !beforeReportPath) return;
+
+ const filename = path.basename(originalPath);
+ const afterPath = path.join(this.reportDir, 'after', path.basename(convertedPath));
+
+ try {
+ // Copy converted file
+ fs.copyFileSync(convertedPath, afterPath);
+
+ // Calculate savings
+ const savedBytes = originalSize - convertedSize;
+ const savingsPercent = ((savedBytes / originalSize) * 100).toFixed(1);
+
+ // Track details for summary and later HTML generation
+ this.stats.fileDetails.push({
+ filename,
+ originalSize,
+ convertedSize,
+ savedBytes,
+ savingsPercent: parseFloat(savingsPercent),
+ originalPath,
+ convertedPath: path.basename(convertedPath)
+ });
+
+ this.log(`Added ${filename} to report`, 'debug');
+ } catch (error) {
+ this.log(`Failed to add ${filename} to report: ${error.message}`, 'debug');
+ }
+ }
+
+ // Recursively find all files with given extensions
+ findFiles(dir, extensions) {
+ const files = [];
+
+ const walk = (currentDir) => {
+ const items = fs.readdirSync(currentDir);
+ for (const item of items) {
+ const fullPath = path.join(currentDir, item);
+ const stat = fs.statSync(fullPath);
+
+ if (stat.isDirectory()) {
+ walk(fullPath);
+ } else if (extensions.some(ext => item.toLowerCase().endsWith(ext))) {
+ files.push(fullPath);
+ }
+ }
+ };
+
+ walk(dir);
+ return files;
+ }
+
+ // Get file size in bytes
+ getFileSize(filePath) {
+ try {
+ return fs.statSync(filePath).size;
+ } catch (error) {
+ return 0;
+ }
+ }
+
+ // Convert image using ImageMagick
+ async convertImage(inputPath, outputPath, quality = 85) {
+ return new Promise((resolve, reject) => {
+ const command = `magick "${inputPath}" -quality ${quality} "${outputPath}"`;
+
+ if (this.config.dryRun) {
+ this.log(`[DRY RUN] Would convert: ${inputPath} → ${outputPath}`, 'debug');
+ resolve();
+ return;
+ }
+
+ exec(command, (error, stdout, stderr) => {
+ if (error) {
+ this.log(`Failed to convert ${inputPath}: ${error.message}`, 'error');
+ this.stats.errors.push(`Convert failed: ${inputPath} - ${error.message}`);
+ reject(error);
+ } else {
+ this.log(`Converted: ${path.basename(inputPath)} → ${path.basename(outputPath)}`, 'debug');
+ resolve();
+ }
+ });
+ });
+ }
+
+ // Optimize SVG using SVGO
+ async optimizeSvg(filePath) {
+ return new Promise((resolve, reject) => {
+ if (this.config.dryRun) {
+ this.log(`[DRY RUN] Would optimize SVG: ${filePath}`, 'debug');
+ resolve();
+ return;
+ }
+
+ // Get original size before optimization
+ const originalSize = this.getFileSize(filePath);
+ const backupPath = `${filePath}.backup`;
+
+ try {
+ // Create backup
+ fs.copyFileSync(filePath, backupPath);
+
+ const command = `pnpm dlx svgo "${filePath}" --output "${filePath}"`;
+
+ exec(command, (error, stdout, stderr) => {
+ if (error) {
+ // Restore backup on error
+ try {
+ fs.copyFileSync(backupPath, filePath);
+ fs.unlinkSync(backupPath);
+ } catch (restoreError) {
+ this.log(`Failed to restore SVG backup: ${restoreError.message}`, 'warn');
+ }
+ this.log(`Failed to optimize SVG ${filePath}: ${error.message}`, 'error');
+ this.stats.errors.push(`SVG optimization failed: ${filePath} - ${error.message}`);
+ reject(error);
+ return;
+ }
+
+ // Check if optimization reduced file size
+ const optimizedSize = this.getFileSize(filePath);
+
+ if (optimizedSize >= originalSize) {
+ // Optimization made file larger or same size - revert
+ try {
+ fs.copyFileSync(backupPath, filePath);
+ this.log(`Reverted ${path.basename(filePath)} - SVG optimization increased size (${originalSize} → ${optimizedSize} bytes)`, 'warn');
+ } catch (revertError) {
+ this.log(`Failed to revert SVG optimization: ${revertError.message}`, 'warn');
+ }
+ } else {
+ this.log(`Optimized SVG: ${path.basename(filePath)} (${originalSize} → ${optimizedSize} bytes)`, 'debug');
+ }
+
+ // Clean up backup
+ try {
+ fs.unlinkSync(backupPath);
+ } catch (cleanupError) {
+ this.log(`Failed to cleanup SVG backup: ${cleanupError.message}`, 'debug');
+ }
+
+ resolve();
+ });
+ } catch (backupError) {
+ this.log(`Failed to create SVG backup: ${backupError.message}`, 'warn');
+ reject(backupError);
+ }
+ });
+ }
+
+ // Update image references in markdown files
+ updateMarkdownReferences(filePath, replacements) {
+ let content = fs.readFileSync(filePath, 'utf8');
+ let updated = false;
+ let changeCount = 0;
+
+ for (const [oldRef, newRef] of replacements) {
+ const regex = new RegExp(oldRef.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
+ const newContent = content.replace(regex, newRef);
+ if (newContent !== content) {
+ content = newContent;
+ updated = true;
+ changeCount++;
+ this.log(` Updated reference: ${oldRef} → ${newRef}`, 'debug');
+ }
+ }
+
+ if (updated && !this.config.dryRun) {
+ fs.writeFileSync(filePath, content);
+ this.stats.references.updated += changeCount;
+ }
+
+ return updated;
+ }
+
+ // Find all markdown references to images
+ findImageReferences() {
+ const mdFiles = this.findFiles(this.config.docsDir, ['.md', '.mdx']);
+ mdFiles.push(...this.findFiles('.', ['.md']).filter(f => !f.includes('node_modules')));
+
+ const references = new Map();
+
+ for (const file of mdFiles) {
+ const content = fs.readFileSync(file, 'utf8');
+
+ // Pattern 1: static/images/path/file.ext
+ const staticPattern = /!\[([^\]]*)\]\(static\/images\/([^)]+)\.(gif|png|jpg|jpeg)\)/g;
+
+ // Pattern 2: images/path/file.ext
+ const relativePattern = /!\[([^\]]*)\]\(images\/([^)]+)\.(gif|png|jpg|jpeg)\)/g;
+
+ let match;
+
+ // Find static/images references
+ while ((match = staticPattern.exec(content)) !== null) {
+ const [fullMatch, altText, imagePath, ext] = match;
+ const key = `static/images/${imagePath}.${ext}`;
+ if (!references.has(key)) references.set(key, []);
+ references.get(key).push({
+ file,
+ oldRef: fullMatch,
+ newRef: ``
+ });
+ }
+
+ // Reset regex
+ relativePattern.lastIndex = 0;
+
+ // Find images/ references
+ while ((match = relativePattern.exec(content)) !== null) {
+ const [fullMatch, altText, imagePath, ext] = match;
+ const key = `static/images/${imagePath}.${ext}`;
+ if (!references.has(key)) references.set(key, []);
+ references.get(key).push({
+ file,
+ oldRef: fullMatch,
+ newRef: ``
+ });
+ }
+ }
+
+ return references;
+ }
+
+ // Main optimization workflow
+ async optimize() {
+ this.log('🚀 Starting Discord API Docs Image Optimization');
+ this.log(`Mode: ${this.config.dryRun ? 'DRY RUN' : 'LIVE'}`, 'warn');
+
+ // Step 1: Analyze current images
+ this.log('\n📊 Analyzing current images...');
+ const imageFiles = this.findFiles(this.config.imagesDir, ['.gif', '.png', '.jpg', '.jpeg']);
+ const svgFiles = this.findFiles(this.config.imagesDir, ['.svg']);
+
+ // Calculate initial size
+ for (const file of [...imageFiles, ...svgFiles]) {
+ this.stats.sizeBefore += this.getFileSize(file);
+ }
+
+ this.log(`Found ${imageFiles.length} raster images and ${svgFiles.length} SVGs`);
+ this.log(`Total size before: ${(this.stats.sizeBefore / 1024 / 1024).toFixed(1)}MB`);
+
+ // Step 2: Convert images to WebP
+ this.log('\n🔄 Converting images to WebP...');
+ const conversions = [];
+
+ for (const imagePath of imageFiles) {
+ const ext = path.extname(imagePath).toLowerCase();
+ const baseName = path.basename(imagePath, ext);
+ const dir = path.dirname(imagePath);
+ const webpPath = path.join(dir, `${baseName}.webp`);
+
+ try {
+ // Copy original to report directory before conversion
+ const originalSize = this.getFileSize(imagePath);
+ const beforeReportPath = this.copyOriginalToReport(imagePath);
+
+ // Convert to WebP
+ await this.convertImage(imagePath, webpPath);
+
+ // Check if optimization actually reduced file size
+ const convertedSize = this.getFileSize(webpPath);
+
+ if (convertedSize >= originalSize) {
+ // Optimization made file larger or same size - revert
+ try {
+ fs.unlinkSync(webpPath);
+ this.log(`Reverted ${path.basename(imagePath)} - optimization increased size (${originalSize} → ${convertedSize} bytes)`, 'warn');
+ continue;
+ } catch (unlinkError) {
+ this.log(`Failed to remove larger optimized file ${webpPath}: ${unlinkError.message}`, 'warn');
+ }
+ }
+
+ // Add to report after successful optimization
+ this.addComparisonToReport(imagePath, webpPath, originalSize, convertedSize, beforeReportPath);
+
+ conversions.push({ original: imagePath, converted: webpPath, ext });
+
+ if (ext === '.gif') this.stats.conversions.gif++;
+ else if (ext === '.png') this.stats.conversions.png++;
+ else if (ext.match(/\.jpe?g/)) this.stats.conversions.jpg++;
+
+ } catch (error) {
+ this.log(`Skipping ${imagePath} due to conversion error`, 'warn');
+ }
+ }
+
+ // Step 3: Optimize SVGs
+ this.log('\n🎨 Optimizing SVG files...');
+ for (const svgPath of svgFiles) {
+ try {
+ await this.optimizeSvg(svgPath);
+ this.stats.conversions.svg++;
+ } catch (error) {
+ this.log(`Skipping ${svgPath} due to optimization error`, 'warn');
+ }
+ }
+
+ // Step 4: Find all image references
+ this.log('\n🔍 Finding image references in markdown files...');
+ const references = this.findImageReferences();
+ this.log(`Found references to ${references.size} unique images`);
+
+ // Step 5: Update markdown references
+ this.log('\n📝 Updating markdown references...');
+ const fileUpdates = new Map();
+
+ for (const [imagePath, refs] of references) {
+ // Check if we converted this image
+ const webpPath = imagePath.replace(/\.(gif|png|jpg|jpeg)$/i, '.webp');
+ const webpExists = fs.existsSync(webpPath) || this.config.dryRun;
+
+ if (webpExists) {
+ for (const ref of refs) {
+ if (!fileUpdates.has(ref.file)) fileUpdates.set(ref.file, []);
+ fileUpdates.get(ref.file).push([ref.oldRef, ref.newRef]);
+ }
+ } else {
+ this.log(`Warning: WebP not found for ${imagePath}, skipping reference updates`, 'warn');
+ }
+ }
+
+ // Apply updates to files
+ for (const [file, replacements] of fileUpdates) {
+ if (this.updateMarkdownReferences(file, replacements)) {
+ this.stats.references.files++;
+ this.log(`Updated references in ${path.relative('.', file)}`, 'debug');
+ }
+ }
+
+ // Step 6: Calculate final sizes and cleanup
+ if (!this.config.dryRun) {
+ for (const { converted } of conversions) {
+ this.stats.sizeAfter += this.getFileSize(converted);
+ }
+
+ for (const svgPath of svgFiles) {
+ this.stats.sizeAfter += this.getFileSize(svgPath);
+ }
+ }
+
+ // Step 7: Remove original files (only if everything succeeded)
+ if (!this.config.dryRun && this.stats.errors.length === 0) {
+ this.log('\n🗑️ Removing original files...');
+ for (const { original } of conversions) {
+ try {
+ fs.unlinkSync(original);
+ this.log(`Removed: ${path.basename(original)}`, 'debug');
+ } catch (error) {
+ this.log(`Failed to remove ${original}: ${error.message}`, 'warn');
+ }
+ }
+ }
+
+ // Finalize HTML report
+ this.finalizeHtmlReport();
+
+ // Final report
+ this.printSummary();
+ }
+
+ // Finalize HTML report with summary and footer
+ finalizeHtmlReport() {
+ if (!this.reportHtmlPath || this.config.dryRun) return;
+
+ try {
+ // Calculate summary stats
+ const totalOriginalSize = this.stats.fileDetails.reduce((sum, file) => sum + file.originalSize, 0);
+ const totalConvertedSize = this.stats.fileDetails.reduce((sum, file) => sum + file.convertedSize, 0);
+ const totalSaved = totalOriginalSize - totalConvertedSize;
+ const totalSavingsPercent = totalOriginalSize > 0 ? ((totalSaved / totalOriginalSize) * 100).toFixed(1) : '0';
+
+ // Format file sizes
+ const formatBytes = (bytes) => {
+ if (bytes === 0) return '0 B';
+ const k = 1024;
+ const sizes = ['B', 'KB', 'MB', 'GB'];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
+ };
+
+ // Top 10 biggest savers
+ const topSavers = this.stats.fileDetails
+ .sort((a, b) => b.savedBytes - a.savedBytes)
+ .slice(0, 10);
+
+ // Generate summary content
+ const summaryHtml = `
+
+
+
${this.stats.fileDetails.length}
+
Files Optimized
+
+
+
${formatBytes(totalOriginalSize)}
+
Original Size
+
+
+
${formatBytes(totalConvertedSize)}
+
Optimized Size
+
+
+
${formatBytes(totalSaved)}
+
Total Saved (${totalSavingsPercent}%)
+
+
+
+
+ 🏆 Top 10 Space Savers
+
+ ${topSavers.map((file, i) =>
+ `
+ ${i + 1}. ${file.filename} - Saved ${formatBytes(file.savedBytes)} (${file.savingsPercent}%)
+
`
+ ).join('')}
+
+
+ `;
+
+ // Sort files by converted size (descending) - largest optimized files first
+ const sortedFiles = this.stats.fileDetails
+ .sort((a, b) => b.convertedSize - a.convertedSize);
+
+ // Generate HTML comparisons for all files (sorted)
+ const comparisonsHtml = sortedFiles.map(file => {
+ const savingsClass = file.savedBytes > 0 ? 'savings-positive' : 'savings-negative';
+
+ return `
+
+
${file.filename}
+
+ Original: ${formatBytes(file.originalSize)} → Optimized: ${formatBytes(file.convertedSize)}
+ | Saved: ${formatBytes(Math.abs(file.savedBytes))} (${Math.abs(file.savingsPercent)}%)
+
+
+
+
Before
+

+
+
+
After (WebP)
+

+
+
+
`;
+ }).join('\n');
+
+ // Update summary section and add all comparisons
+ const currentContent = fs.readFileSync(this.reportHtmlPath, 'utf8');
+ const updatedContent = currentContent.replace(
+ '
Loading summary...
',
+ `
${summaryHtml}
`
+ );
+
+ // Add footer
+ const htmlFooter = `
+${comparisonsHtml}
+
+
+
+`;
+
+ fs.writeFileSync(this.reportHtmlPath, updatedContent + htmlFooter);
+
+ this.log(`\n📊 Visual comparison report generated: ${this.reportHtmlPath}`);
+ this.log(` View in browser: file://${path.resolve(this.reportHtmlPath)}`);
+ } catch (error) {
+ this.log(`Failed to finalize HTML report: ${error.message}`, 'warn');
+ }
+ }
+
+ printSummary() {
+ console.log('\n' + '='.repeat(60));
+ console.log('📈 OPTIMIZATION SUMMARY');
+ console.log('='.repeat(60));
+
+ console.log(`\n🔄 Conversions:`);
+ console.log(` GIFs → WebP: ${this.stats.conversions.gif}`);
+ console.log(` PNGs → WebP: ${this.stats.conversions.png}`);
+ console.log(` JPGs → WebP: ${this.stats.conversions.jpg}`);
+ console.log(` SVG optimized: ${this.stats.conversions.svg}`);
+
+ console.log(`\n📝 Reference Updates:`);
+ console.log(` Files updated: ${this.stats.references.files}`);
+ console.log(` References updated: ${this.stats.references.updated}`);
+
+ if (!this.config.dryRun) {
+ const beforeMB = (this.stats.sizeBefore / 1024 / 1024).toFixed(1);
+ const afterMB = (this.stats.sizeAfter / 1024 / 1024).toFixed(1);
+ const savedMB = (beforeMB - afterMB).toFixed(1);
+ const percentage = ((savedMB / beforeMB) * 100).toFixed(1);
+
+ console.log(`\n💾 Size Reduction:`);
+ console.log(` Before: ${beforeMB}MB`);
+ console.log(` After: ${afterMB}MB`);
+ console.log(` Saved: ${savedMB}MB (${percentage}% reduction)`);
+ }
+
+ if (this.stats.errors.length > 0) {
+ console.log(`\n❌ Errors (${this.stats.errors.length}):`);
+ this.stats.errors.forEach(error => console.log(` ${error}`));
+ }
+
+ console.log('\n✨ Optimization complete!');
+ }
+}
+
+// CLI handling
+if (import.meta.url === `file://${process.argv[1]}`) {
+ const args = process.argv.slice(2);
+ const dryRun = args.includes('--dry-run');
+ const verbose = !args.includes('--quiet');
+
+ if (args.includes('--help')) {
+ console.log(`
+Discord API Docs Image Optimizer
+
+Usage: node optimize-images.js [options]
+
+Options:
+ --dry-run Preview changes without executing
+ --quiet Suppress verbose output
+ --help Show this help message
+
+Examples:
+ node optimize-images.js --dry-run # Preview what would be changed
+ node optimize-images.js # Run full optimization
+ `);
+ process.exit(0);
+ }
+
+ const config = { ...CONFIG, dryRun, verbose };
+ const optimizer = new ImageOptimizer(config);
+
+ optimizer.optimize().catch(error => {
+ console.error('❌ Optimization failed:', error);
+ process.exit(1);
+ });
+}
+
+export { ImageOptimizer };
\ No newline at end of file
diff --git a/static/images/API_center.gif b/static/images/API_center.gif
deleted file mode 100644
index c22e319897..0000000000
Binary files a/static/images/API_center.gif and /dev/null differ
diff --git a/static/images/activities/activities-hero.png b/static/images/activities/activities-hero.png
deleted file mode 100644
index 9329eab77d..0000000000
Binary files a/static/images/activities/activities-hero.png and /dev/null differ
diff --git a/static/images/activities/activities-hero.webp b/static/images/activities/activities-hero.webp
new file mode 100644
index 0000000000..fa9f7c5cf6
Binary files /dev/null and b/static/images/activities/activities-hero.webp differ
diff --git a/static/images/activities/activity-instance-validation.jpg b/static/images/activities/activity-instance-validation.jpg
deleted file mode 100644
index 60c5f9edad..0000000000
Binary files a/static/images/activities/activity-instance-validation.jpg and /dev/null differ
diff --git a/static/images/activities/activity-instance-validation.webp b/static/images/activities/activity-instance-validation.webp
new file mode 100644
index 0000000000..4e11535574
Binary files /dev/null and b/static/images/activities/activity-instance-validation.webp differ
diff --git a/static/images/activities/application-test-mode-prod.gif b/static/images/activities/application-test-mode-prod.gif
deleted file mode 100644
index d765a258cb..0000000000
Binary files a/static/images/activities/application-test-mode-prod.gif and /dev/null differ
diff --git a/static/images/activities/application-test-mode-prod.webp b/static/images/activities/application-test-mode-prod.webp
new file mode 100644
index 0000000000..378e5718c4
Binary files /dev/null and b/static/images/activities/application-test-mode-prod.webp differ
diff --git a/static/images/activities/bobble-bash.png b/static/images/activities/bobble-bash.png
deleted file mode 100644
index 3d0b67e526..0000000000
Binary files a/static/images/activities/bobble-bash.png and /dev/null differ
diff --git a/static/images/activities/bobble-bash.webp b/static/images/activities/bobble-bash.webp
new file mode 100644
index 0000000000..2e0d013092
Binary files /dev/null and b/static/images/activities/bobble-bash.webp differ
diff --git a/static/images/activities/bobble-league.png b/static/images/activities/bobble-league.png
deleted file mode 100644
index a23a1ada86..0000000000
Binary files a/static/images/activities/bobble-league.png and /dev/null differ
diff --git a/static/images/activities/bobble-league.webp b/static/images/activities/bobble-league.webp
new file mode 100644
index 0000000000..f4b570dca0
Binary files /dev/null and b/static/images/activities/bobble-league.webp differ
diff --git a/static/images/activities/chess-victory.png b/static/images/activities/chess-victory.png
deleted file mode 100644
index 989999a8e8..0000000000
Binary files a/static/images/activities/chess-victory.png and /dev/null differ
diff --git a/static/images/activities/chess-victory.webp b/static/images/activities/chess-victory.webp
new file mode 100644
index 0000000000..57ae1ef6c3
Binary files /dev/null and b/static/images/activities/chess-victory.webp differ
diff --git a/static/images/activities/custom-link-embed.png b/static/images/activities/custom-link-embed.png
deleted file mode 100644
index 6fa852ed78..0000000000
Binary files a/static/images/activities/custom-link-embed.png and /dev/null differ
diff --git a/static/images/activities/custom-link-embed.webp b/static/images/activities/custom-link-embed.webp
new file mode 100644
index 0000000000..e14bd18041
Binary files /dev/null and b/static/images/activities/custom-link-embed.webp differ
diff --git a/static/images/activities/debug-logs-filtering.gif b/static/images/activities/debug-logs-filtering.gif
deleted file mode 100644
index 534bf60154..0000000000
Binary files a/static/images/activities/debug-logs-filtering.gif and /dev/null differ
diff --git a/static/images/activities/debug-logs-filtering.webp b/static/images/activities/debug-logs-filtering.webp
new file mode 100644
index 0000000000..e588836ca5
Binary files /dev/null and b/static/images/activities/debug-logs-filtering.webp differ
diff --git a/static/images/activities/default_orientation_lock_state.png b/static/images/activities/default_orientation_lock_state.png
deleted file mode 100644
index da92fe9d89..0000000000
Binary files a/static/images/activities/default_orientation_lock_state.png and /dev/null differ
diff --git a/static/images/activities/default_orientation_lock_state.webp b/static/images/activities/default_orientation_lock_state.webp
new file mode 100644
index 0000000000..9dc4d92160
Binary files /dev/null and b/static/images/activities/default_orientation_lock_state.webp differ
diff --git a/static/images/activities/developer-mode.gif b/static/images/activities/developer-mode.gif
deleted file mode 100644
index e60333424f..0000000000
Binary files a/static/images/activities/developer-mode.gif and /dev/null differ
diff --git a/static/images/activities/discord-activities.png b/static/images/activities/discord-activities.png
deleted file mode 100644
index 1a5a12b561..0000000000
Binary files a/static/images/activities/discord-activities.png and /dev/null differ
diff --git a/static/images/activities/eights.png b/static/images/activities/eights.png
deleted file mode 100644
index 07bfb3525d..0000000000
Binary files a/static/images/activities/eights.png and /dev/null differ
diff --git a/static/images/activities/eights.webp b/static/images/activities/eights.webp
new file mode 100644
index 0000000000..adaf0a25e1
Binary files /dev/null and b/static/images/activities/eights.webp differ
diff --git a/static/images/activities/embedded-app-flow-diagram.svg b/static/images/activities/embedded-app-flow-diagram.svg
index 90ced7b0b5..54a2699c58 100644
--- a/static/images/activities/embedded-app-flow-diagram.svg
+++ b/static/images/activities/embedded-app-flow-diagram.svg
@@ -1 +1 @@
-