THREE.js objects to STL files and downloading in browser

Update1: packaged this into a script, find it in this Gist 

Update 2: wrote a similar script for how to convert three.js objects to binary stl files

For my Pixel Printer, which is an in browser voxel editor in THREE.js which exports to STL files, I needed to do 2 major things:

  1. Merge the voxels together and remove the interior faces. I covered this in the last post, it is fairly straightforward. 
  2. Transform the THREE.js representation of the group of voxels into an ASCII STL file and figure out how to save that file out of the browser without using a server.

Initially I had it running on a node.js server which wrote the STL file (easier to write binary STL's also), but I really wanted people to use it from my github pages site directly, so I looked into the W3C's saveAs() protocol. I found FileSaver.js  which is a super simple to use wrapper for most browsers. Using it I am able to save STL files right out of the browser without a server. Check it out here

ASCII STL files are very straightforward to produce as long as you already have a list of triangulated faces and vertices. Wikipedia has the format like this:

facet normal ni nj nk
outer loop
vertex v1x v1y v1z
vertex v2x v2y v2z
vertex v3x v3y v3z
endloop
endfacet
I implemented two helper functions to wrap the printing of vectors and vertices
function stringifyVector(vec){
return ""+vec.x+" "+vec.y+" "+vec.z;
}

function stringifyVertex(vec){
return "vertex "+stringifyVector(vec)+" \n";
}
With those two, generating an ASCII STL is as simple as just following the directions above:
function generateSTL(geometry){
var vertices = geometry.vertices;
var tris = geometry.faces;

stl = "solid pixel";
for(var i = 0; i<tris.length; i++){
stl += ("facet normal "+stringifyVector( tris[i].normal )+" \n");
stl += ("outer loop \n");
stl += stringifyVertex( vertices[ tris[i].a ];
stl += stringifyVertex( vertices[ tris[i].b ];
stl += stringifyVertex( vertices[ tris[i].c ];
stl += ("endloop \n");
stl += ("endfacet \n");
}
stl += ("endsolid");

return stl
}

And with that potentially enormous string generated, I create a blob from that string with the type "text/plain", then just use the saveAs() function provided by FileSaver.js:

function saveSTL( geometry ){

var stlString = generateSTL( geometry );

var blob = new Blob([stlString], {type: 'text/plain'});

saveAs(blob, 'pixel_printer.stl');

}