Use FragmentShader with Reactjs Easily ~react-vfx~

0xkoji - Dec 30 '19 - - Dev Community

There are some options to use Shaders with javascript/typescript.
I just saw an npm package that allows me to use fragment shader easily.
I'm using typescript, but in this case I don't really use ts lol.

GitHub logo fand / react-vfx

WebGL effects for React elements

REACT-VFX

REACT-VFX: WebGL effects for React elements!!



Install

npm i -S react-vfx

Usage

REACT-VFX exports VFXSpan, VFXImg and VFXVideo These components works just like <span>, <img> and <video> - accepts all properties they have, but they are rendered in WebGL world with shader effects!

import * as VFX from 'react-vfx';
export default () => (
    <VFX.VFXProvider>
        {/* Render text as image, then apply the shader effect! */}
        <VFX.VFXSpan shader="rainbow">Hi there!</VFX.VFXSpan>

        {/* Render image with shader */}
        <VFX.VFXImg src="cat.png" alt="image" shader="rgbShift"/>

        {/* It also supports animated GIFs! */}
        <VFX.VFXImg src="doge.gif" shader="pixelate"/>

        {/* and videos! */}
        <VFX.VFXVideo src="mind_blown.mp4"
            autoplay playsinline
Enter fullscreen mode Exit fullscreen mode

In this post, I will show you how to use react-vfx for displaying FragmentShaders.

Steps

Step1. Create a new react app by create-react-app

Step2. Install react-vfx

Step3. Create a new component for FragmentShader

Step4. Run the app

Step1 Create react app

In this case, we will use create-react-app. If you have a template, you can use it.

Here is one thing you should know about create-react-app

If you've previously installed create-react-app globally via npm install -g create-react-app, we recommend you uninstall the package using npm uninstall -g create-react-app to ensure that npx always uses the latest version.
Global installs of create-react-app are no longer supported.

If you install react-create-app globally, I recommend you to uninstall it since it may prevent you to create a new react app(Actually my case didn't create an app properly just generate package.json and a couple of files)

$ npx create-react-app myshader --template typescript
# or I used yarn since I have switched a package manager from npm to yarn
$ yarn create react-app myshader --template typescript
Enter fullscreen mode Exit fullscreen mode

If you don't want to use Typescript try the following.

$ npx create-react-app myshader
# or
$ yarn create react-app myshader
Enter fullscreen mode Exit fullscreen mode

This isn't necessary, but I prefer to run before adding a component.

$ yarn start
Enter fullscreen mode Exit fullscreen mode

You will see this.
Alt Text

Step2 Install react-vfx

# using styled-components
$ yarn add react-vfx styled-components
$ yarn add -D @types/styled-components <-- if you use typescript

# or
$ npm install react-vfx styled-components
$ npm install -D @types/styled-components <-- if you use typescript
Enter fullscreen mode Exit fullscreen mode

Step3 Create component

In this case, I created a new file, MyShader.tsx under src. If you are using js, the file's extension should be .jsx

import React from "react";
import * as VFX from "react-vfx";
import styled from "styled-components";

const Content = styled.div`
  width: 100vw;
  height: 100vh;
`;

const metal = `
uniform vec2 resolution;
uniform float time;
void main()
{
    vec2 coord = gl_FragCoord.xy / resolution.xy;
    vec2 st = coord;
    vec3 line = vec3(0.0);

    coord *= 4.;

    float len;

    for (int i = 0; i < 15; i++) {
        len = length(vec2(coord.x, coord.y));
        coord.x += cos(coord.y + sin(len)) + cos(time * .07) * 0.2;
        coord.y += sin(coord.x + cos(len)) + sin(time * 0.1);
    }

    len *= cos(len * 0.4);

    len -= 10.;

    for (float i = 0.0; i < 5.0; i++) {
        len += 0.11 / abs(mod(st.x, 1.09 * i) * 200.) * 1.;
    }

    vec3 color = vec3(cos(len + 0.2) * 1.15, cos(len + 0.1), cos(len - 0.05));

    gl_FragColor = vec4(color, 1.0);
}
`;

const MyShader: React.FC = () => {
  return (
    <>
      <VFX.VFXProvider>
        <VFX.VFXSpan shader={metal}>
          <Content></Content>
        </VFX.VFXSpan>
      </VFX.VFXProvider>
    </>
  );
}

export default MyShader;
Enter fullscreen mode Exit fullscreen mode

As you can see the code is very simple except Fragment shader.

Import packages and create a styled tag, Content and write a Fragment Shader, metal. Then add react-vfx.

Actually, I tried the following. But it didn't render the content properly. Haven't checked the exact issue lol.

const MyShader: React.FC = () => {
  return (
    <>
      <VFX.VFXProvider>
        <VFX.VFXSpan shader={metal}>
        </VFX.VFXSpan>
      </VFX.VFXProvider>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step4 Run app

$ yarn start
Enter fullscreen mode Exit fullscreen mode

If everything works well, you will see the following. (Actually, what you will see is an animation.)

Alt Text

I use threejs to use fragment shader which is pretty good since threejs has nice samples so I just need to modify shader part and threejs input's part. However, with typescript the setup is a little bit troublesome to me. But, react-vfx is very handy since it is written in typescript so I don't need to install any @type file for it. I will use this for updating my portfolio site.

I pushed my sample code.
https://github.com/koji/typescript/tree/master/shadereact

Also, you can find out some nice samples on the creator's site.
https://amagi.dev/react-vfx/

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .