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,642 @@
1
+ ---
2
+ name: threejs-shaders
3
+ description: Three.js shaders - GLSL, ShaderMaterial, uniforms, custom effects. Use when creating custom visual effects, modifying vertices, writing fragment shaders, or extending built-in materials.
4
+ ---
5
+
6
+ # Three.js Shaders
7
+
8
+ ## Quick Start
9
+
10
+ ```javascript
11
+ import * as THREE from "three";
12
+
13
+ const material = new THREE.ShaderMaterial({
14
+ uniforms: {
15
+ time: { value: 0 },
16
+ color: { value: new THREE.Color(0xff0000) },
17
+ },
18
+ vertexShader: `
19
+ void main() {
20
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
21
+ }
22
+ `,
23
+ fragmentShader: `
24
+ uniform vec3 color;
25
+
26
+ void main() {
27
+ gl_FragColor = vec4(color, 1.0);
28
+ }
29
+ `,
30
+ });
31
+
32
+ // Update in animation loop
33
+ material.uniforms.time.value = clock.getElapsedTime();
34
+ ```
35
+
36
+ ## ShaderMaterial vs RawShaderMaterial
37
+
38
+ ### ShaderMaterial
39
+
40
+ Three.js provides built-in uniforms and attributes.
41
+
42
+ ```javascript
43
+ const material = new THREE.ShaderMaterial({
44
+ vertexShader: `
45
+ // Built-in uniforms available:
46
+ // uniform mat4 modelMatrix;
47
+ // uniform mat4 modelViewMatrix;
48
+ // uniform mat4 projectionMatrix;
49
+ // uniform mat4 viewMatrix;
50
+ // uniform mat3 normalMatrix;
51
+ // uniform vec3 cameraPosition;
52
+
53
+ // Built-in attributes available:
54
+ // attribute vec3 position;
55
+ // attribute vec3 normal;
56
+ // attribute vec2 uv;
57
+
58
+ void main() {
59
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
60
+ }
61
+ `,
62
+ fragmentShader: `
63
+ void main() {
64
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
65
+ }
66
+ `,
67
+ });
68
+ ```
69
+
70
+ ### RawShaderMaterial
71
+
72
+ Full control - you define everything.
73
+
74
+ ```javascript
75
+ const material = new THREE.RawShaderMaterial({
76
+ uniforms: {
77
+ projectionMatrix: { value: camera.projectionMatrix },
78
+ modelViewMatrix: { value: new THREE.Matrix4() },
79
+ },
80
+ vertexShader: `
81
+ precision highp float;
82
+
83
+ attribute vec3 position;
84
+ uniform mat4 projectionMatrix;
85
+ uniform mat4 modelViewMatrix;
86
+
87
+ void main() {
88
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
89
+ }
90
+ `,
91
+ fragmentShader: `
92
+ precision highp float;
93
+
94
+ void main() {
95
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
96
+ }
97
+ `,
98
+ });
99
+ ```
100
+
101
+ ## Uniforms
102
+
103
+ ### Uniform Types
104
+
105
+ ```javascript
106
+ const material = new THREE.ShaderMaterial({
107
+ uniforms: {
108
+ // Numbers
109
+ floatValue: { value: 1.5 },
110
+ intValue: { value: 1 },
111
+
112
+ // Vectors
113
+ vec2Value: { value: new THREE.Vector2(1, 2) },
114
+ vec3Value: { value: new THREE.Vector3(1, 2, 3) },
115
+ vec4Value: { value: new THREE.Vector4(1, 2, 3, 4) },
116
+
117
+ // Colors (converted to vec3)
118
+ colorValue: { value: new THREE.Color(0xff0000) },
119
+
120
+ // Matrices
121
+ mat3Value: { value: new THREE.Matrix3() },
122
+ mat4Value: { value: new THREE.Matrix4() },
123
+
124
+ // Textures
125
+ textureValue: { value: texture },
126
+ cubeTextureValue: { value: cubeTexture },
127
+
128
+ // Arrays
129
+ floatArray: { value: [1.0, 2.0, 3.0] },
130
+ vec3Array: {
131
+ value: [new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 1, 0)],
132
+ },
133
+ },
134
+ });
135
+ ```
136
+
137
+ ### GLSL Declarations
138
+
139
+ ```glsl
140
+ // In shader
141
+ uniform float floatValue;
142
+ uniform int intValue;
143
+ uniform vec2 vec2Value;
144
+ uniform vec3 vec3Value;
145
+ uniform vec3 colorValue; // Color becomes vec3
146
+ uniform vec4 vec4Value;
147
+ uniform mat3 mat3Value;
148
+ uniform mat4 mat4Value;
149
+ uniform sampler2D textureValue;
150
+ uniform samplerCube cubeTextureValue;
151
+ uniform float floatArray[3];
152
+ uniform vec3 vec3Array[2];
153
+ ```
154
+
155
+ ### Updating Uniforms
156
+
157
+ ```javascript
158
+ // Direct assignment
159
+ material.uniforms.time.value = clock.getElapsedTime();
160
+
161
+ // Vector/Color updates
162
+ material.uniforms.position.value.set(x, y, z);
163
+ material.uniforms.color.value.setHSL(hue, 1, 0.5);
164
+
165
+ // Matrix updates
166
+ material.uniforms.matrix.value.copy(mesh.matrixWorld);
167
+ ```
168
+
169
+ ## Varyings
170
+
171
+ Pass data from vertex to fragment shader.
172
+
173
+ ```javascript
174
+ const material = new THREE.ShaderMaterial({
175
+ vertexShader: `
176
+ varying vec2 vUv;
177
+ varying vec3 vNormal;
178
+ varying vec3 vPosition;
179
+
180
+ void main() {
181
+ vUv = uv;
182
+ vNormal = normalize(normalMatrix * normal);
183
+ vPosition = (modelViewMatrix * vec4(position, 1.0)).xyz;
184
+
185
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
186
+ }
187
+ `,
188
+ fragmentShader: `
189
+ varying vec2 vUv;
190
+ varying vec3 vNormal;
191
+ varying vec3 vPosition;
192
+
193
+ void main() {
194
+ // Use interpolated values
195
+ gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
196
+ }
197
+ `,
198
+ });
199
+ ```
200
+
201
+ ## Common Shader Patterns
202
+
203
+ ### Texture Sampling
204
+
205
+ ```javascript
206
+ const material = new THREE.ShaderMaterial({
207
+ uniforms: {
208
+ map: { value: texture },
209
+ },
210
+ vertexShader: `
211
+ varying vec2 vUv;
212
+
213
+ void main() {
214
+ vUv = uv;
215
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
216
+ }
217
+ `,
218
+ fragmentShader: `
219
+ uniform sampler2D map;
220
+ varying vec2 vUv;
221
+
222
+ void main() {
223
+ vec4 texColor = texture2D(map, vUv);
224
+ gl_FragColor = texColor;
225
+ }
226
+ `,
227
+ });
228
+ ```
229
+
230
+ ### Vertex Displacement
231
+
232
+ ```javascript
233
+ const material = new THREE.ShaderMaterial({
234
+ uniforms: {
235
+ time: { value: 0 },
236
+ amplitude: { value: 0.5 },
237
+ },
238
+ vertexShader: `
239
+ uniform float time;
240
+ uniform float amplitude;
241
+
242
+ void main() {
243
+ vec3 pos = position;
244
+
245
+ // Wave displacement
246
+ pos.z += sin(pos.x * 5.0 + time) * amplitude;
247
+ pos.z += sin(pos.y * 5.0 + time) * amplitude;
248
+
249
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
250
+ }
251
+ `,
252
+ fragmentShader: `
253
+ void main() {
254
+ gl_FragColor = vec4(0.5, 0.8, 1.0, 1.0);
255
+ }
256
+ `,
257
+ });
258
+ ```
259
+
260
+ ### Fresnel Effect
261
+
262
+ ```javascript
263
+ const material = new THREE.ShaderMaterial({
264
+ vertexShader: `
265
+ varying vec3 vNormal;
266
+ varying vec3 vWorldPosition;
267
+
268
+ void main() {
269
+ vNormal = normalize(normalMatrix * normal);
270
+ vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
271
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
272
+ }
273
+ `,
274
+ fragmentShader: `
275
+ varying vec3 vNormal;
276
+ varying vec3 vWorldPosition;
277
+
278
+ void main() {
279
+ // cameraPosition is auto-provided by ShaderMaterial
280
+ vec3 viewDirection = normalize(cameraPosition - vWorldPosition);
281
+ float fresnel = pow(1.0 - dot(viewDirection, vNormal), 3.0);
282
+
283
+ vec3 baseColor = vec3(0.0, 0.0, 0.5);
284
+ vec3 fresnelColor = vec3(0.5, 0.8, 1.0);
285
+
286
+ gl_FragColor = vec4(mix(baseColor, fresnelColor, fresnel), 1.0);
287
+ }
288
+ `,
289
+ });
290
+ ```
291
+
292
+ ### Noise-Based Effects
293
+
294
+ ```glsl
295
+ // Simple noise function
296
+ float random(vec2 st) {
297
+ return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
298
+ }
299
+
300
+ // Value noise
301
+ float noise(vec2 st) {
302
+ vec2 i = floor(st);
303
+ vec2 f = fract(st);
304
+
305
+ float a = random(i);
306
+ float b = random(i + vec2(1.0, 0.0));
307
+ float c = random(i + vec2(0.0, 1.0));
308
+ float d = random(i + vec2(1.0, 1.0));
309
+
310
+ vec2 u = f * f * (3.0 - 2.0 * f);
311
+
312
+ return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
313
+ }
314
+
315
+ // Usage
316
+ float n = noise(vUv * 10.0 + time);
317
+ ```
318
+
319
+ ### Gradient
320
+
321
+ ```glsl
322
+ // Linear gradient
323
+ vec3 color = mix(colorA, colorB, vUv.y);
324
+
325
+ // Radial gradient
326
+ float dist = distance(vUv, vec2(0.5));
327
+ vec3 color = mix(centerColor, edgeColor, dist * 2.0);
328
+
329
+ // Smooth gradient with custom curve
330
+ float t = smoothstep(0.0, 1.0, vUv.y);
331
+ vec3 color = mix(colorA, colorB, t);
332
+ ```
333
+
334
+ ### Rim Lighting
335
+
336
+ ```javascript
337
+ const material = new THREE.ShaderMaterial({
338
+ vertexShader: `
339
+ varying vec3 vNormal;
340
+ varying vec3 vViewPosition;
341
+
342
+ void main() {
343
+ vNormal = normalize(normalMatrix * normal);
344
+ vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
345
+ vViewPosition = mvPosition.xyz;
346
+ gl_Position = projectionMatrix * mvPosition;
347
+ }
348
+ `,
349
+ fragmentShader: `
350
+ varying vec3 vNormal;
351
+ varying vec3 vViewPosition;
352
+
353
+ void main() {
354
+ vec3 viewDir = normalize(-vViewPosition);
355
+ float rim = 1.0 - max(0.0, dot(viewDir, vNormal));
356
+ rim = pow(rim, 4.0);
357
+
358
+ vec3 baseColor = vec3(0.2, 0.2, 0.8);
359
+ vec3 rimColor = vec3(1.0, 0.5, 0.0);
360
+
361
+ gl_FragColor = vec4(baseColor + rimColor * rim, 1.0);
362
+ }
363
+ `,
364
+ });
365
+ ```
366
+
367
+ ### Dissolve Effect
368
+
369
+ ```glsl
370
+ uniform float progress;
371
+ uniform sampler2D noiseMap;
372
+
373
+ void main() {
374
+ float noise = texture2D(noiseMap, vUv).r;
375
+
376
+ if (noise < progress) {
377
+ discard;
378
+ }
379
+
380
+ // Edge glow
381
+ float edge = smoothstep(progress, progress + 0.1, noise);
382
+ vec3 edgeColor = vec3(1.0, 0.5, 0.0);
383
+ vec3 baseColor = vec3(0.5);
384
+
385
+ gl_FragColor = vec4(mix(edgeColor, baseColor, edge), 1.0);
386
+ }
387
+ ```
388
+
389
+ ## Extending Built-in Materials
390
+
391
+ ### onBeforeCompile
392
+
393
+ Modify existing material shaders.
394
+
395
+ ```javascript
396
+ const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
397
+
398
+ material.onBeforeCompile = (shader) => {
399
+ // Add custom uniform
400
+ shader.uniforms.time = { value: 0 };
401
+
402
+ // Store reference for updates
403
+ material.userData.shader = shader;
404
+
405
+ // Modify vertex shader
406
+ shader.vertexShader = shader.vertexShader.replace(
407
+ "#include <begin_vertex>",
408
+ `
409
+ #include <begin_vertex>
410
+ transformed.y += sin(position.x * 10.0 + time) * 0.1;
411
+ `,
412
+ );
413
+
414
+ // Add uniform declaration
415
+ shader.vertexShader = "uniform float time;\n" + shader.vertexShader;
416
+ };
417
+
418
+ // Update in animation loop
419
+ if (material.userData.shader) {
420
+ material.userData.shader.uniforms.time.value = clock.getElapsedTime();
421
+ }
422
+ ```
423
+
424
+ ### Common Injection Points
425
+
426
+ ```javascript
427
+ // Vertex shader chunks
428
+ "#include <begin_vertex>"; // After position is calculated
429
+ "#include <project_vertex>"; // After gl_Position
430
+ "#include <beginnormal_vertex>"; // Normal calculation start
431
+
432
+ // Fragment shader chunks
433
+ "#include <color_fragment>"; // After diffuse color
434
+ "#include <output_fragment>"; // Final output
435
+ "#include <fog_fragment>"; // After fog applied
436
+ ```
437
+
438
+ ## GLSL Built-in Functions
439
+
440
+ ### Math Functions
441
+
442
+ ```glsl
443
+ // Basic
444
+ abs(x), sign(x), floor(x), ceil(x), fract(x)
445
+ mod(x, y), min(x, y), max(x, y), clamp(x, min, max)
446
+ mix(a, b, t), step(edge, x), smoothstep(edge0, edge1, x)
447
+
448
+ // Trigonometry
449
+ sin(x), cos(x), tan(x)
450
+ asin(x), acos(x), atan(y, x), atan(x)
451
+ radians(degrees), degrees(radians)
452
+
453
+ // Exponential
454
+ pow(x, y), exp(x), log(x), exp2(x), log2(x)
455
+ sqrt(x), inversesqrt(x)
456
+ ```
457
+
458
+ ### Vector Functions
459
+
460
+ ```glsl
461
+ // Length and distance
462
+ length(v), distance(p0, p1), dot(x, y), cross(x, y)
463
+
464
+ // Normalization
465
+ normalize(v)
466
+
467
+ // Reflection and refraction
468
+ reflect(I, N), refract(I, N, eta)
469
+
470
+ // Component-wise
471
+ lessThan(x, y), lessThanEqual(x, y)
472
+ greaterThan(x, y), greaterThanEqual(x, y)
473
+ equal(x, y), notEqual(x, y)
474
+ any(bvec), all(bvec)
475
+ ```
476
+
477
+ ### Texture Functions
478
+
479
+ ```glsl
480
+ // GLSL 1.0 (default) - use texture2D/textureCube
481
+ texture2D(sampler, coord)
482
+ texture2D(sampler, coord, bias)
483
+ textureCube(sampler, coord)
484
+
485
+ // GLSL 3.0 (glslVersion: THREE.GLSL3) - use texture()
486
+ // texture(sampler, coord) replaces texture2D/textureCube
487
+ // Also use: out vec4 fragColor instead of gl_FragColor
488
+
489
+ // Texture size (GLSL 1.30+)
490
+ textureSize(sampler, lod)
491
+ ```
492
+
493
+ ## Common Material Properties
494
+
495
+ ```javascript
496
+ const material = new THREE.ShaderMaterial({
497
+ uniforms: {
498
+ /* ... */
499
+ },
500
+ vertexShader: "/* ... */",
501
+ fragmentShader: "/* ... */",
502
+
503
+ // Rendering
504
+ transparent: true,
505
+ opacity: 1.0,
506
+ side: THREE.DoubleSide,
507
+ depthTest: true,
508
+ depthWrite: true,
509
+
510
+ // Blending
511
+ blending: THREE.NormalBlending,
512
+ // AdditiveBlending, SubtractiveBlending, MultiplyBlending
513
+
514
+ // Wireframe
515
+ wireframe: false,
516
+ wireframeLinewidth: 1, // Note: >1 has no effect on most platforms (WebGL limitation)
517
+
518
+ // Extensions
519
+ extensions: {
520
+ derivatives: true, // For fwidth, dFdx, dFdy
521
+ fragDepth: true, // gl_FragDepth
522
+ drawBuffers: true, // Multiple render targets
523
+ shaderTextureLOD: true, // texture2DLod
524
+ },
525
+
526
+ // GLSL version
527
+ glslVersion: THREE.GLSL3, // For WebGL2 features
528
+ });
529
+ ```
530
+
531
+ ## Shader Includes
532
+
533
+ ### Using Three.js Shader Chunks
534
+
535
+ ```javascript
536
+ import { ShaderChunk } from "three";
537
+
538
+ const fragmentShader = `
539
+ ${ShaderChunk.common}
540
+ ${ShaderChunk.packing}
541
+
542
+ uniform sampler2D depthTexture;
543
+ varying vec2 vUv;
544
+
545
+ void main() {
546
+ float depth = texture2D(depthTexture, vUv).r;
547
+ float linearDepth = perspectiveDepthToViewZ(depth, 0.1, 1000.0);
548
+ gl_FragColor = vec4(vec3(-linearDepth / 100.0), 1.0);
549
+ }
550
+ `;
551
+ ```
552
+
553
+ ### External Shader Files
554
+
555
+ ```javascript
556
+ // With vite/webpack
557
+ import vertexShader from "./shaders/vertex.glsl";
558
+ import fragmentShader from "./shaders/fragment.glsl";
559
+
560
+ const material = new THREE.ShaderMaterial({
561
+ vertexShader,
562
+ fragmentShader,
563
+ });
564
+ ```
565
+
566
+ ## Instanced Shaders
567
+
568
+ ```javascript
569
+ // Instanced attribute
570
+ const offsets = new Float32Array(instanceCount * 3);
571
+ // Fill offsets...
572
+ geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));
573
+
574
+ const material = new THREE.ShaderMaterial({
575
+ vertexShader: `
576
+ attribute vec3 offset;
577
+
578
+ void main() {
579
+ vec3 pos = position + offset;
580
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
581
+ }
582
+ `,
583
+ fragmentShader: `
584
+ void main() {
585
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
586
+ }
587
+ `,
588
+ });
589
+ ```
590
+
591
+ ## Debugging Shaders
592
+
593
+ ```javascript
594
+ // Check for compile errors
595
+ material.onBeforeCompile = (shader) => {
596
+ console.log("Vertex Shader:", shader.vertexShader);
597
+ console.log("Fragment Shader:", shader.fragmentShader);
598
+ };
599
+
600
+ // Visual debugging
601
+ fragmentShader: `
602
+ void main() {
603
+ // Debug UV
604
+ gl_FragColor = vec4(vUv, 0.0, 1.0);
605
+
606
+ // Debug normals
607
+ gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
608
+
609
+ // Debug position
610
+ gl_FragColor = vec4(vPosition * 0.1 + 0.5, 1.0);
611
+ }
612
+ `;
613
+
614
+ // Check WebGL errors
615
+ renderer.debug.checkShaderErrors = true;
616
+ ```
617
+
618
+ ## Performance Tips
619
+
620
+ 1. **Minimize uniforms**: Group related values into vectors
621
+ 2. **Avoid conditionals**: Use mix/step instead of if/else
622
+ 3. **Precalculate**: Move calculations to JS when possible
623
+ 4. **Use textures**: For complex functions, use lookup tables
624
+ 5. **Limit overdraw**: Avoid transparent objects when possible
625
+
626
+ ```glsl
627
+ // Instead of:
628
+ if (value > 0.5) {
629
+ color = colorA;
630
+ } else {
631
+ color = colorB;
632
+ }
633
+
634
+ // Use:
635
+ color = mix(colorB, colorA, step(0.5, value));
636
+ ```
637
+
638
+ ## See Also
639
+
640
+ - `threejs-materials` - Built-in material types
641
+ - `threejs-postprocessing` - Full-screen shader effects
642
+ - `threejs-textures` - Texture sampling in shaders