@lark-apaas/coding-steering 0.1.2 → 0.1.4

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.
@@ -0,0 +1,754 @@
1
+ # React Three Fiber Post-Processing
2
+
3
+ ## Quick Start
4
+
5
+ ```tsx
6
+ import { Canvas } from '@react-three/fiber'
7
+ import { EffectComposer, Bloom, Vignette } from '@react-three/postprocessing'
8
+
9
+ function Scene() {
10
+ return (
11
+ <Canvas>
12
+ <ambientLight />
13
+ <mesh>
14
+ <boxGeometry />
15
+ <meshStandardMaterial color="hotpink" emissive="hotpink" emissiveIntensity={2} />
16
+ </mesh>
17
+
18
+ <EffectComposer>
19
+ <Bloom luminanceThreshold={0.5} luminanceSmoothing={0.9} intensity={1.5} />
20
+ <Vignette offset={0.5} darkness={0.5} />
21
+ </EffectComposer>
22
+ </Canvas>
23
+ )
24
+ }
25
+ ```
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install @react-three/postprocessing postprocessing
31
+ ```
32
+
33
+ ## EffectComposer
34
+
35
+ The container for all post-processing effects.
36
+
37
+ ```tsx
38
+ import { EffectComposer } from '@react-three/postprocessing'
39
+
40
+ function Scene() {
41
+ return (
42
+ <Canvas>
43
+ {/* Scene content */}
44
+ <mesh>...</mesh>
45
+
46
+ {/* Post-processing - must be inside Canvas, after scene content */}
47
+ <EffectComposer
48
+ enabled={true} // Toggle all effects
49
+ depthBuffer={true} // Enable depth buffer
50
+ stencilBuffer={false} // Enable stencil buffer
51
+ autoClear={true} // Auto clear before render
52
+ multisampling={8} // MSAA samples (0 to disable)
53
+ >
54
+ {/* Effects go here */}
55
+ </EffectComposer>
56
+ </Canvas>
57
+ )
58
+ }
59
+ ```
60
+
61
+ ## Common Effects
62
+
63
+ ### Bloom (Glow)
64
+
65
+ ```tsx
66
+ import { EffectComposer, Bloom } from '@react-three/postprocessing'
67
+ import { BlendFunction } from 'postprocessing'
68
+
69
+ <EffectComposer>
70
+ <Bloom
71
+ intensity={1.0} // Bloom intensity
72
+ luminanceThreshold={0.9} // Brightness threshold
73
+ luminanceSmoothing={0.025} // Smoothness of threshold
74
+ mipmapBlur={true} // Enable mipmap blur
75
+ radius={0.8} // Bloom radius
76
+ levels={8} // Mipmap levels
77
+ blendFunction={BlendFunction.ADD}
78
+ />
79
+ </EffectComposer>
80
+
81
+ // For objects to glow, use emissive materials
82
+ <mesh>
83
+ <boxGeometry />
84
+ <meshStandardMaterial
85
+ color="black"
86
+ emissive="#ff00ff"
87
+ emissiveIntensity={2}
88
+ toneMapped={false} // Important for values > 1
89
+ />
90
+ </mesh>
91
+ ```
92
+
93
+ ### Selective Bloom
94
+
95
+ ```tsx
96
+ import { EffectComposer, Bloom, Selection, Select } from '@react-three/postprocessing'
97
+
98
+ function Scene() {
99
+ return (
100
+ <Canvas>
101
+ <Selection>
102
+ <EffectComposer>
103
+ <Bloom
104
+ luminanceThreshold={0}
105
+ intensity={2}
106
+ mipmapBlur
107
+ />
108
+ </EffectComposer>
109
+
110
+ {/* This mesh will bloom */}
111
+ <Select enabled>
112
+ <mesh>
113
+ <sphereGeometry />
114
+ <meshStandardMaterial emissive="red" emissiveIntensity={2} toneMapped={false} />
115
+ </mesh>
116
+ </Select>
117
+
118
+ {/* This mesh will NOT bloom */}
119
+ <mesh position={[2, 0, 0]}>
120
+ <boxGeometry />
121
+ <meshStandardMaterial color="blue" />
122
+ </mesh>
123
+ </Selection>
124
+ </Canvas>
125
+ )
126
+ }
127
+ ```
128
+
129
+ ### Depth of Field
130
+
131
+ ```tsx
132
+ import { EffectComposer, DepthOfField } from '@react-three/postprocessing'
133
+
134
+ <EffectComposer>
135
+ <DepthOfField
136
+ focusDistance={0} // Focus distance (0 = auto)
137
+ focalLength={0.02} // Camera focal length
138
+ bokehScale={2} // Bokeh size
139
+ height={480} // Resolution height
140
+ />
141
+ </EffectComposer>
142
+
143
+ // With target object
144
+ import { useRef } from 'react'
145
+
146
+ function Scene() {
147
+ const targetRef = useRef()
148
+
149
+ return (
150
+ <>
151
+ <mesh ref={targetRef} position={[0, 0, -5]}>
152
+ <boxGeometry />
153
+ <meshStandardMaterial color="red" />
154
+ </mesh>
155
+
156
+ <EffectComposer>
157
+ <DepthOfField
158
+ target={targetRef}
159
+ focalLength={0.02}
160
+ bokehScale={2}
161
+ />
162
+ </EffectComposer>
163
+ </>
164
+ )
165
+ }
166
+ ```
167
+
168
+ ### Vignette
169
+
170
+ ```tsx
171
+ import { EffectComposer, Vignette } from '@react-three/postprocessing'
172
+
173
+ <EffectComposer>
174
+ <Vignette
175
+ offset={0.5} // Vignette size
176
+ darkness={0.5} // Vignette intensity
177
+ eskil={false} // Use Eskil's vignette technique
178
+ />
179
+ </EffectComposer>
180
+ ```
181
+
182
+ ### Noise
183
+
184
+ ```tsx
185
+ import { EffectComposer, Noise } from '@react-three/postprocessing'
186
+ import { BlendFunction } from 'postprocessing'
187
+
188
+ <EffectComposer>
189
+ <Noise
190
+ premultiply // Multiply noise with input
191
+ blendFunction={BlendFunction.ADD}
192
+ opacity={0.5}
193
+ />
194
+ </EffectComposer>
195
+ ```
196
+
197
+ ### Chromatic Aberration
198
+
199
+ ```tsx
200
+ import { EffectComposer, ChromaticAberration } from '@react-three/postprocessing'
201
+ import { BlendFunction } from 'postprocessing'
202
+
203
+ <EffectComposer>
204
+ <ChromaticAberration
205
+ offset={[0.002, 0.002]} // Color offset
206
+ radialModulation={true} // Apply radially
207
+ modulationOffset={0.5}
208
+ blendFunction={BlendFunction.NORMAL}
209
+ />
210
+ </EffectComposer>
211
+ ```
212
+
213
+ ### SSAO (Screen Space Ambient Occlusion)
214
+
215
+ ```tsx
216
+ import { EffectComposer, SSAO } from '@react-three/postprocessing'
217
+ import { BlendFunction } from 'postprocessing'
218
+
219
+ <EffectComposer>
220
+ <SSAO
221
+ blendFunction={BlendFunction.MULTIPLY}
222
+ samples={30} // Amount of samples
223
+ radius={5} // Occlusion radius
224
+ intensity={30} // Occlusion intensity
225
+ luminanceInfluence={0.6}
226
+ color="black"
227
+ worldDistanceThreshold={100}
228
+ worldDistanceFalloff={5}
229
+ worldProximityThreshold={0.01}
230
+ worldProximityFalloff={0.01}
231
+ />
232
+ </EffectComposer>
233
+ ```
234
+
235
+ ### Outline
236
+
237
+ ```tsx
238
+ import { EffectComposer, Outline, Selection, Select } from '@react-three/postprocessing'
239
+
240
+ function Scene() {
241
+ return (
242
+ <Canvas>
243
+ <Selection>
244
+ <EffectComposer autoClear={false}>
245
+ <Outline
246
+ visibleEdgeColor={0xffffff} // Visible edge color
247
+ hiddenEdgeColor={0x22090a} // Hidden edge color
248
+ edgeStrength={2.5} // Edge strength
249
+ pulseSpeed={0} // Pulse animation speed
250
+ blur // Enable blur
251
+ xRay // Show behind objects
252
+ />
253
+ </EffectComposer>
254
+
255
+ {/* Outlined object */}
256
+ <Select enabled>
257
+ <mesh>
258
+ <boxGeometry />
259
+ <meshStandardMaterial color="orange" />
260
+ </mesh>
261
+ </Select>
262
+
263
+ {/* Non-outlined object */}
264
+ <mesh position={[2, 0, 0]}>
265
+ <sphereGeometry />
266
+ <meshStandardMaterial color="blue" />
267
+ </mesh>
268
+ </Selection>
269
+ </Canvas>
270
+ )
271
+ }
272
+ ```
273
+
274
+ ### Color Grading
275
+
276
+ ```tsx
277
+ import { EffectComposer, BrightnessContrast, HueSaturation } from '@react-three/postprocessing'
278
+
279
+ <EffectComposer>
280
+ <BrightnessContrast
281
+ brightness={0} // -1 to 1
282
+ contrast={0} // -1 to 1
283
+ />
284
+ <HueSaturation
285
+ hue={0} // Hue rotation in radians
286
+ saturation={0} // -1 to 1
287
+ />
288
+ </EffectComposer>
289
+ ```
290
+
291
+ ### Tone Mapping
292
+
293
+ ```tsx
294
+ import { EffectComposer, ToneMapping } from '@react-three/postprocessing'
295
+ import { ToneMappingMode } from 'postprocessing'
296
+
297
+ <EffectComposer>
298
+ <ToneMapping
299
+ mode={ToneMappingMode.ACES_FILMIC}
300
+ // Modes: LINEAR, REINHARD, REINHARD2, OPTIMIZED_CINEON, CINEON, ACES_FILMIC, AGX, NEUTRAL
301
+ resolution={256}
302
+ whitePoint={4.0}
303
+ middleGrey={0.6}
304
+ minLuminance={0.01}
305
+ averageLuminance={1.0}
306
+ adaptationRate={1.0}
307
+ />
308
+ </EffectComposer>
309
+ ```
310
+
311
+ ### Glitch
312
+
313
+ ```tsx
314
+ import { EffectComposer, Glitch } from '@react-three/postprocessing'
315
+ import { GlitchMode } from 'postprocessing'
316
+
317
+ <EffectComposer>
318
+ <Glitch
319
+ delay={[1.5, 3.5]} // Min/max delay between glitches
320
+ duration={[0.6, 1.0]} // Min/max duration
321
+ strength={[0.3, 1.0]} // Min/max strength
322
+ mode={GlitchMode.SPORADIC} // DISABLED, SPORADIC, CONSTANT_MILD, CONSTANT_WILD
323
+ active // Enable/disable
324
+ ratio={0.85} // Glitch ratio (0 = none, 1 = always)
325
+ />
326
+ </EffectComposer>
327
+ ```
328
+
329
+ ### Pixelation
330
+
331
+ ```tsx
332
+ import { EffectComposer, Pixelation } from '@react-three/postprocessing'
333
+
334
+ <EffectComposer>
335
+ <Pixelation
336
+ granularity={5} // Pixel size
337
+ />
338
+ </EffectComposer>
339
+ ```
340
+
341
+ ### Scanline
342
+
343
+ ```tsx
344
+ import { EffectComposer, Scanline } from '@react-three/postprocessing'
345
+ import { BlendFunction } from 'postprocessing'
346
+
347
+ <EffectComposer>
348
+ <Scanline
349
+ blendFunction={BlendFunction.OVERLAY}
350
+ density={1.25} // Line density
351
+ opacity={0.5} // Effect opacity
352
+ />
353
+ </EffectComposer>
354
+ ```
355
+
356
+ ### Grid
357
+
358
+ ```tsx
359
+ import { EffectComposer, Grid } from '@react-three/postprocessing'
360
+ import { BlendFunction } from 'postprocessing'
361
+
362
+ <EffectComposer>
363
+ <Grid
364
+ blendFunction={BlendFunction.OVERLAY}
365
+ scale={1.0} // Grid scale
366
+ lineWidth={0.0} // Line width
367
+ />
368
+ </EffectComposer>
369
+ ```
370
+
371
+ ### DotScreen
372
+
373
+ ```tsx
374
+ import { EffectComposer, DotScreen } from '@react-three/postprocessing'
375
+ import { BlendFunction } from 'postprocessing'
376
+
377
+ <EffectComposer>
378
+ <DotScreen
379
+ blendFunction={BlendFunction.NORMAL}
380
+ angle={Math.PI * 0.5} // Pattern angle
381
+ scale={1.0} // Pattern scale
382
+ />
383
+ </EffectComposer>
384
+ ```
385
+
386
+ ### SMAA (Anti-Aliasing)
387
+
388
+ ```tsx
389
+ import { EffectComposer, SMAA } from '@react-three/postprocessing'
390
+
391
+ <EffectComposer multisampling={0}> {/* Disable MSAA when using SMAA */}
392
+ <SMAA />
393
+ </EffectComposer>
394
+ ```
395
+
396
+ ### FXAA (Anti-Aliasing)
397
+
398
+ ```tsx
399
+ import { EffectComposer, FXAA } from '@react-three/postprocessing'
400
+
401
+ <EffectComposer multisampling={0}>
402
+ <FXAA />
403
+ </EffectComposer>
404
+ ```
405
+
406
+ ## Combining Multiple Effects
407
+
408
+ ```tsx
409
+ import { EffectComposer, Bloom, Vignette, ChromaticAberration, Noise, SMAA } from '@react-three/postprocessing'
410
+ import { BlendFunction } from 'postprocessing'
411
+
412
+ function PostProcessing() {
413
+ return (
414
+ <EffectComposer multisampling={0}>
415
+ {/* Glow effect */}
416
+ <Bloom
417
+ intensity={1.5}
418
+ luminanceThreshold={0.9}
419
+ luminanceSmoothing={0.025}
420
+ mipmapBlur
421
+ />
422
+
423
+ {/* Color aberration */}
424
+ <ChromaticAberration
425
+ offset={[0.001, 0.001]}
426
+ radialModulation
427
+ modulationOffset={0.5}
428
+ />
429
+
430
+ {/* Film grain */}
431
+ <Noise
432
+ premultiply
433
+ blendFunction={BlendFunction.ADD}
434
+ opacity={0.2}
435
+ />
436
+
437
+ {/* Vignette */}
438
+ <Vignette
439
+ offset={0.3}
440
+ darkness={0.5}
441
+ />
442
+
443
+ {/* Anti-aliasing (should be last) */}
444
+ <SMAA />
445
+ </EffectComposer>
446
+ )
447
+ }
448
+ ```
449
+
450
+ ## Custom Effects
451
+
452
+ ### Using postprocessing Effect Class
453
+
454
+ ```tsx
455
+ import { forwardRef, useMemo } from 'react'
456
+ import { Effect, BlendFunction } from 'postprocessing'
457
+ import { Uniform } from 'three'
458
+
459
+ // Fragment shader
460
+ const fragmentShader = `
461
+ uniform float time;
462
+ uniform float intensity;
463
+
464
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
465
+ vec2 distortedUv = uv;
466
+ distortedUv.x += sin(uv.y * 10.0 + time) * 0.01 * intensity;
467
+
468
+ vec4 color = texture2D(inputBuffer, distortedUv);
469
+ outputColor = color;
470
+ }
471
+ `
472
+
473
+ // Effect class
474
+ class WaveDistortionEffect extends Effect {
475
+ constructor({ intensity = 1.0, blendFunction = BlendFunction.NORMAL } = {}) {
476
+ super('WaveDistortionEffect', fragmentShader, {
477
+ blendFunction,
478
+ uniforms: new Map([
479
+ ['time', new Uniform(0)],
480
+ ['intensity', new Uniform(intensity)],
481
+ ]),
482
+ })
483
+ }
484
+
485
+ update(renderer, inputBuffer, deltaTime) {
486
+ this.uniforms.get('time').value += deltaTime
487
+ }
488
+ }
489
+
490
+ // React component wrapper
491
+ export const WaveDistortion = forwardRef(({ intensity = 1.0, blendFunction }, ref) => {
492
+ const effect = useMemo(() => new WaveDistortionEffect({ intensity, blendFunction }), [intensity, blendFunction])
493
+ return <primitive ref={ref} object={effect} dispose={null} />
494
+ })
495
+
496
+ // Usage
497
+ <EffectComposer>
498
+ <WaveDistortion intensity={0.5} />
499
+ </EffectComposer>
500
+ ```
501
+
502
+ ### Shader with wrapEffect
503
+
504
+ ```tsx
505
+ import { wrapEffect } from '@react-three/postprocessing'
506
+ import { Effect, BlendFunction } from 'postprocessing'
507
+ import { Uniform } from 'three'
508
+
509
+ class InvertEffect extends Effect {
510
+ constructor({ blendFunction = BlendFunction.NORMAL } = {}) {
511
+ super('InvertEffect', `
512
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
513
+ outputColor = vec4(1.0 - inputColor.rgb, inputColor.a);
514
+ }
515
+ `, {
516
+ blendFunction,
517
+ })
518
+ }
519
+ }
520
+
521
+ export const Invert = wrapEffect(InvertEffect)
522
+
523
+ // Usage
524
+ <EffectComposer>
525
+ <Invert />
526
+ </EffectComposer>
527
+ ```
528
+
529
+ ## Conditional Effects
530
+
531
+ ```tsx
532
+ import { useState } from 'react'
533
+ import { EffectComposer, Bloom, Vignette, Glitch } from '@react-three/postprocessing'
534
+
535
+ function ConditionalPostProcessing() {
536
+ const [effects, setEffects] = useState({
537
+ bloom: true,
538
+ vignette: true,
539
+ glitch: false,
540
+ })
541
+
542
+ return (
543
+ <>
544
+ <EffectComposer>
545
+ {effects.bloom && (
546
+ <Bloom intensity={1.5} luminanceThreshold={0.9} />
547
+ )}
548
+ {effects.vignette && (
549
+ <Vignette offset={0.5} darkness={0.5} />
550
+ )}
551
+ {effects.glitch && (
552
+ <Glitch delay={[1, 3]} duration={[0.5, 1]} strength={[0.3, 1]} />
553
+ )}
554
+ </EffectComposer>
555
+
556
+ {/* UI to toggle effects */}
557
+ <div className="controls">
558
+ <button onClick={() => setEffects(e => ({ ...e, bloom: !e.bloom }))}>
559
+ Toggle Bloom
560
+ </button>
561
+ <button onClick={() => setEffects(e => ({ ...e, vignette: !e.vignette }))}>
562
+ Toggle Vignette
563
+ </button>
564
+ <button onClick={() => setEffects(e => ({ ...e, glitch: !e.glitch }))}>
565
+ Toggle Glitch
566
+ </button>
567
+ </div>
568
+ </>
569
+ )
570
+ }
571
+ ```
572
+
573
+ ## Animated Effects
574
+
575
+ ```tsx
576
+ import { useRef } from 'react'
577
+ import { useFrame } from '@react-three/fiber'
578
+ import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
579
+
580
+ function AnimatedEffects() {
581
+ const bloomRef = useRef()
582
+ const chromaticRef = useRef()
583
+
584
+ useFrame(({ clock }) => {
585
+ const t = clock.elapsedTime
586
+
587
+ // Animate bloom intensity
588
+ if (bloomRef.current) {
589
+ bloomRef.current.intensity = 1 + Math.sin(t) * 0.5
590
+ }
591
+
592
+ // Animate chromatic aberration
593
+ if (chromaticRef.current) {
594
+ const offset = Math.sin(t * 2) * 0.002
595
+ chromaticRef.current.offset.set(offset, offset)
596
+ }
597
+ })
598
+
599
+ return (
600
+ <EffectComposer>
601
+ <Bloom ref={bloomRef} luminanceThreshold={0.9} />
602
+ <ChromaticAberration ref={chromaticRef} />
603
+ </EffectComposer>
604
+ )
605
+ }
606
+ ```
607
+
608
+ ## N8AO (High Quality AO)
609
+
610
+ ```tsx
611
+ import { EffectComposer } from '@react-three/postprocessing'
612
+ import { N8AO } from '@react-three/postprocessing'
613
+
614
+ <EffectComposer>
615
+ <N8AO
616
+ aoRadius={0.5}
617
+ intensity={1}
618
+ aoSamples={6}
619
+ denoiseSamples={4}
620
+ denoiseRadius={12}
621
+ distanceFalloff={1}
622
+ color="black"
623
+ quality="low" // low, medium, high, ultra
624
+ halfRes={false}
625
+ />
626
+ </EffectComposer>
627
+ ```
628
+
629
+ ## God Rays
630
+
631
+ ```tsx
632
+ import { EffectComposer, GodRays } from '@react-three/postprocessing'
633
+ import { useRef } from 'react'
634
+
635
+ function Scene() {
636
+ const sunRef = useRef()
637
+
638
+ return (
639
+ <Canvas>
640
+ {/* Sun mesh (light source for god rays) */}
641
+ <mesh ref={sunRef} position={[0, 5, -10]}>
642
+ <sphereGeometry args={[1]} />
643
+ <meshBasicMaterial color="#ffddaa" />
644
+ </mesh>
645
+
646
+ <EffectComposer>
647
+ {sunRef.current && (
648
+ <GodRays
649
+ sun={sunRef}
650
+ blendFunction={BlendFunction.SCREEN}
651
+ samples={60}
652
+ density={0.96}
653
+ decay={0.9}
654
+ weight={0.4}
655
+ exposure={0.6}
656
+ clampMax={1}
657
+ blur
658
+ />
659
+ )}
660
+ </EffectComposer>
661
+ </Canvas>
662
+ )
663
+ }
664
+ ```
665
+
666
+ ## LUT (Color Lookup Table)
667
+
668
+ ```tsx
669
+ import { EffectComposer, LUT } from '@react-three/postprocessing'
670
+ import { LUTCubeLoader } from 'postprocessing'
671
+ import { useLoader } from '@react-three/fiber'
672
+
673
+ function ColorGradedScene() {
674
+ const texture = useLoader(LUTCubeLoader, '/luts/cinematic.cube')
675
+
676
+ return (
677
+ <EffectComposer>
678
+ <LUT lut={texture} />
679
+ </EffectComposer>
680
+ )
681
+ }
682
+ ```
683
+
684
+ ## Blend Functions
685
+
686
+ ```tsx
687
+ import { BlendFunction } from 'postprocessing'
688
+
689
+ // Available blend functions:
690
+ BlendFunction.SKIP // Skip blending
691
+ BlendFunction.ADD // Additive
692
+ BlendFunction.ALPHA // Alpha
693
+ BlendFunction.AVERAGE // Average
694
+ BlendFunction.COLOR // Color
695
+ BlendFunction.COLOR_BURN // Color Burn
696
+ BlendFunction.COLOR_DODGE // Color Dodge
697
+ BlendFunction.DARKEN // Darken
698
+ BlendFunction.DIFFERENCE // Difference
699
+ BlendFunction.DIVIDE // Divide
700
+ BlendFunction.DST // Destination
701
+ BlendFunction.EXCLUSION // Exclusion
702
+ BlendFunction.HARD_LIGHT // Hard Light
703
+ BlendFunction.HARD_MIX // Hard Mix
704
+ BlendFunction.HUE // Hue
705
+ BlendFunction.INVERT // Invert
706
+ BlendFunction.INVERT_RGB // Invert RGB
707
+ BlendFunction.LIGHTEN // Lighten
708
+ BlendFunction.LINEAR_BURN // Linear Burn
709
+ BlendFunction.LINEAR_DODGE // Linear Dodge
710
+ BlendFunction.LINEAR_LIGHT // Linear Light
711
+ BlendFunction.LUMINOSITY // Luminosity
712
+ BlendFunction.MULTIPLY // Multiply
713
+ BlendFunction.NEGATION // Negation
714
+ BlendFunction.NORMAL // Normal
715
+ BlendFunction.OVERLAY // Overlay
716
+ BlendFunction.PIN_LIGHT // Pin Light
717
+ BlendFunction.REFLECT // Reflect
718
+ BlendFunction.SATURATION // Saturation
719
+ BlendFunction.SCREEN // Screen
720
+ BlendFunction.SET // Set
721
+ BlendFunction.SOFT_LIGHT // Soft Light
722
+ BlendFunction.SRC // Source
723
+ BlendFunction.SUBTRACT // Subtract
724
+ BlendFunction.VIVID_LIGHT // Vivid Light
725
+ ```
726
+
727
+ ## Performance Tips
728
+
729
+ 1. **Limit effect count**: Each effect adds rendering overhead
730
+ 2. **Use multisampling wisely**: Higher values = slower performance
731
+ 3. **Disable when not needed**: Toggle `enabled` prop
732
+ 4. **Lower resolution**: Some effects have resolution props
733
+ 5. **Profile with DevTools**: Monitor GPU usage
734
+
735
+ ```tsx
736
+ // Disable all effects
737
+ <EffectComposer enabled={performanceMode}>
738
+ ...
739
+ </EffectComposer>
740
+
741
+ // Reduce effect quality on mobile
742
+ const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent)
743
+
744
+ <EffectComposer multisampling={isMobile ? 0 : 8}>
745
+ <Bloom mipmapBlur={!isMobile} radius={isMobile ? 0.4 : 0.8} />
746
+ {!isMobile && <SSAO samples={16} />}
747
+ </EffectComposer>
748
+ ```
749
+
750
+ ## See Also
751
+
752
+ - `r3f-shaders` - Custom shader development
753
+ - `r3f-materials` - Emissive materials for bloom
754
+ - `r3f-fundamentals` - Canvas and renderer setup