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.
Files changed (39) hide show
  1. package/README.md +97 -0
  2. package/bin/cli.js +370 -0
  3. package/package.json +29 -0
  4. package/template/.claude/skills/threejs-animation/SKILL.md +552 -0
  5. package/template/.claude/skills/threejs-fundamentals/SKILL.md +488 -0
  6. package/template/.claude/skills/threejs-geometry/SKILL.md +548 -0
  7. package/template/.claude/skills/threejs-interaction/SKILL.md +660 -0
  8. package/template/.claude/skills/threejs-lighting/SKILL.md +481 -0
  9. package/template/.claude/skills/threejs-loaders/SKILL.md +623 -0
  10. package/template/.claude/skills/threejs-materials/SKILL.md +520 -0
  11. package/template/.claude/skills/threejs-postprocessing/SKILL.md +602 -0
  12. package/template/.claude/skills/threejs-shaders/SKILL.md +642 -0
  13. package/template/.claude/skills/threejs-textures/SKILL.md +628 -0
  14. package/template/.codex/skills/threejs-animation/SKILL.md +552 -0
  15. package/template/.codex/skills/threejs-fundamentals/SKILL.md +488 -0
  16. package/template/.codex/skills/threejs-geometry/SKILL.md +548 -0
  17. package/template/.codex/skills/threejs-interaction/SKILL.md +660 -0
  18. package/template/.codex/skills/threejs-lighting/SKILL.md +481 -0
  19. package/template/.codex/skills/threejs-loaders/SKILL.md +623 -0
  20. package/template/.codex/skills/threejs-materials/SKILL.md +520 -0
  21. package/template/.codex/skills/threejs-postprocessing/SKILL.md +602 -0
  22. package/template/.codex/skills/threejs-shaders/SKILL.md +642 -0
  23. package/template/.codex/skills/threejs-textures/SKILL.md +628 -0
  24. package/template/README.md +352 -0
  25. package/template/docs/.gitkeep +0 -0
  26. package/template/plans/.gitkeep +0 -0
  27. package/template/prompts/01-mockup-generation.md +44 -0
  28. package/template/prompts/02-prd-generation.md +119 -0
  29. package/template/prompts/03-tdd-generation.md +127 -0
  30. package/template/prompts/04-execution-plan.md +89 -0
  31. package/template/prompts/05-implementation.md +61 -0
  32. package/template/public/assets/.gitkeep +0 -0
  33. package/template/scripts/config.example.json +12 -0
  34. package/template/scripts/generate-assets-json.js +149 -0
  35. package/template/scripts/generate-mockup.js +197 -0
  36. package/template/scripts/generate-plan.js +295 -0
  37. package/template/scripts/generate-prd.js +297 -0
  38. package/template/scripts/generate-tdd.js +283 -0
  39. 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();