import gradio as gr import os import re from groq import Groq client = Groq(api_key=os.environ.get("GROQ_API_KEY", "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")) SYSTEM_PROMPT = """You are the world's best Three.js developer and scientific visualization engineer. You have built real-time 3D simulations for CERN, NASA, and science museums worldwide. ══════════════════════════════════════════════════ OUTPUT RULE — NON-NEGOTIABLE ══════════════════════════════════════════════════ Return ONLY a complete HTML file. • Starts with: • Ends with: • Zero words outside the HTML. • No markdown, no backticks, no explanation. ══════════════════════════════════════════════════ LENGTH RULE — NON-NEGOTIABLE ══════════════════════════════════════════════════ Minimum 800 lines of actual working code. If you write less than 800 lines you have failed. Fill every line with meaningful code — geometry, math, shaders, physics, HUD, interactions. ══════════════════════════════════════════════════ WHAT YOU MUST ALWAYS WRITE ══════════════════════════════════════════════════ ▸ SECTION 1 — HTML/CSS HEAD (80+ lines) - Load from CDN: Three.js r128, OrbitControls, Google Fonts (Orbitron + DM Sans) - Full-screen canvas: body {margin:0; overflow:hidden; background:#030318;} - HUD overlay CSS: fixed positioned panels, glassmorphism cards, animated badges - Tooltip CSS: position absolute, smooth fade transitions - Keyframe animations for glowing borders, pulsing dots, floating labels ▸ SECTION 2 — HUD HTML (60+ lines) Write this exact structure:
SCIVIS · 3D ENGINE
GOVERNING EQUATIONS
DRAG — ORBIT
SCROLL — ZOOM
SPACE — PAUSE
CLICK — INFO
▸ SECTION 3 — THREE.JS SETUP (30 lines) const scene = new THREE.Scene(); scene.background = new THREE.Color(0x030318); scene.fog = new THREE.FogExp2(0x030318, 0.008); const camera = new THREE.PerspectiveCamera(60, innerWidth/innerHeight, 0.01, 1000); camera.position.set(0, 8, 22); const renderer = new THREE.WebGLRenderer({antialias:true, alpha:false}); renderer.setSize(innerWidth, innerHeight); renderer.setPixelRatio(Math.min(devicePixelRatio, 2)); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; document.body.appendChild(renderer.domElement); const controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.04; controls.autoRotate = true; controls.autoRotateSpeed = 0.4; controls.minDistance = 3; controls.maxDistance = 60; ▸ SECTION 4 — STARFIELD (always include) (function buildStars(){ const geo = new THREE.BufferGeometry(); const n = 6000; const pos = new Float32Array(n*3), col = new Float32Array(n*3); for(let i=0;i { bodies.forEach((b,j) => { if(i===j) return; const d = new THREE.Vector3().subVectors(b.pos,a.pos); const r2 = d.lengthSq() + 0.5; d.normalize().multiplyScalar(G*a.mass*b.mass/r2/a.mass); a.vel.add(d.multiplyScalar(dt)); }); a.pos.addScaledVector(a.vel,dt); }); FOR WAVE/QUANTUM topics — Finite difference wave solver: for(let i=1;i{ p.force.set(0,0,0); particles.forEach(q=>{ if(p===q) return; const d=new THREE.Vector3().subVectors(q.pos,p.pos); const r=Math.max(d.length(),0.1); p.force.addScaledVector(d.normalize(), -ljForce(r,1.0,1.0)); }); p.vel.addScaledVector(p.force.divideScalar(p.mass), dt); p.pos.addScaledVector(p.vel, dt); }); } FOR ELECTROMAGNETIC topics — Biot-Savart field lines: function bField(point, loop){ const B=new THREE.Vector3(); const mu0=4*Math.PI*1e-7; loop.forEach((seg,i)=>{ const next=loop[(i+1)%loop.length]; const dl=new THREE.Vector3().subVectors(next,seg); const r=new THREE.Vector3().subVectors(point,seg); const cross=new THREE.Vector3().crossVectors(dl,r); B.addScaledVector(cross, mu0/(4*Math.PI*Math.pow(r.length(),3))); }); return B; } FOR THERMODYNAMICS topics — Maxwell-Boltzmann + elastic collisions: function collide(a,b){ const d=new THREE.Vector3().subVectors(b.pos,a.pos); const dist=d.length(); if(dist>a.r+b.r) return; const n=d.normalize(); const dv=new THREE.Vector3().subVectors(a.vel,b.vel); const impulse=2*dv.dot(n)/(1/a.mass+1/b.mass); a.vel.addScaledVector(n,-impulse/a.mass); b.vel.addScaledVector(n,impulse/b.mass); } ▸ SECTION 7 — LIGHTING (20 lines) Animated lights that orbit the scene: const lights = [ new THREE.PointLight(0x00e5ff, 4, 60), new THREE.PointLight(0x7c3aed, 3, 50), new THREE.PointLight(0xff6b35, 2, 40), ]; lights.forEach(l=>{l.castShadow=true; scene.add(l);}); scene.add(new THREE.AmbientLight(0x112233, 0.6)); function animateLights(t){ lights[0].position.set(Math.cos(t*0.4)*15, 8, Math.sin(t*0.4)*15); lights[1].position.set(Math.cos(t*0.3+2)*12,-6, Math.sin(t*0.3+2)*12); lights[2].position.set(Math.cos(t*0.5+4)*10, 4, Math.sin(t*0.5+4)*10); } ▸ SECTION 8 — RAYCASTER + CLICK INTERACTIONS (50 lines) Create minimum 4 clickable objects. Each has userData.info = {title, body}. On click: show tooltip at mouse position, smooth camera lerp to object. On hover: scale object to 1.15, change cursor. const raycaster=new THREE.Raycaster(); const mouse=new THREE.Vector2(); const tooltip=document.getElementById('tooltip'); const interactable=[]; renderer.domElement.addEventListener('pointermove',e=>{ mouse.set((e.clientX/innerWidth)*2-1,-(e.clientY/innerHeight)*2+1); raycaster.setFromCamera(mouse,camera); const hits=raycaster.intersectObjects(interactable,true); document.body.style.cursor=hits.length?'pointer':'default'; }); renderer.domElement.addEventListener('click',e=>{ raycaster.setFromCamera(mouse,camera); const hits=raycaster.intersectObjects(interactable,true); if(hits.length){ const obj=hits[0].object; const info=obj.userData.info||obj.parent?.userData.info; if(info){ document.getElementById('ttTitle').textContent=info.title; document.getElementById('ttBody').textContent=info.body; tooltip.style.display='block'; tooltip.style.left=(e.clientX+16)+'px'; tooltip.style.top=(e.clientY-8)+'px'; targetCamPos.copy(obj.position).addScalar(4); } } else { tooltip.style.display='none'; } }); ▸ SECTION 9 — HUD POPULATION (30 lines) Populate title, equations, stats, and fact cards with real data for the topic. document.getElementById('mainTitle').textContent = '[TOPIC NAME]'; document.getElementById('equations').innerHTML = '[EQUATION 1]
[EQUATION 2]
[EQUATION 3]'; const facts=[{label:'[LABEL]',val:'[VALUE]',sub:'[UNIT/CONTEXT]'},...]; const bf=document.getElementById('bottomFacts'); facts.forEach(f=>{ bf.innerHTML+=`
${f.label}
${f.val}
${f.sub}
`; }); ▸ SECTION 10 — ANIMATION LOOP (40 lines) const clock=new THREE.Clock(); let paused=false, simSpeed=1.0; const targetCamPos=camera.position.clone(); window.addEventListener('keydown',e=>{ if(e.code==='Space'){paused=!paused;e.preventDefault();} if(e.key==='r'){simSpeed=1;targetCamPos.set(0,8,22);} if(e.key==='+'||e.key==='=') simSpeed=Math.min(simSpeed*1.5,8); if(e.key==='-') simSpeed=Math.max(simSpeed/1.5,0.1); }); (function animate(){ requestAnimationFrame(animate); const dt=Math.min(clock.getDelta(),0.05)*simSpeed; const t=clock.getElapsedTime(); if(!paused){ particleMat.uniforms.uTime.value=t; updatePhysics(dt,t); animateLights(t); updateGeometry(t); camera.position.lerp(targetCamPos,0.02); } controls.update(); renderer.render(scene,camera); document.getElementById('liveStats').innerHTML= 'FPS: '+Math.round(1/Math.max(clock.getDelta(),0.001))+'
SPEED: '+simSpeed.toFixed(1)+'x
'+new Date().toLocaleTimeString(); })(); window.addEventListener('resize',()=>{ camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth,innerHeight); }); ══════════════════════════════════════════════════ TOPIC-SPECIFIC SCIENCE RULES ══════════════════════════════════════════════════ • Use the REAL constants: G=6.674e-11, c=3e8, h=6.626e-34, e=1.6e-19, me=9.109e-31 • Correct colors: H=white, He=yellow, C=dark gray, N=blue, O=red, Fe=orange, Au=gold • Real orbital mechanics: v=sqrt(GM/r) for circular orbit • Wave equation: λf=c, E=hf for photons • Atomic: Bohr radius a0=5.29e-11m, energy En=-13.6/n² eV • DNA: 3.4Å rise per base pair, 10.5 bp per turn, 2nm diameter • Show actual numerical values in the HUD (not placeholders) ══════════════════════════════════════════════════ VISUAL QUALITY RULES ══════════════════════════════════════════════════ • Use THREE.ACESFilmicToneMapping for cinematic look • Use AdditiveBlending on all glowing/energy objects • MeshStandardMaterial with metalness/roughness for physical objects • MeshPhysicalMaterial for glass/crystal effects: transmission:0.9, ior:1.5 • Always add slight scene fog for depth • Particle sizes: 0.05-0.3 range, size attenuation enabled • Smooth all transitions with lerp: val += (target-val)*0.05 ══════════════════════════════════════════════════ NOW WRITE THE COMPLETE HTML FILE 800+ lines. Real physics. Custom shaders. Beautiful HUD. Museum-quality 3D science visualization. ══════════════════════════════════════════════════""" def generate_visualization(topic, complexity, style, interactivity, detail, progress=gr.Progress()): if not topic.strip(): return "

Please enter a science topic.

", "" token_map = {"standard": 8000, "advanced": 12000, "maximum": 16000} max_tokens = token_map.get(complexity, 12000) progress(0.1, desc="Connecting to Groq...") progress(0.25, desc="Analyzing science topic...") style_detail = { "neon": "Background #030318. Cyan #00e5ff, purple #7c3aed, pink #ff00aa, green #00ff9d. Additive blending for glow. Holographic feel.", "realistic": "Physically accurate colors. MeshStandardMaterial with metalness/roughness. Directional sun light with shadows. Subtle blue atmospheric fog.", "minimal": "Clean #080808 background. Single white+cyan palette. Maximum clarity. Thin wireframe accents. No clutter.", "educational": "Bright palette per element. Large readable HTML labels on every component. Step annotations. Looks like an interactive textbook.", } interact_detail = { "full": "OrbitControls full orbit+pan+zoom. Click any object for info tooltip. Hover scales objects. Keyboard: Space=pause, R=reset, +/-=speed.", "basic": "OrbitControls orbit only. Auto-rotate when idle. No click interactions.", "guided": "Automated camera tour: lerp between 4 key viewpoints every 8 seconds. Labels appear sequentially to narrate the scene.", } depth_detail = { "overview": "2-3 principal elements. Single particle system. Clean focused scene.", "detailed": "All major components of the topic. Multiple particle systems. 4+ interactive click targets. Full HUD with 3 fact cards.", "deep_dive": "Every sub-component. 5+ interactive elements. 4 equations on HUD panel. Numerical simulation values shown live. Step-by-step animation mode accessible via Space bar.", } user_msg = f"""TOPIC: {topic} STYLE: {style_detail.get(style, style_detail['neon'])} INTERACTIVITY: {interact_detail.get(interactivity, interact_detail['full'])} DEPTH: {depth_detail.get(detail, depth_detail['detailed'])} COMPLEXITY: {complexity} — {"Basic geometry, standard materials." if complexity=="standard" else "Custom GLSL shaders required, InstancedMesh where useful." if complexity=="advanced" else "Full custom GLSL shaders, 50k+ particles, physics simulation, post-processing glow."} MANDATORY FOR THIS SPECIFIC TOPIC: 1. Research the actual physics/biology/chemistry of "{topic}" and implement the governing equations 2. The particle system must represent real entities in {topic} (electrons, photons, molecules, etc.) 3. HUD equations panel must show the 3 real formulas that govern {topic} 4. Bottom fact cards must show 3 real numerical facts with actual values for {topic} 5. Each clickable object must have scientifically accurate info in its tooltip 6. Camera starts far and slowly flies in over 4 seconds on page load Write the complete self-contained HTML file. Minimum 800 lines. Start . Output nothing else.""" progress(0.4, desc="AI writing advanced Three.js + physics code...") response = client.chat.completions.create( model="llama-3.3-70b-versatile", max_tokens=max_tokens, temperature=0.15, top_p=0.9, frequency_penalty=0.1, messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_msg} ] ) progress(0.85, desc="Extracting and rendering...") raw = response.choices[0].message.content or "" html = None for pattern in [r'', r'', r'```html\s*([\s\S]*?)\s*```', r'```\s*([\s\S]*?)\s*```']: m = re.search(pattern, raw, re.IGNORECASE) if m: g = m.group(0) html = g if ('⚠ Extraction failed. Try again.

", "" progress(1.0, desc="Done!") lines = html.count('\n') escaped = html.replace('&', '&').replace('"', '"').replace("'", ''') preview_html = f"""
✓ {lines} lines generated
⚛ {topic}
🎨 {style} · {detail} · {complexity}
Copy source below → save as .html → open for fullscreen
""" return preview_html, html CSS = """ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=DM+Sans:wght@300;400;500&display=swap'); body, .gradio-container { background: #04080f !important; font-family: 'DM Sans', sans-serif !important; } .gradio-container { max-width: 1280px !important; margin: 0 auto !important; } .gr-button-primary { background: linear-gradient(135deg,#00e5ff,#7c3aed) !important; border: none !important; font-family: 'Orbitron',monospace !important; letter-spacing: 2px !important; font-weight: 700 !important; border-radius: 10px !important; } .gr-button-secondary { background: rgba(255,255,255,0.03) !important; border: 1px solid rgba(255,255,255,0.08) !important; color: #5a6a7a !important; font-size: 11px !important; border-radius: 20px !important; transition: all 0.15s !important; } .gr-button-secondary:hover { border-color: #00e5ff !important; color: #00e5ff !important; } label { color: #3a4a5a !important; font-size: 9px !important; letter-spacing: 3px !important; font-family: 'Orbitron',monospace !important; } input, textarea, select { background: rgba(255,255,255,0.04) !important; border: 1px solid rgba(255,255,255,0.1) !important; color: #fff !important; border-radius: 8px !important; } .gr-box, .gr-form { background: rgba(255,255,255,0.02) !important; border: 1px solid rgba(255,255,255,0.06) !important; border-radius: 16px !important; } """ TOPICS = [ "Solar System Orbital Mechanics", "DNA Double Helix Replication", "Black Hole Accretion Disk", "Quantum Wave Function Collapse", "Neuron Synaptic Transmission", "Protein Folding Dynamics", "Electromagnetic Wave Propagation", "Hydrogen Electron Orbitals", "Big Bang Universe Expansion", "Mitosis Cell Division", "Gravitational Wave Detection", "Crystal Lattice Formation", ] with gr.Blocks(title="SCIVIS — AI 3D Science Visualizer") as demo: gr.HTML("""
GLSL SHADERS · REAL PHYSICS · 30K+ PARTICLES · GROQ

SCIVIS

AI generates advanced Three.js 3D science visualizations with custom GLSL shaders, real physics equations, and 800+ lines of code.

""") with gr.Row(): with gr.Column(scale=2): topic_input = gr.Textbox(label="SCIENCE TOPIC", placeholder="e.g. DNA Replication, Black Hole Formation, Quantum Entanglement...", lines=1) with gr.Row(): complexity = gr.Dropdown(["standard","advanced","maximum"], value="maximum", label="COMPLEXITY") style = gr.Dropdown(["neon","realistic","minimal","educational"], value="neon", label="STYLE") with gr.Row(): interactivity = gr.Dropdown(["basic","full","guided"], value="full", label="INTERACTIVITY") detail = gr.Dropdown(["overview","detailed","deep_dive"], value="deep_dive", label="DETAIL") gen_btn = gr.Button("⚡ GENERATE 3D VISUALIZATION", variant="primary", size="lg") gr.HTML("""
EVERY OUTPUT INCLUDES
▸ Custom GLSL vertex + fragment shaders with Simplex noise
▸ 25,000–50,000 animated particles via shader uniforms
▸ Real physics equations (Verlet, wave PDE, LJ, Biot-Savart)
▸ Animated orbiting lights with dynamic intensity
▸ Scientific HUD: title, equations, live stats, 3 fact cards
▸ Raycaster tooltips on 4+ clickable objects
▸ Space=pause, R=reset, +/-=speed controls
▸ 800–1100 lines of production code
""") gr.HTML('
QUICK TOPICS
') topic_btns = [] for i in range(0, len(TOPICS), 4): with gr.Row(): for t in TOPICS[i:i+4]: b = gr.Button(t, size="sm", variant="secondary") topic_btns.append((b, t)) with gr.Column(scale=3): preview_out = gr.HTML(value="""
⚛️
VISUALIZATION WILL APPEAR HERE
Select a topic and hit Generate
""", label="LIVE PREVIEW") with gr.Accordion("📄 Generated HTML Source Code — Save as .html to open fullscreen", open=False): code_out = gr.Code(language="html", label="THREE.JS SOURCE", lines=22) gen_btn.click(generate_visualization, inputs=[topic_input, complexity, style, interactivity, detail], outputs=[preview_out, code_out]) for btn, t in topic_btns: btn.click(lambda x=t: x, outputs=topic_input) demo.launch(css=CSS)