Skip to content

Instantly share code, notes, and snippets.

@Poordeveloper
Created November 10, 2015 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Poordeveloper/54d28c07136886a84a02 to your computer and use it in GitHub Desktop.
Save Poordeveloper/54d28c07136886a84a02 to your computer and use it in GitHub Desktop.
dynamic 3D confetti text

dynamic 3D confetti text

Trying to get more comfortable with 3D since I don't really venture beyond the second dimension outside of having to do so for work. Why not do my favourite canvas getImageData trick with Three.js? Using the pretty colors and flat-shaded style as seen in @Yakudoo's pens

window resize is totally busted right now ¯_(ツ)_/¯ so you'll have to refresh if you resize

A Pen by Rachel Smith on CodePen.

License.

<div id="stage"></div>
<canvas id="text" width="700" height="200"></canvas>
<input id="input" type="text" value="EDIT ME"/>
var height,
width,
container,
scene,
camera,
renderer,
particles = [],
mouseVector = new THREE.Vector3(0, 0, 0),
mousePos = new THREE.Vector3(0, 0, 0),
cameraLookAt = new THREE.Vector3(0, 0, 0),
cameraTarget = new THREE.Vector3(0, 0 ,800),
textCanvas,
textCtx,
textPixels = [],
input;
var colors = ['#F7A541', '#F45D4C', '#FA2E59', '#4783c3', '#9c6cb7'];
function initStage() {
width = window.innerWidth;
height = window.innerHeight;
container = document.getElementById('stage');
window.addEventListener('resize', resize);
container.addEventListener('mousemove', mousemove);
}
function initScene() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
container.appendChild(renderer.domElement);
}
function randomPos(vector) {
var radius = width * 3;
var centerX = 0;
var centerY = 0;
// ensure that p(r) ~ r instead of p(r) ~ constant
var r = width + radius * Math.random();
var angle = Math.random() * Math.PI * 2;
// compute desired coordinates
vector.x = centerX + r * Math.cos(angle);
vector.y = centerY + r * Math.sin(angle);
}
function initCamera() {
fieldOfView = 75;
aspectRatio = width / height;
nearPlane = 1;
farPlane = 3000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane);
camera.position.z = 800;
console.log(camera.position);
console.log(cameraTarget);
}
function createLights() {
shadowLight = new THREE.DirectionalLight(0xffffff, 2);
shadowLight.position.set(20, 0, 10);
shadowLight.castShadow = true;
shadowLight.shadowDarkness = 0.01;
scene.add(shadowLight);
light = new THREE.DirectionalLight(0xffffff, .5);
light.position.set(-20, 0, 20);
scene.add(light);
backLight = new THREE.DirectionalLight(0xffffff, 0.8);
backLight.position.set(0, 0, -20);
scene.add(backLight);
}
function Particle() {
this.vx = Math.random() * 0.05;
this.vy = Math.random() * 0.05;
}
Particle.prototype.init = function(i) {
var particle = new THREE.Object3D();
var geometryCore = new THREE.BoxGeometry(20, 20, 20);
var materialCore = new THREE.MeshLambertMaterial({
color: colors[i % colors.length],
shading: THREE.FlatShading
});
var box = new THREE.Mesh(geometryCore, materialCore);
box.geometry.__dirtyVertices = true;
box.geometry.dynamic = true;
particle.targetPosition = new THREE.Vector3((textPixels[i].x - (width / 2)) * 4, (textPixels[i].y) * 5, -10 * Math.random() + 20);
particle.position.set(width * 0.5, height * 0.5, -10 * Math.random() + 20);
randomPos(particle.position);
for (var i = 0; i < box.geometry.vertices.length; i++) {
box.geometry.vertices[i].x += -10 + Math.random() * 20;
box.geometry.vertices[i].y += -10 + Math.random() * 20;
box.geometry.vertices[i].z += -10 + Math.random() * 20;
}
particle.add(box);
this.particle = particle;
}
Particle.prototype.updateRotation = function() {
this.particle.rotation.x += this.vx;
this.particle.rotation.y += this.vy;
}
Particle.prototype.updatePosition = function() {
this.particle.position.lerp(this.particle.targetPosition, 0.02);
}
function render() {
renderer.render(scene, camera);
}
function updateParticles() {
for (var i = 0, l = particles.length; i < l; i++) {
particles[i].updateRotation();
particles[i].updatePosition();
}
}
function setParticles() {
for (var i = 0; i < textPixels.length; i++) {
if (particles[i]) {
particles[i].particle.targetPosition.x = (textPixels[i].x - (width / 2)) * 4;
particles[i].particle.targetPosition.y = (textPixels[i].y) * 5;
particles[i].particle.targetPosition.z = -10 * Math.random() + 20;
} else {
var p = new Particle();
p.init(i);
scene.add(p.particle);
particles[i] = p;
}
}
for (var i = textPixels.length; i < particles.length; i++) {
randomPos(particles[i].particle.targetPosition);
}
}
function initCanvas() {
textCanvas = document.getElementById('text');
textCanvas.style.width = width + 'px';
textCanvas.style.height = 200 + 'px';
textCanvas.width = width;
textCanvas.height = 200;
textCtx = textCanvas.getContext('2d');
textCtx.font = '700 100px Arial';
textCtx.fillStyle = '#555';
}
function initInput() {
input = document.getElementById('input');
input.addEventListener('keyup', updateText);
input.value = 'EDIT ME';
}
function updateText() {
var fontSize = (width / (input.value.length*1.3));
if (fontSize > 120) fontSize = 120;
textCtx.font = '700 ' + fontSize + 'px Arial';
textCtx.clearRect(0, 0, width, 200);
textCtx.textAlign = 'center';
textCtx.textBaseline = "middle";
textCtx.fillText(input.value.toUpperCase(), width / 2, 50);
var pix = textCtx.getImageData(0, 0, width, 200).data;
textPixels = [];
for (var i = pix.length; i >= 0; i -= 4) {
if (pix[i] != 0) {
var x = (i / 4) % width;
var y = Math.floor(Math.floor(i / width) / 4);
if ((x && x % 6 == 0) && (y && y % 6 == 0)) textPixels.push({
x: x,
y: 200-y + -120
});
}
}
setParticles();
}
function animate() {
requestAnimationFrame(animate);
updateParticles();
camera.position.lerp(cameraTarget, 0.2);
camera.lookAt(cameraLookAt);
render();
}
function resize() {
width = window.innerWidth;
height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
textCanvas.style.width = width + 'px';
textCanvas.style.height = 200 + 'px';
textCanvas.width = width;
textCanvas.height = 200;
updateText();
}
function mousemove(e) {
var x = e.pageX - width/2;
var y = e.pageY - height/2;
cameraTarget.x = x*-1;
cameraTarget.y = y;
}
initStage();
initScene();
initCanvas();
initCamera();
createLights();
initInput();
animate();
setTimeout(function() {
updateText();
}, 40);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
body {
overflow: hidden;
background: #A1DBB2;
}
div, canvas {
position: absolute;
}
#text {
z-index: 200;
display: none;
}
input {
z-index: 400;
position: absolute;
text-transform: uppercase;
width: 90%;
bottom: 20px;
background: none;
outline: none;
border: none;
font-size: 30px;
color: #222;
font-weight: bold;
text-align: center;
border-bottom: 1px solid #333;
left: 5%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment