REACT-VFX の shader preset を全部試す

## この記事の概要

[REACT-VFX](https://amagi.dev/react-vfx/) は React アプリケーション内で WebGL のエフェクトを簡単に使えるようになるライブラリです。

WebGL を使ってアレコレするというと [three.js](https://threejs.org/) が有名かもしれませんが、画面の位置と要素の座標をあわせる処理など結構大変です。

そういった点を REACT-VFX は良い感じに処理してくれるので便利です。

そして実は shader のプリセットが結構用意されているのですが、公式ドキュメントではあまり紹介されていません。[^1]

[^1]: リポジトリ内を `preset` で検索しましたがあまりヒットしなかったので、恐らくあまり紹介されていないはず……ただ、違う場所にあって私が見落としているだけの可能性は否めません。

せっかくなので一通り紹介します。

:::note
なお、この記事を執筆している 2024 年 7 月 14 日現在の REACT-VFX のバージョンは 0.9.1 です。
:::

## 一覧

- [uvGradient](#uvgradient)
- [rainbow](#rainbow)
- [glitch](#glitch)
- [rgbGlitch](#rgbglitch)
- [rgbShift](#rgbShift)
- [shine](#shine)
- [blink](#blink)
- [spring](#spring)
- [duotone](#duotone)
- [tritone](#tritone)
- [hueShift](#hueShift)
- [sinewave](#sinewave)
- [pixelate](#pixelate)
- [halftone](#halftone)
- [slitScanTransition](#slitscantransition)
- [warpTransition](#warptransition)
- [pixelateTransition](#pixelatetransition)

## uvGradient

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/4623d19a-cbb1-a6f6-ca3c-763b2dc85c0f.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="uvGradient">uvGradient</VFXSpan>
  )
}
```

## rainbow

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f11debaf-cd79-55b4-393c-f2d72199ff6f.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="rainbow">rainbow</VFXSpan>
  )
}
```

## glitch

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/9ba41f02-97ca-e518-e9c3-617d69f6491d.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="glitch">glitch</VFXSpan>
  )
}
```

## rgbGlitch

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/9e629382-7600-5d33-9a54-0b9926eb7409.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="rgbGlitch">rgbGlitch</VFXSpan>
  )
}
```

## rgbShift

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/b6b67e81-6504-9330-8d2f-7a0f32644e8c.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="rgbShift">rgbShift</VFXSpan>
  )
}
```

## shine

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/e1274c01-ecc8-ace4-22fc-841a4e97b8f3.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="shine">shine</VFXSpan>
  )
}
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/807cac30-2c20-3b5c-0123-db115a8227cf.gif)

## blink

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="blink">blink</VFXSpan>
  )
}
```

## spring

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/ce5ead68-4772-7161-f090-824e17617bb8.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="spring">spring</VFXSpan>
  )
}
```

## duotone

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/b89295f5-e10f-99c1-5fce-63449150e12c.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan
      shader="duotone"
      uniforms={{
        color1: [1, 0.2, 0.2, 1],
        color2: [0.2, 0.2, 1, 1],
        speed: 1,
      }}
    >
      duotone
    </VFXSpan>
  )
}
```

:::note
ここまでの要素は単に`shader`を指定すれば表示されていましたが、`duotone`は uniform 変数で明示的に色を渡す必要があります。
:::

## tritone

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/e6ff50a2-5f4c-7989-d510-d943eb187196.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan
      shader="tritone"
      uniforms={{
        color1: [1, 0.2, 0.2, 1],
        color2: [0.2, 0.2, 1, 1],
        color3: [0.2, 1, 0.2, 1],
        speed: 1,
      }}
    >
  )
}
```

:::note
`tritone`も`duotone`と同様に uniform 変数で明示的に色を渡す必要があります。
:::

## hueShift

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="hueShift" uniforms={{ shift: 0.2 }}>hueShift</VFXSpan>
  )
}
```

:::note
uniform 変数で渡した`shift`の分だけ色相がズレます。
:::

## sinewave

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/b16bac36-0924-a830-ea74-ee5582e659f0.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="sinewave">sinewave</VFXSpan>
  )
}
```

## pixelate

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/58704e84-80f0-2b9b-f47a-290176c2c1e2.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="pixelate">pixelate</VFXSpan>
  )
}
```

## halftone

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f8eb05a6-b710-d64b-9291-d33c4447fc6b.png)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="halftone">halftone</VFXSpan>
  )
}
```

:::note
他の添付画像はアニメーションしていますが、これは静止画です。
もともとアニメーションしていません。
:::

## slitScanTransition

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f9dddede-a781-7d09-a75a-09e7b4c17168.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="slitScanTransition">slitScanTransition</VFXSpan>
  )
}
```

:::note
`*Transition`の名前のものは、画面内に入ったときアニメーションするタイプのものです。
:::

## warpTransition

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f9bb5c45-d220-18b2-2d88-3169daeafb5a.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="warpTransition">warpTransition</VFXSpan>
  )
}
```

## pixelateTransition

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/944f460f-e720-9b2f-5a0f-f52c29e07389.gif)

```jsx:App.jsx
import { VFXSpan } from "react-vfx";

function App() {
  return (
    <VFXSpan shader="pixelateTransition">pixelateTransition</VFXSpan>
  )
}
```

## 最後に

このように、自分でシェーダーが全然書けなくても WebGL でのエフェクトを取り入れることができます。

今回はテキスト要素で例を出していましたが、画像なら`VFXImg`、動画なら`VFXVideo`を使用すれば同様に使うことができます。