Effects

Blend modes, filters, shadows, gradients, masks and backdrops.

App.tsx
1import { BackdropBlur, Canvas, Circle, DropShadow, RoundedRect } from 'react-native-tgfx'
2
3export const Frosted = () => (
4 <Canvas style={{ flex: 1 }}>
5 <Circle cx={118} cy={128} r={88} color="#f59e0b" />
6 <Circle cx={292} cy={236} r={100} color="#ec4899" />
7 <Circle cx={96} cy={352} r={60} color="#0ea5e9" />
8 <BackdropBlur x={36} y={190} r={28}
9 width={330} height={170} blur={0} />
10 <RoundedRect x={36} y={190} r={28}
11 width={330} height={170}
12 color="rgba(255,255,255,0.3)">
13 <DropShadow dy={16} blur={32}
14 color="#00000040" />
15 </RoundedRect>
16 </Canvas>
17)
9:41

Effects and shaders are children of a drawing or Paint.

Blend modes

blendMode on any drawing or Paint (BlendMode).

<Circle cx={80} cy={70} r={45} color="#f2c088" />
<Circle cx={120} cy={70} r={45} color="#6aa9ff" blendMode="multiply" />

Colour filters

<TgfxImage image={photo} x={0} y={0} width={200} height={200} fit="cover">
  <ColorMatrix matrix={GREYSCALE} />
</TgfxImage>

ColorMatrix (4×5, row-major) · BlendColor · Luma · AlphaThreshold

<Path path="M20 80 L80 20 L140 80 L80 140 Z" color="#ffffff">
  <BlendColor color="#e0533d" mode="src" />
</Path>

<AlphaThreshold> makes alpha below threshold transparent and the rest opaque.

Blur and shadow

<Circle cx={100} cy={100} r={40} color="#6aa9ff">
  <Blur blur={12} />
</Circle>
<RoundedRect x={30} y={25} width={160} height={100} r={16} color="#f5f7fa">
  <DropShadow dx={0} dy={6} blur={8} color="rgba(0,0,0,0.45)" />
</RoundedRect>

BlurProps · DropShadowProps

Filter order

Filters apply in declaration order.

<Luma /><Blur blur={8} />   // luminance, then blur the result
<Blur blur={8} /><Luma />   // blur, then take the luminance of that

Blur, then threshold, for a sticker outline or metaball:

<Circle cx={100} cy={100} r={40} color="#6aa9ff">
  <Blur blur={12} />
  <AlphaThreshold threshold={0.6} />
</Circle>

Gradients and noise

LinearGradient · RadialGradient · SweepGradient · DiamondGradient · ColorShader · FractalNoise · Turbulence

<Rect x={0} y={0} width={300} height={140}>
  <LinearGradient
    start={{ x: 0, y: 0 }}
    end={{ x: 300, y: 0 }}
    colors={['#d98a4a', '#6aa9ff']}
  />
</Rect>

Blend combines its shader children left to right:

<Rect x={0} y={0} width={256} height={256}>
  <Blend mode="multiply">
    <RadialGradient center={{ x: 128, y: 128 }} r={128} colors={['blue', 'yellow']} />
    <Turbulence freqX={0.05} freqY={0.05} octaves={4} />
  </Blend>
</Rect>

Film grain

FilmGrain is a child of a Group. It adds grain over what the group drew.

<Group>
  <TgfxImage image={photo} x={0} y={0} width={300} height={200} />
  <FilmGrain size={2} density={0.4} color="rgba(255,255,255,0.35)" />
</Group>

color sets one grain colour. Add secondColor for two-tone grain. With neither, opacity sets the strength.

<FilmGrain size={3} density={0.5} color="white" secondColor="black" />
<FilmGrain size={1.5} density={0.6} opacity={0.25} />

Change seed every frame to make the grain move:

const seed = useSharedValue(0)
useFrameCallback(() => { seed.value += 1 })

<FilmGrain size={2} density={0.4} color="white" seed={seed} />

Grain costs about two draws of its group per frame, so keep the group small.

Mask

MaskProps: mode is 'alpha' or 'luminance'.

<Mask
  mode="luminance"
  mask={
    <Rect x={0} y={0} width={256} height={256}>
      <RadialGradient center={{ x: 128, y: 128 }} r={128} colors={['white', 'black']} />
    </Rect>
  }
>
  <TgfxImage image={photo} x={0} y={0} width={256} height={256} />
</Mask>

Backdrop

BackdropBlur and Glass read the pixels drawn beneath them.

<TgfxImage image={photo} x={0} y={0} width={300} height={200} />
<BackdropBlur x={20} y={40} width={260} height={120} r={24} blur={16} />
<Glass x={20} y={40} width={260} height={120} r={24} refraction={40} frost={30} />

Put the panel after the content it covers. It is not pressable.

Lighting the glass

refraction, depth, frost and dispersion shape the material. splay, lightAngle and lightIntensity light it.

<Glass
  x={20} y={40} width={260} height={120} r={24}
  refraction={40} depth={20} frost={30}
  splay={0}            // 0 follows the edge curvature, 100 aims at the centre
  lightAngle={45}      // degrees; 0 is straight above, positive turns clockwise
  lightIntensity={50}  // 0 removes the highlight and leaves refraction and frost
/>

lightIntensity defaults to 50.

All of these, plus blur, can be animated:

const angle = useSharedValue(45)
const panel = useNode()

<Glass ref={panel} x={20} y={40} width={260} height={120} r={24} lightAngle={angle} />
// or, from an event handler: panel.set({ lightAngle: 120 })

r cannot be animated.

BackdropProps · GlassProps

On this page