JSFiddle - React, Tailwind, and code Playground

JavaScript

// bow-tie
var objString = "v 0 0 0\nv 1 1 0\nv 1 -1 0\nv 0 0 0\nv -1 1 0\nv -1 -1 0\n" +
    "vt 0 .5\nvt 1 1\nvt 1 0\nvt 0 .5\nvt 1 1\nvt 1 0\n" +
    "vn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\n" +
    "f 1/1/1 2/2/2 3/3/3\nf 4/4/4 5/5/5 6/6/6";
// output indices should be [0, 1, 2, 0, 3, 4]
// parse the file
var lines = objString.split("\n");
var data = lines.map(function(line) { return line.split(" "); });
var v = [];
var t = [];
var n = [];
var f = [];
var vIndexMap = new Map(); // map to earliest index in the list
var vtIndexMap = new Map();
var vnIndexMap = new Map();
var indexMap = new Map(); // HashMap<face:string, index:integer>
var nextIndex = 0;
var vertices = [];
var indices = [];
// fill vertex, texture and normal arrays
data.filter(function(d) { return d[0] == "v"; }).forEach(function(d, i) { 
    v[i] = [parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]; 
	var key = [d[1], d[2], d[3]].toString();
    if(!vIndexMap.has(key)) {
    	vIndexMap.set(key, i);
    }
});
data.filter(function(d) { return d[0] == "vt"; }).forEach(function(d, i) { 
    t[i] = [parseFloat(d[1]), parseFloat(d[2])]; 
    var key = [d[1], d[2]].toString();
    if(!vtIndexMap.has(key)) {
    	vtIndexMap.set(key, i);
    }
});
data.filter(function(d) { return d[0] == "vn"; }).forEach(function(d, i) { 
    n[i] = [parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]; 
	var key = [d[1], d[2], d[3]].toString();
    if(!vnIndexMap.has(key)) {
    	vnIndexMap.set(key, i);
    }
});
//
console.log("V", v.toString());
console.log("T", t.toString());
console.log("N", n.toString());
// create vertices and indices arrays by parsing faces
data.filter(function(d) { return d[0] == "f"; }).forEach(function(d) { 
    var f1 = d[1].split("/").map(function(d, i) {
        var index = parseInt(d)-1;
        if(i == 0) index = vIndexMap.get(v[index].toString());
        else if(i == 1) index = vtIndexMap.get(t[index].toString());
        else if(i == 2) index =...