@carbonenginejs/format-stl
v0.1.2
Published
STL format reader/writer with printability inspection helpers for CarbonEngineJS geometry data.
Maintainers
Readme
@carbonenginejs/format-stl
Pure-JavaScript CarbonEngineJS-facing package for the STL triangle-mesh format. It reads ASCII/binary STL, writes ASCII/binary STL from the shared CarbonEngineJS JSON mesh schema, and can inspect geometry for the common topology problems that block useful 3D prints.
CarbonEngine and Fenris Creations (CCP Games) are named in this package for interoperability and target-ecosystem context only. STL itself is not a CCP format, and this package contains no CarbonEngine or Fenris Creations (CCP Games) source code.
Package
- npm: https://www.npmjs.com/package/@carbonenginejs/format-stl
- package:
@carbonenginejs/format-stl - version:
0.1.1 - license:
MIT - runtime: Node
>=18, modern browsers - module: ESM, package root exports
CjsFormatStl
Install
npm install @carbonenginejs/format-stlPublic API
The package root exports one public class: CjsFormatStl. The Cjs prefix
marks this as a CarbonEngineJS format/construction boundary, not an engine
runtime class.
import CjsFormatStl from "@carbonenginejs/format-stl";
const stl = new CjsFormatStl({
emit: "json", // "json" only for reads
source: "mesh.stl", // name written to grannyFileSource
binary: true, // true writes binary STL; false writes ASCII STL
solidName: "mesh",
scale: 1,
recalculateNormals: true,
weldVertices: false, // false preserves STL facet normals on read
weldTolerance: 1e-5, // used by read welding and inspect topology
skipDegenerate: true,
requireWatertight: false, // true rejects writes with printability blockers
classes: {
Root: CjsGeometryRoot,
Mesh: CjsGeometryMesh,
IndexGroup: CjsGeometryIndexGroup
}
});
const json = stl.Read(stlBytes);
const report = stl.Inspect(json);
const bytes = stl.Write(json, { requireWatertight: true });The named export is the same class for callers that prefer named imports:
import { CjsFormatStl } from "@carbonenginejs/format-stl";Format Rules
- The package root exports one public format class:
CjsFormatStl. - Instance methods are PascalCase because format instances can hydrate or sit beside CarbonClasses without colliding with camelCase data fields.
- Static one-shot methods are camelCase because they live on
CjsFormatStlitself, not on hydrated CarbonClass instances. src/CjsFormatStl.jsis the public format boundary. STL parser, writer, topology, and hydration helpers live undersrc/core.Read/ staticreadreturn the shared JSON schema.emit: "raw"is not exposed because parser state is intentionally internal.Write/ staticwritereturnUint8Arrayfor binary STL andstringfor ASCII STL.Inspect/ staticinspectaccepts STL text, STL bytes, a shared JSON root, or one shared JSON mesh.ToJSON/ statictoJSONconverts format output to JSON-compatible data. It is not an STL writer and does not return JSON text.
JSON Graph
STL is triangle-only. It cannot represent UVs, materials, bones, morph targets, animations, transforms, or tangent-space data. The read path emits the shared mesh-side schema with unsupported branches present as empty arrays:
Root
|-- grannyFileFormatRevision, grannyFileSource
|-- meshes: Mesh[]
| |-- name, minBounds, maxBounds
| |-- boneBindings: []
| |-- morphTargets: []
| |-- vertex: VertexChannels
| | |-- position, normal
| | |-- tangent: [], binormal: []
| | |-- texcoord0: [], texcoord1: []
| | `-- blendIndice: [], blendWeight: []
| `-- indices: IndexGroup[]
| `-- name, bytesPerIndex, faces
|-- models: []
`-- animations: []IndexGroup.faces is a flat triangle-index array in groups of three.
STL Coverage
- ASCII STL read/write
- Binary STL read/write
- Per-facet STL normals
- Optional vertex welding on read
- Shared JSON root or mesh input for writes
- Node convenience helpers:
readFile(path, options)andwriteFile(path, input, options) - Sniff helpers:
isStl(input)andisBinaryStl(input)
Printability Inspection
Inspect is deliberately conservative. It does not repair meshes, but it does
tell callers whether a mesh has the obvious blockers before writing or sending
it to a slicer:
- open edges
- non-manifold edges
- inconsistent winding edges
- degenerate triangles
- shell count
- unique vertex and edge counts
- axis-aligned bounds
requireWatertight: true runs the same checks during Write and throws if the
mesh is not closed and consistently wound.
Options
emit:"json"default. Other values currently throw.source: default"memory". Written togrannyFileSourceand reports.binary: defaulttrue.truewrites binary STL bytes;falsewrites ASCII STL text.solidName: default"carbonenginejs". Used for ASCIIsolidnames and the binary header.scale: default1. Applied when writing JSON geometry to STL.recalculateNormals: defaulttrue. Writer recomputes STL facet normals from triangle winding.falseuses averaged vertex normals when present.weldVertices: defaultfalse. On read,falsepreserves each STL facet as separate vertices so facet normals remain exact.truewelds matching positions byweldToleranceand regenerates vertex normals.weldTolerance: default1e-5. Used for read welding and inspect topology.skipDegenerate: defaulttrue. Writer skips zero-area triangles.requireWatertight: defaultfalse. Writer throws when inspection finds printability blockers.classes: optional fornew CjsFormatStl(options),Read, and staticread. Accepted keys areRoot,Mesh, andIndexGroup, exposed asCjsFormatStl.CLASS_KEYS.
Helper Direction
Cutting a model into printable pieces should be a higher-level geometry helper, not a half-hidden STL parser feature. The useful version needs plane or volume cuts, cap generation, consistent winding, optional alignment keys, and a fresh inspection pass for every produced piece.
Turning normal maps into real geometry is also a conversion helper rather than an STL feature. Normal maps describe surface direction, not direct height, so a good helper will need a base mesh or tessellated surface, UVs, tangent frames, height/displacement controls, and validation against the target print scale.
Both helpers should eventually live beside this package or in shared geometry
math once @carbonenginejs/core-math exists.
Tests
npm testTests are fully self-contained and use inline geometry. They do not require local asset folders, network access, or game files.
License
MIT (see LICENSE and NOTICE).
This package contains no CarbonEngine or Fenris Creations (CCP Games) code. Its input/output shape targets the shared CarbonEngineJS JSON mesh schema used for CarbonEngine interoperability.
