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,602 @@
1
+ ---
2
+ name: threejs-postprocessing
3
+ description: Three.js post-processing - EffectComposer, bloom, DOF, screen effects. Use when adding visual effects, color grading, blur, glow, or creating custom screen-space shaders.
4
+ ---
5
+
6
+ # Three.js Post-Processing
7
+
8
+ ## Quick Start
9
+
10
+ ```javascript
11
+ import * as THREE from "three";
12
+ import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
13
+ import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
14
+ import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
15
+
16
+ // Setup composer
17
+ const composer = new EffectComposer(renderer);
18
+
19
+ // Render scene
20
+ const renderPass = new RenderPass(scene, camera);
21
+ composer.addPass(renderPass);
22
+
23
+ // Add bloom
24
+ const bloomPass = new UnrealBloomPass(
25
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
26
+ 1.5, // strength
27
+ 0.4, // radius
28
+ 0.85, // threshold
29
+ );
30
+ composer.addPass(bloomPass);
31
+
32
+ // Animation loop - use composer instead of renderer
33
+ function animate() {
34
+ requestAnimationFrame(animate);
35
+ composer.render(); // NOT renderer.render()
36
+ }
37
+ ```
38
+
39
+ ## EffectComposer Setup
40
+
41
+ ```javascript
42
+ import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
43
+ import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
44
+
45
+ const composer = new EffectComposer(renderer);
46
+
47
+ // First pass: render scene
48
+ const renderPass = new RenderPass(scene, camera);
49
+ composer.addPass(renderPass);
50
+
51
+ // Add more passes...
52
+ composer.addPass(effectPass);
53
+
54
+ // Last pass should render to screen
55
+ effectPass.renderToScreen = true; // Default for last pass
56
+
57
+ // Handle resize
58
+ function onResize() {
59
+ const width = window.innerWidth;
60
+ const height = window.innerHeight;
61
+
62
+ camera.aspect = width / height;
63
+ camera.updateProjectionMatrix();
64
+
65
+ renderer.setSize(width, height);
66
+ composer.setSize(width, height);
67
+ }
68
+ ```
69
+
70
+ ## Common Effects
71
+
72
+ ### Bloom (Glow)
73
+
74
+ ```javascript
75
+ import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
76
+
77
+ const bloomPass = new UnrealBloomPass(
78
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
79
+ 1.5, // strength - intensity of glow
80
+ 0.4, // radius - spread of glow
81
+ 0.85, // threshold - brightness threshold
82
+ );
83
+
84
+ composer.addPass(bloomPass);
85
+
86
+ // Adjust at runtime
87
+ bloomPass.strength = 2.0;
88
+ bloomPass.threshold = 0.5;
89
+ bloomPass.radius = 0.8;
90
+ ```
91
+
92
+ ### Selective Bloom
93
+
94
+ Apply bloom only to specific objects.
95
+
96
+ ```javascript
97
+ import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
98
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
99
+
100
+ // Layer setup
101
+ const BLOOM_LAYER = 1;
102
+ const bloomLayer = new THREE.Layers();
103
+ bloomLayer.set(BLOOM_LAYER);
104
+
105
+ // Mark objects to bloom
106
+ glowingMesh.layers.enable(BLOOM_LAYER);
107
+
108
+ // Dark material for non-blooming objects
109
+ const darkMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
110
+ const materials = {};
111
+
112
+ function darkenNonBloomed(obj) {
113
+ if (obj.isMesh && !bloomLayer.test(obj.layers)) {
114
+ materials[obj.uuid] = obj.material;
115
+ obj.material = darkMaterial;
116
+ }
117
+ }
118
+
119
+ function restoreMaterial(obj) {
120
+ if (materials[obj.uuid]) {
121
+ obj.material = materials[obj.uuid];
122
+ delete materials[obj.uuid];
123
+ }
124
+ }
125
+
126
+ // Custom render loop
127
+ function render() {
128
+ // Render bloom pass
129
+ scene.traverse(darkenNonBloomed);
130
+ composer.render();
131
+ scene.traverse(restoreMaterial);
132
+
133
+ // Render final scene over bloom
134
+ renderer.render(scene, camera);
135
+ }
136
+ ```
137
+
138
+ ### FXAA (Anti-Aliasing)
139
+
140
+ ```javascript
141
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
142
+ import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
143
+
144
+ const fxaaPass = new ShaderPass(FXAAShader);
145
+ fxaaPass.material.uniforms["resolution"].value.set(
146
+ 1 / window.innerWidth,
147
+ 1 / window.innerHeight,
148
+ );
149
+
150
+ composer.addPass(fxaaPass);
151
+
152
+ // Update on resize
153
+ function onResize() {
154
+ fxaaPass.material.uniforms["resolution"].value.set(
155
+ 1 / window.innerWidth,
156
+ 1 / window.innerHeight,
157
+ );
158
+ }
159
+ ```
160
+
161
+ ### SMAA (Better Anti-Aliasing)
162
+
163
+ ```javascript
164
+ import { SMAAPass } from "three/addons/postprocessing/SMAAPass.js";
165
+
166
+ const smaaPass = new SMAAPass(
167
+ window.innerWidth * renderer.getPixelRatio(),
168
+ window.innerHeight * renderer.getPixelRatio(),
169
+ );
170
+
171
+ composer.addPass(smaaPass);
172
+ ```
173
+
174
+ ### SSAO (Ambient Occlusion)
175
+
176
+ ```javascript
177
+ import { SSAOPass } from "three/addons/postprocessing/SSAOPass.js";
178
+
179
+ const ssaoPass = new SSAOPass(
180
+ scene,
181
+ camera,
182
+ window.innerWidth,
183
+ window.innerHeight,
184
+ );
185
+ ssaoPass.kernelRadius = 16;
186
+ ssaoPass.minDistance = 0.005;
187
+ ssaoPass.maxDistance = 0.1;
188
+
189
+ composer.addPass(ssaoPass);
190
+
191
+ // Output modes
192
+ ssaoPass.output = SSAOPass.OUTPUT.Default;
193
+ // SSAOPass.OUTPUT.Default - Final composited output
194
+ // SSAOPass.OUTPUT.SSAO - Just the AO
195
+ // SSAOPass.OUTPUT.Blur - Blurred AO
196
+ // SSAOPass.OUTPUT.Depth - Depth buffer
197
+ // SSAOPass.OUTPUT.Normal - Normal buffer
198
+ ```
199
+
200
+ ### Depth of Field (DOF)
201
+
202
+ ```javascript
203
+ import { BokehPass } from "three/addons/postprocessing/BokehPass.js";
204
+
205
+ const bokehPass = new BokehPass(scene, camera, {
206
+ focus: 10.0, // Focus distance
207
+ aperture: 0.025, // Aperture (smaller = more DOF)
208
+ maxblur: 0.01, // Max blur amount
209
+ });
210
+
211
+ composer.addPass(bokehPass);
212
+
213
+ // Update focus dynamically
214
+ bokehPass.uniforms["focus"].value = distanceToTarget;
215
+ ```
216
+
217
+ ### Film Grain
218
+
219
+ ```javascript
220
+ import { FilmPass } from "three/addons/postprocessing/FilmPass.js";
221
+
222
+ const filmPass = new FilmPass(
223
+ 0.35, // noise intensity
224
+ 0.5, // scanline intensity
225
+ 648, // scanline count
226
+ false, // grayscale
227
+ );
228
+
229
+ composer.addPass(filmPass);
230
+ ```
231
+
232
+ ### Vignette
233
+
234
+ ```javascript
235
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
236
+ import { VignetteShader } from "three/addons/shaders/VignetteShader.js";
237
+
238
+ const vignettePass = new ShaderPass(VignetteShader);
239
+ vignettePass.uniforms["offset"].value = 1.0; // Vignette size
240
+ vignettePass.uniforms["darkness"].value = 1.0; // Vignette intensity
241
+
242
+ composer.addPass(vignettePass);
243
+ ```
244
+
245
+ ### Color Correction
246
+
247
+ ```javascript
248
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
249
+ import { ColorCorrectionShader } from "three/addons/shaders/ColorCorrectionShader.js";
250
+
251
+ const colorPass = new ShaderPass(ColorCorrectionShader);
252
+ colorPass.uniforms["powRGB"].value = new THREE.Vector3(1.2, 1.2, 1.2); // Power
253
+ colorPass.uniforms["mulRGB"].value = new THREE.Vector3(1.0, 1.0, 1.0); // Multiply
254
+
255
+ composer.addPass(colorPass);
256
+ ```
257
+
258
+ ### Gamma Correction
259
+
260
+ ```javascript
261
+ import { GammaCorrectionShader } from "three/addons/shaders/GammaCorrectionShader.js";
262
+
263
+ const gammaPass = new ShaderPass(GammaCorrectionShader);
264
+ composer.addPass(gammaPass);
265
+ ```
266
+
267
+ ### Pixelation
268
+
269
+ ```javascript
270
+ import { RenderPixelatedPass } from "three/addons/postprocessing/RenderPixelatedPass.js";
271
+
272
+ const pixelPass = new RenderPixelatedPass(6, scene, camera); // 6 = pixel size
273
+
274
+ composer.addPass(pixelPass);
275
+ ```
276
+
277
+ ### Glitch Effect
278
+
279
+ ```javascript
280
+ import { GlitchPass } from "three/addons/postprocessing/GlitchPass.js";
281
+
282
+ const glitchPass = new GlitchPass();
283
+ glitchPass.goWild = false; // Continuous glitching
284
+
285
+ composer.addPass(glitchPass);
286
+ ```
287
+
288
+ ### Halftone
289
+
290
+ ```javascript
291
+ import { HalftonePass } from "three/addons/postprocessing/HalftonePass.js";
292
+
293
+ const halftonePass = new HalftonePass(window.innerWidth, window.innerHeight, {
294
+ shape: 1, // 1 = dot, 2 = ellipse, 3 = line, 4 = square
295
+ radius: 4, // Dot size
296
+ rotateR: Math.PI / 12,
297
+ rotateB: (Math.PI / 12) * 2,
298
+ rotateG: (Math.PI / 12) * 3,
299
+ scatter: 0,
300
+ blending: 1,
301
+ blendingMode: 1,
302
+ greyscale: false,
303
+ });
304
+
305
+ composer.addPass(halftonePass);
306
+ ```
307
+
308
+ ### Outline
309
+
310
+ ```javascript
311
+ import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
312
+
313
+ const outlinePass = new OutlinePass(
314
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
315
+ scene,
316
+ camera,
317
+ );
318
+
319
+ outlinePass.edgeStrength = 3;
320
+ outlinePass.edgeGlow = 0;
321
+ outlinePass.edgeThickness = 1;
322
+ outlinePass.pulsePeriod = 0;
323
+ outlinePass.visibleEdgeColor.set(0xffffff);
324
+ outlinePass.hiddenEdgeColor.set(0x190a05);
325
+
326
+ // Select objects to outline
327
+ outlinePass.selectedObjects = [mesh1, mesh2];
328
+
329
+ composer.addPass(outlinePass);
330
+ ```
331
+
332
+ ## Custom ShaderPass
333
+
334
+ Create your own post-processing effects.
335
+
336
+ ```javascript
337
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
338
+
339
+ const CustomShader = {
340
+ uniforms: {
341
+ tDiffuse: { value: null }, // Required: input texture
342
+ time: { value: 0 },
343
+ intensity: { value: 1.0 },
344
+ },
345
+ vertexShader: `
346
+ varying vec2 vUv;
347
+
348
+ void main() {
349
+ vUv = uv;
350
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
351
+ }
352
+ `,
353
+ fragmentShader: `
354
+ uniform sampler2D tDiffuse;
355
+ uniform float time;
356
+ uniform float intensity;
357
+ varying vec2 vUv;
358
+
359
+ void main() {
360
+ vec2 uv = vUv;
361
+
362
+ // Wave distortion
363
+ uv.x += sin(uv.y * 10.0 + time) * 0.01 * intensity;
364
+
365
+ vec4 color = texture2D(tDiffuse, uv);
366
+ gl_FragColor = color;
367
+ }
368
+ `,
369
+ };
370
+
371
+ const customPass = new ShaderPass(CustomShader);
372
+ composer.addPass(customPass);
373
+
374
+ // Update in animation loop
375
+ customPass.uniforms.time.value = clock.getElapsedTime();
376
+ ```
377
+
378
+ ### Invert Colors Shader
379
+
380
+ ```javascript
381
+ const InvertShader = {
382
+ uniforms: {
383
+ tDiffuse: { value: null },
384
+ },
385
+ vertexShader: `
386
+ varying vec2 vUv;
387
+ void main() {
388
+ vUv = uv;
389
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
390
+ }
391
+ `,
392
+ fragmentShader: `
393
+ uniform sampler2D tDiffuse;
394
+ varying vec2 vUv;
395
+
396
+ void main() {
397
+ vec4 color = texture2D(tDiffuse, vUv);
398
+ gl_FragColor = vec4(1.0 - color.rgb, color.a);
399
+ }
400
+ `,
401
+ };
402
+ ```
403
+
404
+ ### Chromatic Aberration
405
+
406
+ ```javascript
407
+ const ChromaticAberrationShader = {
408
+ uniforms: {
409
+ tDiffuse: { value: null },
410
+ amount: { value: 0.005 },
411
+ },
412
+ vertexShader: `
413
+ varying vec2 vUv;
414
+ void main() {
415
+ vUv = uv;
416
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
417
+ }
418
+ `,
419
+ fragmentShader: `
420
+ uniform sampler2D tDiffuse;
421
+ uniform float amount;
422
+ varying vec2 vUv;
423
+
424
+ void main() {
425
+ vec2 dir = vUv - 0.5;
426
+ float dist = length(dir);
427
+
428
+ float r = texture2D(tDiffuse, vUv - dir * amount * dist).r;
429
+ float g = texture2D(tDiffuse, vUv).g;
430
+ float b = texture2D(tDiffuse, vUv + dir * amount * dist).b;
431
+
432
+ gl_FragColor = vec4(r, g, b, 1.0);
433
+ }
434
+ `,
435
+ };
436
+ ```
437
+
438
+ ## Combining Multiple Effects
439
+
440
+ ```javascript
441
+ import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
442
+ import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
443
+ import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
444
+ import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
445
+ import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
446
+ import { VignetteShader } from "three/addons/shaders/VignetteShader.js";
447
+ import { GammaCorrectionShader } from "three/addons/shaders/GammaCorrectionShader.js";
448
+
449
+ const composer = new EffectComposer(renderer);
450
+
451
+ // 1. Render scene
452
+ composer.addPass(new RenderPass(scene, camera));
453
+
454
+ // 2. Bloom
455
+ const bloomPass = new UnrealBloomPass(
456
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
457
+ 0.5,
458
+ 0.4,
459
+ 0.85,
460
+ );
461
+ composer.addPass(bloomPass);
462
+
463
+ // 3. Vignette
464
+ const vignettePass = new ShaderPass(VignetteShader);
465
+ vignettePass.uniforms["offset"].value = 0.95;
466
+ vignettePass.uniforms["darkness"].value = 1.0;
467
+ composer.addPass(vignettePass);
468
+
469
+ // 4. Gamma correction
470
+ composer.addPass(new ShaderPass(GammaCorrectionShader));
471
+
472
+ // 5. Anti-aliasing (always last before output)
473
+ const fxaaPass = new ShaderPass(FXAAShader);
474
+ fxaaPass.uniforms["resolution"].value.set(
475
+ 1 / window.innerWidth,
476
+ 1 / window.innerHeight,
477
+ );
478
+ composer.addPass(fxaaPass);
479
+ ```
480
+
481
+ ## Render to Texture
482
+
483
+ ```javascript
484
+ // Create render target
485
+ const renderTarget = new THREE.WebGLRenderTarget(512, 512);
486
+
487
+ // Render scene to target
488
+ renderer.setRenderTarget(renderTarget);
489
+ renderer.render(scene, camera);
490
+ renderer.setRenderTarget(null);
491
+
492
+ // Use texture
493
+ const texture = renderTarget.texture;
494
+ otherMaterial.map = texture;
495
+ ```
496
+
497
+ ## Multi-Pass Rendering
498
+
499
+ ```javascript
500
+ // Multiple composers for different scenes/layers
501
+ const bgComposer = new EffectComposer(renderer);
502
+ bgComposer.addPass(new RenderPass(bgScene, camera));
503
+
504
+ const fgComposer = new EffectComposer(renderer);
505
+ fgComposer.addPass(new RenderPass(fgScene, camera));
506
+ fgComposer.addPass(bloomPass);
507
+
508
+ // Combine in render loop
509
+ function animate() {
510
+ // Render background without clearing
511
+ renderer.autoClear = false;
512
+ renderer.clear();
513
+
514
+ bgComposer.render();
515
+
516
+ // Render foreground over it
517
+ renderer.clearDepth();
518
+ fgComposer.render();
519
+ }
520
+ ```
521
+
522
+ ## WebGPU Post-Processing (Three.js r150+)
523
+
524
+ ```javascript
525
+ import { postProcessing } from "three/addons/nodes/Nodes.js";
526
+ import { pass, bloom, dof } from "three/addons/nodes/Nodes.js";
527
+
528
+ // Using node-based system
529
+ const scenePass = pass(scene, camera);
530
+ const bloomNode = bloom(scenePass, 0.5, 0.4, 0.85);
531
+
532
+ const postProcessing = new THREE.PostProcessing(renderer);
533
+ postProcessing.outputNode = bloomNode;
534
+
535
+ // Render
536
+ function animate() {
537
+ postProcessing.render();
538
+ }
539
+ ```
540
+
541
+ ## Performance Tips
542
+
543
+ 1. **Limit passes**: Each pass adds a full-screen render
544
+ 2. **Lower resolution**: Use smaller render targets for blur passes
545
+ 3. **Disable unused effects**: Toggle passes on/off
546
+ 4. **Use FXAA over MSAA**: Less expensive anti-aliasing
547
+ 5. **Profile with DevTools**: Check GPU usage
548
+
549
+ ```javascript
550
+ // Disable pass
551
+ bloomPass.enabled = false;
552
+
553
+ // Reduce bloom resolution
554
+ const bloomPass = new UnrealBloomPass(
555
+ new THREE.Vector2(window.innerWidth / 2, window.innerHeight / 2),
556
+ strength,
557
+ radius,
558
+ threshold,
559
+ );
560
+
561
+ // Only apply effects in high-performance scenarios
562
+ const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
563
+ if (!isMobile) {
564
+ composer.addPass(expensivePass);
565
+ }
566
+ ```
567
+
568
+ ## Handle Resize
569
+
570
+ ```javascript
571
+ function onWindowResize() {
572
+ const width = window.innerWidth;
573
+ const height = window.innerHeight;
574
+ const pixelRatio = renderer.getPixelRatio();
575
+
576
+ camera.aspect = width / height;
577
+ camera.updateProjectionMatrix();
578
+
579
+ renderer.setSize(width, height);
580
+ composer.setSize(width, height);
581
+
582
+ // Update pass-specific resolutions
583
+ if (fxaaPass) {
584
+ fxaaPass.material.uniforms["resolution"].value.set(
585
+ 1 / (width * pixelRatio),
586
+ 1 / (height * pixelRatio),
587
+ );
588
+ }
589
+
590
+ if (bloomPass) {
591
+ bloomPass.resolution.set(width, height);
592
+ }
593
+ }
594
+
595
+ window.addEventListener("resize", onWindowResize);
596
+ ```
597
+
598
+ ## See Also
599
+
600
+ - `threejs-shaders` - Custom shader development
601
+ - `threejs-textures` - Render targets
602
+ - `threejs-fundamentals` - Renderer setup