muthuk1's picture
Convert OpenMAIC from Next.js to React (Vite)
f56a29b verified

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:

  1. Interactive: Player controls something in the simulation
  2. Meaningful: Player's actions affect the outcome
  3. 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:

  1. Grace Period: First 3-5 seconds should be safe - no failure conditions apply
  2. Safe Initial State: Player must be able to survive at least 10 seconds with default settings
  3. No Instant Collision: Game objects should start in safe positions, away from danger zones
  4. 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

  1. Immediate feedback: Player knows instantly if action was right/wrong
  2. Visual rewards: Animations, particles, sounds for success
  3. Progression: Levels get progressively harder
  4. Replayability: Random elements, multiple paths to success
  5. Challenge variety: Different objectives (speed, accuracy, efficiency)
  6. 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.