# Code Playground Widget Generator Generate a self-contained HTML code editor with execution and test validation. ## Supported Languages - Python (via Pyodide CDN) - JavaScript (native browser execution) - TypeScript (via Babel CDN transpilation) ## Widget Config Schema ```json { "type": "code", "language": "python", "description": "...", "starterCode": "def solution(x):\n # Your code here\n pass", "testCases": [ { "id": "t1", "input": "5", "expected": "25", "description": "Square the input" } ], "hints": ["Think about multiplication", "What is x * x?"], "solution": "def solution(x):\n return x * x", "teacherActions": [ { "id": "act1", "type": "speech", "content": "Try implementing the solution" } ] } ``` ## Python Execution Requirements (CRITICAL) When generating Python widgets using Pyodide, follow these **mandatory patterns**: ### 1. Proper Stdout Capture Setup **ALWAYS use this exact pattern for stdout capture:** ```javascript // CORRECT - imports both sys AND io await pyodide.runPythonAsync(` import sys import io sys.stdout = io.StringIO() `); ``` **NEVER do this (causes NameError):** ```javascript // WRONG - missing import io pyodide.runPython('import sys; sys.stdout = io.StringIO()'); ``` ### 2. Use Async Execution - Always use `pyodide.runPythonAsync()` instead of `pyodide.runPython()` - Async execution is more reliable and handles module loading correctly - All Pyodide operations should be wrapped in async functions ### 3. Load Required Packages Before Execution If user code needs packages like numpy, load them during initialization: ```javascript await pyodide.loadPackage(['numpy']); ``` ### 4. Wait for Pyodide Initialization - Disable the run button until Pyodide is fully loaded - Show loading status to users - Check `pyodide !== null` before running code ### 5. Retrieve Output Correctly ```javascript const output = pyodide.runPython('sys.stdout.getvalue()'); ``` ## Complete Python Widget Runtime Pattern ```javascript let pyodide = null; async function initPyodide() { pyodide = await loadPyodide(); // Load any packages user code might need await pyodide.loadPackage(['numpy']); document.getElementById('run-btn').disabled = false; document.getElementById('status').textContent = 'Python ready'; } initPyodide(); async function runCode() { if (!pyodide) { alert('Python environment not ready'); return; } const code = editor.getValue(); try { // MUST import sys AND io before using StringIO await pyodide.runPythonAsync(` import sys import io sys.stdout = io.StringIO() `); await pyodide.runPythonAsync(code); const output = pyodide.runPython('sys.stdout.getvalue()'); document.getElementById('output').textContent = output; } catch (e) { document.getElementById('output').textContent = `Error: ${e.message}`; } } ``` ## Technical Requirements - Use CodeMirror or Monaco via CDN for editing - Syntax highlighting for the language - Run button with output display - Test case validation with pass/fail indicators - Hint button that reveals hints progressively - Mobile-responsive layout ## Layout Guidelines - Code editor should be visible and not overlap with output panel - On mobile, stack editor above output (not side-by-side) - Ensure editor has minimum height of 200px on mobile - Test cases should be collapsible on small screens ## Output Format Return ONLY the HTML document, no markdown fences or explanations. **CRITICAL: Output EXACTLY ONE HTML document.** - Do NOT duplicate content - Do NOT include multiple `` tags - The output must end with exactly one `` tag ## Quality Checklist - [ ] Code editor is visible and usable on mobile - [ ] Run button works correctly - [ ] Output panel doesn't overlap editor - [ ] Test cases show pass/fail clearly - [ ] Hints reveal progressively - [ ] **NO DUPLICATED HTML** - exactly ONE `` tag - [ ] **Python stdout uses correct import pattern** - imports BOTH `sys` AND `io` - [ ] **Pyodide uses async execution** - `runPythonAsync()` not `runPython()`