vue-curtains

vue-curtains is an attempt at converting curtains.js WebGL classes into reusable Vue components.

Version Twitter

Getting started

Installation

⚠️ vue-curtains requires Vue 3

Of course you’ll need to create a Vue app first. Then, just add vue-curtains into your project by installing the npm package:

npm install vue-curtains

Components

vue-curtains introduces a bunch of components based on curtains.js classes:

Hooks

The library relies on the Vue 3 Composition API.

Inside your <Curtains></Curtains> component, you’ll have access to a couple useful custom hooks:

useCurtains
useCurtains(callback);

This hook returns the curtains instance injected by the <Curtains></Curtains> component, or null if the instance is undefined (for example if you try to use it outside your <Curtains></Curtains> component).

import { useCurtains } from "vue-curtains";

export default {
  name: "MyComponent",

  setup() {
    useCurtains((curtains) => {
      // get curtains bounding box for example...
      const curtainsBBox = curtains.getBoundingRect();
    });
  }
}
useCurtainsEvent
useCurtainsEvent(event, callback);

This hook lets you subscribe to any of your curtains instance events, so you can use those events from any <Curtains></Curtains> child component in your app.

import { useCurtainsEvent } from "vue-curtains";

export default {
  name: "MyComponent",

  setup() {
    useCurtainsEvent("onScroll", (curtains) => {
      // get the scroll values...
      const scrollValues = curtains.getScrollValues();
    });
  }
}

Examples

Explore

Here are codesandboxes ports of some of the official documentation examples:

Basic example

This is the port of curtains.js documentation basic example:

App.vue

import { Curtains, Plane } from "vue-curtains";

const basicVs = `
  precision mediump float;
    
  attribute vec3 aVertexPosition;
  attribute vec2 aTextureCoord;
    
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;
    
  uniform mat4 uTextureMatrix0;
    
  varying vec3 vVertexPosition;
  varying vec2 vTextureCoord;
    
  void main() {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        
    // varyings
    vVertexPosition = aVertexPosition;
    vTextureCoord = (uTextureMatrix0 * vec4(aTextureCoord, 0.0, 1.0)).xy;
  }
`;


const basicFs = `
  precision mediump float;

  varying vec3 vVertexPosition;
  varying vec2 vTextureCoord;

  uniform sampler2D uSampler0;

  uniform float uTime;
    
  void main() {
    vec2 textureCoord = vTextureCoord;
    // displace our pixels along the X axis based on our time uniform
    // textures coords are ranging from 0.0 to 1.0 on both axis
    textureCoord.x += sin(textureCoord.y * 25.0) * cos(textureCoord.x * 25.0) * (cos(uTime / 50.0)) / 25.0;
    
    gl_FragColor = texture2D(uSampler0, textureCoord);
  }
`;

export default {
  name: "App",
  components: {
    Curtains,
    Plane,
  },
  setup() {
    const planeParams = {
      vertexShader: basicVs,
      fragmentShader: basicFs,
      uniforms: {
        time: {
          name: "uTime",
          value: 0,
        },
      },
    };

    const onRender = (plane) => {
      plane.uniforms.time.value++;
    };

    return {
      planeProps,
      onRender
    };
};
</script>

<template>
  <!-- should be put outside the router -->
  <Curtains id="CurtainsCanvas">

    <Plane id="BasicPlane" :params="planeParams" @render="onRender">
      <img src="/path/to/my-image.jpg" alt="" />
    </Plane>
  
  </Curtains>
</template>

<style scoped>
  #CurtainsCanvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    pointer-events: none;
  }
  
  #BasicPlane {
    width: 80%;
    height: 80vh;
    margin: 10vh auto;
  }

  #BasicPlane img {
    display: none;
  }
</style>
main.js

import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

GitHub

View Github