Seven conversion fixtures, and two packages that require an extension.

Every fixture below was uploaded through the page's file input on 13 November 2026. The exported STL was saved and parsed outside the browser.

How the run was made

The site was built with astro build and served from dist. Headless Chrome loaded the built page, selected each 3MF through #file-input, and waited for the result panel. The download was intercepted at URL.createObjectURL, so the saved file is the exact blob the download button hands over. A separate Python script then read each STL: triangle count, bounding box, connected shells, boundary edges, non-manifold edges and signed volume. Its values are compared with the result panel in the table below; no mismatch was found.

The seven fixtures are: two cubes that differ only in the declared unit, two two-cube plates that differ only in their material assignment, a five-cube plate, a cube with its top face removed, and a cube placed by a mirrored transform. Each row below is one upload and one export.

Fixture, export size and the readings from the exported STL
Fixture Bytes 3MF → STL Triangles Bounds (mm) Shells Boundary edges
cube-20mm.3mf 1,043 → 684 12 20 × 20 × 20 1 0
cube-20in.3mf 1,039 → 684 12 508 × 508 × 508 1 0
two-parts.3mf 1,084 → 1,284 24 40 × 20 × 20 2 0
two-colours.3mf 1,153 → 1,284 24 40 × 20 × 20 2 0
plate-five.3mf 1,311 → 3,084 60 108 × 20 × 20 5 0
open-box.3mf 1,029 → 584 10 20 × 20 × 20 1 4
mirrored-cube.3mf 1,061 → 684 12 20 × 20 × 20 1 0

What the readings show

The two cube fixtures hold the same 12 triangles. The inch declaration multiplies every coordinate by 25.4, so the same shape reports 508 mm instead of 20 mm (508 ÷ 20 = 25.4). Materials and names do not change the triangle count: plate-five has five objects and 60 triangles, and the converter writes one STL with five disconnected shells. Open-box arrives with 10 triangles and leaves with 10, and the four boundary edges of the missing top face are still there in the export. Mirrored-cube is placed by a build transform with a negative determinant; its signed volume is +8,000, the same as the unmirrored cube, so the winding was reversed as the transform was applied.

Signed volume is positive for every closed fixture. Open-box is not closed, and its signed volume of 5,333.333 is the volume of a cube with an open top measured from the origin, not a solid volume; it is listed for completeness only.

Converter result panel after loading plate-five.3mf: 60 triangles, 180 vertices, bounds 108 × 20 × 20 millimetres.
plate-five.3mf: five objects, one STL, 60 triangles and a 108 × 20 × 20 mm box.

The panel's Vertices field counts the mesh entries the loader produced. plate-five reports 180 because the material assignment gives every triangle its own entries; the STL has no vertex table at all, so the independent parse counts unique corner positions instead, which is 40. Triangle counts and bounds agree between the panel and the parse for all seven files.

Converter result panel after loading open-box.3mf: 10 triangles, 8 vertices, bounds 20 × 20 × 20 millimetres.
open-box.3mf: 10 triangles in, 10 out. The converter did not close the missing face.
Converter result panel after loading mirrored-cube.3mf: 12 triangles, 8 vertices, bounds 20 × 20 × 20 millimetres.
mirrored-cube.3mf: the transform flips X, the exported signed volume stays positive.

File-level checks

These commands were run on the fixtures or the exported STLs in the round-4 working directory. Each note states what the command printed; the full stdout is in the run's report.json.

unzip -l samples/two-parts.3mf

3 files: [Content_Types].xml, _rels/.rels, 3D/3dmodel.model. No Metadata/ and no 3D/Objects/ entries.

unzip -t samples/cube-20mm.3mf

All three entries OK; no errors detected in compressed data.

unzip -p samples/cube-20mm.3mf 3D/3dmodel.model | head -c 220

Root element reads unit="millimeter".

unzip -l samples/plate-five.3mf

Three entries; the 3D/3dmodel.model part is 4,280 bytes unzipped.

unzip -p samples/plate-five.3mf 3D/3dmodel.model | grep -o '<triangle v1=' | wc -l

60 triangle elements, matching the 60 in the exported STL.

unzip -p samples/plate-five.3mf 3D/3dmodel.model | grep -o '<object ' | wc -l

5 object elements.

unzip -p samples/two-colours.3mf 3D/3dmodel.model | grep -o '<base name' | wc -l

2 base materials; the STL has no material block.

unzip -p samples/open-box.3mf 3D/3dmodel.model | grep -o '<triangle v1=' | wc -l

10 triangle elements: the hole exists in the source.

unzip -p samples/mirrored-cube.3mf 3D/3dmodel.model | grep -o '<item [^/]*/>'

Build item transform is −1 0 0 0 1 0 0 0 1 20 0 0.

xxd -l 84 results/out/cube-20mm.stl

80-byte header reads "Binary STL written in the browser"; the 4-byte count is 0c 00 00 00, which is 12.

Two packages that require an extension

The extension post uses two packages written with Python's zipfile, not by a slicer. Both declare requiredextensions="p" on the model element. PrusaSlicer 2.9.7 opened both on 13 November 2026; this converter returned a result for one and a visible error for the other.

Two required-extension packages, two readers
PackageEntriesPrusaSlicer 2.9.7This converter, Chrome
cube-required-p.3mf 3 12 facets, 20 × 20 × 20 mm 12 triangles, 20 × 20 × 20 mm, 684-byte STL, no warning
cube-production-split.3mf 4 12 facets, 1 part, 20 × 20 × 20 mm error: Could not convert this file: Maximum call stack size exceeded; no result panel

The first file carries a core triangle mesh in its root model, so it converts despite the declaration; the converter does not read requiredextensions at all. The second moves the mesh into 3D/Objects/object_1.model and points at it with a component p:path. The converter follows the reference and then fails with a stack overflow instead of reporting an unsupported extension. PrusaSlicer reads the same file as one 20 mm part, so the package is not corrupt; the failure is in this converter's component handling.

Converter result panel after loading cube-required-p.3mf: 12 triangles, 8 vertices, bounds 20 × 20 × 20 millimetres, 684-byte STL.
cube-required-p.3mf converts with no warning even though the model requires an extension.
Converter panel after loading cube-production-split.3mf: the result panel is hidden and the status reads Could not convert this file: Maximum call stack size exceeded.
The production-split package fails with a stack overflow; PrusaSlicer opens the same file.

What was not done

No file was printed. No exported STL was imported into a slicer, Bambu Studio, PrusaSlicer, Cura or any other program. The two extension packages above were opened in PrusaSlicer 2.9.7 as an input-side check, not converted by it. No part was measured with calipers, and no third-party converter was run for comparison. The numbers here are the converter's own result panel and a parse of the file it exported.

Limits of the method: one browser, one build, seven conversion fixtures plus two extension packages. The fixtures are synthetic cubes built for the test, not models from a real job. A different build can produce different millisecond timings, and a different fixture will have different bytes, so the byte counts describe these files rather than the converter in general.

Run date: 13 November 2026. The fixtures are downloadable from the first column of the table and from the converter's own sample links on the posts. The four pilot fixtures — cube-20mm, cube-20in, two-parts and two-colours — are the same files used in the earlier round of tests.