← Home

SovrenAI Build

v0 Ready
Conversation Clear
Calculator Login Form Todo List Colors Timer Kanban Weather
Libs: React Vue D3 Chart.js Three.js Tailwind Run: Python Rust
ToBi
What would you like to build? Describe it and I'll create it step by step. Every version gets a barcode. The program runs live in the canvas.
Code · 0 versions Collapse
Versions will appear here as you build.
Each version gets a barcode, binary identity, and alignment check.
The code is editable — change it and the canvas updates.
Live Canvas Refresh
"; document.getElementById('canvasActions').style.display = 'none'; return; } document.getElementById('canvasActions').style.display = 'inline-flex'; const latest = _functions[_functions.length - 1]; try { // Inject error catcher into the code const errorCatcher = 'window.onerror=function(m,s,l){parent.postMessage({type:"canvas-error",message:m,line:l},"*");}<\/scr' + 'ipt>'; const code = latest.code.replace('', errorCatcher + ''); frame.srcdoc = code; } catch (e) { errorEl.textContent = e.message; errorEl.classList.add('visible'); } } // Catch errors from iframe window.addEventListener('message', e => { if (e.data && e.data.type === 'canvas-error') { const errorEl = document.getElementById('canvasError'); errorEl.textContent = `Line ${e.data.line}: ${e.data.message}`; errorEl.classList.add('visible'); } }); function refreshCanvas() { renderCanvas(); } // ── Export ────────────────────────────────────────────────── function exportLatest() { if (_functions.length === 0) return; const latest = _functions[_functions.length - 1]; const blob = new Blob([latest.code], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `build-v${latest.version}-${latest.barcode}.html`; a.click(); URL.revokeObjectURL(url); } function copyLatest() { if (_functions.length === 0) return; navigator.clipboard.writeText(_functions[_functions.length - 1].code) .then(() => addChatMsg('tobi', 'Code copied to clipboard.')) .catch(() => addChatMsg('tobi', 'Could not copy — try Export HTML instead.')); } // ── Canvas actions ───────────────────────────────────────── function copyCanvasCode() { if (_functions.length === 0) return; const code = _functions[_functions.length - 1].code; navigator.clipboard.writeText(code).then(() => { addChatMsg('tobi', 'Canvas code copied to clipboard.'); }).catch(() => { addChatMsg('tobi', 'Could not copy — try Download instead.'); }); } function downloadCanvas() { if (_functions.length === 0) return; const latest = _functions[_functions.length - 1]; const blob = new Blob([latest.code], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `build-v${latest.version}-${latest.barcode}.html`; a.click(); URL.revokeObjectURL(url); } function openCanvasNewTab() { if (_functions.length === 0) return; const code = _functions[_functions.length - 1].code; const blob = new Blob([code], { type: 'text/html' }); const url = URL.createObjectURL(blob); window.open(url, '_blank'); } // ── Session ──────────────────────────────────────────────── function clearSession() { if (_functions.length > 0 && !confirm('Clear all versions and start over?')) return; _functions = []; _history = []; document.getElementById('chatMessages').innerHTML = `
ToBi
Session cleared. What would you like to build?
`; document.getElementById('codeCards').innerHTML = `
Versions will appear here as you build.
Each version gets a barcode, binary identity, and alignment check.
The code is editable — change it and the canvas updates.
`; document.getElementById('exportBar').style.display = 'none'; document.getElementById('versionCount').textContent = 'v0'; document.getElementById('buildStatus').textContent = 'Ready'; renderCanvas(); } // ── Phase 2: Library chip helper ───────────────────────── function prependLib(prefix) { const input = document.getElementById('chatInput'); input.value = prefix + input.value; input.focus(); } // ── Phase 3: Piston execution ─────────────────────────── // Judge0 CE — same as code.html (Piston public API closed 2/15/2026) const JUDGE0_URL = 'https://ce.judge0.com'; const JUDGE0_LANGS = {python:100,javascript:63,typescript:101,rust:108,go:107,java:91,c:75,cpp:76,ruby:72}; async function executePiston(language, code) { const langId = JUDGE0_LANGS[language]; if (!langId) return {stdout:'', stderr:'Unsupported language: '+language, exitCode:1, language}; try { // Java requires class Main if (language === 'java' && !code.includes('class Main')) { code = 'public class Main {\n' + code + '\n}'; } const resp = await fetch(JUDGE0_URL + '/submissions?base64_encoded=false&wait=true', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({language_id: langId, source_code: code}), }); const data = await resp.json(); return { stdout: data.stdout || '', stderr: data.stderr || data.compile_output || '', exitCode: data.status?.id === 3 ? 0 : 1, language: language, }; } catch (e) { return {stdout: '', stderr: 'Judge0 error: ' + e.message, exitCode: 1, language}; } } function showExecOutput(result) { const panel = document.getElementById('execOutput'); const pre = document.getElementById('execResult'); let html = ''; if (result.stdout) html += '' + escapeHtml(result.stdout) + ''; if (result.stderr) html += '' + escapeHtml(result.stderr) + ''; if (!html) html = '(no output)'; pre.innerHTML = html; panel.style.display = 'block'; } // ── Phase 4: Language detection — route non-HTML to Piston ── const PISTON_LANGUAGES = new Set(['python','javascript','typescript','rust','go','java','c','cpp','ruby']); function detectCodeLanguage(answer) { const match = answer.match(/```(\w+)?\n([\s\S]*?)```/); if (!match) return null; const lang = (match[1] || 'html').toLowerCase(); const code = match[2]; return { language: lang, code: code, isPiston: PISTON_LANGUAGES.has(lang) }; } // ── Phase 6: IndexedDB persistence ────────────────────── const DB_NAME = 'gce-build'; const DB_VERSION = 1; let _db = null; async function openBuildDB() { if (_db) return _db; return new Promise((resolve, reject) => { const req = indexedDB.open(DB_NAME, DB_VERSION); req.onupgradeneeded = () => { const db = req.result; if (!db.objectStoreNames.contains('sessions')) { db.createObjectStore('sessions', {keyPath: 'id'}); } }; req.onsuccess = () => { _db = req.result; resolve(_db); }; req.onerror = () => reject(req.error); }); } async function saveSession() { try { const db = await openBuildDB(); const tx = db.transaction('sessions', 'readwrite'); tx.objectStore('sessions').put({ id: _sessionId, functions: _functions, history: _history, timestamp: new Date().toISOString(), }); } catch (e) { console.debug('IndexedDB save fail-open:', e); } } async function loadSession(sessionId) { try { const db = await openBuildDB(); const tx = db.transaction('sessions', 'readonly'); const req = tx.objectStore('sessions').get(sessionId); return new Promise(resolve => { req.onsuccess = () => resolve(req.result || null); req.onerror = () => resolve(null); }); } catch { return null; } } async function listSessions() { try { const db = await openBuildDB(); const tx = db.transaction('sessions', 'readonly'); const req = tx.objectStore('sessions').getAll(); return new Promise(resolve => { req.onsuccess = () => resolve(req.result || []); req.onerror = () => resolve([]); }); } catch { return []; } } // ── Phase 7: Session picker ───────────────────────────── async function populateSessionPicker() { const sessions = await listSessions(); const picker = document.getElementById('sessionPicker'); if (!picker) return; picker.innerHTML = ''; for (const s of sessions.sort((a,b) => b.timestamp?.localeCompare(a.timestamp || ''))) { if (s.id === _sessionId) continue; const label = (s.functions?.[0]?.title || s.id).slice(0, 25); const opt = document.createElement('option'); opt.value = s.id; opt.textContent = label + ' (' + (s.functions?.length || 0) + ' versions)'; picker.appendChild(opt); } } async function switchSession(sessionId) { if (!sessionId) return; await saveSession(); // save current first const saved = await loadSession(sessionId); if (saved) { _functions = saved.functions || []; _history = saved.history || []; _sessionId = saved.id; renderCards(); renderCanvas(); document.getElementById('versionCount').textContent = 'v' + _functions.length; addChatMsg('tobi', 'Switched to session: ' + saved.id.slice(0, 15)); } } async function newSession() { await saveSession(); clearSession(); } // ── Auto-save after every build + load on start ───────── const _origRenderCards = renderCards; renderCards = function() { _origRenderCards(); saveSession(); // auto-save after every card render }; // Load last session on page start (async function() { const saved = await loadSession(_sessionId); if (saved && saved.functions?.length > 0) { _functions = saved.functions; _history = saved.history || []; renderCards(); renderCanvas(); document.getElementById('versionCount').textContent = 'v' + _functions.length; document.getElementById('exportBar').style.display = 'flex'; // BARCODE 16: Restore visible chat messages from persisted history for (const msg of _history) { addChatMsg(msg.role === 'user' ? 'user' : 'tobi', msg.content); } } populateSessionPicker(); })(); // Enter to send document.getElementById('chatInput').addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMsg(); } });