I’ve gotten it successfully working with this code:
import * as ecs from '@8thwall/ecs'
ecs.registerComponent({
  name: 'Camera Shaders',
  schema: {
  },
  schemaDefaults: {
  },
  data: {
  },
  stateMachine: ({world, eid}) => {
    ecs.defineState('default')
      .initial()
      .onEnter(() => {
        window.addEventListener('xrloaded', (e) => {
          const {XR8} = window as any
          const fragmentShaders = [  // Define some simple shaders to apply to the camera feed.
            ` precision mediump float;  // Just the camera feed.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() { gl_FragColor = texture2D(sampler, texUv); }`,
            ` precision mediump float;  // Color boost.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() {
      vec4 c = texture2D(sampler, texUv);
      float y = dot(c.rgb, vec3(0.299, 0.587, 0.114));
      float u = dot(c.rgb, vec3(-.159, -.331, .5)) * 6.0;
      float v = dot(c.rgb, vec3(.5, -.419, -.081)) * 3.0;
      gl_FragColor = vec4(y + 1.4 * v, y - .343 * u - .711 * v, y + 1.765 * u, c.a);
    }`,
            ` precision mediump float;  // Vignette.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() {
      float x = texUv.x - .5;
      float y = texUv.y - .5;
      float v = 1.5 - sqrt(x * x + y * y) * 2.5;
      vec4 c = texture2D(sampler, texUv);
      gl_FragColor = vec4(c.rgb * (v > 1.0 ? 1.0 : v), c.a);
    }`,
            ` precision mediump float;  // Black and white.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() {
      vec4 c = texture2D(sampler, texUv);
      gl_FragColor = vec4(vec3(dot(c.rgb, vec3(0.299, 0.587, 0.114))), c.a);
    }`,
            ` precision mediump float;  // Sepia.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() {
      vec4 c = texture2D(sampler, texUv);
      gl_FragColor.r = dot(c.rgb, vec3(.393, .769, .189));
      gl_FragColor.g = dot(c.rgb, vec3(.349, .686, .168));
      gl_FragColor.b = dot(c.rgb, vec3(.272, .534, .131));
      gl_FragColor.a = c.a;
    }`,
            ` precision mediump float;  // Purple.
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main() {
      vec4 c = texture2D(sampler, texUv);
      float y = dot(c.rgb, vec3(0.299, 0.587, 0.114));
      vec3 p = vec3(.463, .067, .712);
      vec3 rgb = y < .25 ? (y * 4.0) * p : ((y - .25) * 1.333) * (vec3(1.0, 1.0, 1.0) - p) + p;
      gl_FragColor = vec4(rgb, c.a);
    }`,
            ` precision mediump float;  // Shader with time variable
    uniform float time;
    varying vec2 texUv;
    uniform sampler2D sampler;
    void main( void ) {
      vec2 position = texUv;
      float color = 0.0;
      color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
      color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
      color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
      color *= sin( time / 10.0 ) * 0.5;
      gl_FragColor = texture2D(sampler, texUv) + vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
    }`,
          ]
          const vertexShaders = [  // Vertex shaders for swapping whether or not drawing is mirrored.
            ` attribute vec3 position;  // Normal drawing
    attribute vec2 uv;
    varying vec2 texUv;
    void main() {
      gl_Position = vec4(position, 1.0);
      texUv = uv;
    }`,
            ` attribute vec3 position;  // Mirrored drawing
    attribute vec2 uv;
    varying vec2 texUv;
    void main() {
      gl_Position = vec4(position, 1.0);
      texUv = vec2(1.0 - uv.x, uv.y);
    }`,
          ]
          let uniforms = 1.0
          XR8.addCameraPipelineModule({
            name: 'Custom Shaders',
            onStart: ({canvasWidth, canvasHeight}) => {
              console.log('started')
              XR8.GlTextureRenderer.configure({fragmentSource: fragmentShaders[1]})
            },
            onUpdate: ({frameStartResult, processGpuResult}) => {
              if (processGpuResult.gltexturerenderer) {
                const {shader} = processGpuResult.gltexturerenderer
                const {GLctx} = frameStartResult
                const timeLoc = GLctx.getUniformLocation(shader, 'time')
                if (timeLoc) {
                  const p = XR8.GlTextureRenderer.getGLctxParameters(GLctx)
                  GLctx.useProgram(shader)
                  GLctx.uniform1f(timeLoc, uniforms)
                  XR8.GlTextureRenderer.setGLctxParameters(GLctx, p)
                  uniforms += 0.1
                }
              }
            },
          })
        })
      })
  },
  add: (world, component) => {
  },
  tick: (world, component) => {
  },
  remove: (world, component) => {
  },
})
This is a component that I’ve attached to the camera in my scene. As you can see from the screenshot it using the second shader in the list, as the first shader is just the normal camera feed.