Skip to example

vgpu colours

An example of a full-screen vgpu colour swatch cycling continuously through CSS colour strings with Motion.

JavaScript

Source code

<div class="stage">
  <canvas aria-label="A solid colour swatch cycling through hues"></canvas>
</div>

<script type="module">
  import { animate, frame, motionValue } from "motion"
  import { vgpuEffect } from "motion/vgpu"
  import { effect, frame as vgpuFrame, init, surface } from "vgpu"

  animate.addEffect(vgpuEffect)

  const token = (name) =>
    getComputedStyle(document.body).getPropertyValue(name).trim()
  const palette = [0, 1, 2, 3, 4, 5, 6, 0].map((hue) =>
    token(`--hue-${hue}`)
  )
  const stage = document.querySelector(".stage")
  const canvas = document.querySelector("canvas")

  function runColourMotion(gpu, canvasSurface, swatch) {
    vgpuEffect(swatch, {
      "params.tint": motionValue(palette[0]),
    })

    animate(
      swatch,
      { "params.tint": palette },
      {
        duration: 14,
        ease: "linear",
        repeat: Infinity,
      }
    )

    function render() {
      vgpuFrame(gpu, (currentFrame) => {
        currentFrame.pass(canvasSurface, swatch)
      })
    }

    frame.render(render, true)
  }

  const shader = `
    struct Params {
      tint: vec3f,
    }

    @group(0) @binding(0) var<uniform> params: Params;

    @fragment
    fn fs_main() -> @location(0) vec4f {
      return vec4f(
        pow(params.tint, vec3f(1.0 / 2.2)),
        1.0
      );
    }
  `

  async function start() {
    if (!navigator.gpu) {
      throw new Error("This example needs a browser with WebGPU")
    }

    const gpu = await init()
    const canvasSurface = surface(gpu, canvas, { dpr: [1, 2] })
    const swatch = effect(gpu, shader)

    runColourMotion(gpu, canvasSurface, swatch)
  }

  start().catch((error) => {
    stage.textContent = error.message
  })
</script>

<style>
  .stage {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
  }

  .stage canvas {
    display: block;
    width: 100%;
    height: 100%;
  }
</style>