STEP→STL Your file stays in this tab · nothing is uploaded

stl to 3mf

Read the triangles out of a binary or ASCII STL, write them into a 3MF package — in this tab.

Convert .stl to .3mf — 0 B of WebAssembly, 3 parts in the ZIP, both measured in the tab.

This page converts one direction only: mesh container in, mesh container out.

Nothing is read until you press it.

Have a STEP file?The STEP converter is on the home page. Open the STEP converter →
Our control STL
684 B
Triangles it holds — (684 − 84) / 50
12
3MF it becomes, stored / deflated
2,715 / 1,318 B
WebAssembly this page downloads
0 B

Every cell is measured on this page, on 2026-10-29: the 684-byte cube-10x10-reference.stl is read by the shipped STL reader in this tab, and 2,715 (stored) / 1,318 (deflated) bytes come from the writer running in the same tab. 0 B of WebAssembly holds here for a structural reason, not as a boast: an STL already is triangles and a 3MF is a ZIP of text, so neither side needs a CAD kernel. The second row is the binary-STL size identity, 84 + 50 × n, true for any triangle count — not only for these 12.

What changes is the container, not the geometry

The honest description of this stl to 3mf converter is a container swap. A binary STL is a flat list: an 84-byte header, then 50 bytes per triangle holding a normal, three vertices and a two-byte attribute count that is almost always zero. A 3MF is an OPC ZIP package whose model part stores the same triangles as XML. This page reads the first shape and writes the second, and every triangle that goes in comes out with the same three corners in the same winding order.

Everything an STL never had, the output does not invent. There is no colour, no multi-material assignment, no PrintTicket, no object name, no hierarchy and no thumbnail in the package it writes. There is exactly one object, one mesh, one build item, and a unit attribute set to millimeter. That unit is this page’s choice rather than a reading of the source, because an STL carries no unit field at all — the numbers are copied exactly, and the label is an assumption you may have to correct downstream.

What survives and what does not when an STL becomes a 3MF
KeptWritten asNot present at all
Every triangle’s three vertex positions<vertices> plus <triangles> indicesColour and materials
Triangle order and windingone <triangle v1 v2 v3> per input facet, in file orderPrint settings, plate position, layer height
Absolute coordinates, including any offset from the originnumbers copied, no centring and no rescalingObject names, parts, components, thumbnails
A unit declaration<model unit="millimeter"> — this page’s choiceAnything the STL did not carry in the first place

Two pages carry the whole 3MF footprint of this site, and there will not be a third: the 3MF to STL page reads a package, this page writes one, and STEP↔STL remains the main line here. Any further 3MF question is answered inside these two pages rather than on a page of its own.

STL to STEP is a different job, and this page does not do it

It is worth being blunt about the boundary, because “convert” covers two very different operations. Wrapping triangles in a new container is a serialisation change: no information is added, and none has to be inferred. Rebuilding a STEP file is a modelling change: it needs a boundary representation — analytic and NURBS surfaces, curves, and the topology that stitches them into a solid — and an STL has thrown that away. A STEP file produced from a mesh has to have every surface fitted, and the result is an approximation whose quality depends on the fit, not on the file it started from.

So the answer to “can I convert stl to step” is not the answer to “can I convert stl to 3mf”. The first needs reconstruction; the second needs a ZIP writer. The STL to STEP page sets out the reconstruction case in its own numbers, and nothing on this page changes it.

What the .3mf this page writes contains

Three parts, and no others. [Content_Types].xml maps the two extensions, _rels/.rels names the root model part, and 3D/3dmodel.model holds the geometry. The model element declares the core 3MF namespace and unit="millimeter", then declares one <object id="1" type="model"> whose <mesh> carries every vertex and every triangle, and closes with <build><item objectid="1"/></build>.

Vertices are not merged. A shared vertex table would make a cube eight entries instead of thirty-six, but merging costs a hash of 3n positions and changes the indexing this page can verify against the input, so each triangle keeps its own three vertex entries and points at indices 3i, 3i+1, 3i+2. That is also why the stored package is larger than the STL it came from: the same geometry written as text costs more bytes than 50 bytes per triangle, until the model part is deflated.

ZIP entries are written stored (method 0) with a CRC32 per part, which every ZIP reader accepts without negotiation. The model part is deflated instead when the runtime reports CompressionStream('deflate-raw') — probed by constructing one, not assumed — and the fallback is the stored path. The result panel prints the method that actually ran, so the byte counts you see are the ones your browser produced.

When it will not convert, or comes out wrong

The numbers on this page, and where they come from

Every byte count this page prints, measured on 2026-10-29
InputBytes inTrianglesBounding boxStored 3MFDeflated 3MFRead back
cube-10x10-reference.stl (binary)6841210 × 10 × 10 mm2,7151,31812 triangles, same box
the same cube written as ASCII1,2061210 × 10 × 10 mm2,715—12 triangles, same box
EDULITE_A3_robot-arm.3mf expanded to STL (upper bound)68,135,3841,362,706834.827 × 525.459 × 72.5 mm284,165,43427,354,6711,362,706 triangles, same box

The control STL obeys the identity this site prints everywhere: 84 + 50 × 12 = 684. The upper-bound row starts from the STL that the 3MF to STL page writes out of its largest sample, so the two directions are exercised on the same 1,362,706 triangles. Both samples live in _dev/, outside the deploy tree, and never become downloadable.

npm test

That command parses both STL flavours with the shipped reader, writes the package both ways, then reads the result back with the site’s own 3MF reader and compares triangle count, byte count and bounding box — the same reader that powers the 3MF to STL page.

Questions people actually ask

What does converting an STL to 3MF actually change? The container and nothing else. An STL stores one triangle per fixed 50-byte record; a 3MF stores the same vertices as XML inside a ZIP package. The triangles, their order and their winding come out unchanged, and the 3MF this page writes has no colour, no material assignment and no print settings, because the STL had none to carry over.

Can I get an editable STEP file back from an STL this way? No. A STEP file needs a boundary representation — surfaces, curves and their topology — and an STL holds only triangles. Replacing the container does not recreate that data. The separate question of whether an STL can ever become STEP at all is answered on its own page, and wrapping an STL in 3MF changes nothing about it.

Does this STL to 3MF converter upload my file? No. The page is static, and the worker reads bytes it already has in this tab and writes the package there. No WebAssembly kernel is downloaded either: 0 bytes, because parsing 50-byte triangle records and writing a ZIP needs no CAD kernel.

Why is the 3MF bigger than the STL when stored, and smaller when deflated? Because the model part is text. Every vertex becomes an element with three quoted decimal attributes, and this writer does not merge vertices, so each triangle carries three vertex entries. Our 1,362,706-triangle upper-bound sample is 68,135,384 bytes as binary STL, 284,165,434 bytes as a stored package, and 27,354,671 bytes once the model part is deflated.

Which browser features does the writer depend on? Only standard ones for the stored path: DataView, typed arrays and a hand-rolled CRC32. The deflate path additionally asks for CompressionStream('deflate-raw') and falls back to stored output when that constructor throws, which is why the result panel prints the method that actually ran instead of assuming one. Chrome 156 is the only browser tested here; Safari, Firefox and iOS are unverified.

Is the unit in the output really millimetres? The model element says unit="millimeter", and that is this page's choice rather than a reading of the source: an STL has no unit field at all, so there is nothing to read. If your STL was authored in inches, the numbers are copied exactly and the package labels them millimetres, which is wrong by a factor of 25.4 unless you scale the mesh yourself.

This page does not claim to recover CAD features. A mesh container goes in, a mesh container comes out — the same triangles, re-serialised.