JSFiddle - React, Tailwind, and code Playground

by grano

HTML

<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
<script>
  var sphereRadius = {
    value: 20
  };

  function getMaterial(params) {

    var diffuse = params.diffuse === undefined ? 0xffffff : params.diffuse;
    var diffuseBack = params.diffuseBack === undefined ? diffuse : params.diffuseBack;

    var inside = params.inside === undefined ? true : params.inside;
    inside = inside ? 1 : -1;

    let lambert = new THREE.ShaderMaterial({
      uniforms: THREE.UniformsUtils.merge([THREE.ShaderLib.lambert.uniforms, {
        clippingSphere: {
          value: new THREE.Vector4()
        },
        diffuseBack: {
          value: new THREE.Color()
        }
      }]),

      vertexShader: THREE.ShaderLib.lambert.vertexShader
        .replace(/varying vec3 vLightFront;/g, 'varying vec3 vLightFront;\nvarying vec4 worldPosition;')
        .replace(/#include <worldpos_vertex>/g, 'worldPosition = modelMatrix * vec4( transformed, 1.0 );'),

      fragmentShader: THREE.ShaderLib.lambert.fragmentShader
        .replace(/uniform float opacity;/g, 'uniform float opacity;\nuniform vec4 clippingSphere;\nuniform vec3 diffuseBack;')
        .replace(/varying vec3 vLightFront;/g, 'varying vec3 vLightFront;\nvarying vec4 worldPosition;')
        .replace(/#include <clipping_planes_fragment>/g, '#include <clipping_planes_fragment>\n if (distance(worldPosition.xyz, clippingSphere.xyz) * sign(clippingSphere.w) > clippingSphere.w) discard;')
        .replace(/#include <dithering_fragment>/g, '#include <dithering_fragment>\n if (!gl_FrontFacing) gl_FragColor.xyz = diffuseBack;'),

      lights: true,

      side: THREE.DoubleSide,

      flatShading: false
    });

    lambert.uniforms.clippingSphere.value.set(0, 0, 0, sphereRadius.value * inside);
   ...

CSS

body {
  overflow: hidden;
  margin: 0;
}

#circle {
  position: absolute;
  text-align: center;
  width: 60px;
  height: 60px;
  -webkit-border-radius: 30px;
  -moz-border-radius: 30px;
  border-radius: 30px;
  background: rgba(0, 128, 128, .5);
  font-size: 50px;
  font-family: Times New Roman;
  color: rgba(0, 165, 255, .75);
  cursor: pointer;
}

.noselect {
  -webkit-touch-callout: none;
  /* iOS Safari */
  -webkit-user-select: none;
  /* Safari */
  -khtml-user-select: none;
  /* Konqueror HTML */
  -moz-user-select: none;
  /* Firefox */
  -ms-user-select: none;
  /* Internet Explorer/Edge */
  user-select: none;
  /* Non-prefixed version, currently
  supported by Chrome and Opera */
}


/* unvisited link */

a:link {
  color: orange;
}


/* visited link */

a:visited {
  color: orange;
}


/* mouse over link */

a:hover {
  color: orange;
}


/* selected link */

a:active {
  color: orange;
}

JavaScript

var hide = true;
circle.addEventListener("click", function() {
  if (hide) {
    circle.style.background = "#20869f";
    circle.style.color = "aqua";
    info.style.width = "640px";
    info.style.height = "214px";
  } else {
    circle.style.background = "rgba(0, 128, 128, .5)";
    circle.style.color = "rgba(0, 165, 255, .5)";
    info.style.width = "62px";
    info.style.height = "62px";
  }
  hide = !hide;
}, false);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(1, 1.5, 8).setLength(55);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor(0x779999);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, -10, 0);
controls.update();
controls.enablePan = false;
controls.maxDistance = 80;
controls.maxPolarAngle = THREE.Math.degToRad(95);

var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(10, 5, 10);
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff, 0.5);
light2.position.set(10, 5, -10);
scene.add(light2);
scene.add(new THREE.AmbientLight(0xffffff, 0.6));

//scene.add(new THREE.GridHelper(50, 10));
var r = "https://threejs.org/examples/textures/cube/Bridge2/";
var urls = [r + "posx.jpg", r + "negx.jpg",
  r + "posy.jpg", r + "negy.jpg",
  r + "posz.jpg", r + "negz.jpg"
];
textureCube = new THREE.CubeTextureLoader().load(urls);
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
scene.add(new THREE.Mesh(new THREE.SphereGeometry(20.1, 64, 32), new THREE.MeshBasicMaterial({
  color: "white",
  transparent: true,
  opacity: 0.075,
  envMap: textureCube
})));

// sea
var seaGeom = new THREE.PlaneGeometry(50, 50, 15, 15);
seaGeom.rotateX(-Math.PI * 0.5);
seaGeom.translate(0, -2.5, 0);
seaGeom.vertices.forEach(v => {
 ...