I figured out a solution, the bounding box calculation is async, so it's not available right away, but there is an 'onSync' callback from Text that you can tap into:
onSync={(mesh)=> {
const visibleBounds = mesh.textRenderInfo.visibleBounds;
}
You can adjust the maxWidth and the fontSize by taking the viewport width and dividing by some number:
<Text color="white"
anchorX="center"
anchorY="top"
fontSize={viewport.width / 100}
position={[0,startingPosition - (offset),1]}
maxWidth={viewport.width / 3}
For the margins between text, I pushed the size of the text plus a margin to a state array, and when iterating over the jsx took the sum of the heights at the current index as the start position.
The whole thing looks like this:
import { useThree } from "@react-three/fiber";
import { Float, Text } from "@react-three/drei"
import { useState, useEffect } from "react";
export default function AboutText() {
const text = [
"1. sample text",
"2. sample text",
"3. sample text",
]
const [heights, setHeights] = useState([])
const startingPosition = 5
const { viewport } = useThree();
useEffect(() => {
console.log('heights updated:', heights);
}, [heights, viewport]);
const TextJSX = text.map((paragraph, i)=>{
const offset = ((i > 0) && heights.length > 0 ) ? heights.slice(0, i).reduce((a, b) => a + b, 0) : 0
console.log(viewport.width)
return(
<Float rotationIntensity={0.2} floatIntensity={.5} key={i}>
<Text color="white"
anchorX="center"
anchorY="top"
fontSize={viewport.width / 100}
position={[0,startingPosition - (offset),1]}
//width of text object
maxWidth={viewport.width / 3}
//text is async, will run onSync when it gets a height
onSync={(mesh)=> {
console.log("onsync")
const visibleBounds = mesh.textRenderInfo.visibleBounds;
const top = Math.abs(visibleBounds[1])
const bottom = Math.abs(visibleBounds[3])
const margin = + 0.2
//heights state will keep building unless it's cleared out.
setHeights(prevHeights => {
if(prevHeights.length === text.length){
return [(top + bottom + margin)];
} else {
return [...prevHeights, (top + bottom + margin)]}
}
)
}}
>
<meshBasicMaterial
color={"#FFF"}
fog={false}
/>
{paragraph}
</Text>
</Float>
)
})
return (
<>
{TextJSX}
</>
)}