Help converting shader from ShaderToy

I want to use this shader from ShaderToy on a plane in my project.

I already made a setup with the ShaderMaterial, but I still need help how to convert the mainImage function to three.js and I can’t get it working. I have trouble setting up the iResolution, iTime, fragColor and fragCoord uniforms in the fragmentShader and also need help with the vertexShader.

Can anyone help me with the fragmentShader, vertexShader and the setup of the uniforms?

I asked Chat GPT. This was its answer

To convert the provided ShaderToy fragment shader to work with Three.js, we will follow a similar process as outlined earlier. We need to create a corresponding vertex shader for Three.js and modify the fragment shader to match Three.js’s conventions. Also, we will set up the necessary uniforms and JavaScript code to render it using Three.js.

Vertex Shader

The vertex shader can be a simple pass-through shader, as the main graphical effect is in the fragment shader.

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

Fragment Shader

In the fragment shader, we adapt the mainImage function to the standard main function used in Three.js shaders and use the uniforms provided by Three.js.

uniform float iTime;
uniform vec2 iResolution;

void main() {
    vec2 uv = -1.0 + 2.0 * gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;

    vec3 color = vec3(0.0);
    for( int i = 0; i < 128; i++ ) {
        float pha = sin(float(i) * 546.13 + 1.0) * 0.5 + 0.5;
        float siz = pow(sin(float(i) * 651.74 + 5.0) * 0.5 + 0.5, 4.0);
        float pox = sin(float(i) * 321.55 + 4.1) * iResolution.x / iResolution.y;
        float rad = 0.1 + 0.5 * siz + sin(pha + siz) / 4.0;
        vec2 pos = vec2(pox + sin(iTime / 15.0 + pha + siz), -1.0 - rad + (2.0 + 2.0 * rad) * mod(pha + 0.3 * (iTime / 7.0) * (0.2 + 0.8 * siz), 1.0));
        float dis = length(uv - pos);
        vec3 col = mix(vec3(0.194 * sin(iTime / 6.0) + 0.3, 0.2, 0.3 * pha), vec3(1.1 * sin(iTime / 9.0) + 0.3, 0.2 * pha, 0.4), 0.5 + 0.5 * sin(float(i)));
        float f = length(uv - pos) / rad;
        f = sqrt(clamp(1.0 + (sin(iTime * siz) * 0.5) * f, 0.0, 1.0));
        color += col.zyx * (1.0 - smoothstep(rad * 0.15, rad, dis));

    color *= sqrt(1.5 - 0.5 * length(uv));
    gl_FragColor = vec4(color, 1.0);

JavaScript/Three.js Code

Now, we set up the Three.js scene, including the uniforms, material, geometry, and mesh.

const uniforms = {
    iTime: { value: 0 },
    iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }

const material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vertexShader, // The vertex shader code
    fragmentShader: fragmentShader // The modified fragment shader code

const geometry = new THREE.PlaneBufferGeometry(2, 2);
const mesh = new THREE.Mesh(geometry, material);

function animate() {

    uniforms.iTime.value += 0.05;

    renderer.render(scene, camera);

Make sure to replace vertexShader and fragmentShader with your actual shader code strings. This setup will render the effect of the original ShaderToy shader in a Three.js context. Remember to adjust the uniforms and rendering loop to suit your specific application’s needs.
In this conversion:

  • We’ve replaced mainImage(out vec4 fragColor, in vec2 fragCoord) with void main().
  • We’ve modified the calculation of uv to use gl_FragCoord instead of fragCoord.
  • The uniforms iTime and iResolution are declared at the top, which you will pass from your Three.js application.

This shader should now work within a Three.js context, using a ShaderMaterial with this fragment shader and a basic vertex shader. Remember to update the uniform values (iTime and iResolution) in your JavaScript code as your scene updates.

1 Like

See from the Collection of examples from

Little Shader Book

a bit more complicated …

And because I was curious.
The ChatGPT answer from @anidivr above is pretty good.
It was almost a verbatim copy paste.
Only error was to change planeBufferGeometry to planeGeoneyrty since I am using r159
Seems ChatGPT learned from an older version.

Since there is a new release every month :thinking:, I asked ChatGPT myself.

Answer translated from German:

"My information is based on knowledge up to January 2022, and I have not received any updates or specific release information for three.js since then. Therefore, I am not referring to a specific release of three.js and my answers cannot take into account the latest features or changes released after my last update. I don’t have real-time access to the Internet, so I can’t get information about the latest three.js versions or other recent developments. It is recommended to regularly check the official three.js documentation and the project’s GitHub page to get the latest information and ensure that your code is compatible with current versions. "


I assume that’s the response from the free version using GPT 3.5.

The answer I posted was from the paid GPT 4 Turbo version. It is much more helpful.

Exactly, I don’t pay anything. :slightly_smiling_face:

1 Like