# Loaders, exporters and text/SVG shapes All of these live under `three/addons/`, which the import map of template.html already provides. Import from the addon file, NOT from the `THREE` namespace (`THREE.STLExporter` is undefined): ```js import { STLExporter } from 'three/addons/exporters/STLExporter.js'; import { STLLoader } from 'three/addons/loaders/STLLoader.js'; import { SVGLoader } from 'three/addons/loaders/SVGLoader.js'; import { FontLoader } from 'three/addons/loaders/FontLoader.js'; import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; ``` ## Export STL `STLExporter.parse(object3d)` traverses `object3d` and exports every `Mesh` in WORLD coordinates. Give it a throw-away `Group` of plain meshes - never the scene (grid, lights, helpers would be included) and never Brush objects with stale matrices: ```js function toSTL(objs, binary = false) { const g = new THREE.Group(); for (const o of objs) { // o.mesh: Mesh or Brush (result of CSG) const m = new THREE.Mesh(o.mesh.geometry); // plain Mesh, geometry is shared m.matrix.copy(o.mesh.matrixWorld); m.matrixAutoUpdate = false; g.add(m); } g.updateMatrixWorld(true); return new STLExporter().parse(g, { binary }); // string (ASCII) or DataView (binary) } ``` Call `obj.updateMatrixWorld(true)` after changing position/rotation and before exporting or evaluating CSG. Holes must already be subtracted (export the group results, not the hole brushes). ## Import STL ```js pickFile('.stl', false, buf => { // ArrayBuffer (see single-file-webapp skill) const geo = new STLLoader().parse(buf); // handles ASCII and binary geo.computeVertexNormals(); geo.center(); // optional addObject({ type: 'stl', geometry: geo }); }); ``` ## Extrude an SVG ```js pickFile('.svg', true, text => { const data = new SVGLoader().parse(text); const shapes = data.paths.flatMap(p => SVGLoader.createShapes(p)); const geo = new THREE.ExtrudeGeometry(shapes, { depth: 2, bevelEnabled: false }); geo.rotateX(Math.PI); // SVG y points down geo.center(); addObject({ type: 'svg', geometry: geo }); }); ``` SVG units are px; scale with `geo.scale(s, s, 1)` (e.g. `s = 0.1` for mm-ish sizes). ## Solid text ```js const FONT_URL = 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/fonts/helvetiker_regular.typeface.json'; const font = await new FontLoader().loadAsync(FONT_URL); // load once, cache const geo = new TextGeometry('Hi', { font, size: 10, height: 2, curveSegments: 6 }); geo.center(); ``` (`height` is the extrusion depth; in three >= r163 the option is called `depth`.) ## Group with holes = CSG result ```js function buildGroup(members) { // members: [{mesh, hole}] const ev = new Evaluator(); ev.useGroups = false; const solids = members.filter(m => !m.hole), holes = members.filter(m => m.hole); let result = null; for (const s of solids) { s.mesh.updateMatrixWorld(true); result = result ? ev.evaluate(result, s.mesh, ADDITION) : s.mesh; } for (const h of holes) { h.mesh.updateMatrixWorld(true); result = ev.evaluate(result, h.mesh, SUBTRACTION); } result.material = solids[0].mesh.material; return result; // a Brush; keep `members` for ungroup } ``` Operands must be `Brush` instances (create every object as a Brush from the start, so any object can take part in CSG later). Render holes with a transparent material (`transparent: true, opacity: 0.35`) until grouped.