Overview
Paper Shaders are highly customizable through parameters that control colors, animation, distortion, and visual effects. This guide covers how to customize shaders to match your design needs.
Using Presets
Each shader comes with carefully crafted presets that showcase different aesthetics:
import { MeshGradient , meshGradientPresets } from '@paper-design/shaders-react' ;
function App () {
// Find a preset by name
const beachPreset = meshGradientPresets . find ( p => p . name === 'Beach' );
return (
< MeshGradient
{ ... beachPreset . params }
style = { { width: 400 , height: 400 } }
/>
);
}
// Presets aren't exported in vanilla package
// But you can reference them from React package source
// Or define your own preset objects
const beachPreset = {
colors: [ '#bcecf6' , '#00aaff' , '#00f7ff' , '#ffd447' ],
distortion: 0.8 ,
swirl: 0.35 ,
speed: 0.1 ,
};
Available Preset Exports
Each shader component exports its presets:
import {
meshGradientPresets ,
smokeRingPresets ,
neuroNoisePresets ,
dotOrbitPresets ,
dotGridPresets ,
simplexNoisePresets ,
metaballsPresets ,
wavesPresets ,
perlinNoisePresets ,
voronoiPresets ,
warpPresets ,
godRaysPresets ,
spiralPresets ,
swirlPresets ,
ditheringPresets ,
grainGradientPresets ,
pulsingBorderPresets ,
colorPanelsPresets ,
staticMeshGradientPresets ,
staticRadialGradientPresets ,
paperTexturePresets ,
flutedGlassPresets ,
waterPresets ,
imageDitheringPresets ,
heatmapPresets ,
liquidMetalPresets ,
halftoneDotsPresets ,
halftoneCmykPresets ,
} from '@paper-design/shaders-react' ;
Color Customization
Color Formats
Shaders accept colors in multiple formats:
// Hex colors (most common)
< MeshGradient colors = { [ '#5100ff' , '#00ff80' , '#ffcc00' ] } />
// RGB/RGBA
< MeshGradient colors = { [ 'rgb(81, 0, 255)' , 'rgba(0, 255, 128, 0.8)' ] } />
// HSL/HSLA
< MeshGradient colors = { [ 'hsl(258, 100%, 50%)' , 'hsla(150, 100%, 50%, 0.8)' ] } />
// Array notation (0-1 range RGBA)
< MeshGradient colors = { [
[ 0.32 , 0 , 1 , 1 ], // RGB + alpha
[ 0 , 1 , 0.5 , 0.8 ] // RGB + alpha
] } />
import { getShaderColorFromString } from '@paper-design/shaders' ;
const uniforms = {
u_colors: [
getShaderColorFromString ( '#5100ff' ),
getShaderColorFromString ( 'rgb(0, 255, 128)' ),
getShaderColorFromString ( 'hsl(258, 100%, 50%)' ),
[ 0.32 , 0 , 1 , 1 ], // Can also pass arrays directly
],
u_colorsCount: 4 ,
};
Color Limits
Each shader has a maximum color count:
import { meshGradientMeta } from '@paper-design/shaders' ;
console . log ( meshGradientMeta . maxColorCount ); // 10
Common limits:
MeshGradient : 10 colors
DotOrbit : 40 colors
GodRays : 5 colors
Warp : 10 colors
StaticMeshGradient : 10 colors
StaticRadialGradient : 10 colors
Working with Alpha
Colors support transparency:
// 50% transparent colors
< MeshGradient colors = { [
'#5100ff80' , // Hex with alpha
'rgba(0, 255, 128, 0.5)' , // RGBA
'hsla(258, 100%, 50%, 0.5)' , // HSLA
[ 0.32 , 0 , 1 , 0.5 ] // Array with alpha
] } />
Transparent colors let background elements show through, enabling layered effects.
Parameter Ranges
Most shader parameters use normalized 0-1 ranges for consistency:
Common Parameters
< MeshGradient
distortion = { 0.8 } // 0-1: organic noise distortion
swirl = { 0.1 } // 0-1: vortex distortion
grainMixer = { 0 } // 0-1: grain on shape edges
grainOverlay = { 0 } // 0-1: post-processing grain
speed = { 1 } // 0+: animation speed (can be negative)
/>
Speed Parameter
The speed parameter is special:
// Normal animation
< MeshGradient speed = { 1 } />
// Static (no animation, no performance cost)
< MeshGradient speed = { 0 } />
// Slow motion
< MeshGradient speed = { 0.5 } />
// Fast
< MeshGradient speed = { 2 } />
// Reverse
< MeshGradient speed = { - 1 } />
When speed={0}, requestAnimationFrame stops entirely, making static shaders
completely free from ongoing performance costs.
Frame Parameter
Set starting frame for deterministic results:
// Start at 5 seconds in
< MeshGradient speed = { 1 } frame = { 5000 } />
// Useful for:
// - Matching animation state across multiple shaders
// - Creating consistent screenshots/thumbnails
// - Synchronized animations
Shader-Specific Parameters
MeshGradient
< MeshGradient
colors = { [ '#e0eaff' , '#241d9a' , '#f75092' , '#9f50d3' ] }
distortion = { 0.8 } // Organic noise (0-1)
swirl = { 0.1 } // Vortex effect (0-1)
grainMixer = { 0 } // Edge grain (0-1)
grainOverlay = { 0 } // Overall grain (0-1)
speed = { 1 }
// Sizing (see Sizing guide)
fit = "contain"
scale = { 1 }
rotation = { 0 }
/>
DotOrbit
< DotOrbit
colors = { [ '#d2822d' , '#0c3b7e' , '#b31a57' , '#37a066' ] }
colorBack = "#000000" // Background color
scale = { 0.3 } // Dot size (0.1-2)
speed = { 1 } // Orbit speed
dotShape = { 1 } // 0=circle, 1=soft, 2=ring, 3=square
dotSize = { 0.5 } // Individual dot size (0-1)
fadeToCenter = { 0 } // Center fade (0-1)
animateSize = { 0 } // Size animation (0-1)
/>
Water (Image Filter)
< Water
image = "/path/to/image.jpg"
colorBack = "#909090"
colorHighlight = "#ffffff"
highlights = { 0.3 } // Highlight intensity (0-1)
layering = { 0.5 } // Depth layers (0-1)
edges = { 0.8 } // Edge detection (0-1)
waves = { 0.3 } // Wave distortion (0-1)
caustic = { 0.1 } // Light caustics (0-1)
size = { 1 } // Effect scale (0-2)
speed = { 1 }
/>
Warp
import { WarpPatterns } from '@paper-design/shaders' ;
< Warp
colors = { [ '#ff0000' , '#00ff00' , '#0000ff' ] }
pattern = { WarpPatterns . checks } // checks, stripes, split
distortion = { 0.5 } // Noise distortion (0-1)
swirl = { 0.5 } // Swirl effect (0-1)
softness = { 0.5 } // Color blend (0-1)
speed = { 1 }
/>
GodRays
< GodRays
colors = { [ '#ff0000' , '#ffff00' , '#ffffff' ] }
raySize = { 0.5 } // Ray thickness (0-1)
rayDensity = { 0.5 } // Number of rays (0-1)
brightness = { 0.7 } // Overall brightness (0-1)
centerGlow = { 0.3 } // Center light (0-1)
speed = { 1 }
/>
Experiment with parameters in Paper (the visual editor) or check the API
reference for complete parameter lists.
Dynamic Updates
Update parameters in response to user interaction:
import { useState } from 'react' ;
import { MeshGradient } from '@paper-design/shaders-react' ;
function App () {
const [ distortion , setDistortion ] = useState ( 0.8 );
const [ swirl , setSwirl ] = useState ( 0.1 );
return (
< div >
< MeshGradient
colors = { [ '#5100ff' , '#00ff80' , '#ffcc00' ] }
distortion = { distortion }
swirl = { swirl }
style = { { width: 400 , height: 400 } }
/>
< label >
Distortion: { distortion . toFixed ( 2 ) }
< input
type = "range"
min = "0"
max = "1"
step = "0.01"
value = { distortion }
onChange = { ( e ) => setDistortion ( Number ( e . target . value )) }
/>
</ label >
< label >
Swirl: { swirl . toFixed ( 2 ) }
< input
type = "range"
min = "0"
max = "1"
step = "0.01"
value = { swirl }
onChange = { ( e ) => setSwirl ( Number ( e . target . value )) }
/>
</ label >
</ div >
);
}
const distortionSlider = document . getElementById ( 'distortion' );
const swirlSlider = document . getElementById ( 'swirl' );
distortionSlider . addEventListener ( 'input' , ( e ) => {
shaderMount . setUniforms ({
u_distortion: Number ( e . target . value ),
});
});
swirlSlider . addEventListener ( 'input' , ( e ) => {
shaderMount . setUniforms ({
u_swirl: Number ( e . target . value ),
});
});
Combining Shaders
Layer multiple shaders for complex effects:
function LayeredShaders () {
return (
< div style = { { position: 'relative' , width: 400 , height: 400 } } >
{ /* Background gradient */ }
< MeshGradient
colors = { [ '#000000' , '#1a1a2e' ] }
speed = { 0.5 }
style = { { position: 'absolute' , inset: 0 } }
/>
{ /* Overlay texture */ }
< PaperTexture
colorMix = { 0.1 }
grainIntensity = { 0.3 }
speed = { 0 }
style = { {
position: 'absolute' ,
inset: 0 ,
mixBlendMode: 'overlay' ,
opacity: 0.3 ,
} }
/>
{ /* Top pattern */ }
< DotOrbit
colors = { [ '#00ff88' , '#0088ff' ] }
colorBack = "transparent"
scale = { 0.3 }
speed = { 1 }
style = { {
position: 'absolute' ,
inset: 0 ,
mixBlendMode: 'screen' ,
} }
/>
</ div >
);
}
Use CSS mix-blend-mode and opacity to blend shaders together creatively.
Responsive Parameters
Adjust parameters based on screen size:
import { useState , useEffect } from 'react' ;
function ResponsiveShader () {
const [ isMobile , setIsMobile ] = useState ( false );
useEffect (() => {
const checkMobile = () => setIsMobile ( window . innerWidth < 768 );
checkMobile ();
window . addEventListener ( 'resize' , checkMobile );
return () => window . removeEventListener ( 'resize' , checkMobile );
}, []);
return (
< MeshGradient
colors = { [ '#5100ff' , '#00ff80' , '#ffcc00' ] }
speed = { isMobile ? 0.5 : 1 } // Slower on mobile
distortion = { isMobile ? 0.5 : 0.8 } // Less distortion on mobile
maxPixelCount = { isMobile ? 1920 * 1080 : 1920 * 1080 * 4 }
style = { { width: '100%' , height: isMobile ? 300 : 500 } }
/>
);
}
Color Palette Tools
Generating Complementary Colors
// Helper to generate color variations
function generatePalette ( baseColor , count ) {
const hue = parseInt ( baseColor . slice ( 1 , 3 ), 16 );
const palette = [];
for ( let i = 0 ; i < count ; i ++ ) {
const offset = ( 360 / count ) * i ;
const newHue = ( hue + offset ) % 360 ;
palette . push ( `hsl( ${ newHue } , 70%, 50%)` );
}
return palette ;
}
const colors = generatePalette ( '#5100ff' , 4 );
Color Interpolation
// Interpolate between two colors
function interpolateColors ( color1 , color2 , steps ) {
const c1 = getShaderColorFromString ( color1 );
const c2 = getShaderColorFromString ( color2 );
const colors = [];
for ( let i = 0 ; i < steps ; i ++ ) {
const t = i / ( steps - 1 );
colors . push ([
c1 [ 0 ] + ( c2 [ 0 ] - c1 [ 0 ]) * t ,
c1 [ 1 ] + ( c2 [ 1 ] - c1 [ 1 ]) * t ,
c1 [ 2 ] + ( c2 [ 2 ] - c1 [ 2 ]) * t ,
c1 [ 3 ] + ( c2 [ 3 ] - c1 [ 3 ]) * t ,
]);
}
return colors ;
}
Best Practices
Performance-Conscious Customization
Use static shaders when possible
Set speed={0} for backgrounds that don’t need animation.
Limit color count
More colors = more GPU calculations. Use 3-5 colors for best performance.
Reduce parameters on mobile
Lower distortion, grain, and other effects on mobile devices.
Test on target devices
Always test customizations on actual devices, not just desktop.
Visual Quality Tips
Use complementary colors (opposite on color wheel) for vibrant looks
Use analogous colors (adjacent on color wheel) for harmony
Include one darker color for depth
Test with different backgrounds
Subtle effects: 0.2-0.5 speed
Standard: 0.8-1.2 speed
Energetic: 1.5-2.5 speed
Match speed to your brand personality
Start with preset as baseline
Adjust one parameter at a time
Avoid maxing out all effects (looks noisy)
Less is often more
Preset Switching
Create smooth preset transitions:
import { useState } from 'react' ;
import { MeshGradient , meshGradientPresets } from '@paper-design/shaders-react' ;
function PresetSwitcher () {
const [ presetIndex , setPresetIndex ] = useState ( 0 );
const currentPreset = meshGradientPresets [ presetIndex ];
return (
< div >
< MeshGradient
{ ... currentPreset . params }
style = { {
width: 400 ,
height: 400 ,
transition: 'all 0.5s ease' , // Smooth transitions
} }
/>
< div >
{ meshGradientPresets . map (( preset , i ) => (
< button
key = { preset . name }
onClick = { () => setPresetIndex ( i ) }
disabled = { i === presetIndex }
>
{ preset . name }
</ button >
)) }
</ div >
</ div >
);
}
CSS transitions only work on the container element, not shader parameters.
For parameter transitions, use state and interpolate values over time.
Saving Custom Presets
Store and share your custom configurations:
// Define custom preset
const myCustomPreset = {
name: 'Ocean Sunset' ,
params: {
colors: [ '#ff6b35' , '#f7931e' , '#c9cba3' , '#1d3557' ],
distortion: 0.6 ,
swirl: 0.4 ,
grainMixer: 0.1 ,
grainOverlay: 0 ,
speed: 0.3 ,
fit: 'contain' ,
scale: 1 ,
rotation: 0 ,
},
};
// Save to localStorage
localStorage . setItem ( 'shaderPreset' , JSON . stringify ( myCustomPreset ));
// Load from localStorage
const loadedPreset = JSON . parse ( localStorage . getItem ( 'shaderPreset' ));
Next Steps
Sizing & Fit Control how shaders scale and fit containers
Performance Optimize customized shaders for production
API Reference Explore all shader parameters
React Usage React-specific customization patterns