HTMLのcanvasタグとJavaScriptを使って3Dっぽいことをするサンプルです。WebGLを使わずに3Dっぽいことをしています。サンプルは下の方に表示されます。

class Vertex{
    constructor(x, y, z){
        this.x = x;
        this.y = y;
        this.z = z;
    }

    rotate(sin, cos){
        this._screenX =  this.x * cos * cos - this.y * sin + this.z * cos * sin + 200;
        this._screenY =  this.x * sin * cos + this.y * cos + this.z * sin * sin + 200;
        this._screenZ = -this.x * sin + this.z * cos;
    }

    get screenX(){ return this._screenX; }
    get screenY(){ return this._screenY; }
    get screenZ(){ return this._screenZ; }
}

class Face{
    constructor(indices, color){
        this._indices = indices;
        this._color = color;
    }
    
    calcZ(vertices){
        return (vertices[this._indices[0]].screenZ + vertices[this._indices[1]].screenZ + vertices[this.indices[2]].screenZ) / 3.0;
    }

    get indices(){ return this._indices; }
    get color(){ return this._color; }
}

const vertices = [
    new Vertex(-100, -100, -100),
    new Vertex(-100,  100,  100),
    new Vertex(100, -100,  100),
    new Vertex(100,  100, -100)
];

const faces = [
    new Face([0, 3, 2], "#FF0000"),
    new Face([0, 2, 1], "#00FF00"),
    new Face([0, 1, 3], "#0000FF"),
    new Face([1, 2, 3], "#00FFFF")
];

let context = null;
let time = 0;

window.addEventListener("load", () => {
    const canvas = document.getElementById("ese");
    context = canvas.getContext('2d');

    setInterval(draw, 33);
}, false);

const draw = () => {
    context.clearRect(0, 0, 400, 400);

    updateVertices(vertices, time);
    zsort(faces, vertices);

    for(const face of faces){
        drawTriangle(context, vertices, face);
    }

    time += 0.01;
};

const updateVertices = (vertices, time) => {
    for(const vertex of vertices){
        vertex.rotate(Math.sin(time), Math.cos(time));
    }
};

const zsort = (faces, vertices) => {
    faces.sort((face1, face2) => {
        return face1.calcZ(vertices) - face2.calcZ(vertices);
    });
};

const drawTriangle = (context, vertices, face) => {
    const vertex1 = vertices[face.indices[0]];
    const vertex2 = vertices[face.indices[1]];
    const vertex3 = vertices[face.indices[2]];

    context.fillStyle = face.color;
    context.beginPath();

    context.moveTo(vertex1.screenX, vertex1.screenY);
    context.lineTo(vertex2.screenX, vertex2.screenY);
    context.lineTo(vertex3.screenX, vertex3.screenY);
    context.lineTo(vertex1.screenX, vertex1.screenY);

    context.closePath();
    context.fill();
    context.stroke();
};