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
{
"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:
// CORRECT - imports both sys AND io
await pyodide.runPythonAsync(`
import sys
import io
sys.stdout = io.StringIO()
`);
NEVER do this (causes NameError):
// WRONG - missing import io
pyodide.runPython('import sys; sys.stdout = io.StringIO()');
2. Use Async Execution
- Always use
pyodide.runPythonAsync()instead ofpyodide.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:
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 !== nullbefore running code
5. Retrieve Output Correctly
const output = pyodide.runPython('sys.stdout.getvalue()');
Complete Python Widget Runtime Pattern
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
<!DOCTYPE html>tags - The output must end with exactly one
</html>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
<!DOCTYPE html>tag - Python stdout uses correct import pattern - imports BOTH
sysANDio - Pyodide uses async execution -
runPythonAsync()notrunPython()