Educational Game Widget Generator
Generate a self-contained HTML game that is FUN, ENGAGING, and EDUCATIONAL.
Core Principle: GAMES, NOT QUIZZES
CRITICAL: Avoid boring multiple-choice quizzes! Students already have enough tests. Create games that are:
- Interactive: Players DO something, not just click answers
- Skill-based: Success depends on player action, not just knowing the answer
- Engaging: Fun mechanics that make students want to play more
- Meaningful simulation: If there's a visual simulation, it MUST be part of the gameplay
Game Types (PREFER THESE OVER QUIZ)
1. Physics/Action Games (HIGHLY RECOMMENDED)
- Timing games: Click at the right moment to hit a target
- Aim and launch: Adjust angle/power to hit targets
- Balance games: Keep an object balanced or in motion
- Catch/avoid games: Move to catch falling objects or avoid obstacles
- Example: Instead of asking "What force is needed?", let players ADJUST thrust and SEE if they land safely
2. Drag-and-Drop Puzzles
- Sort items into correct categories
- Arrange steps in correct order
- Match pairs by dragging
- Build structures by placing pieces
3. Interactive Simulations as Games
- Let players ADJUST parameters and see results
- Challenge: "Land the spacecraft safely" - player controls thrust
- Challenge: "Reach the target" - player adjusts angle and power
- Challenge: "Balance the forces" - player adds/removes weights
4. Card/Matching Games
- Memory match with concept pairs
- Flashcard flip to reveal answers
- Sorting cards into categories
5. Strategy/Decision Games
- Turn-based decisions with consequences
- Resource management challenges
- Multi-step problem solving
When Quiz is Unavoidable
If you MUST include quiz elements:
- Make it INTERACTIVE (drag answer to target, not click radio button)
- Add PHYSICS/ACTION component (answer unlocks next gameplay)
- Use VISUAL questions (identify the diagram, not text questions)
- Keep questions SHORT and FEW (max 3-5)
- Include EXPLANATION as gameplay reward, not punishment
Simulation-Game Integration (CRITICAL)
If your game has a visual simulation, it MUST be:
- Interactive: Player controls something in the simulation
- Meaningful: Player's actions affect the outcome
- Aligned with learning: The physics/concept being taught is what the player manipulates
BAD Example:
Question: "What thrust is needed for 1000kg at 9.8m/s²?"
Options: [4900N, 9800N, 19600N, 0N]
Player clicks answer → Animation plays (success or failure)
Problem: Simulation is just decoration. Player doesn't interact with it.
GOOD Example:
Game: "Land the spacecraft safely"
Player controls: Thrust slider (0-15000N)
Real-time physics: Spacecraft falls at rate determined by (thrust - mass*g)
Challenge: Adjust thrust to land at velocity < 5m/s
Feedback: Visual speedometer shows current velocity
Learning: Player EXPERIENCES F=ma by adjusting thrust and seeing result
Widget Config Schema
{
"type": "game",
"gameType": "action",
"description": "...",
"gameConfig": {
"controls": ["thrust_slider", "angle_adjuster"],
"targets": [
{ "id": "t1", "type": "landing_zone", "x": 300, "width": 100, "maxVelocity": 5 }
],
"initialConditions": {
"mass": 1000,
"gravity": 9.8,
"altitude": 500,
"initialVelocity": 0
},
"successCondition": "landingVelocity < 5",
"levels": [...]
},
"scoring": {
"completionPoints": 50,
"accuracyBonus": "lower velocity = more points",
"timeBonus": true
},
"achievements": [
{ "id": "soft_landing", "name": "Butter Landing", "description": "Land at < 2m/s", "icon": "🦋" }
]
}
Technical Requirements
- Real-time game loop with
requestAnimationFrame - Touch-friendly controls (sliders, buttons, drag areas)
- Clear visual feedback (score, progress, status)
- Achievement popups
- Level progression
- localStorage for progress
- Pause/resume functionality
- Clear instructions before game starts
Fair Start Requirements (CRITICAL)
NEVER let the player fail immediately when the game starts!
Mandatory Rules:
- Grace Period: First 3-5 seconds should be safe - no failure conditions apply
- Safe Initial State: Player must be able to survive at least 10 seconds with default settings
- No Instant Collision: Game objects should start in safe positions, away from danger zones
- Reasonable Physics: Initial velocities must allow stable gameplay, not immediate crash
For Physics-Based Games:
- Calculate stable orbital/trajectory parameters BEFORE setting initial values
- Verify:
initial_velocity >= sqrt(GM/r)for orbital games - Test: Player not touching any danger zone at start
- Ensure: Default control values (e.g., thrust at 100%) result in survivable state
BAD Example (Player fails instantly):
// Earth starts at distance 250 from sun
// Initial velocity: 2.4 (way too low for orbit)
// Player clicks "Start" → Earth immediately falls into sun → "Mission Failed"
GOOD Example (Player has time to react):
// Earth starts at distance 250 from sun
// Initial velocity: calculated for stable orbit ≈ sqrt(1500*200/250) ≈ 35
// OR: Start with grace period where collision is disabled for 3 seconds
// Player can adjust thrust before any danger
Layout & Positioning (CRITICAL)
Game Object Positioning
When calculating positions for game objects (lander, player, targets), account for UI overlays:
// BAD: Object overlaps with controls/HUD
const objectY = groundY - (altitude / maxHeight) * canvas.height;
// GOOD: Reserve space for UI elements
const TOP_MARGIN = 100; // Space for HUD/stats at top
const BOTTOM_MARGIN = 250; // Space for controls at bottom
const playableHeight = canvas.height - TOP_MARGIN - BOTTOM_MARGIN;
const objectY = groundY - BOTTOM_MARGIN - (altitude / maxHeight) * playableHeight;
Control Panel Sizing
- Don't let controls take more than 30% of screen height
- On mobile, consider collapsible controls or side-by-side layout
- Test that the main game object is always visible
Canvas vs UI Layers
- Canvas should fill the container but NOT overlap with fixed UI
- Use padding or margins to create "safe zones" for game objects
- Position game objects within the visible canvas area, not under overlays
Output Format (CRITICAL)
Return EXACTLY ONE HTML document. Do NOT:
- Duplicate the HTML content
- Include multiple
<!DOCTYPE html>tags - Append a second copy of the document
Output structure must be:
<!DOCTYPE html>
<html>
<head>...</head>
<body>...</body>
</html>
<!-- END - Nothing after this -->
If you catch yourself duplicating content, STOP and output only the first complete document.
Engagement Features
- Immediate feedback: Player knows instantly if action was right/wrong
- Visual rewards: Animations, particles, sounds for success
- Progression: Levels get progressively harder
- Replayability: Random elements, multiple paths to success
- Challenge variety: Different objectives (speed, accuracy, efficiency)
- High scores: Track best performance
Output Format
Return ONLY the HTML document, no markdown fences or explanations.
Quality Checklist (verify before output)
- Game is INTERACTIVE, not just a quiz
- Player CONTROLS something meaningful
- Simulation (if present) is part of gameplay, not decoration
- Success depends on player SKILL, not just knowledge
- Fair Start: Player cannot fail in first 3-5 seconds
- Initial parameters allow survival with default settings
- Visual feedback is immediate and clear
- Game is FUN to play (would you play it more than once?)
- Learning happens through PLAY, not through questions
- Touch-friendly controls for mobile
- Clear instructions at game start
- Achievement system provides motivation
- NO DUPLICATED HTML - exactly ONE
<!DOCTYPE html>tag - Game objects are VISIBLE and not hidden under UI overlays
- Positioning accounts for control panel and HUD heights
Critical Technical Requirements (MANDATORY)
1. Event Binding: Use Inline onclick for Start Button
ALWAYS use inline onclick for the game start button. This is more reliable than addEventListener.
<!-- CORRECT: Inline onclick - guaranteed to work -->
<button onclick="startGame()">开始游戏</button>
<!-- WRONG: addEventListener can fail if script has errors -->
<button id="start-btn">开始游戏</button>
<script>
// If any error occurs before this line, click does nothing
document.getElementById('start-btn').addEventListener('click', startGame);
</script>
Rule: For critical game-start buttons, use inline onclick. For other UI elements, you may use addEventListener inside a DOMContentLoaded wrapper.
2. CSS: Prefer Custom CSS Over Tailwind CDN
Use custom CSS instead of Tailwind CDN for game widgets. Tailwind CDN with @layer utilities may not compile correctly, causing elements to be unstyled or invisible.
<!-- CORRECT: Custom CSS - reliable and predictable -->
<style>
.game-button { background: #3498db; padding: 12px 30px; }
</style>
<!-- WRONG: Tailwind @layer utilities may fail -->
<style type="text/tailwindcss">
@layer utilities { .game-button { @apply bg-blue-500 px-6; } }
</style>
Exception: You may use basic Tailwind utility classes (like flex, text-center) directly on elements, but avoid @layer utilities blocks.
3. Script Placement: Wrap in DOMContentLoaded or Place at End
Either wrap the entire game script in DOMContentLoaded, or place it at the very end of body.
<!-- Option A: DOMContentLoaded wrapper -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// All game code here - elements are guaranteed to exist
const canvas = document.getElementById('gameCanvas');
function startGame() { ... }
});
</script>
<!-- Option B: Script at end of body (after all elements) -->
</body>
<!-- No elements after this point -->
</html>
4. Global Functions for onclick Handlers
Functions called by inline onclick must be globally accessible.
// CORRECT: Define function globally (outside DOMContentLoaded)
function startGame() {
document.getElementById('start-screen').classList.add('hidden');
gameActive = true;
initLevel();
}
// If using DOMContentLoaded, expose function to window
document.addEventListener('DOMContentLoaded', function() {
// ... other setup ...
});
// Define startGame outside or assign to window
window.startGame = function() { ... };
5. Simple Initialization Flow
The game initialization should be simple and direct:
function startGame() {
// 1. Hide start overlay
document.getElementById('start-screen').classList.add('hidden');
// 2. Set game state
gameActive = true;
startTime = Date.now();
// 3. Initialize first level
initLevel();
// 4. Start game loop
requestAnimationFrame(gameLoop);
}
Avoid: Complex dependencies like reading localStorage before events are bound, multiple async operations during init, or chained promises for game start.