JSFiddle - React, Tailwind, and code Playground

by Paul West

HTML

<script src="https://cdn.jsdelivr.net/npm/three@0.93.0/build/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.93.0/examples/js/controls/OrbitControls.js"></script>

CSS

body {
  overflow: hidden;
  margin: 0;
}

JavaScript

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

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

var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));

scene.add(new THREE.GridHelper(4, 4));

var geom = new THREE.SphereGeometry(1, 8, 4);

// heart morphTargets

var heart = geom.vertices.map(v => {
  let tv = v.clone();
  let absX = Math.abs(tv.x * 0.75);
  // reference for the formula of heart: https://www.youtube.com/watch?v=aNR4n0i2ZlM
  tv.y += absX * (Math.sqrt((20 - absX) / 15));
  tv.z *= 0.5;
  tv.x *= 1.2;
  return tv;
});

geom.morphTargets.push({
  name: "heart",
  vertices: heart
});


var mesh = new THREE.Mesh(geom, new THREE.MeshLambertMaterial({
  color: "red",
  wireframe: false,
  morphTargets: true,
  transparent: true
}));
scene.add(mesh);

// tweenings

var tweenHeart = new TWEEN.Tween(mesh.morphTargetInfluences)
  .to({
    "0": 1
  }, 1000)
  .delay(500)
  .yoyo(true)
  .repeat(Infinity);

tweenHeart.start();

render();

function render() {
  requestAnimationFrame(render);
  TWEEN.update();
  renderer.render(scene, camera);
}