@canvas3/nuxt

Module for ThreeJS
9,343
Install
npm install @canvas3/nuxt
Latest Version:0.1.58
Vue:3
License:MIT
Last Updated:Oct 23, 2026
Links: npm
Maintainer: tomaskmet

Canvas3 Nuxt Module

A Nuxt module that integrates ThreeJS into your Nuxt app, providing a smooth-scroll engine, WebGL image effects, scroll-triggered animations, and a shader/animation API — all wired together through Vue directives and a global Canvas3 composable-like utility.

✨ Example use cases

Features

  • 🎬 Smooth scroll engine – Custom lerp-based scroll with speed tracking, fixed-to-parent elements, and mobile breakpoint handling.
  • 🖼 WebGL image replacement – Turn any <img> into a shader-driven ThreeJS mesh via the v-canvas3-image directive.
  • 👀 Scroll-triggered activation – Activate/deactivate elements (and their linked meshes) as they enter/leave the viewport with v-canvas3-scroll-action.
  • 🎨 Custom shader support – Bring your own vertex/fragment shaders per mesh, plus a global post-processing scroll shader pass.
  • ⏱ Animation scheduler – Register callbacks that run conditionally on scroll, resize, mouse move, or custom render triggers, avoiding unnecessary renders.
  • 🖱 Mouse-reactive uniforms – Automatic uMouse / uMouseMovement uniforms updated on mouse movement for interactive shaders.
  • 📱 Responsive & reduced-motion aware – Built-in isMobile / prefersReducedMotion / disabled options to gracefully degrade.
  • 🧩 Global utility API – Canvas3 import exposes scene, camera, renderer, mesh, and scroll controls anywhere in your app.
  • 🏗 Layout-based setup – Ships a ready-to-use canvas3 Nuxt layout that wraps your page content with the scroll/canvas containers.

Quick Setup

Install the module to your Nuxt application with one command:

npx nuxi module add canvas3-nuxt

That's it! You can now use the Canvas3 module in your Nuxt app ✨

1. Use the canvas3 layout

<!-- pages/index.vue -->
<script setup>
definePageMeta({ layout: 'canvas3' })
</script>

2. Enable Canvas3 in the layout

The layout exposes canvas3enabled and canvas3options props. Enable it once your options (shaders, fonts, etc.) are ready:

<!-- app.vue or a wrapping component -->
<template>
  <NuxtLayout
    :canvas3enabled="ready"
    :canvas3options="canvas3Options"
    @canvas3-ready="onReady"
  >
    <NuxtPage />
  </NuxtLayout>
</template>

<script setup>
import { ref } from 'vue'

const ready = ref(false)
const canvas3Options = {
  shaders: {
    default: { vertexShader: defaultVert, fragmentShader: defaultFrag },
    scroll: { vertexShader: scrollVert, fragmentShader: scrollFrag },
  },
  activateMeshOptions: {
    image: { uAniInImage: { value: 1, duration: 1, ease: 'power2.out' } },
  },
  canvasElement: { zIndex: -1 },
  prefersReducedMotion: false,
  isMobile: false,
  disabled: false,
}

function onReady() {
  ready.value = true
}

ready.value = true
</script>

Directives

v-canvas3-image

Converts an <img> element into a ThreeJS mesh rendered in sync with the DOM element's position, size, and scroll offset. The original image is hidden (opacity set to 0) and replaced visually by the WebGL mesh.

Requirements: must be applied to an <img> tag.

Binding value (Canvas3ImageBinding):

Option Type Description
shaderName string Key of a custom shader registered in canvas3Options.shaders. Falls back to shaders.default.
uniforms MeshMaterialUniform Extra/overriding shader uniforms merged into the material on creation and reactively on update.
activateMeshUniforms MeshMaterialUniform Uniforms animated (0 → 1) when the mesh's linked scroll-action element becomes active/inactive.
<template>
  <img
    src="https://raw.githubusercontent.com/kmettom/Canvas3Nuxt/HEAD/images/hero.jpg"
    alt="Hero"
    v-canvas3-image="{
      shaderName: 'wave',
      uniforms: {
        vectorVNoise: { value: [2, 2], duration: 0 },
      },
      activateMeshUniforms: {
        uAniInImage: { value: 1, duration: 1.2, ease: 'power2.out' },
      },
    }"
  >
</template>

Behavior notes:

  • Waits for the image to load (complete/load event) and for the canvas to be initiated before creating the mesh.
  • Automatically re-creates the mesh if src changes.
  • Cleans up (disposes geometry/material/texture, removes from scene) on unmount.
  • Respects canvas3options.disabled, adding a .reduced-motion class instead of creating a mesh.

v-canvas3-scroll-action

Marks an element to be tracked by the scroll engine. When the element enters/exits the configured viewport range, it toggles an active class, fires callbacks, and (optionally) activates any WebGL image meshes nested inside it (matched via data-mesh-id, set automatically by v-canvas3-image).

Binding value (ScrollActionBindOptionType):

Option Type Description
activateOnce boolean Once activated, the element is never deactivated again.
trackOnly boolean Skip class toggling and mesh activation; only fires callbacks/tracking.
activeRange number Fraction of viewport height used as the "active zone" (default 1, i.e. full viewport).
activeRangeMargin number Extra pixel margin added to the active range for speed-tracking calculations.
scrollSpeed { value: number } Applies a parallax translate based on scroll position, proportional to value.
scrollSpeedSetTo { value: number, duration: number } Animates scrollSpeed.value to a new target over duration seconds via GSAP.
fixToParent { containerId: string, fixPosition: number, margin: number } Pins the element's first child inside a container (by id) at a given viewport position while the container is in view.
activateCallback (item) => void Called when the element becomes active.
deactivateCallback (item) => void Called when the element becomes inactive (unless activateOnce).
onScrollCallback (item, scrollSpeed, currentPosition) => void Called continuously while the element is in view and the page is scrolling.
<template>
  <section
    v-canvas3-scroll-action="{
      activeRange: 0.8,
      activateCallback: onSectionActive,
      deactivateCallback: onSectionInactive,
    }"
  >
    <img src="https://raw.githubusercontent.com/kmettom/Canvas3Nuxt/HEAD/images/panel.jpg" alt="Panel" v-canvas3-image="{}">
  </section>
</template>

<script setup>
function onSectionActive(item) {
  console.log('Section entered view', item.elNode)
}
function onSectionInactive(item) {
  console.log('Section left view', item.elNode)
}
</script>

Parallax example:

<div v-canvas3-scroll-action="{ scrollSpeed: { value: 0.3 } }">
  <div>Moves at 0.3x scroll speed</div>
</div>

Pin-to-parent example:

<div id="stickyContainer" style="height: 200vh;">
  <div
    v-canvas3-scroll-action="{
      fixToParent: { containerId: 'stickyContainer', fixPosition: 0.5, margin: 0 },
    }"
  >
    <div>Pinned child, centered at 50% viewport while parent is in view</div>
  </div>
</div>

Global Canvas3 Utility

The module auto-imports a Canvas3 utility (via Nuxt's addImports) that exposes scene/camera/renderer access and imperative controls, independent of the directives.

Method Description
addMeshToScene(mesh) Adds a raw ThreeJS Mesh directly to the Canvas3 scene.
getMeshFromSceneByName(name) Retrieves a scene object by its name.
addImageAsMesh(imgEl, shaderName, meshId, uniforms, activateMeshUniforms) Lower-level API used internally by v-canvas3-image; can be called manually.
removeMesh(id) Disposes and removes a mesh (and its material/texture) by id.
getShaderMaterial(mesh) Type-casts and returns a mesh's ShaderMaterial.
addAnimationToRender(name, setup) Registers a named animation callback (see below).
removeAnimationFromRender(name) Unregisters a named animation callback.
setAnimationsToRender(state) Globally toggles whether onAnimationsRender animations run.
setAnimationToRender(name, state, id) Adds/removes an animationId driving a specific animation's render state.
setRenderDisabled(state) Pauses/resumes the entire render loop.
setMeshPositionsUpdate(state) Forces continuous recalculation of image mesh positions/sizes (e.g. during layout shifts).
resizeOnChange() Recalculates canvas size, camera, and mesh positions — call on custom resize triggers.
scrollTo(position, delay?) Smoothly animates scroll to a pixel position.
scrollToTop(delay?) Smoothly animates scroll to the top.
scrollToElBySelector(selector, delay?, margin?) Scrolls to an element matched by a CSS selector.
getScrollPosition() Returns the current rendered scroll position.
getScrollSpeed() Returns the current normalized scroll speed (0–1).
getCamera() Returns the active THREE.PerspectiveCamera.
getRenderer() Returns the active THREE.WebGLRenderer.
getScene() Returns the active THREE.Scene.

Animation callback example:

import { Canvas3 } from '#imports'

Canvas3.addAnimationToRender('rotateLogo', {
  onScroll: false,
  onResize: false,
  onMouseMove: true,
  onAnimationsRender: false,
  render: false,
  animationCallback: () => {
    const mesh = Canvas3.getMeshFromSceneByName('logoMesh')
    if (mesh) mesh.rotation.y += 0.01
  },
})

// later, to stop it:
Canvas3.removeAnimationFromRender('rotateLogo')

Manual scroll control example:

import { Canvas3 } from '#imports'

function goToSection() {
  Canvas3.scrollToElBySelector('#contact', 0, -80)
}

Options Reference (Canvas3OptionsType)

Option Type Description
shaders { default: Shader, scroll?: Shader, [name]: Shader } Registry of vertex/fragment shader pairs. default is required; scroll enables the post-processing scroll-speed effect pass.
activateMeshOptions.image Record<string, MeshAnimation> Default in/out uniform animations applied to image meshes on activation (e.g. uAniInImage).
canvasElement.zIndex number z-index applied to the fixed WebGL canvas container.
prefersReducedMotion boolean Flag to adapt behavior for reduced-motion users.
isMobile boolean Flag to adapt behavior for mobile devices.
disabled boolean Globally disables mesh creation; v-canvas3-image falls back to a .reduced-motion class.

Contribution

Local development
# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with the playground
npm run dev

# Build the playground
npm run dev:build

# Run ESLint
npm run lint

# Run Vitest
npm run test
npm run test:watch

# Release new version
npm run release

Version History

Version Released Vue License
0.1.58 ^3.5.18 MIT
0.1.57 ^3.5.18 MIT
0.1.56 ^3.5.18 MIT
0.1.55 ^3.5.18 MIT
0.1.53 ^3.5.18 MIT