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,89 @@
1
+ # Execution Plan Generation Prompt
2
+
3
+ ## Tool
4
+ LLM with Three.js skills enabled (Claude Code, Cursor, etc.)
5
+
6
+ **IMPORTANT:** Start a NEW CHAT with clear context
7
+
8
+ ## Files to Attach
9
+ - `docs/prd.md` - Product requirements
10
+ - `docs/tdd.md` - Technical design
11
+ - `public/assets/{game_name}/assets.json` - Asset index
12
+
13
+ ## Prompt Template
14
+
15
+ ```
16
+ Implement the game defined in docs/prd.md adhering to the technical design
17
+ in docs/tdd.md.
18
+
19
+ Note the assets index in public/assets/{game_name}/assets.json.
20
+
21
+ Use the Three.js skills for implementation patterns.
22
+
23
+ Create an execution plan that:
24
+
25
+ ## Overview
26
+ - Target file(s) to create
27
+ - Key references to PRD and TDD sections
28
+ - Asset path format
29
+
30
+ ## Implementation Phases
31
+ For each phase, specify:
32
+ - Phase name and priority (Critical/Important/Polish)
33
+ - What to implement
34
+ - Key code sections from TDD to use
35
+ - Verification steps
36
+
37
+ Suggested phases:
38
+ 1. Core Engine (Critical) - Scene, camera, lighting, ground
39
+ 2. Asset Loading (Critical) - GLTF loader, fallbacks
40
+ 3. ECS Architecture (Critical) - Entities, components, manager
41
+ 4. Selection System (Critical) - Click/box select, visuals
42
+ 5. Command System (Critical) - Move, attack commands
43
+ 6. Movement System (Critical) - Unit movement, collision
44
+ 7. Combat System (Critical) - Damage, death
45
+ 8. Economy/Resource System (Important) - If applicable
46
+ 9. AI System (Important) - Enemy behavior
47
+ 10. UI & Game States (Important) - Menus, HUD
48
+ 11. Effects (Polish) - Juice, particles
49
+ 12. Mobile/Polish (Polish) - Touch controls, onboarding
50
+
51
+ ## HTML File Structure
52
+ Show the expected structure:
53
+ - DOCTYPE, head, meta tags
54
+ - Style block organization
55
+ - Import map for Three.js
56
+ - Script module organization
57
+
58
+ ## Map Setup
59
+ - Initial entity positions
60
+ - Resource placement
61
+ - Obstacle placement
62
+
63
+ ## Verification Checklist
64
+ From PRD success criteria, list what must work:
65
+ - [ ] Game loads without errors
66
+ - [ ] [Other criteria...]
67
+
68
+ ## Estimated Scope
69
+ - Approximate lines of code
70
+ - Expected complexity
71
+ ```
72
+
73
+ ## Output
74
+ Save to: `plans/{descriptive-name}.md`
75
+
76
+ **Naming convention:** Use a memorable name like:
77
+ - `plans/initial-implementation.md`
78
+ - `plans/core-gameplay.md`
79
+ - Or use a random word generator for unique names
80
+
81
+ ## Next Step
82
+ After saving the plan, proceed to implementation:
83
+
84
+ ```
85
+ Please proceed with implementing the game based on the plan in
86
+ plans/{plan-name}.md
87
+
88
+ Use the Three.js skills for reference.
89
+ ```
@@ -0,0 +1,61 @@
1
+ # Implementation Prompt
2
+
3
+ ## Tool
4
+ Claude Code / Cursor with Three.js skills enabled
5
+
6
+ ## Files to Attach
7
+ - `plans/{plan-name}.md` - The execution plan
8
+
9
+ ## Prompt Template
10
+
11
+ ```
12
+ Please proceed with implementing the game based on the plan in
13
+ plans/{plan-name}.md
14
+
15
+ Use the Three.js skills for reference.
16
+ ```
17
+
18
+ ## What to Expect
19
+ The AI will:
20
+ 1. Read the plan and understand the phased approach
21
+ 2. Create the HTML file structure
22
+ 3. Implement each phase sequentially
23
+ 4. Test and verify as it goes
24
+
25
+ ## During Implementation
26
+ You may need to:
27
+ - Answer clarifying questions
28
+ - Approve file creations
29
+ - Test the game in browser and report issues
30
+ - Request adjustments to specific features
31
+
32
+ ## Common Follow-up Prompts
33
+
34
+ **If something doesn't work:**
35
+ ```
36
+ The [feature] isn't working correctly. When I [action], it [actual behavior]
37
+ instead of [expected behavior]. Can you fix this?
38
+ ```
39
+
40
+ **To add a feature:**
41
+ ```
42
+ Can you add [feature] to the game? It should [description of behavior].
43
+ ```
44
+
45
+ **To improve performance:**
46
+ ```
47
+ The game is running slowly. Can you optimize [specific system/area]?
48
+ ```
49
+
50
+ **To adjust visuals:**
51
+ ```
52
+ Can you adjust the [visual element] to be more [description]?
53
+ ```
54
+
55
+ **To test specific functionality:**
56
+ ```
57
+ Can you verify that [specific feature] works by [test steps]?
58
+ ```
59
+
60
+ ## Verification
61
+ After implementation, test all items in the plan's verification checklist.
File without changes
@@ -0,0 +1,12 @@
1
+ {
2
+ "google_ai_studio": {
3
+ "api_key": "YOUR_GOOGLE_AI_STUDIO_API_KEY"
4
+ },
5
+ "anthropic": {
6
+ "api_key": "YOUR_ANTHROPIC_API_KEY"
7
+ },
8
+ "game": {
9
+ "name": "your_game_name",
10
+ "description": "A 3D real-time strategy game set in a medieval fantasy world where players gather resources, build bases, and destroy the enemy."
11
+ }
12
+ }
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Asset Index Generator
5
+ *
6
+ * Generates an assets.json file that indexes all assets in a game's asset folder.
7
+ *
8
+ * Usage:
9
+ * node generate-assets-json.js <game_name>
10
+ *
11
+ * Example:
12
+ * node generate-assets-json.js medieval
13
+ *
14
+ * This will scan public/assets/medieval/ and create public/assets/medieval/assets.json
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ // Get game name from command line argument
21
+ const gameName = process.argv[2];
22
+
23
+ if (!gameName) {
24
+ console.error('Usage: node generate-assets-json.js <game_name>');
25
+ console.error('Example: node generate-assets-json.js medieval');
26
+ process.exit(1);
27
+ }
28
+
29
+ // Paths
30
+ const scriptDir = __dirname;
31
+ const projectRoot = path.join(scriptDir, '..');
32
+ const assetsDir = path.join(projectRoot, 'public', 'assets', gameName);
33
+ const outputPath = path.join(assetsDir, 'assets.json');
34
+
35
+ // Check if assets directory exists
36
+ if (!fs.existsSync(assetsDir)) {
37
+ console.error(`Error: Assets directory not found: ${assetsDir}`);
38
+ console.error(`Please create the directory and add your assets first.`);
39
+ process.exit(1);
40
+ }
41
+
42
+ // File extensions to index
43
+ const SUPPORTED_EXTENSIONS = {
44
+ '3d': ['.gltf', '.glb', '.obj', '.fbx'],
45
+ 'images': ['.png', '.jpg', '.jpeg', '.webp', '.gif'],
46
+ 'audio': ['.mp3', '.wav', '.ogg'],
47
+ 'other': ['.json', '.txt']
48
+ };
49
+
50
+ // Get category from extension
51
+ function getCategory(ext) {
52
+ ext = ext.toLowerCase();
53
+
54
+ if (SUPPORTED_EXTENSIONS['3d'].includes(ext)) {
55
+ return ext === '.gltf' || ext === '.glb' ? 'glTF' : '3D';
56
+ }
57
+ if (SUPPORTED_EXTENSIONS.images.includes(ext)) {
58
+ return 'PNG'; // Keep as PNG for consistency with existing format
59
+ }
60
+ if (SUPPORTED_EXTENSIONS.audio.includes(ext)) {
61
+ return 'Audio';
62
+ }
63
+ return 'Other';
64
+ }
65
+
66
+ // Recursively scan directory for assets
67
+ function scanDirectory(dir, relativeTo) {
68
+ const assets = [];
69
+
70
+ if (!fs.existsSync(dir)) {
71
+ return assets;
72
+ }
73
+
74
+ const items = fs.readdirSync(dir, { withFileTypes: true });
75
+
76
+ for (const item of items) {
77
+ const fullPath = path.join(dir, item.name);
78
+
79
+ if (item.isDirectory()) {
80
+ // Recursively scan subdirectories
81
+ assets.push(...scanDirectory(fullPath, relativeTo));
82
+ } else if (item.isFile()) {
83
+ const ext = path.extname(item.name).toLowerCase();
84
+
85
+ // Skip if not a supported extension or is the output file itself
86
+ if (item.name === 'assets.json') continue;
87
+
88
+ const allExtensions = [
89
+ ...SUPPORTED_EXTENSIONS['3d'],
90
+ ...SUPPORTED_EXTENSIONS.images,
91
+ ...SUPPORTED_EXTENSIONS.audio
92
+ ];
93
+
94
+ if (!allExtensions.includes(ext)) continue;
95
+
96
+ const relativePath = path.relative(relativeTo, fullPath);
97
+ const category = getCategory(ext);
98
+
99
+ assets.push({
100
+ name: item.name,
101
+ path: `public/assets/${gameName}/${relativePath.replace(/\\/g, '/')}`,
102
+ relativePath: relativePath.replace(/\\/g, '/'),
103
+ category: category,
104
+ extension: ext,
105
+ focusGlTF: ext === '.gltf' || ext === '.glb'
106
+ });
107
+ }
108
+ }
109
+
110
+ return assets;
111
+ }
112
+
113
+ // Main execution
114
+ console.log(`Scanning assets in: ${assetsDir}`);
115
+
116
+ const assets = scanDirectory(assetsDir, assetsDir);
117
+
118
+ // Sort assets by name
119
+ assets.sort((a, b) => a.name.localeCompare(b.name));
120
+
121
+ // Count by category
122
+ const categoryCounts = {};
123
+ for (const asset of assets) {
124
+ categoryCounts[asset.category] = (categoryCounts[asset.category] || 0) + 1;
125
+ }
126
+
127
+ // Count glTF assets
128
+ const glTFCount = assets.filter(a => a.focusGlTF).length;
129
+
130
+ // Build output
131
+ const output = {
132
+ metadata: {
133
+ generatedAt: new Date().toISOString(),
134
+ root: `public/assets/${gameName}`,
135
+ totalAssets: assets.length,
136
+ glTFAssetCount: glTFCount,
137
+ categories: categoryCounts
138
+ },
139
+ assets: assets
140
+ };
141
+
142
+ // Write output
143
+ fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
144
+
145
+ console.log(`\nGenerated: ${outputPath}`);
146
+ console.log(`\nSummary:`);
147
+ console.log(` Total assets: ${assets.length}`);
148
+ console.log(` glTF/GLB models: ${glTFCount}`);
149
+ console.log(` Categories:`, categoryCounts);
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Mockup Generation Script
5
+ *
6
+ * Uses Google AI Studio (Gemini) to generate a game concept mockup
7
+ * based on the asset preview and description.
8
+ *
9
+ * Usage:
10
+ * node generate-mockup.js
11
+ *
12
+ * Requires:
13
+ * - config.json with google_ai_studio.api_key and game settings
14
+ * - public/assets/{game_name}/Preview.jpg
15
+ * - public/assets/{game_name}/assets.json
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const https = require('https');
21
+
22
+ // Load config
23
+ const scriptDir = __dirname;
24
+ const projectRoot = path.join(scriptDir, '..');
25
+ const configPath = path.join(scriptDir, 'config.json');
26
+
27
+ if (!fs.existsSync(configPath)) {
28
+ console.error('Error: config.json not found');
29
+ console.error('Copy config.example.json to config.json and add your API keys');
30
+ process.exit(1);
31
+ }
32
+
33
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
34
+ const { google_ai_studio, game } = config;
35
+
36
+ // Check config first, then env vars
37
+ const apiKey = (google_ai_studio?.api_key && !google_ai_studio.api_key.includes('YOUR_'))
38
+ ? google_ai_studio.api_key
39
+ : process.env.GOOGLE_API_KEY || process.env.GOOGLE_AI_STUDIO_API_KEY;
40
+
41
+ if (!apiKey) {
42
+ console.error('Error: Google AI Studio API key not found');
43
+ console.error('Set GOOGLE_API_KEY env var or configure scripts/config.json');
44
+ process.exit(1);
45
+ }
46
+
47
+ // Use resolved key
48
+ google_ai_studio.api_key = apiKey;
49
+
50
+ // Paths
51
+ const assetsDir = path.join(projectRoot, 'public', 'assets', game.name);
52
+ const previewPath = path.join(assetsDir, 'Preview.jpg');
53
+ const assetsJsonPath = path.join(assetsDir, 'assets.json');
54
+ const outputDir = path.join(projectRoot, 'public', game.name);
55
+ const outputPath = path.join(outputDir, 'concept.jpg');
56
+
57
+ // Check required files
58
+ if (!fs.existsSync(previewPath)) {
59
+ console.error(`Error: Preview image not found: ${previewPath}`);
60
+ process.exit(1);
61
+ }
62
+
63
+ if (!fs.existsSync(assetsJsonPath)) {
64
+ console.error(`Error: assets.json not found: ${assetsJsonPath}`);
65
+ console.error('Run: node generate-assets-json.js ' + game.name);
66
+ process.exit(1);
67
+ }
68
+
69
+ // Read files
70
+ const previewImage = fs.readFileSync(previewPath);
71
+ const previewBase64 = previewImage.toString('base64');
72
+ const assetsJson = JSON.parse(fs.readFileSync(assetsJsonPath, 'utf-8'));
73
+
74
+ // Build asset summary (just glTF names for brevity)
75
+ const assetNames = assetsJson.assets
76
+ .filter(a => a.focusGlTF)
77
+ .map(a => a.name.replace('.gltf', ''))
78
+ .join(', ');
79
+
80
+ // Build prompt
81
+ const prompt = `You are a game concept artist. Based on the attached preview image showing available 3D assets and the following game description, create a detailed mockup image showing how this game would look during gameplay.
82
+
83
+ GAME DESCRIPTION:
84
+ ${game.description}
85
+
86
+ AVAILABLE ASSETS (3D models):
87
+ ${assetNames}
88
+
89
+ The mockup should show:
90
+ 1. An actual gameplay scene (not a title screen)
91
+ 2. Multiple game elements arranged naturally (buildings, units, terrain, resources)
92
+ 3. Appropriate UI elements for this game type (health bars, resource counters, minimap, etc.)
93
+ 4. The camera perspective that best suits this game type
94
+ 5. The visual style matching the provided assets
95
+
96
+ Create a polished, professional game screenshot mockup that shows the core gameplay loop in action.`;
97
+
98
+ console.log('Generating mockup with Google AI Studio...');
99
+ console.log('Game:', game.name);
100
+ console.log('Description:', game.description);
101
+
102
+ // Gemini API request
103
+ const requestBody = JSON.stringify({
104
+ contents: [{
105
+ parts: [
106
+ {
107
+ text: prompt
108
+ },
109
+ {
110
+ inline_data: {
111
+ mime_type: 'image/jpeg',
112
+ data: previewBase64
113
+ }
114
+ }
115
+ ]
116
+ }],
117
+ generationConfig: {
118
+ responseModalities: ['image', 'text'],
119
+ responseMimeType: 'image/jpeg'
120
+ }
121
+ });
122
+
123
+ const options = {
124
+ hostname: 'generativelanguage.googleapis.com',
125
+ port: 443,
126
+ path: `/v1beta/models/gemini-2.0-flash-exp:generateContent?key=${google_ai_studio.api_key}`,
127
+ method: 'POST',
128
+ headers: {
129
+ 'Content-Type': 'application/json',
130
+ 'Content-Length': Buffer.byteLength(requestBody)
131
+ }
132
+ };
133
+
134
+ const req = https.request(options, (res) => {
135
+ let data = '';
136
+
137
+ res.on('data', (chunk) => {
138
+ data += chunk;
139
+ });
140
+
141
+ res.on('end', () => {
142
+ try {
143
+ const response = JSON.parse(data);
144
+
145
+ if (response.error) {
146
+ console.error('API Error:', response.error.message);
147
+ process.exit(1);
148
+ }
149
+
150
+ // Find image in response
151
+ const candidates = response.candidates || [];
152
+ let imageData = null;
153
+
154
+ for (const candidate of candidates) {
155
+ const parts = candidate.content?.parts || [];
156
+ for (const part of parts) {
157
+ if (part.inline_data?.mime_type?.startsWith('image/')) {
158
+ imageData = part.inline_data.data;
159
+ break;
160
+ }
161
+ }
162
+ if (imageData) break;
163
+ }
164
+
165
+ if (!imageData) {
166
+ console.error('No image generated in response');
167
+ console.error('Response:', JSON.stringify(response, null, 2));
168
+ process.exit(1);
169
+ }
170
+
171
+ // Ensure output directory exists
172
+ if (!fs.existsSync(outputDir)) {
173
+ fs.mkdirSync(outputDir, { recursive: true });
174
+ }
175
+
176
+ // Save image
177
+ const imageBuffer = Buffer.from(imageData, 'base64');
178
+ fs.writeFileSync(outputPath, imageBuffer);
179
+
180
+ console.log('\nMockup generated successfully!');
181
+ console.log('Output:', outputPath);
182
+
183
+ } catch (err) {
184
+ console.error('Error parsing response:', err.message);
185
+ console.error('Raw response:', data.substring(0, 500));
186
+ process.exit(1);
187
+ }
188
+ });
189
+ });
190
+
191
+ req.on('error', (err) => {
192
+ console.error('Request error:', err.message);
193
+ process.exit(1);
194
+ });
195
+
196
+ req.write(requestBody);
197
+ req.end();