JSFiddle - React, Tailwind, and code Playground

by Douglas Duhaime

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="vertexshader">

attribute vec2 offset;

varying vec2 vOffset;

void main() {

    vOffset = offset;

	gl_PointSize = 25.0;

	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

}

</script>

<script type="x-shader/x-fragment" id="fragmentshader">

uniform sampler2D texture;
uniform vec2 repeat;

varying vec2 vOffset;

void main() {

    vec2 uv = vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y );

    vec4 tex = texture2D( texture, uv * repeat + vOffset );
    
    if ( tex.a < 0.5 ) discard;

    gl_FragColor = tex;

}

</script>

CSS

body {
	background-color: #000;
	margin: 0px;
	overflow: hidden;
}

JavaScript

var renderer, scene, camera, controls;
var pointCloud, uniforms, attributes;

init();
animate();

function init() {

    // info
    info = document.createElement( 'div' );
    info.style.position = 'absolute';
    info.style.top = '30px';
    info.style.width = '100%';
    info.style.textAlign = 'center';
    info.style.color = '#fff';
    info.style.fontWeight = 'bold';
    info.style.backgroundColor = 'transparent';
    info.style.zIndex = '1';
    info.style.fontFamily = 'Monospace';
    info.innerHTML = 'Drag mouse to rotate camera; scroll to zoom';
    document.body.appendChild( info );

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor( 0x000000, 1 );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
    
    // scene
    scene = new THREE.Scene();

    //camera
    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.z = 400;

    // controls
    controls = new THREE.OrbitControls( camera, renderer.domElement );

    // vertices
    var geometry = new THREE.SphereGeometry( 100, 16, 12 );
    geometry.mergeVertices(); // to remove duplicate vertices at the poles
    var vertices = geometry.vertices;

    // geometry
    geometry = new THREE.BufferGeometry();
 
    // attributes
    numVertices = vertices.length;
    var positions = new Float32Array( numVertices * 3 ); // 3 coordinates per point
    var offsets = new Float32Array( numVertices * 2 ); // 2 coordinates per point

    geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geometry.addAttribute( 'offset', new THREE.BufferAttribute( offsets, 2 ) );

    // populate positions
    geometry.attributes.position.copyVector3sArray( vertices );

    // populate offsets
    var offset = new THREE.Vector2();

    for ( var i = 0, index = 0, l = numVertices; i < l; i ++, index += 2 ) {

        offset.set(...