JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script type="x-shader/x-vertex" id="vertex-shader">
	precision highp float;
	
    attribute float alpha;
	attribute vec3 position;
	attribute float size;
	
    varying float v_alpha;
	varying float v_size;
	
	uniform mat4 projectionMatrix;
	uniform mat4 modelViewMatrix;
	
	void main() {
        v_alpha = alpha;
		v_size = size;
        vec4 myPosition = modelViewMatrix * vec4(position, 1.0);
		gl_PointSize = v_size * (1. / -myPosition.z);
        gl_Position = projectionMatrix * myPosition;
		
    }
</script>

<script type="x-shader/x-fragment" id="fragment-shader">
	precision highp float;

	uniform vec3 color;

    varying float v_alpha;
	
    void main() {
        gl_FragColor = vec4(color, v_alpha);
    }

</script>

CSS

body{margin:0;
overflow:hidden;}

JavaScript

//All numeric values use SI units.
	var camera, scene, renderer;
	var gravity = -9.81;
	var particleindex = 0, particleCount = 1000,
    particle_geometry = new THREE.BufferGeometry();
	//Positions as [x,y,z,x,y,z, ...]
	var positions = [];
	//var colors = [];
	var uniforms =
	{
        color: { value: new THREE.Color(0xff0000)},
    };
	var alphas = new Float32Array(particleCount * 1);
	var size = 200.0;
	var sizes = [];
	var particle_emitted = [];
	var particle_velocities = [];
	var particle_has_bounced = [];
	var particle_life = 20;
	
	for(var i = 0; i < particleCount; i++)
	{
		sizes.push(size);
		positions.push(0.0, 0.0, 0.0);
		//colors.push(255, 0, 0);
		alphas[i] = 1.0;
		particle_emitted.push(false);
	}
	
	//var colorAttribute = new THREE.Uint8BufferAttribute(colors, 3);
	//colorAttribute.normalized = true;
	
	particle_geometry.addAttribute('position', 
    new THREE.Float32BufferAttribute(positions, 3));
	//particle_geometry.addAttribute('color', colorAttribute);
	particle_geometry.addAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));
	particle_geometry.addAttribute( 'alpha', new THREE.BufferAttribute(alphas, 1));
	
	var material = new THREE.RawShaderMaterial
	({
		uniforms: uniforms,
		vertexShader: document.getElementById( 'vertex-shader' ).textContent,
		fragmentShader: document.getElementById( 'fragment-shader' ).textContent,
		transparent: true
	});
	
	var particleSystem = new THREE.Points(particle_geometry, material),
	height = 0, max_pos_dist_xz = 20, max_neg_dist_xz = max_pos_dist_xz / 2;
	var particle_offset = particle_geometry.attributes.size.array[0];
	var dt = 1 / 60;

	var planegeometry, planematerial, planemesh;
	planegeometry = new THREE.PlaneGeometry(200, 200, 0);
	planematerial = new THREE.MeshBasicMaterial();
	planemesh = new THREE.Mesh(planegeometry, planematerial);
	
	function init()
	{
		camera = new THREE.PerspectiveCamera(70, window.innerWidth /
        window.innerHeight, 0.01, 1e6);
		var controls = new...