create-threejs-game 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -0
- package/bin/cli.js +370 -0
- package/package.json +29 -0
- package/template/.claude/skills/threejs-animation/SKILL.md +552 -0
- package/template/.claude/skills/threejs-fundamentals/SKILL.md +488 -0
- package/template/.claude/skills/threejs-geometry/SKILL.md +548 -0
- package/template/.claude/skills/threejs-interaction/SKILL.md +660 -0
- package/template/.claude/skills/threejs-lighting/SKILL.md +481 -0
- package/template/.claude/skills/threejs-loaders/SKILL.md +623 -0
- package/template/.claude/skills/threejs-materials/SKILL.md +520 -0
- package/template/.claude/skills/threejs-postprocessing/SKILL.md +602 -0
- package/template/.claude/skills/threejs-shaders/SKILL.md +642 -0
- package/template/.claude/skills/threejs-textures/SKILL.md +628 -0
- package/template/.codex/skills/threejs-animation/SKILL.md +552 -0
- package/template/.codex/skills/threejs-fundamentals/SKILL.md +488 -0
- package/template/.codex/skills/threejs-geometry/SKILL.md +548 -0
- package/template/.codex/skills/threejs-interaction/SKILL.md +660 -0
- package/template/.codex/skills/threejs-lighting/SKILL.md +481 -0
- package/template/.codex/skills/threejs-loaders/SKILL.md +623 -0
- package/template/.codex/skills/threejs-materials/SKILL.md +520 -0
- package/template/.codex/skills/threejs-postprocessing/SKILL.md +602 -0
- package/template/.codex/skills/threejs-shaders/SKILL.md +642 -0
- package/template/.codex/skills/threejs-textures/SKILL.md +628 -0
- package/template/README.md +352 -0
- package/template/docs/.gitkeep +0 -0
- package/template/plans/.gitkeep +0 -0
- package/template/prompts/01-mockup-generation.md +44 -0
- package/template/prompts/02-prd-generation.md +119 -0
- package/template/prompts/03-tdd-generation.md +127 -0
- package/template/prompts/04-execution-plan.md +89 -0
- package/template/prompts/05-implementation.md +61 -0
- package/template/public/assets/.gitkeep +0 -0
- package/template/scripts/config.example.json +12 -0
- package/template/scripts/generate-assets-json.js +149 -0
- package/template/scripts/generate-mockup.js +197 -0
- package/template/scripts/generate-plan.js +295 -0
- package/template/scripts/generate-prd.js +297 -0
- package/template/scripts/generate-tdd.js +283 -0
- package/template/scripts/pipeline.js +229 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Execution Plan Generation Script
|
|
5
|
+
*
|
|
6
|
+
* Uses Claude API (Opus 4.5) to generate an implementation plan
|
|
7
|
+
* based on the PRD and TDD.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node generate-plan.js [plan-name]
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* node generate-plan.js initial-implementation
|
|
14
|
+
*
|
|
15
|
+
* Requires:
|
|
16
|
+
* - config.json with anthropic.api_key and game settings
|
|
17
|
+
* - docs/prd.md
|
|
18
|
+
* - docs/tdd.md
|
|
19
|
+
* - public/assets/{game_name}/assets.json
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const https = require('https');
|
|
25
|
+
|
|
26
|
+
// Generate random plan name if not provided
|
|
27
|
+
function generatePlanName() {
|
|
28
|
+
const adjectives = ['swift', 'bold', 'bright', 'calm', 'dark', 'eager', 'fair', 'grand', 'keen', 'light', 'mossy', 'noble', 'proud', 'quick', 'rare', 'sage', 'true', 'vast', 'warm', 'wise'];
|
|
29
|
+
const nouns = ['dawn', 'dusk', 'flame', 'frost', 'glade', 'grove', 'haven', 'isle', 'lake', 'marsh', 'oak', 'peak', 'pine', 'ridge', 'shore', 'stone', 'tide', 'vale', 'wind', 'wood'];
|
|
30
|
+
const names = ['ada', 'blake', 'chen', 'darwin', 'euler', 'feynman', 'gauss', 'hopper', 'ito', 'jung', 'knuth', 'lovelace', 'maxwell', 'newton', 'oracle', 'pascal', 'quine', 'riemann', 'shannon', 'turing'];
|
|
31
|
+
|
|
32
|
+
const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
33
|
+
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
34
|
+
const name = names[Math.floor(Math.random() * names.length)];
|
|
35
|
+
|
|
36
|
+
return `${adj}-${noun}-${name}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Load config
|
|
40
|
+
const scriptDir = __dirname;
|
|
41
|
+
const projectRoot = path.join(scriptDir, '..');
|
|
42
|
+
const configPath = path.join(scriptDir, 'config.json');
|
|
43
|
+
|
|
44
|
+
if (!fs.existsSync(configPath)) {
|
|
45
|
+
console.error('Error: config.json not found');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
50
|
+
const { anthropic, game } = config;
|
|
51
|
+
|
|
52
|
+
// Check config first, then env vars
|
|
53
|
+
const apiKey = (anthropic?.api_key && !anthropic.api_key.includes('YOUR_'))
|
|
54
|
+
? anthropic.api_key
|
|
55
|
+
: process.env.ANTHROPIC_API_KEY;
|
|
56
|
+
|
|
57
|
+
if (!apiKey) {
|
|
58
|
+
console.error('Error: Anthropic API key not found');
|
|
59
|
+
console.error('Set ANTHROPIC_API_KEY env var or configure scripts/config.json');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Use resolved key
|
|
64
|
+
anthropic.api_key = apiKey;
|
|
65
|
+
|
|
66
|
+
// Plan name from args or generate
|
|
67
|
+
const planName = process.argv[2] || generatePlanName();
|
|
68
|
+
|
|
69
|
+
// Paths
|
|
70
|
+
const prdPath = path.join(projectRoot, 'docs', 'prd.md');
|
|
71
|
+
const tddPath = path.join(projectRoot, 'docs', 'tdd.md');
|
|
72
|
+
const assetsJsonPath = path.join(projectRoot, 'public', 'assets', game.name, 'assets.json');
|
|
73
|
+
const plansDir = path.join(projectRoot, 'plans');
|
|
74
|
+
const outputPath = path.join(plansDir, `${planName}.md`);
|
|
75
|
+
|
|
76
|
+
// Check required files
|
|
77
|
+
const missingFiles = [];
|
|
78
|
+
if (!fs.existsSync(prdPath)) missingFiles.push(prdPath + ' (run generate-prd.js first)');
|
|
79
|
+
if (!fs.existsSync(tddPath)) missingFiles.push(tddPath + ' (run generate-tdd.js first)');
|
|
80
|
+
if (!fs.existsSync(assetsJsonPath)) missingFiles.push(assetsJsonPath);
|
|
81
|
+
|
|
82
|
+
if (missingFiles.length > 0) {
|
|
83
|
+
console.error('Error: Missing required files:');
|
|
84
|
+
missingFiles.forEach(f => console.error(' - ' + f));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Read files
|
|
89
|
+
const prdContent = fs.readFileSync(prdPath, 'utf-8');
|
|
90
|
+
const tddContent = fs.readFileSync(tddPath, 'utf-8');
|
|
91
|
+
const assetsJson = fs.readFileSync(assetsJsonPath, 'utf-8');
|
|
92
|
+
|
|
93
|
+
// Build prompt
|
|
94
|
+
const prompt = `Implement the game defined in the PRD below, adhering to the technical design in the TDD.
|
|
95
|
+
|
|
96
|
+
## PRD (Product Requirements Document):
|
|
97
|
+
${prdContent}
|
|
98
|
+
|
|
99
|
+
## TDD (Technical Design Document):
|
|
100
|
+
${tddContent.substring(0, 80000)}
|
|
101
|
+
|
|
102
|
+
## Available Assets (assets.json):
|
|
103
|
+
\`\`\`json
|
|
104
|
+
${assetsJson}
|
|
105
|
+
\`\`\`
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
Create a concise execution plan for implementing this game. The plan should be actionable and reference specific sections from the TDD.
|
|
110
|
+
|
|
111
|
+
# ${game.name.charAt(0).toUpperCase() + game.name.slice(1)} - Implementation Plan
|
|
112
|
+
|
|
113
|
+
## Overview
|
|
114
|
+
- Target file: \`public/index.html\` (single HTML file with inline CSS/JS)
|
|
115
|
+
- Key references to PRD and TDD sections
|
|
116
|
+
- Asset path format: \`assets/${game.name}/glTF/<FILENAME>.gltf\`
|
|
117
|
+
|
|
118
|
+
## Implementation Phases
|
|
119
|
+
|
|
120
|
+
### Phase 1: Core Engine (Critical)
|
|
121
|
+
What to implement from TDD:
|
|
122
|
+
- HTML structure with import map for Three.js r160
|
|
123
|
+
- Renderer with letterboxing
|
|
124
|
+
- Camera system
|
|
125
|
+
- Lighting setup
|
|
126
|
+
- Ground plane
|
|
127
|
+
|
|
128
|
+
### Phase 2: Asset Loading (Critical)
|
|
129
|
+
- GLTFLoader setup
|
|
130
|
+
- Core asset manifest
|
|
131
|
+
- Fallback primitives
|
|
132
|
+
|
|
133
|
+
### Phase 3: ECS Architecture (Critical)
|
|
134
|
+
- Entity class
|
|
135
|
+
- All component classes
|
|
136
|
+
- Entity Manager
|
|
137
|
+
- Entity Factory
|
|
138
|
+
|
|
139
|
+
### Phase 4: Selection System (Critical)
|
|
140
|
+
- Click selection
|
|
141
|
+
- Box selection
|
|
142
|
+
- Visual feedback (rings, animations)
|
|
143
|
+
|
|
144
|
+
### Phase 5: Command System (Critical)
|
|
145
|
+
- Move commands
|
|
146
|
+
- Attack commands
|
|
147
|
+
- Context-sensitive commands
|
|
148
|
+
|
|
149
|
+
### Phase 6: Movement System (Critical)
|
|
150
|
+
- Unit movement
|
|
151
|
+
- Collision/separation
|
|
152
|
+
- Turn rate smoothing
|
|
153
|
+
|
|
154
|
+
### Phase 7: Combat System (Critical)
|
|
155
|
+
- Melee attacks
|
|
156
|
+
- Ranged attacks (if applicable)
|
|
157
|
+
- Damage and death
|
|
158
|
+
|
|
159
|
+
### Phase 8: Economy System (Important)
|
|
160
|
+
- Resource gathering (if applicable)
|
|
161
|
+
- Building placement (if applicable)
|
|
162
|
+
- Unit training (if applicable)
|
|
163
|
+
|
|
164
|
+
### Phase 9: AI System (Important)
|
|
165
|
+
- State machine
|
|
166
|
+
- Economy behavior
|
|
167
|
+
- Combat behavior
|
|
168
|
+
|
|
169
|
+
### Phase 10: UI & Game States (Important)
|
|
170
|
+
- Menu screen
|
|
171
|
+
- HUD elements
|
|
172
|
+
- Pause screen
|
|
173
|
+
- Game over screen
|
|
174
|
+
|
|
175
|
+
### Phase 11: Effects (Polish)
|
|
176
|
+
- Screen shake
|
|
177
|
+
- Time dilation
|
|
178
|
+
- Particles
|
|
179
|
+
- Death sequences
|
|
180
|
+
|
|
181
|
+
### Phase 12: Mobile/Polish (Polish)
|
|
182
|
+
- Touch controls
|
|
183
|
+
- Onboarding tooltips
|
|
184
|
+
- Final polish
|
|
185
|
+
|
|
186
|
+
## Map Setup
|
|
187
|
+
- Initial entity positions
|
|
188
|
+
- Resource placement
|
|
189
|
+
- Obstacle placement
|
|
190
|
+
|
|
191
|
+
## Verification Checklist
|
|
192
|
+
From PRD Success Criteria:
|
|
193
|
+
- [ ] Game loads without errors
|
|
194
|
+
- [ ] (Include all success criteria)
|
|
195
|
+
|
|
196
|
+
## Estimated Code Size
|
|
197
|
+
~3000-4000 lines of JavaScript
|
|
198
|
+
|
|
199
|
+
## Next Step
|
|
200
|
+
To implement, use this prompt with Claude Code:
|
|
201
|
+
\`\`\`
|
|
202
|
+
Please proceed with implementing the game based on the plan in plans/${planName}.md
|
|
203
|
+
Use the Three.js skills for reference.
|
|
204
|
+
\`\`\`
|
|
205
|
+
`;
|
|
206
|
+
|
|
207
|
+
console.log('Generating execution plan with Claude API...');
|
|
208
|
+
console.log('Game:', game.name);
|
|
209
|
+
console.log('Plan name:', planName);
|
|
210
|
+
|
|
211
|
+
// Claude API request
|
|
212
|
+
const requestBody = JSON.stringify({
|
|
213
|
+
model: 'claude-sonnet-4-20250514',
|
|
214
|
+
max_tokens: 8000,
|
|
215
|
+
messages: [{
|
|
216
|
+
role: 'user',
|
|
217
|
+
content: prompt
|
|
218
|
+
}]
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const options = {
|
|
222
|
+
hostname: 'api.anthropic.com',
|
|
223
|
+
port: 443,
|
|
224
|
+
path: '/v1/messages',
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: {
|
|
227
|
+
'Content-Type': 'application/json',
|
|
228
|
+
'x-api-key': anthropic.api_key,
|
|
229
|
+
'anthropic-version': '2023-06-01'
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const req = https.request(options, (res) => {
|
|
234
|
+
let data = '';
|
|
235
|
+
|
|
236
|
+
res.on('data', (chunk) => {
|
|
237
|
+
data += chunk;
|
|
238
|
+
process.stdout.write('.');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
res.on('end', () => {
|
|
242
|
+
console.log('\n');
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const response = JSON.parse(data);
|
|
246
|
+
|
|
247
|
+
if (response.error) {
|
|
248
|
+
console.error('API Error:', response.error.message);
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Extract text content
|
|
253
|
+
const content = response.content || [];
|
|
254
|
+
let planContent = '';
|
|
255
|
+
|
|
256
|
+
for (const block of content) {
|
|
257
|
+
if (block.type === 'text') {
|
|
258
|
+
planContent += block.text;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!planContent) {
|
|
263
|
+
console.error('No content in response');
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Ensure plans directory exists
|
|
268
|
+
if (!fs.existsSync(plansDir)) {
|
|
269
|
+
fs.mkdirSync(plansDir, { recursive: true });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Save plan
|
|
273
|
+
fs.writeFileSync(outputPath, planContent);
|
|
274
|
+
|
|
275
|
+
console.log('Execution plan generated successfully!');
|
|
276
|
+
console.log('Output:', outputPath);
|
|
277
|
+
console.log('');
|
|
278
|
+
console.log('Next step - run in Claude Code:');
|
|
279
|
+
console.log(` Please proceed with implementing the game based on the plan in plans/${planName}.md`);
|
|
280
|
+
|
|
281
|
+
} catch (err) {
|
|
282
|
+
console.error('Error parsing response:', err.message);
|
|
283
|
+
console.error('Raw response:', data.substring(0, 1000));
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
req.on('error', (err) => {
|
|
290
|
+
console.error('Request error:', err.message);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
req.write(requestBody);
|
|
295
|
+
req.end();
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PRD Generation Script
|
|
5
|
+
*
|
|
6
|
+
* Uses Claude API (Opus 4.5) to generate a Product Requirements Document
|
|
7
|
+
* based on the concept mockup, assets, and game description.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node generate-prd.js
|
|
11
|
+
*
|
|
12
|
+
* Requires:
|
|
13
|
+
* - config.json with anthropic.api_key and game settings
|
|
14
|
+
* - public/{game_name}/concept.jpg (run generate-mockup.js first)
|
|
15
|
+
* - public/assets/{game_name}/Preview.jpg
|
|
16
|
+
* - public/assets/{game_name}/assets.json
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const https = require('https');
|
|
22
|
+
|
|
23
|
+
// Load config
|
|
24
|
+
const scriptDir = __dirname;
|
|
25
|
+
const projectRoot = path.join(scriptDir, '..');
|
|
26
|
+
const configPath = path.join(scriptDir, 'config.json');
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(configPath)) {
|
|
29
|
+
console.error('Error: config.json not found');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
34
|
+
const { anthropic, game } = config;
|
|
35
|
+
|
|
36
|
+
// Check config first, then env vars
|
|
37
|
+
const apiKey = (anthropic?.api_key && !anthropic.api_key.includes('YOUR_'))
|
|
38
|
+
? anthropic.api_key
|
|
39
|
+
: process.env.ANTHROPIC_API_KEY;
|
|
40
|
+
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
console.error('Error: Anthropic API key not found');
|
|
43
|
+
console.error('Set ANTHROPIC_API_KEY env var or configure scripts/config.json');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Use resolved key
|
|
48
|
+
anthropic.api_key = apiKey;
|
|
49
|
+
|
|
50
|
+
// Paths
|
|
51
|
+
const assetsDir = path.join(projectRoot, 'public', 'assets', game.name);
|
|
52
|
+
const conceptPath = path.join(projectRoot, 'public', game.name, 'concept.jpg');
|
|
53
|
+
const previewPath = path.join(assetsDir, 'Preview.jpg');
|
|
54
|
+
const assetsJsonPath = path.join(assetsDir, 'assets.json');
|
|
55
|
+
const outputPath = path.join(projectRoot, 'docs', 'prd.md');
|
|
56
|
+
|
|
57
|
+
// Check required files
|
|
58
|
+
const missingFiles = [];
|
|
59
|
+
if (!fs.existsSync(conceptPath)) missingFiles.push(conceptPath);
|
|
60
|
+
if (!fs.existsSync(previewPath)) missingFiles.push(previewPath);
|
|
61
|
+
if (!fs.existsSync(assetsJsonPath)) missingFiles.push(assetsJsonPath);
|
|
62
|
+
|
|
63
|
+
if (missingFiles.length > 0) {
|
|
64
|
+
console.error('Error: Missing required files:');
|
|
65
|
+
missingFiles.forEach(f => console.error(' - ' + f));
|
|
66
|
+
if (missingFiles.includes(conceptPath)) {
|
|
67
|
+
console.error('\nRun: node generate-mockup.js first');
|
|
68
|
+
}
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Read files
|
|
73
|
+
const conceptImage = fs.readFileSync(conceptPath).toString('base64');
|
|
74
|
+
const previewImage = fs.readFileSync(previewPath).toString('base64');
|
|
75
|
+
const assetsJson = fs.readFileSync(assetsJsonPath, 'utf-8');
|
|
76
|
+
|
|
77
|
+
// Load Three.js skills for context
|
|
78
|
+
const skillsDir = path.join(projectRoot, '.claude', 'skills');
|
|
79
|
+
let skillsContext = '';
|
|
80
|
+
if (fs.existsSync(skillsDir)) {
|
|
81
|
+
const skillFolders = fs.readdirSync(skillsDir);
|
|
82
|
+
for (const folder of skillFolders.slice(0, 3)) { // Just first 3 for context length
|
|
83
|
+
const skillPath = path.join(skillsDir, folder, 'SKILL.md');
|
|
84
|
+
if (fs.existsSync(skillPath)) {
|
|
85
|
+
const content = fs.readFileSync(skillPath, 'utf-8');
|
|
86
|
+
skillsContext += `\n\n### ${folder}\n${content.substring(0, 2000)}...`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Build prompt
|
|
92
|
+
const prompt = `${game.description}
|
|
93
|
+
|
|
94
|
+
I have concept mockups that reflect how the game looks (attached as concept.jpg).
|
|
95
|
+
I have also added a preview of the assets that are available (attached as Preview.jpg).
|
|
96
|
+
|
|
97
|
+
Here is the assets.json index of all available assets:
|
|
98
|
+
\`\`\`json
|
|
99
|
+
${assetsJson}
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
Create a comprehensive Game Design Document (PRD) with the following sections:
|
|
103
|
+
|
|
104
|
+
## 1. Summary
|
|
105
|
+
- Brief description of the game
|
|
106
|
+
- Target platform (browser-based)
|
|
107
|
+
- Key assumptions and constraints for V1
|
|
108
|
+
- Match length / session time
|
|
109
|
+
|
|
110
|
+
## 2. Technical Requirements
|
|
111
|
+
- Three.js version (r160 recommended)
|
|
112
|
+
- Delivery format (single HTML file preferred)
|
|
113
|
+
- Unit system (world units = meters)
|
|
114
|
+
- Required loaders (GLTFLoader)
|
|
115
|
+
- Valid materials and lights
|
|
116
|
+
|
|
117
|
+
## 3. Canvas & Viewport
|
|
118
|
+
- Internal resolution (e.g., 960×540)
|
|
119
|
+
- Aspect ratio handling (letterboxing if fixed)
|
|
120
|
+
- Background style
|
|
121
|
+
|
|
122
|
+
## 4. Visual Style & Art Direction
|
|
123
|
+
- Overall look description
|
|
124
|
+
- Color palette with hex codes and purposes
|
|
125
|
+
- Mood/atmosphere
|
|
126
|
+
- Camera style and defaults (pitch, yaw, zoom range)
|
|
127
|
+
- Lighting mood
|
|
128
|
+
|
|
129
|
+
## 5. Player Specifications
|
|
130
|
+
- Faction/player identity if applicable
|
|
131
|
+
- Unit types with appearance, size, role, and stats
|
|
132
|
+
- Starting setup (resources, units, position)
|
|
133
|
+
- Movement constraints
|
|
134
|
+
|
|
135
|
+
## 6. Physics & Movement
|
|
136
|
+
- Movement model (kinematic, physics-based)
|
|
137
|
+
- Gravity, speeds, collision approach
|
|
138
|
+
- Unit movement values table
|
|
139
|
+
|
|
140
|
+
## 7. Obstacles/Enemies
|
|
141
|
+
- Enemy types and behaviors
|
|
142
|
+
- Neutral obstacles using available assets
|
|
143
|
+
- Spawn timing and difficulty scaling
|
|
144
|
+
|
|
145
|
+
## 8. World & Environment
|
|
146
|
+
- Map layout and dimensions
|
|
147
|
+
- Resource/pickup nodes and their values
|
|
148
|
+
- Buildings/structures using available GLTF assets (reference specific asset names)
|
|
149
|
+
- Fallback primitives if assets fail to load
|
|
150
|
+
|
|
151
|
+
## 9. Collision & Scoring
|
|
152
|
+
- Collision shapes and approach
|
|
153
|
+
- Win/lose conditions
|
|
154
|
+
- Score system and point values
|
|
155
|
+
- High score storage (localStorage key)
|
|
156
|
+
|
|
157
|
+
## 10. Controls
|
|
158
|
+
- Complete input mapping table
|
|
159
|
+
- Desktop and touch/mobile controls
|
|
160
|
+
- Keyboard shortcuts
|
|
161
|
+
|
|
162
|
+
## 11. Game States
|
|
163
|
+
- Menu state (buttons, background)
|
|
164
|
+
- Playing state (active systems, UI shown)
|
|
165
|
+
- Paused state (trigger, display, frozen elements)
|
|
166
|
+
- Game Over state (display, stats, retry flow)
|
|
167
|
+
|
|
168
|
+
## 12. Game Feel & Juice (REQUIRED)
|
|
169
|
+
- Input response feedback (selection, commands)
|
|
170
|
+
- Animation timing table
|
|
171
|
+
- Screen effects (shake, flash, zoom, time dilation)
|
|
172
|
+
- Death sequences
|
|
173
|
+
- Milestone celebrations
|
|
174
|
+
- Idle life animations
|
|
175
|
+
|
|
176
|
+
## 13. UX Requirements
|
|
177
|
+
- Controls visibility
|
|
178
|
+
- Onboarding flow
|
|
179
|
+
- Readability considerations
|
|
180
|
+
- Forgiving mechanics
|
|
181
|
+
|
|
182
|
+
## 14. Out of Scope (V1)
|
|
183
|
+
- Features explicitly NOT included
|
|
184
|
+
|
|
185
|
+
## 15. Success Criteria
|
|
186
|
+
- Checklist of requirements the game must meet
|
|
187
|
+
|
|
188
|
+
Reference the assets.json for available models. Use specific asset names (e.g., "TownCenter_FirstAge_Level1.gltf") when specifying which assets to use for game elements.`;
|
|
189
|
+
|
|
190
|
+
console.log('Generating PRD with Claude API (Opus 4.5)...');
|
|
191
|
+
console.log('Game:', game.name);
|
|
192
|
+
|
|
193
|
+
// Claude API request
|
|
194
|
+
const requestBody = JSON.stringify({
|
|
195
|
+
model: 'claude-sonnet-4-20250514',
|
|
196
|
+
max_tokens: 16000,
|
|
197
|
+
messages: [{
|
|
198
|
+
role: 'user',
|
|
199
|
+
content: [
|
|
200
|
+
{
|
|
201
|
+
type: 'image',
|
|
202
|
+
source: {
|
|
203
|
+
type: 'base64',
|
|
204
|
+
media_type: 'image/jpeg',
|
|
205
|
+
data: conceptImage
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
type: 'image',
|
|
210
|
+
source: {
|
|
211
|
+
type: 'base64',
|
|
212
|
+
media_type: 'image/jpeg',
|
|
213
|
+
data: previewImage
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: 'text',
|
|
218
|
+
text: prompt
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}]
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const options = {
|
|
225
|
+
hostname: 'api.anthropic.com',
|
|
226
|
+
port: 443,
|
|
227
|
+
path: '/v1/messages',
|
|
228
|
+
method: 'POST',
|
|
229
|
+
headers: {
|
|
230
|
+
'Content-Type': 'application/json',
|
|
231
|
+
'x-api-key': anthropic.api_key,
|
|
232
|
+
'anthropic-version': '2023-06-01'
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const req = https.request(options, (res) => {
|
|
237
|
+
let data = '';
|
|
238
|
+
|
|
239
|
+
res.on('data', (chunk) => {
|
|
240
|
+
data += chunk;
|
|
241
|
+
process.stdout.write('.');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
res.on('end', () => {
|
|
245
|
+
console.log('\n');
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const response = JSON.parse(data);
|
|
249
|
+
|
|
250
|
+
if (response.error) {
|
|
251
|
+
console.error('API Error:', response.error.message);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Extract text content
|
|
256
|
+
const content = response.content || [];
|
|
257
|
+
let prdContent = '';
|
|
258
|
+
|
|
259
|
+
for (const block of content) {
|
|
260
|
+
if (block.type === 'text') {
|
|
261
|
+
prdContent += block.text;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!prdContent) {
|
|
266
|
+
console.error('No content in response');
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Ensure docs directory exists
|
|
271
|
+
const docsDir = path.join(projectRoot, 'docs');
|
|
272
|
+
if (!fs.existsSync(docsDir)) {
|
|
273
|
+
fs.mkdirSync(docsDir, { recursive: true });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Save PRD
|
|
277
|
+
fs.writeFileSync(outputPath, prdContent);
|
|
278
|
+
|
|
279
|
+
console.log('PRD generated successfully!');
|
|
280
|
+
console.log('Output:', outputPath);
|
|
281
|
+
console.log('Length:', prdContent.length, 'characters');
|
|
282
|
+
|
|
283
|
+
} catch (err) {
|
|
284
|
+
console.error('Error parsing response:', err.message);
|
|
285
|
+
console.error('Raw response:', data.substring(0, 1000));
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
req.on('error', (err) => {
|
|
292
|
+
console.error('Request error:', err.message);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
req.write(requestBody);
|
|
297
|
+
req.end();
|