opengame-agentic-game-creation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenGame: Agentic Web Game Creation
OpenGame:智能体驱动的网页游戏创作
Skill by ara.so — Daily 2026 Skills collection.
OpenGame is an open-source TypeScript framework that generates fully playable web games end-to-end from a single natural language prompt. It combines Game Skill (Template Skill + Debug Skill), an optional specialized GameCoder-27B LLM, and OpenGame-Bench for automated evaluation across Build Health, Visual Usability, and Intent Alignment.
由 ara.so 开发的 Skill — 属于 Daily 2026 Skills 系列。
OpenGame 是一个开源的 TypeScript 框架,可通过单个自然语言提示词端到端生成可直接游玩的网页游戏。它结合了Game Skill(模板技能 + 调试技能)、可选的专用GameCoder-27B大语言模型(LLM),以及用于在构建健康度、视觉可用性和意图匹配度三个维度进行自动化评估的OpenGame-Bench。
What OpenGame Does
OpenGame 功能介绍
- Takes a high-level game design prompt and produces a runnable browser game (HTML/JS/CSS)
- Template Skill: Maintains a growing library of project skeletons to scaffold stable architectures
- Debug Skill: Keeps a living protocol of verified fixes to repair cross-file integration errors systematically
- OpenGame-Bench: Evaluates generated games via headless browser execution + VLM judging across 150 diverse prompts
- Supports any OpenAI-compatible LLM backend (GPT-4o, Claude, GameCoder-27B, etc.)
- 接收高层级的游戏设计提示词,生成可在浏览器中运行的游戏(HTML/JS/CSS)
- 模板技能:维护一个不断扩充的项目骨架库,用于搭建稳定的架构
- 调试技能:保留一份实时更新的已验证修复协议,系统性修复跨文件集成错误
- OpenGame-Bench:通过无头浏览器执行 + 视觉语言模型(VLM)评判,针对150种不同提示词评估生成的游戏
- 支持任何兼容OpenAI的LLM后端(GPT-4o、Claude、GameCoder-27B等)
Prerequisites
前置要求
- Node.js >= 20.0.0
- An OpenAI-compatible API key (or self-hosted GameCoder-27B endpoint)
- Node.js >= 20.0.0
- 兼容OpenAI的API密钥(或自托管的GameCoder-27B端点)
Installation
安装步骤
bash
undefinedbash
undefinedClone the repository
Clone the repository
git clone https://github.com/leigest519/OpenGame.git
cd OpenGame
git clone https://github.com/leigest519/OpenGame.git
cd OpenGame
Install dependencies
Install dependencies
npm install
npm install
Copy and configure environment variables
Copy and configure environment variables
cp .env.example .env
undefinedcp .env.example .env
undefined.env
Configuration
.env.env
配置
.envbash
undefinedbash
undefinedRequired: LLM API credentials
Required: LLM API credentials
OPENAI_API_KEY=$OPENAI_API_KEY
OPENAI_BASE_URL=https://api.openai.com/v1 # or your custom endpoint
MODEL_NAME=gpt-4o # or gamecoder-27b, claude-3-5-sonnet, etc.
OPENAI_API_KEY=$OPENAI_API_KEY
OPENAI_BASE_URL=https://api.openai.com/v1 # or your custom endpoint
MODEL_NAME=gpt-4o # or gamecoder-27b, claude-3-5-sonnet, etc.
Optional: OpenGame-Bench VLM judging
Optional: OpenGame-Bench VLM judging
VLM_API_KEY=$VLM_API_KEY
VLM_BASE_URL=https://api.openai.com/v1
VLM_MODEL_NAME=gpt-4o
VLM_API_KEY=$VLM_API_KEY
VLM_BASE_URL=https://api.openai.com/v1
VLM_MODEL_NAME=gpt-4o
Optional: Output directory for generated games
Optional: Output directory for generated games
OUTPUT_DIR=./output
OUTPUT_DIR=./output
Optional: Max debug iterations
Optional: Max debug iterations
MAX_DEBUG_ITERATIONS=5
---MAX_DEBUG_ITERATIONS=5
---Key CLI Commands
核心CLI命令
bash
undefinedbash
undefinedGenerate a game from a prompt
Generate a game from a prompt
npm run generate -- --prompt "Build a top-down shooter where a spaceship avoids asteroids"
npm run generate -- --prompt "Build a top-down shooter where a spaceship avoids asteroids"
Generate with a specific model
Generate with a specific model
npm run generate --
--prompt "Create a tower defense game with 3 enemy types"
--model gpt-4o
--output ./my-games
--prompt "Create a tower defense game with 3 enemy types"
--model gpt-4o
--output ./my-games
npm run generate --
--prompt "Create a tower defense game with 3 enemy types"
--model gpt-4o
--output ./my-games
--prompt "Create a tower defense game with 3 enemy types"
--model gpt-4o
--output ./my-games
Run OpenGame-Bench evaluation on a set of prompts
Run OpenGame-Bench evaluation on a set of prompts
npm run bench -- --prompts ./bench/prompts.json --output ./bench-results
npm run bench -- --prompts ./bench/prompts.json --output ./bench-results
Evaluate a single already-generated game directory
Evaluate a single already-generated game directory
npm run evaluate -- --game-dir ./output/my-game
npm run evaluate -- --game-dir ./output/my-game
Run the local dev server for a generated game
Run the local dev server for a generated game
npm run serve -- --game-dir ./output/my-game
npm run serve -- --game-dir ./output/my-game
List available template skeletons
List available template skeletons
npm run templates -- --list
npm run templates -- --list
Add a new template skeleton from an existing game directory
Add a new template skeleton from an existing game directory
npm run templates -- --add ./output/my-game --name platformer-base
---npm run templates -- --add ./output/my-game --name platformer-base
---Programmatic API
编程式API
Basic Game Generation
基础游戏生成
typescript
import { OpenGameAgent } from './src/agent';
import { GameSkill } from './src/skills/gameSkill';
import { TemplateSkill } from './src/skills/templateSkill';
import { DebugSkill } from './src/skills/debugSkill';
async function generateGame(prompt: string) {
// Initialize skills
const templateSkill = new TemplateSkill({
libraryPath: './templates',
});
const debugSkill = new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
});
const gameSkill = new GameSkill({ templateSkill, debugSkill });
// Create and run the agent
const agent = new OpenGameAgent({
apiKey: process.env.OPENAI_API_KEY!,
baseURL: process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1',
model: process.env.MODEL_NAME ?? 'gpt-4o',
gameSkill,
outputDir: './output',
});
const result = await agent.generate({ prompt });
console.log('Game generated at:', result.outputPath);
console.log('Build status:', result.buildHealth);
return result;
}
generateGame(
'Make a Pac-Man style maze game with 3 levels, power-ups, and ghost AI'
).catch(console.error);typescript
import { OpenGameAgent } from './src/agent';
import { GameSkill } from './src/skills/gameSkill';
import { TemplateSkill } from './src/skills/templateSkill';
import { DebugSkill } from './src/skills/debugSkill';
async function generateGame(prompt: string) {
// Initialize skills
const templateSkill = new TemplateSkill({
libraryPath: './templates',
});
const debugSkill = new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
});
const gameSkill = new GameSkill({ templateSkill, debugSkill });
// Create and run the agent
const agent = new OpenGameAgent({
apiKey: process.env.OPENAI_API_KEY!,
baseURL: process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1',
model: process.env.MODEL_NAME ?? 'gpt-4o',
gameSkill,
outputDir: './output',
});
const result = await agent.generate({ prompt });
console.log('Game generated at:', result.outputPath);
console.log('Build status:', result.buildHealth);
return result;
}
generateGame(
'Make a Pac-Man style maze game with 3 levels, power-ups, and ghost AI'
).catch(console.error);Using Template Skill Directly
直接使用模板技能
typescript
import { TemplateSkill } from './src/skills/templateSkill';
const templateSkill = new TemplateSkill({ libraryPath: './templates' });
// Find the best matching template for a game type
const template = await templateSkill.match({
prompt: 'side-scrolling platformer with double jump',
gameType: 'platformer',
});
console.log('Matched template:', template.name);
console.log('Skeleton files:', template.files);
// Scaffold a new project from a template
const scaffolded = await templateSkill.scaffold({
template,
outputDir: './output/my-platformer',
context: { gameName: 'MyPlatformer', playerSpeed: 300 },
});
// Save a successful game as a new template for future use
await templateSkill.save({
sourceDir: './output/successful-game',
name: 'tower-defense-base',
tags: ['tower-defense', 'wave-based', 'grid'],
});typescript
import { TemplateSkill } from './src/skills/templateSkill';
const templateSkill = new TemplateSkill({ libraryPath: './templates' });
// Find the best matching template for a game type
const template = await templateSkill.match({
prompt: 'side-scrolling platformer with double jump',
gameType: 'platformer',
});
console.log('Matched template:', template.name);
console.log('Skeleton files:', template.files);
// Scaffold a new project from a template
const scaffolded = await templateSkill.scaffold({
template,
outputDir: './output/my-platformer',
context: { gameName: 'MyPlatformer', playerSpeed: 300 },
});
// Save a successful game as a new template for future use
await templateSkill.save({
sourceDir: './output/successful-game',
name: 'tower-defense-base',
tags: ['tower-defense', 'wave-based', 'grid'],
});Using Debug Skill for Iterative Repair
使用调试技能进行迭代修复
typescript
import { DebugSkill } from './src/skills/debugSkill';
import { BuildRunner } from './src/build/runner';
const debugSkill = new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
});
const buildRunner = new BuildRunner({ gameDir: './output/my-game' });
// Run the debug loop
const debugResult = await debugSkill.repair({
gameDir: './output/my-game',
buildRunner,
onIteration: (iter, error, fix) => {
console.log(`Iteration ${iter}: fixing "${error.message}" with "${fix.description}"`);
},
});
if (debugResult.success) {
console.log('Game repaired after', debugResult.iterations, 'iterations');
// Protocol is automatically updated with the new verified fix
} else {
console.log('Could not repair after max iterations:', debugResult.lastError);
}typescript
import { DebugSkill } from './src/skills/debugSkill';
import { BuildRunner } from './src/build/runner';
const debugSkill = new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
});
const buildRunner = new BuildRunner({ gameDir: './output/my-game' });
// Run the debug loop
const debugResult = await debugSkill.repair({
gameDir: './output/my-game',
buildRunner,
onIteration: (iter, error, fix) => {
console.log(`Iteration ${iter}: fixing "${error.message}" with "${fix.description}"`);
},
});
if (debugResult.success) {
console.log('Game repaired after', debugResult.iterations, 'iterations');
// Protocol is automatically updated with the new verified fix
} else {
console.log('Could not repair after max iterations:', debugResult.lastError);
}OpenGame-Bench Evaluation
OpenGame-Bench 评估
typescript
import { OpenGameBench } from './src/bench/evaluator';
const bench = new OpenGameBench({
vlmApiKey: process.env.VLM_API_KEY!,
vlmBaseURL: process.env.VLM_BASE_URL ?? 'https://api.openai.com/v1',
vlmModel: process.env.VLM_MODEL_NAME ?? 'gpt-4o',
headlessBrowser: true,
});
// Evaluate a single game
const scores = await bench.evaluate({
gameDir: './output/my-game',
originalPrompt: 'Make a Pac-Man style maze game with 3 levels',
});
console.log('Build Health: ', scores.buildHealth); // 0–100
console.log('Visual Usability: ', scores.visualUsability); // 0–100
console.log('Intent Alignment: ', scores.intentAlignment); // 0–100
console.log('Overall: ', scores.overall);
// Batch evaluation across multiple prompts
import promptsData from './bench/prompts.json';
const batchResults = await bench.evaluateBatch({
prompts: promptsData,
agent, // OpenGameAgent instance
outputDir: './bench-results',
concurrency: 4,
});
console.log('Mean Build Health: ', batchResults.mean.buildHealth);
console.log('Mean Intent Alignment: ', batchResults.mean.intentAlignment);typescript
import { OpenGameBench } from './src/bench/evaluator';
const bench = new OpenGameBench({
vlmApiKey: process.env.VLM_API_KEY!,
vlmBaseURL: process.env.VLM_BASE_URL ?? 'https://api.openai.com/v1',
vlmModel: process.env.VLM_MODEL_NAME ?? 'gpt-4o',
headlessBrowser: true,
});
// Evaluate a single game
const scores = await bench.evaluate({
gameDir: './output/my-game',
originalPrompt: 'Make a Pac-Man style maze game with 3 levels',
});
console.log('Build Health: ', scores.buildHealth); // 0–100
console.log('Visual Usability: ', scores.visualUsability); // 0–100
console.log('Intent Alignment: ', scores.intentAlignment); // 0–100
console.log('Overall: ', scores.overall);
// Batch evaluation across multiple prompts
import promptsData from './bench/prompts.json';
const batchResults = await bench.evaluateBatch({
prompts: promptsData,
agent, // OpenGameAgent instance
outputDir: './bench-results',
concurrency: 4,
});
console.log('Mean Build Health: ', batchResults.mean.buildHealth);
console.log('Mean Intent Alignment: ', batchResults.mean.intentAlignment);Project Structure
项目结构
OpenGame/
├── src/
│ ├── agent/ # Core OpenGameAgent orchestration
│ ├── skills/
│ │ ├── gameSkill.ts # Combines Template + Debug skills
│ │ ├── templateSkill.ts# Template library management & matching
│ │ └── debugSkill.ts # Debug protocol & iterative repair
│ ├── build/
│ │ └── runner.ts # Headless build execution & error capture
│ ├── bench/
│ │ └── evaluator.ts # OpenGame-Bench scoring pipeline
│ └── llm/
│ └── client.ts # OpenAI-compatible LLM client
├── templates/ # Template skeleton library (grows over time)
├── bench/
│ └── prompts.json # 150 benchmark game prompts
├── output/ # Generated games land here
├── debug-protocol.json # Living verified-fix protocol
├── .env.example
└── package.jsonOpenGame/
├── src/
│ ├── agent/ # Core OpenGameAgent orchestration
│ ├── skills/
│ │ ├── gameSkill.ts # Combines Template + Debug skills
│ │ ├── templateSkill.ts# Template library management & matching
│ │ └── debugSkill.ts # Debug protocol & iterative repair
│ ├── build/
│ │ └── runner.ts # Headless build execution & error capture
│ ├── bench/
│ │ └── evaluator.ts # OpenGame-Bench scoring pipeline
│ └── llm/
│ └── client.ts # OpenAI-compatible LLM client
├── templates/ # Template skeleton library (grows over time)
├── bench/
│ └── prompts.json # 150 benchmark game prompts
├── output/ # Generated games land here
├── debug-protocol.json # Living verified-fix protocol
├── .env.example
└── package.jsonCommon Patterns
常见模式
Full Pipeline: Prompt → Playable Game
完整流程:提示词 → 可游玩游戏
typescript
import { OpenGameAgent } from './src/agent';
import { GameSkill } from './src/skills/gameSkill';
import { TemplateSkill } from './src/skills/templateSkill';
import { DebugSkill } from './src/skills/debugSkill';
import { OpenGameBench } from './src/bench/evaluator';
async function fullPipeline(prompt: string) {
const agent = new OpenGameAgent({
apiKey: process.env.OPENAI_API_KEY!,
baseURL: process.env.OPENAI_BASE_URL!,
model: process.env.MODEL_NAME ?? 'gpt-4o',
gameSkill: new GameSkill({
templateSkill: new TemplateSkill({ libraryPath: './templates' }),
debugSkill: new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
}),
}),
outputDir: './output',
});
// Step 1: Generate
const result = await agent.generate({ prompt });
console.log('Generated:', result.outputPath);
// Step 2: Evaluate
const bench = new OpenGameBench({
vlmApiKey: process.env.VLM_API_KEY!,
vlmModel: 'gpt-4o',
headlessBrowser: true,
});
const scores = await bench.evaluate({
gameDir: result.outputPath,
originalPrompt: prompt,
});
console.log('Scores:', scores);
// Step 3: If good quality, promote to template library
if (scores.overall >= 80) {
const templateSkill = new TemplateSkill({ libraryPath: './templates' });
await templateSkill.save({
sourceDir: result.outputPath,
name: `auto-${Date.now()}`,
tags: ['auto-promoted'],
});
console.log('Promoted to template library!');
}
return { result, scores };
}typescript
import { OpenGameAgent } from './src/agent';
import { GameSkill } from './src/skills/gameSkill';
import { TemplateSkill } from './src/skills/templateSkill';
import { DebugSkill } from './src/skills/debugSkill';
import { OpenGameBench } from './src/bench/evaluator';
async function fullPipeline(prompt: string) {
const agent = new OpenGameAgent({
apiKey: process.env.OPENAI_API_KEY!,
baseURL: process.env.OPENAI_BASE_URL!,
model: process.env.MODEL_NAME ?? 'gpt-4o',
gameSkill: new GameSkill({
templateSkill: new TemplateSkill({ libraryPath: './templates' }),
debugSkill: new DebugSkill({
protocolPath: './debug-protocol.json',
maxIterations: 5,
}),
}),
outputDir: './output',
});
// Step 1: Generate
const result = await agent.generate({ prompt });
console.log('Generated:', result.outputPath);
// Step 2: Evaluate
const bench = new OpenGameBench({
vlmApiKey: process.env.VLM_API_KEY!,
vlmModel: 'gpt-4o',
headlessBrowser: true,
});
const scores = await bench.evaluate({
gameDir: result.outputPath,
originalPrompt: prompt,
});
console.log('Scores:', scores);
// Step 3: If good quality, promote to template library
if (scores.overall >= 80) {
const templateSkill = new TemplateSkill({ libraryPath: './templates' });
await templateSkill.save({
sourceDir: result.outputPath,
name: `auto-${Date.now()}`,
tags: ['auto-promoted'],
});
console.log('Promoted to template library!');
}
return { result, scores };
}Custom LLM Endpoint (e.g., GameCoder-27B self-hosted)
自定义LLM端点(例如自托管的GameCoder-27B)
typescript
const agent = new OpenGameAgent({
apiKey: process.env.GAMECODER_API_KEY!,
baseURL: process.env.GAMECODER_BASE_URL!, // e.g. http://localhost:8000/v1
model: 'gamecoder-27b',
gameSkill,
outputDir: './output',
});typescript
const agent = new OpenGameAgent({
apiKey: process.env.GAMECODER_API_KEY!,
baseURL: process.env.GAMECODER_BASE_URL!, // e.g. http://localhost:8000/v1
model: 'gamecoder-27b',
gameSkill,
outputDir: './output',
});Loading Prompts from File and Batch Generating
从文件加载提示词并批量生成
typescript
import fs from 'fs/promises';
async function batchGenerate(promptsFile: string) {
const prompts: string[] = JSON.parse(await fs.readFile(promptsFile, 'utf8'));
for (const [i, prompt] of prompts.entries()) {
console.log(`Generating ${i + 1}/${prompts.length}: ${prompt.slice(0, 60)}...`);
try {
const result = await agent.generate({ prompt });
console.log(' ✅ Output:', result.outputPath);
} catch (err) {
console.error(' ❌ Failed:', err);
}
}
}
batchGenerate('./bench/prompts.json');typescript
import fs from 'fs/promises';
async function batchGenerate(promptsFile: string) {
const prompts: string[] = JSON.parse(await fs.readFile(promptsFile, 'utf8'));
for (const [i, prompt] of prompts.entries()) {
console.log(`Generating ${i + 1}/${prompts.length}: ${prompt.slice(0, 60)}...`);
try {
const result = await agent.generate({ prompt });
console.log(' ✅ Output:', result.outputPath);
} catch (err) {
console.error(' ❌ Failed:', err);
}
}
}
batchGenerate('./bench/prompts.json');Troubleshooting
故障排除
Build fails immediately with no output
构建立即失败且无输出
- Ensure :
NODE_VERSION >= 20.0.0node --version - Verify your API key and base URL are set correctly in
.env - Check that exists and is writable
OUTPUT_DIR
- 确保 :执行
NODE_VERSION >= 20.0.0检查node --version - 验证 文件中API密钥和基础URL设置正确
.env - 检查 目录是否存在且可写入
OUTPUT_DIR
LLM returns incomplete or truncated code
LLM返回不完整或截断的代码
- Increase the model's max token limit in your API settings or agent config
- Switch to a larger/more capable model: or
MODEL_NAME=gpt-4ogamecoder-27b - The Debug Skill will attempt iterative repair; raise if needed
MAX_DEBUG_ITERATIONS
- 在API设置或agent配置中增加模型的最大令牌限制
- 切换到更强大的模型:或
MODEL_NAME=gpt-4ogamecoder-27b - 调试技能会尝试迭代修复;必要时提高 的值
MAX_DEBUG_ITERATIONS
Debug loop exhausted without success
调试循环耗尽仍未成功
- Inspect — it may need a manual verified fix entry for a novel error pattern
debug-protocol.json - Check for the raw build errors
./output/<game>/build.log - Reduce game complexity in the prompt and regenerate
- 检查 — 可能需要为新的错误模式手动添加已验证的修复条目
debug-protocol.json - 查看 获取原始构建错误信息
./output/<game>/build.log - 简化提示词中的游戏复杂度并重新生成
OpenGame-Bench headless browser errors
OpenGame-Bench无头浏览器错误
- Ensure Chromium/Chrome is installed:
npx playwright install chromium - For CI environments, set or use a virtual framebuffer
DISPLAY=:99
- 确保已安装Chromium/Chrome:执行
npx playwright install chromium - 对于CI环境,设置 或使用虚拟帧缓冲区
DISPLAY=:99
Template matching returns wrong skeleton
模板匹配返回错误的骨架
- Add a better-matched template:
npm run templates -- --add ./output/good-example --name my-game-type - Templates are matched by semantic similarity to the prompt; more diverse templates improve accuracy
- 添加更匹配的模板:执行
npm run templates -- --add ./output/good-example --name my-game-type - 模板通过与提示词的语义相似度匹配;更多样化的模板可提高匹配准确性
Rate limits or API quota errors
速率限制或API配额错误
- Add retry logic or use in batch evaluation
concurrency: 1 - For self-hosted GameCoder-27B, verify the vLLM/TGI server is healthy:
curl $GAMECODER_BASE_URL/health
- 添加重试逻辑,或在批量评估中设置
concurrency: 1 - 对于自托管的GameCoder-27B,验证vLLM/TGI服务器是否正常:执行
curl $GAMECODER_BASE_URL/health
Benchmark: OpenGame-Bench
基准测试:OpenGame-Bench
OpenGame-Bench evaluates 150 diverse game prompts across three axes:
| Metric | Description |
|---|---|
| Build Health | Does the game compile and run without errors in a headless browser? |
| Visual Usability | Are UI elements visible, legible, and interactable? (VLM-judged) |
| Intent Alignment | Does the generated game match the original prompt's design intent? (VLM-judged) |
bash
undefinedOpenGame-Bench针对150种不同的游戏提示词从三个维度进行评估:
| 指标 | 描述 |
|---|---|
| 构建健康度 | 游戏能否在无头浏览器中编译并无错误运行? |
| 视觉可用性 | UI元素是否可见、清晰且可交互?(由VLM评判) |
| 意图匹配度 | 生成的游戏是否与原始提示词的设计意图相符?(由VLM评判) |
bash
undefinedRun full benchmark (150 prompts)
Run full benchmark (150 prompts)
npm run bench --
--prompts ./bench/prompts.json
--output ./bench-results
--concurrency 4
--prompts ./bench/prompts.json
--output ./bench-results
--concurrency 4
npm run bench --
--prompts ./bench/prompts.json
--output ./bench-results
--concurrency 4
--prompts ./bench/prompts.json
--output ./bench-results
--concurrency 4
Results are saved to ./bench-results/summary.json
Results are saved to ./bench-results/summary.json
---
---Resources
资源
- Project Page: https://www.opengame-project-page.com/
- arXiv Paper: https://arxiv.org/abs/2604.18394
- Hugging Face: https://huggingface.co/papers/2604.18394
- License: Apache-2.0
- 项目页面:https://www.opengame-project-page.com/
- arXiv论文:https://arxiv.org/abs/2604.18394
- Hugging Face:https://huggingface.co/papers/2604.18394
- 许可证:Apache-2.0