How to render canvas element with no repeat? Box UV mapping

I am trying to build a box where I can draw the images myself through a canvas element. Here is what I have so far:

The thing is, I do not want the canvas image to repeat every face, I want to be unique and render it contantly, so if you see, the “Hello world” text is being cut after the edge, I want it to render fully in the next face.

Is that possible using a simple BoxGeometry and MeshBasic material?

This is what I have tried so far.

const ratio = devicePixelRatio;
    drawingCanvas.width = 600 * ratio;
    drawingCanvas.height = 600 * ratio; = `${600}px`; = `${600}px`;

    const ctx = drawingCanvas.getContext("2d");
    if (ctx) {
      ctx.scale(ratio, ratio);

      ctx.fillStyle = "white";
      ctx.fillRect(0, 0, 600, 600);

      ctx.fillStyle = "blue";
      ctx.font = "80px Arial";
      ctx.fillText("Hello World", 600 / 2 - 15, 600 / 2 - 15);

    const map = new THREE.CanvasTexture(

    const cube = new THREE.Mesh(
      new THREE.BoxGeometry(200, 200, 200),
      new THREE.MeshBasicMaterial({

You need to change the UV coordinates of your cube vertices accordingly. I’m not sure what the syntax is but you need to assign a custom array of UVs for each face of the cube, something like this (top and bottom faces not included):

const forntFaceUvs = [
    new Vector2(0, 0),
    new Vector2(0.25, 0),
    new Vector2(0, 1),
    new Vector2(0.25, 1)

const rightFaceUVs = [
    new Vector2(0.25, 0),
    new Vector2(0.5, 0),
    new Vector2(0.25, 1),
    new Vector2(0.5, 1)

const backFaceUVs = [
    new Vector2(0.5, 0),
    new Vector2(0.75, 0),
    new Vector2(0.5, 1),
    new Vector2(0.75, 1)

const leftFaceUVs = [
    new Vector2(0.75, 0),
    new Vector2(1, 0),
    new Vector2(0.75, 1),
    new Vector2(1, 1)

You also need to make sure the canvas aspect ratio is wide enough so the text doesn’t get distorted.

Yeah this is what I was thinking, do you know how to modify the UV for BoxGeometry? Because I personally didn’t find a way for it yet…

You can play with the Texture’s wrap, repeat, and offset

Something like this example.

const texture = new THREE.CanvasTexture(canvas);
texture.wrapS = THREE.RepeatWrapping;
texture.repeat.set(1, 1);
function animation( time ) {
  texture.offset.x -= 0.01;
  renderer.render( scene, camera );

I quess all you need is here: javascript - THREE.js generate UV coordinate - Stack Overflow.

There are several approaches, some of them are already mentioned above:

  • modify the texture coordinates of box vertices, by changing the buffer attribute called 'uv'
  • define separate texture for each side of the box and use an array of materials
  • use texture repeat and offset to show specific part of the canvas on each side
  • use a fake box (a cylinder with 4 sides), because its texture coordinates are OK

Here is a demo of the 4-th approach. Note, that I provide it only as a reference. Personally, I’d prefer the first approach.


1 Like