From 09e69faeb1a4109329efc57394edcd74fbfd1d62 Mon Sep 17 00:00:00 2001 From: Shawn Anderson Date: Fri, 10 Oct 2025 18:25:07 -0700 Subject: [PATCH] Integrate infinite loop variants into main dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive dashboard integration for 30 infinite variant demos: Dashboard Updates (index.html): - Added "Infinite Variants" filter button with šŸ”„ emoji - Added HTML category section for infinite variants display - Added JavaScript grid initialization for variants - Updated emoji mapping to include infiniteVariants category - Fixed stats: Categories 7→8, Total Demos now includes variants (142) Auto-Generation System (generate_index.py): - Added infiniteVariants to demos object structure - Implemented scanning of infinite_variants/*/test_output/ directories - Auto-detects variant numbers and maps to friendly names: * Variant 1: Pattern Synthesis * Variant 2: Utility Commands * Variant 3: Pluggable Templates * Variant 4: Quality Evaluation * Variant 5: Config-Driven * Variant 6: State Management * Variant 7: Meta Self-Improvement - Supports both HTML and JS file detection - Generates descriptions with variant context Screenshot System (generate_screenshots.js): - Added infiniteVariants category with 1500ms delay - Pattern: infinite_variants/infinite_variant_*/test_output/*.html - Successfully captured all 30 variant demo screenshots Package Management (package.json): - Added npm run screenshots:variants command - Configured Playwright dependency for screenshot generation Result: All 30 variant demos now seamlessly integrated into dashboard with auto-discovery, screenshots, and filter functionality. šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- generate_index.py | 45 +++- generate_screenshots.js | 214 ++++++++++++++++ index.html | 522 ++++++++++++++++++++++++++++++++++++++-- package.json | 32 +++ 4 files changed, 793 insertions(+), 20 deletions(-) create mode 100755 generate_screenshots.js create mode 100644 package.json diff --git a/generate_index.py b/generate_index.py index e2eefc1..086561a 100755 --- a/generate_index.py +++ b/generate_index.py @@ -89,7 +89,8 @@ def generate_demo_data(): 'mapbox': [], 'claudeDevTools': [], 'uiSingle': [], - 'uiModular': [] + 'uiModular': [], + 'infiniteVariants': [] } # Scan Three.js demos @@ -220,6 +221,47 @@ def generate_demo_data(): 'techniques': ['Separation of Concerns', 'Modular Architecture'] }) + # Scan Infinite Variants test outputs + if os.path.exists('infinite_variants'): + variant_dirs = sorted(Path('infinite_variants').glob('infinite_variant_*/test_output')) + for variant_dir in variant_dirs: + # Extract variant number + variant_match = re.search(r'infinite_variant_(\d+)', str(variant_dir)) + variant_num = variant_match.group(1) if variant_match else '?' + + # Variant names for better titles + variant_names = { + '1': 'Pattern Synthesis', + '2': 'Utility Commands', + '3': 'Pluggable Templates', + '4': 'Quality Evaluation', + '5': 'Config-Driven', + '6': 'State Management', + '7': 'Meta Self-Improvement' + } + variant_name = variant_names.get(variant_num, f'Variant {variant_num}') + + # Scan HTML and JS files in this variant's test_output + variant_files = sorted(list(variant_dir.glob('*.html')) + list(variant_dir.glob('*.js'))) + for filepath in variant_files: + # Extract title based on file type + if filepath.suffix == '.html': + title = extract_title_from_html(str(filepath)) or filepath.name + description = extract_description_from_html(str(filepath)) + else: + # For .js files, use filename as title + title = filepath.stem.replace('_', ' ').title() + description = f"Meta-aware JavaScript code pattern" + + demos['infiniteVariants'].append({ + 'number': len(demos['infiniteVariants']) + 1, + 'title': title, + 'description': f"[Variant {variant_num}: {variant_name}] {description}", + 'path': str(filepath), + 'type': variant_name, + 'techniques': ['Infinite Loop Variant', variant_name] + }) + return demos def generate_index_html(demos): @@ -317,6 +359,7 @@ def main(): print(f" • Claude DevTools: {len(demos['claudeDevTools'])}") print(f" • UI Single File: {len(demos['uiSingle'])}") print(f" • UI Modular: {len(demos['uiModular'])}") + print(f" • Infinite Variants: {len(demos['infiniteVariants'])}") print(f" • Total: {sum(len(demos[cat]) for cat in demos)}") print("\n✨ Generating index.html...") diff --git a/generate_screenshots.js b/generate_screenshots.js new file mode 100755 index 0000000..9a3ea40 --- /dev/null +++ b/generate_screenshots.js @@ -0,0 +1,214 @@ +#!/usr/bin/env node + +/** + * Screenshot Generator for Infinite Agents Dashboard + * + * Automatically captures screenshots of all demos for preview thumbnails. + * Uses Playwright to render each demo and save a screenshot. + * + * Installation: + * npm install -D playwright + * npx playwright install chromium + * + * Usage: + * node generate_screenshots.js + * node generate_screenshots.js --category threejs + * node generate_screenshots.js --single threejs_viz/threejs_viz_1.html + */ + +const { chromium } = require('playwright'); +const fs = require('fs'); +const path = require('path'); + +// Demo categories and their file patterns +const DEMO_CATEGORIES = { + threejs: { + pattern: 'threejs_viz/threejs_viz_*.html', + delay: 3000, // Extra time for WebGL to render + }, + sdg: { + pattern: 'sdg_viz/sdg_viz_*.html', + delay: 2000, + }, + d3: { + pattern: 'd3_test/d3_viz_*.html', + delay: 1500, + }, + mapbox: { + pattern: 'mapbox_test/mapbox_globe_*/index.html', + delay: 3000, // Mapbox needs time to load tiles + }, + claudeDevTools: { + pattern: 'claude_code_devtools/claude_devtool_*.html', + delay: 1000, + }, + uiSingle: { + pattern: 'src/ui_hybrid_*.html', + delay: 800, + }, + uiInfinite: { + pattern: 'src_infinite/ui_hybrid_*.html', + delay: 800, + }, + uiModular: { + pattern: 'src_group/ui_hybrid_*/index.html', + delay: 800, + }, + infiniteVariants: { + pattern: 'infinite_variants/infinite_variant_*/test_output/*.html', + delay: 1500, // Mixed content, some may have animations + }, +}; + +// Parse command line arguments +const args = process.argv.slice(2); +const categoryFilter = args.find(arg => arg.startsWith('--category='))?.split('=')[1]; +const singleFile = args.find(arg => arg.startsWith('--single='))?.split('=')[1]; +const PORT = args.find(arg => arg.startsWith('--port='))?.split('=')[1] || 8889; + +// Create screenshots directory +const SCREENSHOTS_DIR = path.join(__dirname, 'screenshots'); +if (!fs.existsSync(SCREENSHOTS_DIR)) { + fs.mkdirSync(SCREENSHOTS_DIR, { recursive: true }); + console.log(`āœ… Created screenshots directory: ${SCREENSHOTS_DIR}`); +} + +// Scan directory for demo files +function scanDirectory(pattern) { + const glob = require('glob'); + return glob.sync(pattern); +} + +// Get all demo files +function getAllDemos() { + const demos = []; + + for (const [category, config] of Object.entries(DEMO_CATEGORIES)) { + if (categoryFilter && category !== categoryFilter) continue; + + const files = scanDirectory(config.pattern); + files.forEach(file => { + demos.push({ + path: file, + category, + delay: config.delay, + }); + }); + } + + return demos; +} + +// Capture screenshot for a single demo +async function captureScreenshot(browser, demo, index, total) { + const page = await browser.newPage(); + + try { + // Set viewport size (desktop resolution) + await page.setViewportSize({ width: 1920, height: 1080 }); + + const url = `http://localhost:${PORT}/${demo.path}`; + console.log(`\nšŸ“ø [${index + 1}/${total}] ${demo.path}`); + + // Navigate to demo + await page.goto(url, { + waitUntil: 'networkidle', + timeout: 30000, + }); + + // Wait for demo to render + await page.waitForTimeout(demo.delay); + + // Generate screenshot filename + const screenshotFilename = demo.path.replace(/\//g, '_').replace('.html', '.png'); + const screenshotPath = path.join(SCREENSHOTS_DIR, screenshotFilename); + + // Capture screenshot + await page.screenshot({ + path: screenshotPath, + fullPage: false, // Just viewport, not entire scrollable page + }); + + console.log(` āœ… Saved: ${screenshotFilename}`); + + } catch (error) { + console.error(` āŒ Failed: ${error.message}`); + } finally { + await page.close(); + } +} + +// Main execution +async function main() { + console.log('šŸš€ Infinite Agents Screenshot Generator\n'); + + // Get demo files + let demos; + if (singleFile) { + demos = [{ + path: singleFile, + category: 'custom', + delay: 2000, + }]; + } else { + demos = getAllDemos(); + } + + if (demos.length === 0) { + console.error('āŒ No demo files found!'); + console.log('\nMake sure:'); + console.log(' 1. You are in the project root directory'); + console.log(' 2. Demo files exist in their respective directories'); + console.log(' 3. Category filter is correct (if using --category)'); + process.exit(1); + } + + console.log(`šŸ“Š Found ${demos.length} demos to screenshot\n`); + + // Check if server is running + console.log(`šŸ” Checking if server is running on http://localhost:${PORT}...`); + try { + const http = require('http'); + await new Promise((resolve, reject) => { + const req = http.get(`http://localhost:${PORT}`, (res) => { + resolve(); + }); + req.on('error', reject); + req.setTimeout(3000, () => reject(new Error('Timeout'))); + }); + console.log(' āœ… Server is running\n'); + } catch (error) { + console.error(' āŒ Server is not running!'); + console.log(`\nšŸ”§ Start the server first:`); + console.log(` python3 -m http.server ${PORT}\n`); + process.exit(1); + } + + // Launch browser + console.log('🌐 Launching browser...'); + const browser = await chromium.launch({ + headless: true, + }); + console.log(' āœ… Browser ready\n'); + + // Capture screenshots + console.log('šŸ“ø Capturing screenshots...'); + console.log('━'.repeat(50)); + + for (let i = 0; i < demos.length; i++) { + await captureScreenshot(browser, demos[i], i, demos.length); + } + + // Cleanup + await browser.close(); + + console.log('\n' + '━'.repeat(50)); + console.log(`\n✨ Done! Captured ${demos.length} screenshots`); + console.log(`šŸ“ Screenshots saved to: ${SCREENSHOTS_DIR}\n`); +} + +// Run +main().catch(error => { + console.error('\nāŒ Fatal error:', error); + process.exit(1); +}); diff --git a/index.html b/index.html index 5708dfe..e97a054 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,9 @@ + + + @@ -242,6 +245,81 @@ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2); } + /* Screenshot Preview in Card */ + .demo-screenshot { + width: 100%; + height: 200px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; + cursor: pointer; + } + + .demo-screenshot img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; + } + + .demo-card:hover .demo-screenshot img { + transform: scale(1.05); + } + + .demo-screenshot-placeholder { + color: white; + font-size: 4rem; + opacity: 0.5; + text-align: center; + padding: 20px; + } + + .demo-screenshot-placeholder-text { + font-size: 0.9rem; + opacity: 0.7; + margin-top: 10px; + font-weight: 500; + } + + .demo-screenshot-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + justify-content: center; + transition: background 0.3s ease; + pointer-events: none; + } + + .demo-card:hover .demo-screenshot-overlay { + background: rgba(0, 0, 0, 0.3); + } + + .demo-screenshot-overlay span { + background: white; + color: var(--primary); + padding: 10px 20px; + border-radius: 25px; + font-weight: 600; + font-size: 0.9rem; + opacity: 0; + transform: translateY(10px); + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); + } + + .demo-card:hover .demo-screenshot-overlay span { + opacity: 1; + transform: translateY(0); + } + .demo-card::before { content: ''; position: absolute; @@ -358,6 +436,7 @@ .hidden { display: none !important; } + @@ -375,15 +454,15 @@
-
107
+
142
Total Demos
-
7
+
8
Categories
-
5
+
10
Three.js 3D
@@ -406,6 +485,7 @@ +
@@ -417,7 +497,7 @@

Three.js 3D Visualizations

Progressive WebGL/WebGPU visualizations with foundation → expert learning path

-
5 demos
+
10 demos
@@ -500,6 +580,19 @@
+ +
+
+
šŸ”„
+
+

Infinite Loop Variants

+

7 self-contained infinite loop repositories testing different architectural innovations

+
+
30 demos
+
+
+
+