#!/usr/bin/env python3 """ Generate index.html dashboard by scanning demo directories. Automatically discovers all HTML demos and updates the dashboard. Usage: python3 generate_index.py Or make executable and run: chmod +x generate_index.py ./generate_index.py """ import os import json import re from pathlib import Path from datetime import datetime def scan_directory(path, pattern="*.html"): """Scan directory for HTML files matching pattern.""" if not os.path.exists(path): return [] files = sorted(Path(path).glob(pattern)) return [str(f.relative_to('.')) for f in files] def extract_title_from_html(filepath): """Extract title from HTML file.""" try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read(2000) # Read first 2KB # Try to find title in various formats title_match = re.search(r'
]*>(.*?)
', content, re.IGNORECASE | re.DOTALL) if p_match: text = p_match.group(1).strip() # Remove HTML tags text = re.sub(r'<[^>]+>', '', text) return text[:150] except Exception as e: print(f"Warning: Could not read {filepath}: {e}") return "Interactive demo" def generate_demo_data(): """Generate demo data by scanning directories.""" demos = { 'threejs': [], 'sdg': [], 'd3': [], 'mapbox': [], 'claudeDevTools': [], 'uiSingle': [], 'uiModular': [], 'infiniteVariants': [] } # Scan Three.js demos threejs_files = scan_directory('threejs_viz', 'threejs_viz_*.html') for i, filepath in enumerate(threejs_files, 1): title = extract_title_from_html(filepath) or f"Three.js Viz {i}" description = extract_description_from_html(filepath) demos['threejs'].append({ 'number': i, 'title': title.replace('Three.js - ', ''), 'description': description, 'path': filepath, 'type': 'Foundation' if i <= 5 else 'Intermediate' if i <= 12 else 'Advanced', 'techniques': [] }) # Scan SDG demos sdg_files = scan_directory('sdg_viz', 'sdg_viz_*.html') for i, filepath in enumerate(sdg_files, 1): title = extract_title_from_html(filepath) or f"SDG Network Viz {i}" description = extract_description_from_html(filepath) demos['sdg'].append({ 'number': i, 'title': title, 'description': description, 'path': filepath, 'type': 'Network', 'techniques': ['D3.js', 'Force Simulation'] }) # Scan D3 demos d3_files = scan_directory('d3_test', 'd3_viz_*.html') for i, filepath in enumerate(d3_files, 1): title = extract_title_from_html(filepath) or f"D3 Viz {i}" description = extract_description_from_html(filepath) # Remove "D3 Visualization N: " prefix if present if title.startswith('D3 Visualization'): parts = title.split(':', 1) if len(parts) > 1: title = parts[1].strip() demos['d3'].append({ 'number': i, 'title': title, 'description': description, 'path': filepath, 'type': 'D3 Visualization', 'techniques': ['D3.js', 'Data Visualization', 'SVG'] }) # Scan Mapbox Globe demos mapbox_dirs = sorted(Path('mapbox_test').glob('mapbox_globe_*/index.html')) if os.path.exists('mapbox_test') else [] for i, filepath in enumerate(mapbox_dirs, 1): title = extract_title_from_html(str(filepath)) or f"Mapbox Globe {i}" description = extract_description_from_html(str(filepath)) # Remove "Globe Viz N: " prefix if present if title.startswith('Globe Viz'): parts = title.split(':', 1) if len(parts) > 1: title = parts[1].strip() demos['mapbox'].append({ 'number': i, 'title': title, 'description': description, 'path': str(filepath), 'type': 'Globe Visualization', 'techniques': ['Mapbox GL JS', '3D Globe', 'GeoJSON'] }) # Scan Claude Code DevTools demos devtools_files = scan_directory('claude_code_devtools', 'claude_devtool_*.html') for i, filepath in enumerate(devtools_files, 1): title = extract_title_from_html(filepath) or f"DevTool {i}" description = extract_description_from_html(filepath) # Remove " - Claude Code DevTools" suffix if present if ' - Claude Code DevTools' in title: title = title.replace(' - Claude Code DevTools', '') demos['claudeDevTools'].append({ 'number': i, 'title': title, 'description': description, 'path': filepath, 'type': 'DevTool', 'techniques': ['Developer Tools', 'Web APIs'] }) # Scan UI Single File demos src_files = scan_directory('src', 'ui_hybrid_*.html') for i, filepath in enumerate(src_files, 1): demos['uiSingle'].append({ 'number': i, 'title': f"UI Hybrid {i}", 'description': 'Themed hybrid UI component combining multiple interface elements', 'path': filepath, 'type': 'Single File', 'techniques': ['Themed Design', 'Hybrid Components'] }) # Scan UI Infinite demos src_infinite_files = scan_directory('src_infinite', 'ui_hybrid_*.html') offset = len(demos['uiSingle']) for i, filepath in enumerate(src_infinite_files, 1): demos['uiSingle'].append({ 'number': offset + i, 'title': f"UI Hybrid {i} (Infinite)", 'description': 'Infinite mode generated themed component', 'path': filepath, 'type': 'Single File (Infinite)', 'techniques': ['Infinite Generation', 'Progressive Complexity'] }) # Scan UI Modular demos modular_dirs = sorted(Path('src_group').glob('ui_hybrid_*/index.html')) if os.path.exists('src_group') else [] for i, filepath in enumerate(modular_dirs, 1): demos['uiModular'].append({ 'number': i, 'title': f"UI Hybrid {i} (Modular)", 'description': 'Professional 3-file architecture with separated HTML, CSS, and JavaScript', 'path': str(filepath), 'type': 'Modular', '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): """Generate the complete index.html file.""" total_demos = sum(len(demos[cat]) for cat in demos) threejs_count = len(demos['threejs']) sdg_count = len(demos['sdg']) d3_count = len(demos['d3']) mapbox_count = len(demos['mapbox']) devtools_count = len(demos['claudeDevTools']) ui_count = len(demos['uiSingle']) + len(demos['uiModular']) # Read template (current index.html structure) template_path = 'index.html' if os.path.exists(template_path): with open(template_path, 'r', encoding='utf-8') as f: template = f.read() else: print("Error: index.html template not found") return None # Replace the demos data in the JavaScript section demos_json = json.dumps(demos, indent=8) # Find and replace the demos object in the script pattern = r'const demos = \{[\s\S]*?\};' replacement = f'const demos = {demos_json};' updated_html = re.sub(pattern, replacement, template) # Update stats in HTML updated_html = re.sub( r'