Curtains JS in NextJS not rendering images

340 Views Asked by At

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

0

There are 0 best solutions below