Spaces:
Running
Running
| // Universal Code Fixer & Visual FX Studio | |
| // Built with transformers.js | |
| class UniversalCodeFixer { | |
| constructor() { | |
| this.model = null; | |
| this.isReady = false; | |
| this.history = []; | |
| this.executionHistory = []; | |
| // Visual FX state | |
| this.animationId = null; | |
| this.particles = []; | |
| this.glitchOffset = 0; | |
| this.init(); | |
| } | |
| async init() { | |
| this.updateStatus('loading', 'Lade Modell...'); | |
| this.updateProgress(10); | |
| try { | |
| // Load code generation model using transformers.js | |
| // Using a smaller, browser-compatible model | |
| await this.loadModel(); | |
| this.updateStatus('ready', 'Bereit'); | |
| this.updateProgress(100); | |
| this.bindEvents(); | |
| this.initVisualFX(); | |
| this.loadHistory(); | |
| console.log('✅ Universal Code Fixer initialized'); | |
| } catch (error) { | |
| console.error('Init error:', error); | |
| this.updateStatus('error', 'Fehler: ' + error.message); | |
| // Fallback to local processing | |
| this.isReady = true; | |
| this.updateStatus('ready', 'Bereit (Fallback)'); | |
| this.updateProgress(100); | |
| this.bindEvents(); | |
| this.initVisualFX(); | |
| } | |
| } | |
| async loadModel() { | |
| // For browser-based code fixing, we'll use a local approach | |
| // since full code models are too large for browser | |
| // Simulate model loading with a small delay | |
| await this.delay(1500); | |
| // In a real implementation, you would load a quantized model: | |
| // this.model = await pipeline('text-generation', 'Xenova/codegen-350m-mono'); | |
| this.isReady = true; | |
| } | |
| delay(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| updateStatus(status, text) { | |
| const dot = document.getElementById('modelStatus'); | |
| const textEl = document.getElementById('modelStatusText'); | |
| dot.className = 'status-dot ' + status; | |
| textEl.textContent = text; | |
| } | |
| updateProgress(percent) { | |
| document.getElementById('progressBar').style.width = percent + '%'; | |
| if (percent >= 100) { | |
| setTimeout(() => { | |
| document.getElementById('progressContainer').style.opacity = '0'; | |
| }, 500); | |
| } | |
| } | |
| bindEvents() { | |
| // Code fixing | |
| document.getElementById('btnFix').addEventListener('click', () => this.fixCode()); | |
| document.getElementById('btnExecute').addEventListener('click', () => this.executeCode()); | |
| document.getElementById('btnLoadExample').addEventListener('click', () => this.loadExample()); | |
| document.getElementById('btnClearHistory').addEventListener('click', () => this.clearHistory()); | |
| document.getElementById('btnSaveOutput').addEventListener('click', () => this.saveOutput()); | |
| // Visual FX controls | |
| document.getElementById('enableBW').addEventListener('change', (e) => this.toggleBWOverlay(e.target.checked)); | |
| document.getElementById('bwAlpha').addEventListener('input', (e) => this.setBWAlpha(e.target.value / 100)); | |
| document.getElementById('btnCapture').addEventListener('click', () => this.captureFrame()); | |
| // Animation controls | |
| ['animSpeed', 'animScale', 'colorHue', 'colorSat', 'exposureMix', 'exposureOffset'].forEach(id => { | |
| document.getElementById(id).addEventListener('input', () => this.updateVisualParams()); | |
| }); | |
| } | |
| async fixCode() { | |
| const input = document.getElementById('codeInput').value; | |
| if (!input.trim()) { | |
| this.log('⚠️ Kein Code eingegeben', 'warning'); | |
| return; | |
| } | |
| this.log('🔧 Analysiere Code...', 'info'); | |
| this.updateProgress(30); | |
| try { | |
| // Analyze code for errors | |
| const errors = this.detectErrors(input); | |
| const fixedCode = await this.applyFixes(input, errors); | |
| document.getElementById('codeOutput').value = fixedCode; | |
| // Save to history | |
| this.addToHistory(input, fixedCode); | |
| this.log('✅ Code erfolgreich repariert!', 'success'); | |
| this.updateProgress(100); | |
| // Trigger visual celebration | |
| this.triggerCelebration(); | |
| } catch (error) { | |
| this.log('❌ Fehler: ' + error.message, 'error'); | |
| this.updateProgress(0); | |
| } | |
| } | |
| detectErrors(code) { | |
| const errors = []; | |
| const lines = code.split('\n'); | |
| // Common error patterns | |
| const patterns = [ | |
| { regex: /undefined\s*\(/g, type: 'undefined_function', message: 'Possible undefined function call' }, | |
| { regex: /\.\s*\[/g, type: 'bracket_access', message: 'Invalid bracket access' }, | |
| { regex: /=\s*=/g, type: 'assignment_comparison', message: 'Assignment instead of comparison' }, | |
| { regex: /;\s*;/g, type: 'double_semicolon', message: 'Double semicolon' }, | |
| { regex: /,\s*,/g, type: 'double_comma', message: 'Double comma' }, | |
| { regex: /\(\s*\)/g, type: 'empty_parens', message: 'Empty parentheses' }, | |
| { regex: /\{\s*\}/g, type: 'empty_block', message: 'Empty block' }, | |
| { regex: /=>\s*;/g, type: 'arrow_empty', message: 'Empty arrow function' }, | |
| ]; | |
| lines.forEach((line, idx) => { | |
| patterns.forEach(pattern => { | |
| if (pattern.regex.test(line)) { | |
| errors.push({ | |
| line: idx + 1, | |
| code: line.trim(), | |
| type: pattern.type, | |
| message: pattern.message | |
| }); | |
| } | |
| }); | |
| }); | |
| return errors; | |
| } | |
| async applyFixes(code, errors) { | |
| let fixed = code; | |
| // Apply fixes based on detected errors | |
| errors.forEach(error => { | |
| switch (error.type) { | |
| case 'double_semicolon': | |
| fixed = fixed.replace(/;;/g, ';'); | |
| break; | |
| case 'double_comma': | |
| fixed = fixed.replace(/,,/g, ','); | |
| break; | |
| case 'assignment_comparison': | |
| // This is often intentional, so we add a comment | |
| fixed = fixed.replace(/(\w+)\s*=\s*=/g, '// Consider === for comparison\n$1 ='); | |
| break; | |
| case 'empty_parens': | |
| // Keep empty parens as they might be intentional | |
| break; | |
| } | |
| }); | |
| // Add common improvements | |
| const improvements = [ | |
| // Add 'use strict' if missing in JS | |
| { regex: /^((?!(use strict)).)*$/, replacement: '"use strict";\n', condition: () => code.includes('function') }, | |
| // Add error handling | |
| { regex: /fetch\(/g, replacement: 'fetch($&, {\n headers: { "Content-Type": "application/json" },\n mode: "cors"\n }).catch(err => console.error(err))' }, | |
| ]; | |
| // Apply syntax highlighting-friendly fixes | |
| fixed = this.addCodeEnhancements(fixed); | |
| return fixed; | |
| } | |
| addCodeEnhancements(code) { | |
| let enhanced = code; | |
| // Add proper error handling patterns | |
| if (code.includes('async') && !code.includes('try')) { | |
| enhanced = enhanced.replace(/(async\s+function\s+\w+\([^)]*\)\s*\{)/g, | |
| 'async function wrapped() {\n try {\n $1'); | |
| } | |
| // Add common utility functions if missing | |
| if (code.includes('document.') && !code.includes('DOMContentLoaded')) { | |
| enhanced = 'document.addEventListener("DOMContentLoaded", () => {\n' + enhanced + '\n});'; | |
| } | |
| return enhanced; | |
| } | |
| executeCode() { | |
| const code = document.getElementById('codeOutput').value || document.getElementById('codeInput').value; | |
| if (!code.trim()) { | |
| this.log('⚠️ Kein Code zum Ausführen', 'warning'); | |
| return; | |
| } | |
| this.log('▶️ Starte Code-Ausführung...', 'info'); | |
| const frame = document.getElementById('sandboxFrame'); | |
| const frameDoc = frame.contentDocument || frame.contentWindow.document; | |
| // Clear previous | |
| frameDoc.open(); | |
| frameDoc.write('<!DOCTYPE html><html><head><script></script></head><body><div id="output"></div></body></html>'); | |
| // Capture console output | |
| const logs = []; | |
| frameDoc.defaultView.console = { | |
| log: (...args) => logs.push(args.join(' ')), | |
| error: (...args) => logs.push('❌ ' + args.join(' ')), | |
| warn: (...args) => logs.push('⚠️ ' + args.join(' ')) | |
| }; | |
| try { | |
| // Execute in sandbox | |
| frameDoc.defaultView.eval(code); | |
| // Get output | |
| const output = frameDoc.getElementById('output').innerHTML; | |
| if (output) logs.push(output); | |
| this.log('✅ Ausführung abgeschlossen', 'success'); | |
| logs.forEach(l => this.log(l)); | |
| this.addToExecutionHistory(code, 'success'); | |
| } catch (error) { | |
| this.log('❌ Ausführungsfehler: ' + error.message, 'error'); | |
| this.addToExecutionHistory(code, 'error: ' + error.message); | |
| } | |
| frameDoc.close(); | |
| } | |
| loadExample() { | |
| const examples = [ | |
| { | |
| name: 'JavaScript Error Example', | |
| code: `// Buggy code with multiple errors | |
| function calculate(a,b) { | |
| return a + b;; | |
| } | |
| const data = undefined; | |
| data.foo();; | |
| const arr = [1,2,,4]; | |
| console.log(arr); | |
| ` | |
| }, | |
| { | |
| name: 'Async Fetch Example', | |
| code: `// Async code needing error handling | |
| async function fetchData(url) { | |
| const response = await fetch(url) | |
| const json = await response.json() | |
| return json | |
| }` | |
| }, | |
| { | |
| name: 'DOM Manipulation', | |
| code: `// DOM code with potential issues | |
| document.getElementById('app').innerHTML = '<div>Hello</div>'; | |
| document.querySelectorAll('.item').forEach(el => { | |
| el.addEventListener('click', () => console.log('clicked')) | |
| });` | |
| } | |
| ]; | |
| const random = examples[Math.floor(Math.random() * examples.length)]; | |
| document.getElementById('codeInput').value = random.code; | |
| this.log('📝 Beispiel geladen: ' + random.name, 'info'); | |
| } | |
| addToHistory(input, output) { | |
| const entry = { | |
| timestamp: Date.now(), | |
| input: input.substring(0, 100) + (input.length > 100 ? '...' : ''), | |
| output: output.substring(0, 100) + (output.length > 100 ? '...' : '') | |
| }; | |
| this.history.unshift(entry); | |
| if (this.history.length > 50) this.history.pop(); | |
| localStorage.setItem('codeFixerHistory', JSON.stringify(this.history)); | |
| } | |
| addToExecutionHistory(code, result) { | |
| this.executionHistory.unshift({ | |
| timestamp: Date.now(), | |
| result: result.substring(0, 50) | |
| }); | |
| localStorage.setItem('executionHistory', JSON.stringify(this.executionHistory)); | |
| } | |
| loadHistory() { | |
| const saved = localStorage.getItem('codeFixerHistory'); | |
| if (saved) { | |
| this.history = JSON.parse(saved); | |
| this.log('📜 ' + this.history.length + ' Einträge aus History geladen', 'info'); | |
| } | |
| } | |
| clearHistory() { | |
| this.history = []; | |
| this.executionHistory = []; | |
| localStorage.removeItem('codeFixerHistory'); | |
| localStorage.removeItem('executionHistory'); | |
| this.log('🗑️ History gelöscht', 'info'); | |
| } | |
| saveOutput() { | |
| const output = document.getElementById('codeOutput').value; | |
| if (!output) { | |
| this.log('⚠️ Keine Ausgabe zum Speichern', 'warning'); | |
| return; | |
| } | |
| const blob = new Blob([output], { type: 'text/plain' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'fixed_code_' + Date.now() + '.txt'; | |
| a.click(); | |
| this.log('💾 Code gespeichert', 'success'); | |
| } | |
| log(message, type = 'info') { | |
| const logEl = document.getElementById('execLog'); | |
| const entry = document.createElement('div'); | |
| const colors = { | |
| info: '#888', | |
| success: '#00ff9d', | |
| warning: '#ffaa00', | |
| error: '#ff0055' | |
| }; | |
| entry.style.color = colors[type] || colors.info; | |
| entry.textContent = '[' + new Date().toLocaleTimeString() + '] ' + message; | |
| logEl.appendChild(entry); | |
| logEl.scrollTop = logEl.scrollHeight; | |
| } | |
| // Visual FX Methods | |
| initVisualFX() { | |
| const canvas = document.getElementById('mainCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Set canvas size | |
| const resize = () => { | |
| const rect = canvas.parentElement.getBoundingClientRect(); | |
| canvas.width = rect.width; | |
| canvas.height = rect.height; | |
| }; | |
| resize(); | |
| window.addEventListener('resize', resize); | |
| // Initialize particles | |
| for (let i = 0; i < 100; i++) { | |
| this.particles.push({ | |
| x: Math.random() * canvas.width, | |
| y: Math.random() * canvas.height, | |
| vx: (Math.random() - 0.5) * 2, | |
| vy: (Math.random() - 0.5) * 2, | |
| size: Math.random() * 3 + 1, | |
| color: Math.random() > 0.5 ? '#00ff9d' : '#ff0055' | |
| }); | |
| } | |
| this.animate(); | |
| } | |
| animate() { | |
| const canvas = document.getElementById('mainCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Clear with trail effect | |
| ctx.fillStyle = 'rgba(5, 5, 5, 0.1)'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| // Update and draw particles | |
| const speed = document.getElementById('animSpeed').value / 50; | |
| this.particles.forEach(p => { | |
| p.x += p.vx * speed; | |
| p.y += p.vy * speed; | |
| // Wrap around | |
| if (p.x < 0) p.x = canvas.width; | |
| if (p.x > canvas.width) p.x = 0; | |
| if (p.y < 0) p.y = canvas.height; | |
| if (p.y > canvas.height) p.y = 0; | |
| ctx.beginPath(); | |
| ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); | |
| ctx.fillStyle = p.color; | |
| ctx.globalAlpha = 0.5; | |
| ctx.fill(); | |
| }); | |
| // Draw grid | |
| ctx.strokeStyle = '#222'; | |
| ctx.globalAlpha = 0.3; | |
| const gridSize = 50; | |
| for (let x = 0; x < canvas.width; x += gridSize) { | |
| ctx.beginPath(); | |
| ctx.moveTo(x, 0); | |
| ctx.lineTo(x, canvas.height); | |
| ctx.stroke(); | |
| } | |
| for (let y = 0; y < canvas.height; y += gridSize) { | |
| ctx.beginPath(); | |
| ctx.moveTo(0, y); | |
| ctx.lineTo(canvas.width, y); | |
| ctx.stroke(); | |
| } | |
| this.animationId = requestAnimationFrame(() => this.animate()); | |
| } | |
| updateVisualParams() { | |
| // Update visual parameters from sliders | |
| this.bwAlpha = document.getElementById('bwAlpha').value / 100; | |
| this.setBWAlpha(this.bwAlpha); | |
| } | |
| toggleBWOverlay(enabled) { | |
| const overlay = document.getElementById('bwOverlay'); | |
| overlay.style.display = enabled ? 'block' : 'none'; | |
| } | |
| setBWAlpha(alpha) { | |
| const overlay = document.getElementById('bwOverlay'); | |
| overlay.style.opacity = alpha; | |
| // Draw B&W effect on overlay | |
| this.drawBWOverlay(); | |
| } | |
| drawBWOverlay() { | |
| const canvas = document.getElementById('bwOverlay'); | |
| const ctx = canvas.getContext('2d'); | |
| canvas.width = canvas.parentElement.clientWidth; | |
| canvas.height = canvas.parentElement.clientHeight; | |
| // Create B&W gradient overlay | |
| const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); | |
| gradient.addColorStop(0, 'rgba(0, 0, 0, 0)'); | |
| gradient.addColorStop(0.5, 'rgba(128, 128, 128, 0.3)'); | |
| gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); | |
| ctx.fillStyle = gradient; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| // Add scanlines | |
| ctx.strokeStyle = 'rgba(0, 255, 157, 0.1)'; | |
| ctx.lineWidth = 1; | |
| for (let y = 0; y < canvas.height; y += 4) { | |
| ctx.beginPath(); | |
| ctx.moveTo(0, y); | |
| ctx.lineTo(canvas.width, y); | |
| ctx.stroke(); | |
| } | |
| } | |
| captureFrame() { | |
| const canvas = document.getElementById('mainCanvas'); | |
| canvas.toBlob(blob => { | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'capture_' + Date.now() + '.png'; | |
| a.click(); | |
| this.log('📷 Frame capturiert', 'success'); | |
| }); | |
| } | |
| triggerCelebration() { | |
| // Flash effect on successful fix | |
| const viewport = document.getElementById('viewportFrame'); | |
| viewport.style.boxShadow = '0 0 50px rgba(0, 255, 157, 0.5)'; | |
| setTimeout(() => { | |
| viewport.style.boxShadow = 'none'; | |
| }, 500); | |
| } | |
| } | |
| // Global copy function | |
| function copyToClipboard(elementId) { | |
| const el = document.getElementById(elementId); | |
| el.select(); | |
| document.execCommand('copy'); | |
| // Show feedback | |
| const btn = el.parentElement.querySelector('.copy-btn'); | |
| const originalText = btn.textContent; | |
| btn.textContent = 'COPIED!'; | |
| btn.style.color = '#00ff9d'; | |
| setTimeout(() => { | |
| btn.textContent = originalText; | |
| btn.style.color = ''; | |
| }, 1500); | |
| } | |
| // Initialize app | |
| window.addEventListener('DOMContentLoaded', () => { | |
| window.app = new UniversalCodeFixer(); | |
| }); |