<div id="loader">
    <canvas></canvas>
</div>

<!-- dribbble -->
<a class="dribbble" href="https://dribbble.com/shots/6772849--Loader" target="_blank"><img src="https://dribbble.com/assets/logo-small-2x-9fe74d2ad7b25fba0f50168523c15fda4c35534f9ea0b1011179275383035439.png" alt=""></a>
#loader {
    canvas {
        width: 240px;
        height: 240px;
    }
}

html {
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
}

* {
    box-sizing: inherit;
    &:before,
    &:after {
        box-sizing: inherit;
    }
}

// Center & dribbble
body {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #275EFE;
    .dribbble {
        position: fixed;
        display: block;
        right: 24px;
        bottom: 24px;
        img {
            display: block;
            width: 76px;
        }
    }
}
View Compiled
$(document).ready(function() {

    let $canvas = $('#loader canvas'),
        canvas = $canvas[0],
        renderer = new THREE.WebGLRenderer({
            canvas: canvas,
            context: canvas.getContext('webgl2'),
            antialias: true,
            alpha: true
        });

    renderer.setSize($canvas.width(), $canvas.height());
    renderer.setPixelRatio(window.devicePixelRatio || 1);

    let scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(45, $canvas.width() / $canvas.height(), 0.1, 1000);

    camera.position.z = 500;

    let shape = new THREE.TorusGeometry(70, 20, 60, 160);
    let material = new THREE.MeshPhongMaterial({
        color: 0xE4ECFA,
        shininess: 20,
        opacity: .96,
        transparent: true
    });
    let donut = new THREE.Mesh(shape, material);

    scene.add(donut);

    let lightTop = new THREE.DirectionalLight(0xFFFFFF, .3);
    lightTop.position.set(0, 200, 0);
    lightTop.castShadow = true;
    scene.add(lightTop);

    let frontTop = new THREE.DirectionalLight(0xFFFFFF, .4);
    frontTop.position.set(0, 0, 300);
    frontTop.castShadow = true;
    scene.add(frontTop);

    scene.add(new THREE.AmbientLight(0xCDD9ED));

    function twist(geometry, amount) {
        const quaternion = new THREE.Quaternion();
        for(let i = 0; i < geometry.vertices.length; i++) {
            quaternion.setFromAxisAngle(
                new THREE.Vector3(1, 0, 0),
                (Math.PI / 180) * (geometry.vertices[i].x / amount)
            );
            geometry.vertices[i].applyQuaternion(quaternion);
        }
        geometry.verticesNeedUpdate = true;
    }

    let mat = Math.PI,
        speed = Math.PI / 120,
        forwards = 1;

    var render = function() {

        requestAnimationFrame(render);

        donut.rotation.x -= speed * forwards;

        mat = mat - speed;

        if(mat <= 0) {
            mat = Math.PI;
            forwards = forwards * -1;
        }

        twist(shape, (mat >= Math.PI / 2 ? -120 : 120) * forwards);

        renderer.render(scene, camera);

    };

    render();

});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://code.jquery.com/jquery-3.4.1.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.min.js