0

I'm trying to Create the nextJS Slideshow component using curtainsJS and GSAP. I'm following this algorithm. I'm used curtainsJS npm library to create this slide show. this is the slideshow I have created

but images not rendering in the canvas in code sandbox it work perfectly with HTML. here is my slideshow class component

// @ts-ignore
import { Curtains, Plane }from 'curtainsjs'
import gsap, { Power2, TweenMax } from 'gsap'
interface IObjectKeys{
    [key: string]: HTMLElement | null;
}
interface IButtons extends IObjectKeys{
    prevButton: HTMLElement | null;
    nextButton: HTMLElement | null;
}
 class WebglSlideshow{
    private webGLContainer: HTMLElement | null;
    private slideShow: HTMLElement | null;
    private slides: HTMLCollectionOf<Element>;
    private duration: number;
    private activeTextureIndex: number;
    private nextTextureIndex: number;
    private nbSlides: number;
    private isAnimating: boolean;
    private curtains: any;
    private slideshowPlane: any;
    private buttons: IButtons ;

    constructor() {
        this.webGLContainer = document.getElementById('curtains-canvas')
        this.slideShow = document.getElementById('slides-list')
        this.slides = document.getElementsByClassName('slide')
        this.buttons = {
            prevButton: document.getElementById('previous-slide'),
            nextButton: document.getElementById('next-slide')
        }
        this.duration = 1
        this.activeTextureIndex = 0;
        this.nextTextureIndex = 1;
        this.nbSlides = this.slides.length,

            this.isAnimating = false;

        this.init();
    }

    private init() {
        this.setupCurtains();
        this.setupButtonPlanes();
        this.setupSlideshowPlane();
        this.initNavigation();
        
    }
    private setupCurtains() {
        // create a new Curtains object
        this.curtains = new Curtains({
            container: this.webGLContainer
        }).onError( () => {
            // TODO handle webgl errors
        });
    }

    private setupSlideshowPlane() {
        const vs = `
      #ifdef GL_ES
      precision mediump float;
      #endif

      // default mandatory variables
      attribute vec3 aVertexPosition;
      attribute vec2 aTextureCoord;

      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;

      // varyings : notice we've got 2 texture coords varyings
      // one for our visible texture
      // and one for the upcoming texture
      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
      varying vec2 vActiveTextureCoord;
      varying vec2 vNextTextureCoord;

      // textures matrices
      uniform mat4 activeTexMatrix;
      uniform mat4 nextTexMatrix;

      // custom uniforms
      uniform float uTransition;

      void main() {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

        // varyings
        vTextureCoord = aTextureCoord;
        vActiveTextureCoord = (activeTexMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
        vNextTextureCoord = (nextTexMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
        vVertexPosition = aVertexPosition;
      }
    `;

        const fs = `
      #ifdef GL_ES
      precision mediump float;
      #endif

      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
      varying vec2 vActiveTextureCoord;
      varying vec2 vNextTextureCoord;

      // custom uniforms
      uniform float uTransition;
      uniform float uButtonPos;

      // our textures samplers
      // notice how it matches the sampler attributes of the textures we created dynamically
      uniform sampler2D activeTex;
      uniform sampler2D nextTex;

      // Simplex 2D noise
      //
      vec3 permute(vec3 x) {
        return mod(((x*34.0)+1.0)*x, 289.0);
      }

      float snoise(vec2 v){
        const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
        vec2 i  = floor(v + dot(v, C.yy) );
        vec2 x0 = v -   i + dot(i, C.xx);
        vec2 i1;
        i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
        vec4 x12 = x0.xyxy + C.xxzz;
        x12.xy -= i1;
        i = mod(i, 289.0);
        vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
        + i.x + vec3(0.0, i1.x, 1.0 ));
        vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
        dot(x12.zw,x12.zw)), 0.0);
        m = m*m ;
        m = m*m ;
        vec3 x = 2.0 * fract(p * C.www) - 1.0;
        vec3 h = abs(x) - 0.5;
        vec3 ox = floor(x + 0.5);
        vec3 a0 = x - ox;
        m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
        vec3 g;
        g.x  = a0.x  * x0.x  + h.x  * x0.y;
        g.yz = a0.yz * x12.xz + h.yz * x12.yw;
        return 130.0 * dot(m, g);
      }

      void main() {
        vec4 noise = vec4(vec3(snoise(vTextureCoord * sqrt(2.0))), 1.0);

        float distanceFromCenter = distance(vTextureCoord, vec2(uButtonPos, 0.5)) * 0.9;

        // calculate an effect that goes from 0 to 1 depenging on uOpacity and distanceToLeft
        float spreadFromCenter = clamp((uTransition * (1.0 - distanceFromCenter) - 1.0) + uTransition * 2.0, 0.0, 1.0);

        vec4 firstImage = texture2D(activeTex, vActiveTextureCoord + noise.r * spreadFromCenter * 0.175);
        vec4 secondImage = texture2D(nextTex, vNextTextureCoord - noise.r * (1.0 - spreadFromCenter) * 0.175);

        // mix both texture
        vec4 finalImage = mix(firstImage, secondImage, spreadFromCenter);

        // handling premultiplied alpha
        finalImage = vec4(finalImage.rgb * finalImage.a, finalImage.a);

        gl_FragColor = finalImage;
      }
    `;
        const slideParams = {
            vertexShader: vs,
            fragmentShader: fs,
            uniforms: {
                transition: {
                    name: "uTransition",
                    type: "1f",
                    value: 0,
                },
                buttonPos: {
                    name: "uButtonPos",
                    type: "1f",
                    value: 0,
                },
            }
        }

        // add the slideshow plane
        this.slideshowPlane = new Plane(this.curtains,this.slideShow, slideParams);

        if(this.slideshowPlane) {
            this.slideshowPlane.userData = {
                activeTex: this.slideshowPlane.createTexture({name:"activeTex"}),
                nextTex: this.slideshowPlane.createTexture({name:"nextTex"})
            }
            this.slideshowPlane.onReady( () => {
                    this.slideshowPlane.userData.activeTex.setSource(this.slideshowPlane.images[this.activeTextureIndex]);

                    this.slideshowPlane.userData.nextTex?.setSource(this.slideshowPlane.images[this.nextTextureIndex]);


                });
        }
    }

    private setupButtonPlanes() {

        const buttonVs = `
      #ifdef GL_ES
      precision mediump float;
      #endif
    
      // default mandatory variables
      attribute vec3 aVertexPosition;
      attribute vec2 aTextureCoord;
    
      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;
    
      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
    
      // custom uniforms
      uniform float uTime;
    
      void main() {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    
        // varyings
        vTextureCoord = aTextureCoord;
        vVertexPosition = aVertexPosition;
      }
    `;

        const buttonFs = `
      #ifdef GL_ES
      precision mediump float;
      #endif
    
      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
    
      // custom uniforms
      uniform float uTime;
      uniform float uHoverEffect;
    
      void main() {
        vec4 color;
        float circleRadius = mix(0.7, 0.8, uHoverEffect);
        float distortionEffect = mix(0.025, 0.05, uHoverEffect);
        vec2 distortedTextCoords = vec2(vTextureCoord.x + sin(uTime / 30.0) * cos(vTextureCoord.y * 5.0) * distortionEffect, vTextureCoord.y + cos(uTime / 30.0) * sin(vTextureCoord.x * 5.0) * distortionEffect);
    
        float hole = step(circleRadius, distance(distortedTextCoords, vec2(0.5, 0.5)) * 2.0);
        vec3 circle = vec3(1.0 - hole);

        // red button
        circle.r *= 0.95;
        circle.g *= 0.1;
        circle.b *= 0.2;
    
        float opacity = 0.75 + (1.0 - uHoverEffect) * 0.25;
    
        color = vec4(circle * opacity, step(0.5, circle.r) * opacity);
    
        gl_FragColor = color;
      }
    `;

        const buttonParams = {
            vertexShader: buttonVs,
            fragmentShader: buttonFs,
            transparent: true, 
            uniforms: {
                time: {
                    name: "uTime",
                    type: "1f",
                    value: 0,
                },
                hoverEffect: {
                    name: "uHoverEffect",
                    type: "1f",
                    value: 0,
                },
            }
        };

        for(let key in this.buttons) {
            if(key === "nextButton") buttonParams.uniforms.time.value = 90;
            let buttonPlane = new Plane(this.curtains, this.buttons[key], buttonParams)

            if(buttonPlane) {
                buttonPlane.userData = {
                    name: key,
                    grow: 0,
                    growTween: null,
                };

                buttonPlane.onReady( () => {
                    // mouse enter
                    buttonPlane.htmlElement.addEventListener("mouseenter", () => {
                        if (buttonPlane.userData.growTween) buttonPlane.userData.growTween.kill();

                        buttonPlane.userData.growTween = TweenMax.to(buttonPlane.userData, 0.5, {
                            grow: 1,
                            ease: Power2.easeOut,
                            onUpdate: () => {
                                buttonPlane.uniforms.hoverEffect.value = buttonPlane.userData.grow;
                            },
                            onComplete: () => {
                                buttonPlane.userData.growTween = null;
                            }
                        });
                    });

                    // mouse leave
                    buttonPlane.htmlElement.addEventListener("mouseleave", () => {
                        if (buttonPlane.userData.growTween) buttonPlane.userData.growTween.kill();

                        buttonPlane.userData.growTween = TweenMax.to(buttonPlane.userData, 0.5, {
                            grow: 0,
                            ease: Power2.easeOut,
                            onUpdate: () => {
                                buttonPlane.uniforms.hoverEffect.value = buttonPlane.userData.grow;
                            },
                            onComplete: () => {
                                buttonPlane.userData.growTween = null;
                            }
                        });
                    });
                }).onRender( () => {
                    buttonPlane.uniforms.time.value++;
                });
            }
        }
    }

    private initNavigation() {

        // show first slide title
        //this.options.slides[this.activeTextureIndex].classList.add("slide--active");
        TweenMax.to(this.slides[this.activeTextureIndex].querySelector(".slide-title"), this.duration / 2, {
            ease: Power2.easeIn,
            opacity: 1,
            scaleX: 1,
            scaleY: 1,
            force3D: true,
        }).delay(this.duration / 2);

        // going to next image
        this.buttons.nextButton?.addEventListener("click", () => {
            if (!this.isAnimating) {
                this.isAnimating = true;

                // check what will be next image
                if (this.activeTextureIndex < this.nbSlides - 1) {
                    this.nextTextureIndex = this.activeTextureIndex + 1;
                }
                else {
                    this.nextTextureIndex = 0;
                }

                // apply it to our next texture
                this.slideshowPlane.userData.nextTex.setSource(this.slideshowPlane.images[this.nextTextureIndex]);

                // change button pos uniform
                this.slideshowPlane.uniforms.buttonPos.value = 1;

                // launch tween
                this.changeSlide();
            }
        });

        // going to previous image
        this.buttons.prevButton?.addEventListener("click", () => {
            if (!this.isAnimating) {
                this.isAnimating = true;

                // check what will be next image
                if (this.activeTextureIndex === 0) {
                    this.nextTextureIndex = this.nbSlides - 1;
                }
                else {
                    this.nextTextureIndex = this.activeTextureIndex - 1;
                }

                // apply it to our next texture
                this.slideshowPlane.userData.nextTex.setSource(this.slideshowPlane.images[this.nextTextureIndex]);

                // change button pos uniform
                this.slideshowPlane.uniforms.buttonPos.value = 0;

                // launch tween
                this.changeSlide();
            }
        });
    }

    private changeSlide() {

        this.changeTitles();

        TweenMax.to(this.slideshowPlane.uniforms.transition, this.duration, {
            value: 1,
            ease: Power2.easeOut,
            onStart: () => {
                this.slides[this.activeTextureIndex].classList.remove("slide--active");
            },
            onComplete: () => {
                this.isAnimating = false;
                this.activeTextureIndex = this.nextTextureIndex;
                // our next texture becomes our active texture
                this.slideshowPlane.userData.activeTex.setSource(this.slideshowPlane.images[this.activeTextureIndex]);
                // reset transition value
                this.slideshowPlane.uniforms.transition.value = 0;

                // show active slide title
               this.slides[this.activeTextureIndex].classList.add("slide--active");
            }
        });
    }

    private changeTitles() {

        const activeTitle = this.slides[this.activeTextureIndex].querySelector(".slide-title");
        const nextTitle = this.slides[this.nextTextureIndex].querySelector(".slide-title");

        TweenMax.to(activeTitle, this.duration / 2, {
            ease: Power2.easeIn,
            opacity: 0,
            scaleX: 1.15,
            scaleY: 1.15,
            force3D: true,
        });

        TweenMax.to(nextTitle, this.duration / 2, {
            ease: Power2.easeOut,
            opacity: 1,
            scaleX: 1,
            scaleY: 1,
            force3D: true,
        }).delay(this.duration / 2);
    }
}

export default WebglSlideshow

here is my nextJS page


import React, {useEffect} from 'react'
const WebglSlideshow = require('../../components/webgl-slideshow/webgl-slideshow');




function OurWorks() {
    useEffect(()=>{
        new WebglSlideshow.default()
    },[])
    return (

                    <>
                        <div id="curtains-canvas"></div>

                        <div id="slideshow">

                            <button id="previous-slide" className="slideshow-button">&#x279C;</button>
                            <button id="next-slide" className="slideshow-button">&#x279C;</button>

                            <div id="slides-list">
                                <div className="slide">
                                    <h2 className="slide-title" data-title="Hong Kong">Hong Kong</h2>
                                    <img src="/images/home_hero_1.png"
                                         alt="Photo by Simon Zhu on Unsplash"  crossOrigin={""}/>
                                </div>
                                <div className="slide">
                                    <h2 className="slide-title" data-title="Hong Kong">testing</h2>
                                    <img src="/images/modern-hd-map.jpg"
                                         alt="Photo by Simon Zhu on Unsplash"  crossOrigin={""}/>
                                </div>
                                <div className="slide">
                                    <h2 className="slide-title" data-title="Hong Kong">testing</h2>
                                    <img src="/images/work-place.png"
                                         alt="Photo by Simon Zhu on Unsplash"  crossOrigin={""}/>
                                </div>

                            </div>

                        </div>
                    </>

    )
}

export default OurWorks

please look into the code and help me. thank you

Buddhika Prasadh
  • 356
  • 1
  • 5
  • 16

0 Answers0