JSFiddle - React, Tailwind, and code Playground

by clmsvie

HTML

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
    
<script type="importmap">
	{
		"imports": {
			"three": "https://unpkg.com/[email protected]/build/three.module.js",
      "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
		}
	}
</script>

<link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Inter:[email protected]&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap"
      rel="stylesheet"
    />

CSS

body {
	  margin: 0;
    overflow: hidden;
}

div {
  position: absolute;
  left: 0;
  bottom: 1em;
  text-align: center;
  width: 100%;
  color: #fff;
  font: 500 2em sans-serif;
}

JavaScript

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

// init
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 2;

const scene = new THREE.Scene();
scene.background = new THREE.Color(0xff6f61);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animation);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.autoRotate = false; // Auto-rotate disabled

window.onresize = () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
};

// Logic -------
const spritesPool = [];
const letters = [];
const fixedLetterWidth = 0.2; // Fixed width for each letter (adjusted for THREE.js units)
const spacing = 0.1; // Fixed spacing between letters
let currentXPosition = 0;

const message = "Hello World!";

// Calculate total width to center the text
const totalWidth = (fixedLetterWidth + spacing) * message.length - spacing;
currentXPosition = -totalWidth / 2;

message.split("").forEach((char) => {
  const sprite =
    spritesPool.pop() ??
    new THREE.Sprite(
      new THREE.SpriteMaterial({
        map: new THREE.CanvasTexture(createCanvas(500)),
      })
    );

  scene.add(sprite);

  const canvasTexture = sprite.material.map;
  drawLetter(canvasTexture, char);

  positionSprite(sprite, currentXPosition);
  currentXPosition += fixedLetterWidth + spacing; // Update position for the next character
});

function positionSprite(sprite, xPosition) {
  sprite.visible = true;
  sprite.scale.set(fixedLetterWidth, fixedLetterWidth, 1); // Scale based on the fixed letter width
  sprite.position.set(xPosition, 0, 0); // Adjust position based on width
}

function drawLetter(canvasTexture,...