chore: establish learning module baseline
This commit is contained in:
commit
2d04197f3f
2409 files changed
+533050
No files matched your search
@@ -0,0 +1,396 @@
|
||||
# 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
|
||||
|
||||
```json
|
||||
{
|
||||
"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):
|
||||
```javascript
|
||||
// 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):
|
||||
```javascript
|
||||
// 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:
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
## CRITICAL: postMessage Listener for Widget Actions (REQUIRED)
|
||||
|
||||
The platform drives this widget by posting messages into the iframe
|
||||
(`SET_WIDGET_STATE`, `HIGHLIGHT_ELEMENT`, `ANNOTATE_ELEMENT`, `REVEAL_ELEMENT`).
|
||||
Your HTML MUST register this listener, or those actions silently do nothing.
|
||||
Register it at the end of the body (or inside your DOMContentLoaded setup) so the
|
||||
game can be driven the same way a player would drive it:
|
||||
|
||||
```javascript
|
||||
window.addEventListener('message', function(event) {
|
||||
const { type, target, state, content } = event.data;
|
||||
|
||||
switch (type) {
|
||||
case 'SET_WIDGET_STATE':
|
||||
// Apply state to controls / game params. Keys map to controls by id;
|
||||
// route to the game via a global setter when one exists.
|
||||
if (state) {
|
||||
Object.entries(state).forEach(([key, value]) => {
|
||||
const control = document.getElementById(key + '-slider') || document.getElementById(key) || document.querySelector('[data-var="' + key + '"]');
|
||||
if (control) {
|
||||
control.value = value;
|
||||
control.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
if (typeof window.setGameParam === 'function') window.setGameParam(key, value);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'HIGHLIGHT_ELEMENT':
|
||||
const highlightEl = document.querySelector(target);
|
||||
if (highlightEl) {
|
||||
highlightEl.style.outline = '3px solid rgba(139, 92, 246, 0.8)';
|
||||
highlightEl.style.outlineOffset = '4px';
|
||||
highlightEl.style.animation = 'pulse-highlight 2s infinite';
|
||||
setTimeout(() => {
|
||||
highlightEl.style.outline = '';
|
||||
highlightEl.style.animation = '';
|
||||
}, 3000);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ANNOTATE_ELEMENT':
|
||||
const annotateEl = document.querySelector(target);
|
||||
if (annotateEl && content) {
|
||||
const rect = annotateEl.getBoundingClientRect();
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'teacher-annotation';
|
||||
tooltip.style.cssText = 'position:fixed; top:' + (rect.top - 40) + 'px; left:' + rect.left + 'px; background:rgba(139,92,246,0.95); color:white; padding:8px 12px; border-radius:8px; font-size:14px; z-index:1000; animation:fadeIn 0.3s;';
|
||||
tooltip.textContent = content;
|
||||
document.body.appendChild(tooltip);
|
||||
setTimeout(() => tooltip.remove(), 4000);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'REVEAL_ELEMENT':
|
||||
const revealEl = document.querySelector(target);
|
||||
if (revealEl) {
|
||||
revealEl.style.display = '';
|
||||
revealEl.style.opacity = '1';
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.textContent = '@keyframes pulse-highlight { 0%, 100% { outline-color: rgba(139, 92, 246, 0.8); } 50% { outline-color: rgba(139, 92, 246, 0.4); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }';
|
||||
document.head.appendChild(style);
|
||||
```
|
||||
|
||||
### Element Naming Convention
|
||||
|
||||
So highlight/annotate/reveal can target controls, use consistent ids:
|
||||
- Sliders: `id="{param}-slider"` (e.g., `id="thrust-slider"`)
|
||||
- Buttons: `id="{action}-btn"` (e.g., `id="start-btn"`, `id="reset-btn"`)
|
||||
- If game parameters live only in JS state, expose `window.setGameParam(key, value)`
|
||||
so `SET_WIDGET_STATE` can drive them.
|
||||
|
||||
## 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:
|
||||
```html
|
||||
<!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.
|
||||
|
||||
```html
|
||||
<!-- 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.
|
||||
|
||||
```html
|
||||
<!-- 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.**
|
||||
|
||||
```html
|
||||
<!-- 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.**
|
||||
|
||||
```javascript
|
||||
// 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:**
|
||||
|
||||
```javascript
|
||||
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.
|
||||
@@ -0,0 +1,73 @@
|
||||
Create an educational GAME widget for: {{title}}
|
||||
|
||||
## Game Type
|
||||
|
||||
{{gameType}}
|
||||
|
||||
## Description
|
||||
|
||||
{{description}}
|
||||
|
||||
## Key Points
|
||||
|
||||
{{keyPoints}}
|
||||
|
||||
## Scoring Configuration
|
||||
|
||||
{{scoring}}
|
||||
|
||||
## Language
|
||||
|
||||
{{languageDirective}}
|
||||
|
||||
---
|
||||
|
||||
Generate a FUN, INTERACTIVE HTML game with these MANDATORY features:
|
||||
|
||||
### Game Design (CRITICAL - NOT A QUIZ!)
|
||||
1. **Interactive gameplay**: Player MUST control something meaningful (NOT just click answers)
|
||||
2. **Real game mechanics**: Timing, aiming, dragging, balancing, catching, or building
|
||||
3. **Skill-based success**: Outcome depends on player action, not just correct answer
|
||||
4. **Engaging feedback**: Animations, sounds, visual effects for actions
|
||||
|
||||
### Preferred Game Types (in order of preference)
|
||||
1. **Physics/Action**: Control parameters to achieve a goal (land safely, hit target, balance)
|
||||
2. **Timing/Aim**: Click at right moment or adjust aim to succeed
|
||||
3. **Drag-and-drop**: Sort, arrange, or build by dragging elements
|
||||
4. **Simulation game**: Let player experiment with variables to find solution
|
||||
5. **Card/Match**: Memory or matching games
|
||||
6. **Quiz**: ONLY as last resort - make it visually interesting
|
||||
|
||||
### Simulation Integration (if game has visual simulation)
|
||||
- Simulation MUST be interactive (player controls something)
|
||||
- Simulation physics MUST match what player is learning
|
||||
- Visual feedback MUST show player's progress toward goal
|
||||
- Example: Don't ask "What thrust?" → LET PLAYER ADJUST thrust and see result!
|
||||
|
||||
### Game Elements
|
||||
1. **Clear objective**: "Land safely", "Hit the target", "Sort correctly"
|
||||
2. **Player controls**: Sliders, buttons, drag areas, or click targets
|
||||
3. **Real-time feedback**: Score, progress bar, visual indicators
|
||||
4. **Levels or challenges**: Progressive difficulty
|
||||
5. **Achievement system**: Unlockable badges for accomplishments
|
||||
6. **Replay value**: Random elements or multiple solutions
|
||||
|
||||
### Visual Design
|
||||
1. Attractive theme matching the subject
|
||||
2. Clear UI for controls and feedback
|
||||
3. Animations for success/failure
|
||||
4. Responsive layout (mobile + desktop)
|
||||
|
||||
### Technical (MANDATORY)
|
||||
1. **Inline onclick for start button**: `<button onclick="startGame()">开始</button>` - NOT addEventListener
|
||||
2. **Custom CSS preferred**: Avoid Tailwind `@layer utilities` blocks; use plain CSS
|
||||
3. **DOMContentLoaded wrapper**: Wrap game code in `document.addEventListener('DOMContentLoaded', ...)`
|
||||
4. **Global start function**: `function startGame()` must be callable from onclick
|
||||
5. Embedded `<script type="application/json" id="widget-config">`
|
||||
6. `requestAnimationFrame` for smooth animations
|
||||
7. Touch-friendly controls (min 44px touch targets)
|
||||
8. localStorage for progress/high scores
|
||||
9. Pause functionality
|
||||
|
||||
### Output
|
||||
Return ONLY the HTML document. Make the game FUN enough that students want to play again!
|
||||
Reference in new issue
Block a user