Multiline fillText?

Hey guys,

I’m currently setting up some simple text output for a main menu. Each button has a title and little blurb. The titles work great since they are one line of text. The blurbs however vary due to their length. I have a texture set up where the text is output to, and am trying to have it so the blurbs can be multi-line.

Passing in \n doesn’t seem to do anything.

Here is how I am handling the text elements:
function UpdateMainUITextContext(title, body){

	if(mainUITextMesh != null){
		scene.remove(mainUITextMesh);
	}

	const canvasSize = 512;
	var canvas = document.createElement('canvas');
	canvas.width = canvas.height = canvasSize;
	mainUITextContext = canvas.getContext('2d');

	mainUITextContext.fillStyle = 'black';// "rgba(255, 0, 0, 0.95)";
	mainUITextContext.font = "Bold 60px Arial";
	mainUITextContext.textAlign = 'center';
	mainUITextContext.textBaseline = 'middle';
	//mainUITextContext.fillRect(0, 0, canvasSize, canvasSize); //used this to see where i was placing text
	mainUITextContext.fillText(title, canvas.width / 2, 150, canvas.width);
	mainUITextContext.font = "Normal 60px Arial";
	mainUITextContext.fillText(body, canvas.width / 2, canvas.height / 2, canvas.width);

	var texture = new THREE.Texture(canvas);
	texture.needsUpdate = true;

	var material1 = new THREE.MeshBasicMaterial( { 
		map: texture, 
		side: THREE.DoubleSide,
		depthWrite: false,
		depthTest: false,
		color: 0xff0000
	});

	material1.transparent = true;

	mainUITextMesh = new THREE.Mesh(
		new THREE.PlaneGeometry(4.5, 4.5),
		material1
	);
	
	mainUITextMesh.renderOrder = 11;
	mainUITextMesh.position.set(0,0,0);

	scene.add(mainUITextMesh);
}

Appreciate any assistance guys!

So, TIL - fillText doesn’t support multiline text output. However, you can just stack your fillText calls. So, since this is just a PoC - I broke the blurbs of text into lines, stuffed those into my custom object as an array, then just step over that with a for loop which hits fillText for each element.

Hacky but gets the job done for now!

I might have missed something in the code - but it seems like you’re just painting the text on a transparent CanvasTexture and apply it to a plane to get a flat, transparent text?

If that’s the case - maybe Troika would be helpful? It renders flat text using fancy, performant maths and also supports multilines out-of-the-box.

Awesome! I’m checking this out now it looks sweet. My project is three-js and vanilla JS otherwise. Any idea how I can use this? I’m pretty new to JS - but I know I can’t import anything and have to put the src in my index.html but not sure which scripts it needs to work. Thanks!

Yeah, it seems a bit hidden - you can access and download built modules on unpkg (for both troika-three-text and it’s troika-dependencies.)

Awesome! Thanks so much! Is there a specific part of my project that these scripts should live in? I made a custom folder called Text in my JS folder and it’s breaking hard currently lol

Uncaught TypeError: Failed to resolve module specifier “three”. Relative references must start with either “/”, “./”, or “…/”.

Uncaught TypeError: Cannot read property ‘defineWorkerModule’ of undefined
at troika-three-text.umd.js:1053
at troika-three-text.umd.js:4
at troika-three-text.umd.js:5

Uncaught TypeError: Cannot read property ‘defineWorkerModule’ of undefined
at troika-three-text.umd.min.js:20
at troika-three-text.umd.min.js:10
at troika-three-text.umd.min.js:10

Then this is from my index.html

<script type="module" src="js/text/troika-three-text.esm.js"></script>
<script type="module" src="js/text/troika-three-text.umd.js"></script>
<script type="module" src="js/text/troika-three-text.umd.min.js"></script>