---
title: Composing effects
description: Stack components as layers and nest them to control which layers an effect touches.
icon: layer-plus
category: code
---

# Composing effects

Stack components as layers and nest them to control which layers an effect touches. This page builds one hero background, a grid over a flowing swirl, a layer at a time.

## Stacking layers

Every component inside a `<Shader>` is a **layer**. Layers are drawn in the order they appear in your markup, like layers in Figma: the first is at the bottom, the last on top.

Some components draw something new, like a swirl or a grid. Others are **effects**: they change what's already been drawn. An effect on its own applies to every layer before it.

Here `<Swirl>` is the background, `<Grid>` draws lines over it, and `<GridDistortion>` bends both around your cursor:

```vue-html
<Shader>
  <!-- Bottom: the background -->
  <Swirl
    color-a="#7355fe"
    color-b="#91e040"
    color-space="oklab"
    :blend="18"
    :detail="0.9"
    :speed="1.5"
  />

  <!-- Grid lines over the swirl -->
  <Grid
    color="#00a2fa"
    :cells="10"
    :thickness="3.2"
    blend-mode="hardLight"
  />

  <!-- Bends everything before it around your cursor -->
  <GridDistortion
    :intensity="5"
    :radius="1.75"
    :decay="1.8"
    :grid-size="8"
    edges="wrap"
  />
</Shader>
```

```jsx
<Shader>
  {/* Bottom: the background */}
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  {/* Grid lines over the swirl */}
  <Grid
    color="#00a2fa"
    cells={10}
    thickness={3.2}
    blendMode="hardLight"
  />

  {/* Bends everything before it around your cursor */}
  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```tsx
<Shader>
  <!-- Bottom: the background -->
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  <!-- Grid lines over the swirl -->
  <Grid
    color="#00a2fa"
    cells={10}
    thickness={3.2}
    blendMode="hardLight"
  />

  <!-- Bends everything before it around your cursor -->
  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```tsx
<Shader>
  {/* Bottom: the background */}
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  {/* Grid lines over the swirl */}
  <Grid
    color="#00a2fa"
    cells={10}
    thickness={3.2}
    blendMode="hardLight"
  />

  {/* Bends everything before it around your cursor */}
  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```javascript
const shader = await createShader(canvas, {
  components: [
    // Bottom: the background
    { type: 'Swirl', props: {
        colorA: '#7355fe',
        colorB: '#91e040',
        colorSpace: 'oklab',
        blend: 18,
        detail: 0.9,
        speed: 1.5,
      } },
    // Grid lines over the swirl
    { type: 'Grid', props: {
        color: '#00a2fa',
        cells: 10,
        thickness: 3.2,
        blendMode: 'hardLight',
      } },
    // Bends everything before it around your cursor
    { type: 'GridDistortion', props: {
        intensity: 5,
        radius: 1.75,
        decay: 1.8,
        gridSize: 8,
        edges: 'wrap',
      } },
  ],
})
```

Move your cursor over the canvas. `<GridDistortion>` comes last, so it bends the swirl and the grid together. The grid's `blendMode` sets how its lines mix with the swirl underneath; [blending and masking](/docs/guide/blending-masking) covers every mode.

## Applying effects to specific layers

To limit an effect to specific layers, put those layers inside it. The effect then applies to its **children** only.

Let's make the grid ripple on its own. Wrapped in `<WaveDistortion>`, the grid lines bend in a slow triangle wave, and the swirl behind them is left alone:

```vue-html
<Shader>
  <Swirl
    color-a="#7355fe"
    color-b="#91e040"
    color-space="oklab"
    :blend="18"
    :detail="0.9"
    :speed="1.5"
  />

  <!-- Only the grid waves -->
  <WaveDistortion
    wave-type="triangle"
    :strength="0.8"
    :frequency="0.7"
    :angle="235"
    :speed="0.5"
    edges="mirror"
    blend-mode="linearDodge"
  >
    <Grid
      color="#00a2fa"
      :cells="10"
      :thickness="3.2"
      blend-mode="hardLight"
    />
  </WaveDistortion>

  <GridDistortion
    :intensity="5"
    :radius="1.75"
    :decay="1.8"
    :grid-size="8"
    edges="wrap"
  />
</Shader>
```

```jsx
<Shader>
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  {/* Only the grid waves */}
  <WaveDistortion
    waveType="triangle"
    strength={0.8}
    frequency={0.7}
    angle={235}
    speed={0.5}
    edges="mirror"
    blendMode="linearDodge"
  >
    <Grid
      color="#00a2fa"
      cells={10}
      thickness={3.2}
      blendMode="hardLight"
    />
  </WaveDistortion>

  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```tsx
<Shader>
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  <!-- Only the grid waves -->
  <WaveDistortion
    waveType="triangle"
    strength={0.8}
    frequency={0.7}
    angle={235}
    speed={0.5}
    edges="mirror"
    blendMode="linearDodge"
  >
    <Grid
      color="#00a2fa"
      cells={10}
      thickness={3.2}
      blendMode="hardLight"
    />
  </WaveDistortion>

  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```tsx
<Shader>
  <Swirl
    colorA="#7355fe"
    colorB="#91e040"
    colorSpace="oklab"
    blend={18}
    detail={0.9}
    speed={1.5}
  />

  {/* Only the grid waves */}
  <WaveDistortion
    waveType="triangle"
    strength={0.8}
    frequency={0.7}
    angle={235}
    speed={0.5}
    edges="mirror"
    blendMode="linearDodge"
  >
    <Grid
      color="#00a2fa"
      cells={10}
      thickness={3.2}
      blendMode="hardLight"
    />
  </WaveDistortion>

  <GridDistortion
    intensity={5}
    radius={1.75}
    decay={1.8}
    gridSize={8}
    edges="wrap"
  />
</Shader>
```

```javascript
const shader = await createShader(canvas, {
  components: [
    { type: 'Swirl', props: {
        colorA: '#7355fe',
        colorB: '#91e040',
        colorSpace: 'oklab',
        blend: 18,
        detail: 0.9,
        speed: 1.5,
      } },
    // Only the grid waves
    { type: 'WaveDistortion', props: {
        waveType: 'triangle',
        strength: 0.8,
        frequency: 0.7,
        angle: 235,
        speed: 0.5,
        edges: 'mirror',
        blendMode: 'linearDodge',
      }, children: [
      { type: 'Grid', props: {
          color: '#00a2fa',
          cells: 10,
          thickness: 3.2,
          blendMode: 'hardLight',
        } },
    ]},
    { type: 'GridDistortion', props: {
        intensity: 5,
        radius: 1.75,
        decay: 1.8,
        gridSize: 8,
        edges: 'wrap',
      } },
  ],
})
```

`<GridDistortion>` still applies to everything, because it stays outside the wrapper. Without the wrapper, `<WaveDistortion>` would bend the swirl too.

This works at any depth. An effect can wrap another effect, and they apply from the inside out: the innermost layer is drawn first, and each wrapper applies to the result.

## Knowing which components take children

Components that draw something new, such as `<Swirl>` and `<Grid>`, don't take children. Effects such as `<WaveDistortion>` and `<GridDistortion>` do. On an effect's [component page](/docs/components), the usage example shows it wrapping a child.

## Next steps

- [Blending and masking](/docs/guide/blending-masking): control how layers mix, and reveal one layer through another.
- [Dynamic props](/docs/guide/dynamic-props): drive props from the mouse or animate them without writing animation code.
- [Performance](/docs/guide/performance): what each layer costs and how to keep effects fast.