Search code examples
javascriptthree.jsbarbajs

Uncaught (in promise) TypeError: _this.settings is not a function - Working with barba.js and three.js


I'm developing a site using barba.js. In this page, "slider", I have a three.js scene. If I open up the page everything is fine. If I navigate from slider to home and then come back to slider page, I got this error:

Uncaught (in promise) TypeError: _this.settings is not a function

The script that controls the slider page is Sketch.js.

import * as THREE from 'three';
import TextTexture from 'three.texttexture';
import TextSprite from '@seregpie/three.text-sprite';
import gsap from 'gsap';
import { Power2 } from 'gsap';
import layout from './Layout'
import { TimelineMax } from "gsap/all";

export default class Sketch {

  constructor() {
    const container = document.querySelector('#sliderhome');
    if (container === null || container === undefined) return

    this.container = container
    const sliderContainer = document.querySelector("#sliderhome");

    console.log("init")
    if (sliderContainer) {
      this.initSlider();
    }
  }

  initSlider() {
    this.scene = new THREE.Scene();
    this.vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}`;
    this.fragment = `
        uniform float time;
        uniform float progress;
        uniform float intensity;
        uniform float width;
        uniform float scaleX;
        uniform float scaleY;
        uniform float transition;
        uniform float radius;
        uniform float swipe;
        uniform sampler2D texture1;
        uniform sampler2D texture2;
        uniform sampler2D displacement;
        uniform vec4 resolution;
        varying vec2 vUv;
        mat2 getRotM(float angle) {
            float s = sin(angle);
            float c = cos(angle);
            return mat2(c, -s, s, c);
        }
        const float PI = 3.1415;
        const float angle1 = PI *0.25;
        const float angle2 = -PI *0.75;


        void main() {
            vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);

            vec4 disp = texture2D(displacement, newUV);
            vec2 dispVec = vec2(disp.r, disp.g);

            vec2 distortedPosition1 = newUV + getRotM(angle1) * dispVec * intensity * progress;
            vec4 t1 = texture2D(texture1, distortedPosition1);

            vec2 distortedPosition2 = newUV + getRotM(angle2) * dispVec * intensity * (1.0 - progress);
            vec4 t2 = texture2D(texture2, distortedPosition2);

            gl_FragColor = mix(t1, t2, progress);

        }

    `;

    this.uniforms = {
      intensity: {value: 1, type:'f', min:0., max:3}
    }
    this.renderer = new THREE.WebGLRenderer();
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(this.width, this.height);
    this.renderer.setClearColor(0xeeeeee, 1);
    this.duration = 1;
    this.easing = 'easeInOut'

    this.clicker = document.getElementById("nextSlide");
    this.clickNavigate = document.querySelectorAll(".c-navigator_item");


    this.container = document.getElementById("slider");
    this.images = JSON.parse(this.container.getAttribute('data-images'));
    this.titles = JSON.parse(this.container.getAttribute('data-titles'));
    this.subtitles = JSON.parse(this.container.getAttribute('data-subtitles'));
    this.chinesetitles = JSON.parse(this.container.getAttribute('data-chinese'));
    this.navigators = JSON.parse(this.container.getAttribute('data-id'));
    this.colors = JSON.parse(this.container.getAttribute('data-colors'));
    this.urls = JSON.parse(this.container.getAttribute('data-url'));
    this.width = this.container.offsetWidth;
    this.height = this.container.offsetHeight;
    this.container.appendChild(this.renderer.domElement);

    /* Define a global index */
    this.index = 0;

    this.camera = new THREE.PerspectiveCamera(
      70,
      window.innerWidth / window.innerHeight,
      0.001,
      1000
    );

    this.camera.position.set(0, 0, 2);
    this.time = 0;
    this.current = 0;
    this.textures = [];

    this.title = [];
    this.subtitle = [];
    this.chinesetitle = [];
    this.navigatorIndex = [];
    this.color = [];
    this.url = [];

    this.paused = true;


    this.initiate( ()=> {
      this.setupResize();
      this.settings();
      this.addObjects();
      this.resize();
      this.clickEvent();
      this.play();
    })


  }

  initiate(cb){
    const promises = [];
    const titlesObject = [];
    const subtitlesObject = [];
    const chineseObject = [];
    const navigatorIndexes = [];
    const colorObject = [];
    const urlObject = [];

    let that = this;

    this.images.forEach((url,i)=>{
      let promise = new Promise(resolve => {
        that.textures[i] = new THREE.TextureLoader().load( url, resolve );
      });
      promises.push(promise);
    })

    this.titles.forEach((el,j)=>{
      let promiseS = new Promise(resolve => {
        that.title[j] = el;
      });
      titlesObject.push(promiseS);
    })

    this.subtitles.forEach((subel,z)=>{
      let promiseZ = new Promise(resolve => {
        that.subtitle[z] = subel;
      });
      subtitlesObject.push(promiseZ);
    })

    this.chinesetitles.forEach((ch,y)=>{
      let promiseY = new Promise(resolve => {
        that.chinesetitle[y] = ch;
      });
      chineseObject.push(promiseY);
    })

    this.colors.forEach((co,r)=>{
      let promiseR = new Promise(resolve => {
        that.color[r] = co;
      });
      colorObject.push(promiseR);
    })

    this.urls.forEach((ur,o)=>{
      let promiseO = new Promise(resolve => {
        that.url[o] = ur;
      });
      urlObject.push(promiseO);
    })



    Promise.all(promises).then(() => {
      cb();
      console.log(cb)
    });


  }

  clickEvent(){
    this.clicker.addEventListener('click',()=>{
      this.next();
    })

    let that = this;
    Array.from(this.clickNavigate).forEach(link => {

      link.addEventListener('click', function(e) {
        that.navigate(e);
      });

    });

  }


  settings() {
    let that = this;
    //if(this.debug) this.gui = new dat.GUI();
    this.settings = {progress:0.5};
    // if(this.debug) this.gui.add(this.settings, "progress", 0, 1, 0.01);

    Object.keys(this.uniforms).forEach((item)=> {
      this.settings[item] = this.uniforms[item].value;
      //if(this.debug) this.gui.add(this.settings, item, this.uniforms[item].min, this.uniforms[item].max, 0.01);
    })
  }

  setupResize() {
    window.addEventListener("resize", this.resize.bind(this));
  }

  resize() {
    this.width = this.container.offsetWidth;
    this.height = this.container.offsetHeight;
    this.renderer.setSize(this.width, this.height);
    this.camera.aspect = this.width / this.height;


    // image cover
    this.imageAspect = this.textures[0].image.height/this.textures[0].image.width;
    let a1; let a2;
    if(this.height/this.width>this.imageAspect) {
      a1 = (this.width/this.height) * this.imageAspect ;
      a2 = 1;
    } else{
      a1 = 1;
      a2 = (this.height/this.width) / this.imageAspect;
    }

    this.material.uniforms.resolution.value.x = this.width;
    this.material.uniforms.resolution.value.y = this.height;
    this.material.uniforms.resolution.value.z = a1;
    this.material.uniforms.resolution.value.w = a2;

    const dist  = this.camera.position.z;
    const height = 1;
    this.camera.fov = 2*(180/Math.PI)*Math.atan(height/(2*dist));

    this.plane.scale.x = this.camera.aspect;
    this.plane.scale.y = 1;

    this.camera.updateProjectionMatrix();


  }

  addObjects() {
    let that = this;
    this.material = new THREE.ShaderMaterial({
      extensions: {
        derivatives: "#extension GL_OES_standard_derivatives : enable"
      },
      side: THREE.DoubleSide,
      uniforms: {
        time: { type: "f", value: 0 },
        progress: { type: "f", value: 0 },
        border: { type: "f", value: 0 },
        intensity: { type: "f", value: 0 },
        scaleX: { type: "f", value: 40 },
        scaleY: { type: "f", value: 40 },
        transition: { type: "f", value: 40 },
        swipe: { type: "f", value: 0 },
        width: { type: "f", value: 0 },
        radius: { type: "f", value: 0 },
        texture1: { type: "f", value: this.textures[0] },
        texture2: { type: "f", value: this.textures[1] },
        displacement: { type: "f", value: new THREE.TextureLoader().load('https://www.gianlucarinaldidev.it/jijide/wp-content/uploads/2021/06/disp1.jpg') },
        resolution: { type: "v4", value: new THREE.Vector4() },
      },
      // wireframe: true,
      vertexShader: this.vertex,
      fragmentShader: this.fragment
    });

    this.geometry = new THREE.PlaneGeometry(1, 1, 2, 2);

    this.plane = new THREE.Mesh(this.geometry, this.material);
    this.scene.add(this.plane);

    let text2 = document.getElementById("titleContainer");
    text2.innerHTML = this.title[0];

    let subtext2 = document.getElementById("subtitleContainer");
    subtext2.innerHTML = this.subtitle[0];

    let chinese2 = document.getElementById("chineseContainer");
    chinese2.innerHTML = this.chinesetitle[0];

    let nextSlide = document.getElementById("nextSlide");
    nextSlide.innerHTML = this.title[1];

    let color = document.getElementById("colorContainer");
    color.innerHTML = this.color[0];

    let url = document.getElementById("productUrl");
    url.href= this.url[0];


    this.theNextTitle = this.title[1];
    this.theNextTexture = this.textures[1];
    this.theNextSubtitle = this.subtitle[1];
    this.theNextChinese = this.chinesetitle[1];
    this.theNextUrl = this.url[1];

  }

  stop() {
    this.paused = true;
  }

  play() {
    this.paused = false;
    this.render();
  }

  next(){
    this.current = this.index;

    /*if (this.index == 0) {
      this.current = -1;
    }*/

    console.log("After clicking Next, Current is now " + this.current)
    //this.current = this.sync();
    if(this.isRunning) return;
    this.isRunning = true;

    let len = this.textures.length;
    let nextTexture =this.textures[(this.current +1)%len];

    this.material.uniforms.texture2.value = nextTexture;
    this.theNextTexture = this.textures[(this.current + 1)];
    this.material.uniforms.texture2.value = this.theNextTexture;

    let tl = new TimelineMax();

    /* Titles */
    let text2 = document.getElementById("titleContainer");
    let textLenght = this.title.length;
    let nextTitle = this.title[(this.current +1)%textLenght];
    let nextNextTitle = this.title[(this.current +2)%textLenght];
    if (this.index == 0) {
      nextNextTitle = this.title[1];
    }
    //text2.innerHTML = nextTitle;

    this.theNextTitle = this.title[(this.current + 1)];
    text2.innerHTML = this.theNextTitle;

    /* Subtitles */
    let subtext2 = document.getElementById("subtitleContainer");
    let subtextLenght = this.subtitle.length;
    let nextSubtitle = this.subtitle[(this.current +1)%subtextLenght];
    //subtext2.innerHTML = nextSubtitle;

    this.theNextSubtitle = this.subtitle[(this.current + 1)];
    subtext2.innerHTML = this.theNextSubtitle;

    /* Chinese */
    let chinese2 = document.getElementById("chineseContainer");
    let chinesetextLenght = this.chinesetitle.length;
    let nextChinese = this.chinesetitle[(this.current +1)%chinesetextLenght];
    //chinese2.innerHTML = nextChinese;

    /* URL */
    let url2 = document.getElementById("productUrl");
    let urltextLenght = this.url.length;
    let nextUrl = this.url[(this.current +1)%urltextLenght];

    this.theNextUrl = this.url[(this.current + 1)];
    url2.href = this.theNextUrl;

    let nextSlide = document.getElementById("nextSlide");
    nextSlide.innerHTML = nextNextTitle;


    tl.to(this.material.uniforms.progress,this.duration,{
      value:1,
      ease: Power2[this.easing],
      onComplete:()=>{
        console.log('FINISH');
        this.current = (this.current +1)%len;
        this.material.uniforms.texture1.value = this.theNextTexture;
        this.material.uniforms.progress.value = 0;
        this.isRunning = false;

        text2.innerHTML = this.theNextTitle
        subtext2.innerHTML = this.theNextSubtitle;
        chinese2.innerHTML = this.theNextChinese;
        url2.href = this.theNextUrl;

        nextSlide.innerHTML = nextNextTitle;

        this.index = (this.index +1);
        if (this.index > 7) {
          this.index = 0;
        }

        console.log("Index is" + this.index)

        /*if (this.current == 0) {
          this.material.uniforms.texture1.value = this.textures[0];
          text2.innerHTML = this.title[0];
          subtext2.innerHTML = this.subtitle[0];
          chinese2.innerHTML = this.chinesetitle[0];
        }*/

    }})
  }



  navigate(e) {
    let el__id = e.target.dataset.id;
    this.index = el__id;
    this.current = el__id;


    if(this.isRunning) return;
    this.isRunning = true;

    this.material.uniforms.texture2.value = this.textures[el__id];

    let tl = new TimelineMax();

    let text2 = document.getElementById("titleContainer");
    text2.innerHTML = this.title[el__id];

    let subtext2 = document.getElementById("subtitleContainer");
    subtext2.innerHTML = this.subtitle[el__id];

    let chinese2 = document.getElementById("chineseContainer");
    chinese2.innerHTML = this.chinesetitle[el__id];

    let color = document.getElementById("colorContainer");
    color.innerHTML = this.color[el__id];

    let url = document.getElementById("productUrl");
    url.href = this.url[el__id];

    let nextSlideNavigate = document.getElementById("nextSlide");
    let textLenght = this.title.length;
    //this.title[(this.current +1)%textLenght];
    let len = this.textures.length;
    this.index++;
    if (this.index > 7) {
      this.index = 0;
    }

    if (this.index == 0) {
      let nextNextNavigateTitle = this.title[0];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 1) {
      let nextNextNavigateTitle = this.title[1];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 2) {
      let nextNextNavigateTitle = this.title[2];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 3) {
      let nextNextNavigateTitle = this.title[3];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 4) {
      let nextNextNavigateTitle = this.title[4];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 5) {
      let nextNextNavigateTitle = this.title[5];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 6) {
      let nextNextNavigateTitle = this.title[6];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    if (this.index == 7) {
      let nextNextNavigateTitle = this.title[7];
      nextSlideNavigate.innerHTML = nextNextNavigateTitle;
    }
    //let nextNextNavigateTitle = this.title[this.index];


    //this.index = el__id;
    console.log("In Navigate, Current is now " + this.current)

    //nextSlide.innerHTML = this.title[el__id + 1];


    tl.to(this.material.uniforms.progress,this.duration,{
      value:1,
      ease: Power2[this.easing],
      onComplete:()=>{
        //this.current = this.current;
        //this.current = el__id;
        this.material.uniforms.texture1.value = this.textures[el__id];
        this.material.uniforms.progress.value = 0;
        this.isRunning = false;

    }})


  }

  sync() {
    return this.index;
  }

  render() {
    if (this.paused) return;
    this.time += 0.05;
    this.material.uniforms.time.value = this.time;
    // this.material.uniforms.progress.value = this.settings.progress;

    Object.keys(this.uniforms).forEach((item)=> {
      this.material.uniforms[item].value = this.settings[item];
    });


    requestAnimationFrame(this.render.bind(this));
    this.renderer.render(this.scene, this.camera);
  }

  destroy() {
    console.log("destroyed")
    //cancelAnimationFrame(this.slider.id);// Stop the animation
    //this.renderer.domElement.addEventListener('dblclick', null, false); //remove listener to render
    this.renderer = null;
    this.scene = null;
    this.projector = null;
    this.camera = null;
    this.controls = null;
    this.container = null;
    this.images = null;
    this.titles = null;
    this.subtitles = null;
    this.chinesetitles = null;
    this.navigators = null;
    this.colors = null;
    this.urls = null;
    this.uniforms = null;
    //empty(this.modelContainer);
  }

reinit(newContainer = document) {

  const container = newContainer.querySelector('#sliderhome')

  if (container === null || container === undefined) return

  this.container = container
  this.initSlider();
}
}

The error is this:

Uncaught (in promise) TypeError: _this.settings is not a function
    at eval (Sketch.js?c65f:127)
    at eval (Sketch.js?c65f:193)
eval @ Sketch.js?c65f:127
eval @ Sketch.js?c65f:193
Promise.then (async)
initiate @ Sketch.js?c65f:192
initSlider @ Sketch.js?c65f:125
reinit @ Sketch.js?c65f:574
eval @ Router.js?7be6:168
eval @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
Promise.then (async)
eval @ barba.umd.js?baf6:1
r.do @ barba.umd.js?baf6:1
r.j @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
Promise.then (async)
eval @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
s @ barba.umd.js?baf6:1
r @ barba.umd.js?baf6:1
Promise.then (async)
eval @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
Promise.then (async)
t @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
s @ barba.umd.js?baf6:1
r.doPage @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
s @ barba.umd.js?baf6:1
eval @ barba.umd.js?baf6:1
Promise.then (async)
i @ barba.umd.js?baf6:1
e.page @ barba.umd.js?baf6:1
e.go @ barba.umd.js?baf6:1
e.U @ barba.umd.js?baf6:1

    // In initSlider()
    this.initiate( ()=> {
      this.setupResize();
      this.settings();
      this.addObjects();
      this.resize();
      this.clickEvent();
      this.play();
    })

and line 193:

  Promise.all(promises).then(() => {
    cb();
  });

Here I do have the Router.js script that controls the routing in Barba.js:

import barba from '@barba/core'
import barbaPrefetch from '@barba/prefetch'
import gsap from 'gsap'
import LocomotiveScroll from 'locomotive-scroll';
import iman from './InstanceManager'
import cursor from "./Cursor"

export default class Router {

    constructor() {
    this.cpLoader = document.querySelector('.js-cp-loader')
    this.cpLoaderBg = document.querySelector('.js-cp-loader-bg')

        const product = document.getElementById("product");
        if (product) {
            this.initScroll();
        }

    this.init()
  }

  goTo (url) {
    barba.go(url)
  }

  prefetch (url) {
    barba.prefetch(url)
  }

    initScroll() {
        // Map number x from range [a, b] to [c, d]
    const map = (x, a, b, c, d) => (x - a) * (d - c) / (b - a) + c;

    // Linear interpolation
    const lerp = (a, b, n) => (1 - n) * a + n * b;

    const clamp = (num, min, max) => num <= min ? min : num >= max ? max : num;

    const randomNumber = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);

        this.scroll = new LocomotiveScroll({
        el: document.querySelector('[data-scroll-container]'),
        smooth: true,
        direction: 'horizontal',
        lerp: 0.05
    });

        this.scroll.on('scroll', (obj) => {
        for (const key of Object.keys(obj.currentElements)) {
            if ( obj.currentElements[key].el.classList.contains('gallery__item-imginner') ) {
                let progress = obj.currentElements[key].progress;
                const saturateVal = progress < 0.5 ? clamp(map(progress,0,0.5,0,1),0,1) : clamp(map(progress,0.5,1,1,0),0,1);
                const brightnessVal = progress < 0.5 ? clamp(map(progress,0,0.5,0,1),0,1) : clamp(map(progress,0.5,1,1,0),0,1);
                obj.currentElements[key].el.style.filter = `opacity(${brightnessVal})`
            }
        }
    });
    this.scroll.update();
    }

    update() {
        this.scroll.update();
    }

    destroy() {
        this.scroll.destroy();
    }

  defaultLeave = ({ current, next }, context) => {
    try {
      const done = context.async()

      gsap.set(this.cpLoader, {
        zIndex: 1000,
        visibility: 'visible'
      })

      gsap.to(this.cpLoaderBg, {
        duration: 0.6,
        opacity: 1,
        onComplete: () => {
          done()
        }
      })
    } catch (err) {
      console.warn('default leave error', err)
    }
  }

  defaultEnter({ current, next }, context) {
    try {
      const done = context.async()
      done()

      gsap.to(this.cpLoaderBg, {
        duration: 0.6,
        opacity: 0,
        onComplete: () => {
          gsap.set(this.cpLoader, {
            zIndex: -1,
            visibility: 'hidden'
          })
        }
      })
    } catch (err) {
      console.warn('default enter error', err)
    }
  }


  init() {
    barba.use(barbaPrefetch)

        barba.hooks.after(({ current, next }) => {

            const product = document.getElementById("product");
            if (product) {
                this.initScroll();
            }

        });


    barba.hooks.afterLeave(( { current, next } ) => {
      cursor.destroy()
      iman.map('destroy')

    })

        // update the scroll after entering a page
        barba.hooks.after(() => {
            scroll.update();
        });

    barba.hooks.beforeEnter(({ current, next }) => {
      try {
        if (current.container) {
          window.scrollTo(0, 0)


                    const slider = iman.get('sketch')
                    if (slider) {
            slider.reinit(next.container)
          }

          setTimeout(() => {
            cursor.reinit(next.container)
          }, 400)
        }
      } catch (err) {
        console.warn('beforeEnter err',err)
      }
    })


    const self = this
    this.instance = barba.init({
      debug: false,
      timeout: 11000,
      transitions: [
        {
          name: 'default',
          leave({ current, next }) {
            try {
              self.defaultLeave({ current, next }, this)
            } catch (err) {
              console.warn('default LEAVE error', err)
            }
          },
          enter({ current, next }) {
            try {
              self.defaultEnter({ current, next }, this)

            } catch (err) {
              console.warn('default ENTER error', err)
            }
          },
        }
      ],
      requestError: (trigger, action, url, response) => {
        // console.log('requestError:trigger', trigger)
        // console.log('requestError:action', action)
        // console.log('requestError:url', url)
        // console.log('requestError:response', response)

        // go to a custom 404 page if the user click on a link that return a 404 response status
        if (action === 'click' && response.status && response.status === 404) {
          // window.location.replace(`${mainUrl}/404/`)
        }

        // prevent Barba from redirecting the user to the requested URL
        // this is equivalent to e.preventDefault()
        return false
      },
    })
  }
}

And here the Application.js script:

import Router from './Router'

import * as THREE from './three.js';
import TextTexture from 'three.texttexture';
import TextSprite from '@seregpie/three.text-sprite';

import Sketch from './Sketch';


import layout from './Layout'
import iman from './InstanceManager'
import cursor from './Cursor'
import initiaLoader from './InitialLoader'

import { debounce } from "../util"

class Application {
  onLoad() {
    window.addEventListener('load', () => {
      layout.init()
      iman.add('layout', layout, true)

      cursor.init()
      cursor.activateMovement()

      initiaLoader.init()

      iman.add('sketch', new Sketch())
      iman.add('scrollAnimator', new ScrollAnimator())
    })
  }

  onContentLoaded() {
    document.addEventListener('DOMContentLoaded', () => {
      document.documentElement.className = 'js'
      iman.add('router', new Router(), true)
    })
  }

  onResize() {
    window.addEventListener('resize', debounce(() => {
            layout.resize()
            iman.map('resize')
        }, 100))
  }

  init() {
    this.onContentLoaded()
    this.onLoad()
    this.onResize()
  }
}

const application = new Application()

export default application

Thanks in advance to everyone.


Solution

  • Your problem appears to be with the following class method...

      settings() {
        let that = this;
        //if(this.debug) this.gui = new dat.GUI();
        this.settings = {progress:0.5};
        // if(this.debug) this.gui.add(this.settings, "progress", 0, 1, 0.01);
    
        Object.keys(this.uniforms).forEach((item)=> {
          this.settings[item] = this.uniforms[item].value;
          //if(this.debug) this.gui.add(this.settings, item, this.uniforms[item].min, this.uniforms[item].max, 0.01);
        })
      }
    

    ...where settings is initially defined as a method, but then within the execution of this.settings(), it is resetting this.settings to an object.

    Thus, the next time this.settings() is attempted to be executed, it fails. Here's a minimal reproducible representation of the issue.

    class Test {
      constructor() {
        this.v = 42;
      }
      
      settings() {   
        console.log( 'In settings function' );
        this.settings = {a:1};
      }
    }
    
    t = new Test();
    
    t.settings();   // Succeeds, but resets settings method to an object.
    
    t.settings();   // Fails, because this.settings is no longer a function.