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,283 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TDD Generation Script
|
|
5
|
+
*
|
|
6
|
+
* Uses Claude API (Opus 4.5) to generate a Technical Design Document
|
|
7
|
+
* based on the PRD, assets, and concept mockup.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node generate-tdd.js
|
|
11
|
+
*
|
|
12
|
+
* Requires:
|
|
13
|
+
* - config.json with anthropic.api_key and game settings
|
|
14
|
+
* - docs/prd.md (run generate-prd.js first)
|
|
15
|
+
* - public/{game_name}/concept.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 prdPath = path.join(projectRoot, 'docs', 'prd.md');
|
|
52
|
+
const conceptPath = path.join(projectRoot, 'public', game.name, 'concept.jpg');
|
|
53
|
+
const assetsJsonPath = path.join(projectRoot, 'public', 'assets', game.name, 'assets.json');
|
|
54
|
+
const previewPath = path.join(projectRoot, 'public', 'assets', game.name, 'Preview.jpg');
|
|
55
|
+
const outputPath = path.join(projectRoot, 'docs', 'tdd.md');
|
|
56
|
+
|
|
57
|
+
// Check required files
|
|
58
|
+
const missingFiles = [];
|
|
59
|
+
if (!fs.existsSync(prdPath)) missingFiles.push(prdPath + ' (run generate-prd.js first)');
|
|
60
|
+
if (!fs.existsSync(conceptPath)) missingFiles.push(conceptPath);
|
|
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
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Read files
|
|
70
|
+
const prdContent = fs.readFileSync(prdPath, 'utf-8');
|
|
71
|
+
const conceptImage = fs.readFileSync(conceptPath).toString('base64');
|
|
72
|
+
const assetsJson = fs.readFileSync(assetsJsonPath, 'utf-8');
|
|
73
|
+
|
|
74
|
+
// Load Three.js skills for context
|
|
75
|
+
const skillsDir = path.join(projectRoot, '.claude', 'skills');
|
|
76
|
+
let skillsContext = '';
|
|
77
|
+
if (fs.existsSync(skillsDir)) {
|
|
78
|
+
const skillFolders = fs.readdirSync(skillsDir);
|
|
79
|
+
for (const folder of skillFolders) {
|
|
80
|
+
const skillPath = path.join(skillsDir, folder, 'SKILL.md');
|
|
81
|
+
if (fs.existsSync(skillPath)) {
|
|
82
|
+
const content = fs.readFileSync(skillPath, 'utf-8');
|
|
83
|
+
// Include more skill content for TDD
|
|
84
|
+
skillsContext += `\n\n### ${folder}\n${content}`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Build prompt
|
|
90
|
+
const prompt = `Based on the following PRD, create a comprehensive Technical Design Document (TDD) that will ensure we can implement this game with minimal problems and maximum speed.
|
|
91
|
+
|
|
92
|
+
## PRD (Product Requirements Document):
|
|
93
|
+
${prdContent}
|
|
94
|
+
|
|
95
|
+
## Available Assets (assets.json):
|
|
96
|
+
\`\`\`json
|
|
97
|
+
${assetsJson}
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
## Three.js Skills Reference:
|
|
101
|
+
${skillsContext.substring(0, 30000)}
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Create a Technical Design Document with the following sections. Include COMPLETE, RUNNABLE code examples (not pseudocode):
|
|
106
|
+
|
|
107
|
+
## 1. Overview
|
|
108
|
+
- Technical stack summary table
|
|
109
|
+
- Reference materials list
|
|
110
|
+
|
|
111
|
+
## 2. Architecture Overview
|
|
112
|
+
- High-level module structure diagram (ASCII art)
|
|
113
|
+
- Game state flow diagram
|
|
114
|
+
|
|
115
|
+
## 3. Core Engine Systems
|
|
116
|
+
Include full implementation code for:
|
|
117
|
+
- Renderer setup with letterboxing
|
|
118
|
+
- Scene setup with fog and background
|
|
119
|
+
- RTS/appropriate Camera system class
|
|
120
|
+
- Lighting system setup
|
|
121
|
+
- Asset loading system with LoadingManager, GLTF loading, fallback primitives
|
|
122
|
+
- Asset manifest listing core assets to load
|
|
123
|
+
|
|
124
|
+
## 4. Entity Component System (ECS)
|
|
125
|
+
Include full code for:
|
|
126
|
+
- Core Entity class
|
|
127
|
+
- All component classes (Transform, Health, Movement, Combat, Collision, Selectable, etc.)
|
|
128
|
+
- Unit and building stats configuration objects
|
|
129
|
+
- Entity Factory with creation methods
|
|
130
|
+
|
|
131
|
+
## 5. Game Systems
|
|
132
|
+
Include full implementation code for each:
|
|
133
|
+
- Entity Manager (add, remove, query)
|
|
134
|
+
- Selection System (click, box select, visual feedback)
|
|
135
|
+
- Command System (move, attack, context-sensitive commands)
|
|
136
|
+
- Movement System (steering, separation, turn rate)
|
|
137
|
+
- Combat System (melee, ranged, projectiles, damage application)
|
|
138
|
+
- Economy/Resource System (gathering, dropoff, training queues)
|
|
139
|
+
- AI System (state machine, economy, military, raids)
|
|
140
|
+
|
|
141
|
+
## 6. Visual Effects System
|
|
142
|
+
Include code for:
|
|
143
|
+
- Effects Manager class
|
|
144
|
+
- Screen shake implementation
|
|
145
|
+
- Time dilation
|
|
146
|
+
- Floating text
|
|
147
|
+
- Particle effects (sparks, debris)
|
|
148
|
+
- Death sequences (unit collapse, building destruction)
|
|
149
|
+
|
|
150
|
+
## 7. UI System
|
|
151
|
+
Include complete:
|
|
152
|
+
- HTML structure
|
|
153
|
+
- Full CSS styles
|
|
154
|
+
- HUD elements
|
|
155
|
+
- Menu screens (main, pause, game over)
|
|
156
|
+
- Build palette if applicable
|
|
157
|
+
- Mobile touch controls
|
|
158
|
+
|
|
159
|
+
## 8. Main Game Loop
|
|
160
|
+
Include full implementation:
|
|
161
|
+
- Game State enum
|
|
162
|
+
- Complete Game class with all methods
|
|
163
|
+
- Animation loop
|
|
164
|
+
- Win/lose condition checking
|
|
165
|
+
- HUD updates
|
|
166
|
+
|
|
167
|
+
## 9. Implementation Phases
|
|
168
|
+
Ordered list with:
|
|
169
|
+
- Phase name and priority (Critical/Important/Polish)
|
|
170
|
+
- What to implement
|
|
171
|
+
- Dependencies
|
|
172
|
+
|
|
173
|
+
## 10. Performance Considerations
|
|
174
|
+
- Rendering optimizations
|
|
175
|
+
- Game logic optimizations
|
|
176
|
+
- Memory management tips
|
|
177
|
+
|
|
178
|
+
## 11. Testing Checklist
|
|
179
|
+
- All success criteria as checkboxes
|
|
180
|
+
|
|
181
|
+
## 12. Appendix
|
|
182
|
+
- Color palette reference table
|
|
183
|
+
- Animation timing reference table
|
|
184
|
+
- Unit stats reference table
|
|
185
|
+
- Building stats reference table
|
|
186
|
+
|
|
187
|
+
All code should use Three.js r160 APIs and follow best practices.`;
|
|
188
|
+
|
|
189
|
+
console.log('Generating TDD with Claude API (Opus 4.5)...');
|
|
190
|
+
console.log('Game:', game.name);
|
|
191
|
+
console.log('This may take a minute due to the comprehensive output...');
|
|
192
|
+
|
|
193
|
+
// Claude API request
|
|
194
|
+
const requestBody = JSON.stringify({
|
|
195
|
+
model: 'claude-sonnet-4-20250514',
|
|
196
|
+
max_tokens: 64000,
|
|
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: 'text',
|
|
210
|
+
text: prompt
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
}]
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const options = {
|
|
217
|
+
hostname: 'api.anthropic.com',
|
|
218
|
+
port: 443,
|
|
219
|
+
path: '/v1/messages',
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers: {
|
|
222
|
+
'Content-Type': 'application/json',
|
|
223
|
+
'x-api-key': anthropic.api_key,
|
|
224
|
+
'anthropic-version': '2023-06-01'
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const req = https.request(options, (res) => {
|
|
229
|
+
let data = '';
|
|
230
|
+
|
|
231
|
+
res.on('data', (chunk) => {
|
|
232
|
+
data += chunk;
|
|
233
|
+
process.stdout.write('.');
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
res.on('end', () => {
|
|
237
|
+
console.log('\n');
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const response = JSON.parse(data);
|
|
241
|
+
|
|
242
|
+
if (response.error) {
|
|
243
|
+
console.error('API Error:', response.error.message);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Extract text content
|
|
248
|
+
const content = response.content || [];
|
|
249
|
+
let tddContent = '';
|
|
250
|
+
|
|
251
|
+
for (const block of content) {
|
|
252
|
+
if (block.type === 'text') {
|
|
253
|
+
tddContent += block.text;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!tddContent) {
|
|
258
|
+
console.error('No content in response');
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Save TDD
|
|
263
|
+
fs.writeFileSync(outputPath, tddContent);
|
|
264
|
+
|
|
265
|
+
console.log('TDD generated successfully!');
|
|
266
|
+
console.log('Output:', outputPath);
|
|
267
|
+
console.log('Length:', tddContent.length, 'characters');
|
|
268
|
+
|
|
269
|
+
} catch (err) {
|
|
270
|
+
console.error('Error parsing response:', err.message);
|
|
271
|
+
console.error('Raw response:', data.substring(0, 1000));
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
req.on('error', (err) => {
|
|
278
|
+
console.error('Request error:', err.message);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
req.write(requestBody);
|
|
283
|
+
req.end();
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Full Pipeline Orchestration Script
|
|
5
|
+
*
|
|
6
|
+
* Runs the complete game generation pipeline:
|
|
7
|
+
* 1. Generate assets.json (if needed)
|
|
8
|
+
* 2. Generate concept mockup
|
|
9
|
+
* 3. Generate PRD
|
|
10
|
+
* 4. Generate TDD
|
|
11
|
+
* 5. Generate execution plan
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node pipeline.js [--skip-mockup] [--skip-to=step]
|
|
15
|
+
*
|
|
16
|
+
* Options:
|
|
17
|
+
* --skip-mockup Skip mockup generation (use existing concept.jpg)
|
|
18
|
+
* --skip-to=step Skip to a specific step (assets, mockup, prd, tdd, plan)
|
|
19
|
+
* --plan-name=name Use specific plan name instead of random
|
|
20
|
+
*
|
|
21
|
+
* Requires:
|
|
22
|
+
* - config.json with API keys and game settings
|
|
23
|
+
* - Assets in public/assets/{game_name}/
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const { execSync, spawn } = require('child_process');
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
|
|
30
|
+
// Parse arguments
|
|
31
|
+
const args = process.argv.slice(2);
|
|
32
|
+
const skipMockup = args.includes('--skip-mockup');
|
|
33
|
+
const skipToArg = args.find(a => a.startsWith('--skip-to='));
|
|
34
|
+
const skipTo = skipToArg ? skipToArg.split('=')[1] : null;
|
|
35
|
+
const planNameArg = args.find(a => a.startsWith('--plan-name='));
|
|
36
|
+
const planName = planNameArg ? planNameArg.split('=')[1] : null;
|
|
37
|
+
|
|
38
|
+
// Script directory
|
|
39
|
+
const scriptDir = __dirname;
|
|
40
|
+
const projectRoot = path.join(scriptDir, '..');
|
|
41
|
+
const configPath = path.join(scriptDir, 'config.json');
|
|
42
|
+
|
|
43
|
+
// Check config
|
|
44
|
+
if (!fs.existsSync(configPath)) {
|
|
45
|
+
console.error('Error: config.json not found');
|
|
46
|
+
console.error('Copy config.example.json to config.json and configure it');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
51
|
+
const gameName = config.game?.name;
|
|
52
|
+
|
|
53
|
+
if (!gameName) {
|
|
54
|
+
console.error('Error: game.name not set in config.json');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
59
|
+
console.log('ā THREE.JS GAME GENERATION PIPELINE ā');
|
|
60
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log('Game:', gameName);
|
|
63
|
+
console.log('Description:', config.game?.description?.substring(0, 60) + '...');
|
|
64
|
+
console.log('');
|
|
65
|
+
|
|
66
|
+
// Steps
|
|
67
|
+
const steps = ['assets', 'mockup', 'prd', 'tdd', 'plan'];
|
|
68
|
+
const stepIndex = skipTo ? steps.indexOf(skipTo) : 0;
|
|
69
|
+
|
|
70
|
+
if (skipTo && stepIndex === -1) {
|
|
71
|
+
console.error('Invalid --skip-to value. Options:', steps.join(', '));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Run a script and wait for completion
|
|
76
|
+
function runScript(scriptName, args = []) {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
console.log(`\n${'ā'.repeat(60)}`);
|
|
79
|
+
console.log(`Running: ${scriptName} ${args.join(' ')}`);
|
|
80
|
+
console.log('ā'.repeat(60) + '\n');
|
|
81
|
+
|
|
82
|
+
const child = spawn('node', [path.join(scriptDir, scriptName), ...args], {
|
|
83
|
+
cwd: projectRoot,
|
|
84
|
+
stdio: 'inherit'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
child.on('close', (code) => {
|
|
88
|
+
if (code === 0) {
|
|
89
|
+
resolve();
|
|
90
|
+
} else {
|
|
91
|
+
reject(new Error(`${scriptName} exited with code ${code}`));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
child.on('error', reject);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check if file exists
|
|
100
|
+
function checkFile(filePath, description) {
|
|
101
|
+
if (fs.existsSync(filePath)) {
|
|
102
|
+
console.log(`ā ${description}: ${path.basename(filePath)}`);
|
|
103
|
+
return true;
|
|
104
|
+
} else {
|
|
105
|
+
console.log(`ā ${description}: NOT FOUND`);
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Main pipeline
|
|
111
|
+
async function runPipeline() {
|
|
112
|
+
try {
|
|
113
|
+
const assetsDir = path.join(projectRoot, 'public', 'assets', gameName);
|
|
114
|
+
|
|
115
|
+
// Step 1: Check/Generate assets.json
|
|
116
|
+
if (stepIndex <= 0) {
|
|
117
|
+
console.log('\nš¦ STEP 1: Asset Index');
|
|
118
|
+
console.log('ā'.repeat(40));
|
|
119
|
+
|
|
120
|
+
const assetsJsonPath = path.join(assetsDir, 'assets.json');
|
|
121
|
+
const previewPath = path.join(assetsDir, 'Preview.jpg');
|
|
122
|
+
|
|
123
|
+
// Check for assets directory
|
|
124
|
+
if (!fs.existsSync(assetsDir)) {
|
|
125
|
+
console.error(`\nError: Assets directory not found: ${assetsDir}`);
|
|
126
|
+
console.error('Please add your assets first.');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check for preview image
|
|
131
|
+
if (!checkFile(previewPath, 'Preview image')) {
|
|
132
|
+
// Try alternative names
|
|
133
|
+
const altNames = ['preview.jpg', 'Preview.png', 'preview.png', 'preview.jpeg'];
|
|
134
|
+
let found = false;
|
|
135
|
+
for (const alt of altNames) {
|
|
136
|
+
const altPath = path.join(assetsDir, alt);
|
|
137
|
+
if (fs.existsSync(altPath)) {
|
|
138
|
+
console.log(` Found alternative: ${alt}, renaming to Preview.jpg`);
|
|
139
|
+
fs.renameSync(altPath, previewPath);
|
|
140
|
+
found = true;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!found) {
|
|
145
|
+
console.error('\nWarning: No preview image found. Mockup generation may fail.');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Generate assets.json if needed
|
|
150
|
+
if (!fs.existsSync(assetsJsonPath)) {
|
|
151
|
+
await runScript('generate-assets-json.js', [gameName]);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(`ā assets.json already exists`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Step 2: Generate mockup
|
|
158
|
+
if (stepIndex <= 1 && !skipMockup) {
|
|
159
|
+
console.log('\nšØ STEP 2: Concept Mockup');
|
|
160
|
+
console.log('ā'.repeat(40));
|
|
161
|
+
|
|
162
|
+
const conceptPath = path.join(projectRoot, 'public', gameName, 'concept.jpg');
|
|
163
|
+
|
|
164
|
+
if (fs.existsSync(conceptPath)) {
|
|
165
|
+
console.log('ā concept.jpg already exists');
|
|
166
|
+
console.log(' Use --skip-mockup to keep it, or delete to regenerate');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
await runScript('generate-mockup.js');
|
|
170
|
+
} else if (skipMockup) {
|
|
171
|
+
console.log('\nšØ STEP 2: Concept Mockup (SKIPPED)');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Step 3: Generate PRD
|
|
175
|
+
if (stepIndex <= 2) {
|
|
176
|
+
console.log('\nš STEP 3: Product Requirements Document');
|
|
177
|
+
console.log('ā'.repeat(40));
|
|
178
|
+
|
|
179
|
+
await runScript('generate-prd.js');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Step 4: Generate TDD
|
|
183
|
+
if (stepIndex <= 3) {
|
|
184
|
+
console.log('\nš§ STEP 4: Technical Design Document');
|
|
185
|
+
console.log('ā'.repeat(40));
|
|
186
|
+
|
|
187
|
+
await runScript('generate-tdd.js');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Step 5: Generate Plan
|
|
191
|
+
if (stepIndex <= 4) {
|
|
192
|
+
console.log('\nš STEP 5: Execution Plan');
|
|
193
|
+
console.log('ā'.repeat(40));
|
|
194
|
+
|
|
195
|
+
const planArgs = planName ? [planName] : [];
|
|
196
|
+
await runScript('generate-plan.js', planArgs);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Summary
|
|
200
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
201
|
+
console.log('ā
PIPELINE COMPLETE');
|
|
202
|
+
console.log('ā'.repeat(60));
|
|
203
|
+
console.log('');
|
|
204
|
+
console.log('Generated files:');
|
|
205
|
+
checkFile(path.join(assetsDir, 'assets.json'), ' assets.json');
|
|
206
|
+
checkFile(path.join(projectRoot, 'public', gameName, 'concept.jpg'), ' concept.jpg');
|
|
207
|
+
checkFile(path.join(projectRoot, 'docs', 'prd.md'), ' prd.md');
|
|
208
|
+
checkFile(path.join(projectRoot, 'docs', 'tdd.md'), ' tdd.md');
|
|
209
|
+
|
|
210
|
+
// Find the plan file
|
|
211
|
+
const plansDir = path.join(projectRoot, 'plans');
|
|
212
|
+
if (fs.existsSync(plansDir)) {
|
|
213
|
+
const plans = fs.readdirSync(plansDir).filter(f => f.endsWith('.md'));
|
|
214
|
+
if (plans.length > 0) {
|
|
215
|
+
const latestPlan = plans[plans.length - 1];
|
|
216
|
+
console.log(` plan: ${latestPlan}`);
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log('Next step - run in Claude Code:');
|
|
219
|
+
console.log(` Please proceed with implementing the game based on the plan in plans/${latestPlan}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.error('\nā Pipeline failed:', err.message);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
runPipeline();
|