{"record":{"id":"8019d8e5c6880845","repo":"BabylonJS/Babylon.js","slug":"triangle-strip-fan-fill-mode-is-not-implemented","errorCode":null,"errorMessage":"Triangle strip/fan fill mode is not implemented","messagePattern":"Triangle strip/fan fill mode is not implemented","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/serializers/src/glTF/2.0/glTFExporter.ts","lineNumber":1370,"sourceCode":"        indices: Nullable<IndicesArray>,\r\n        is32Bits: boolean,\r\n        start: number,\r\n        count: number,\r\n        offset: number,\r\n        fillMode: number,\r\n        sideOrientation: number,\r\n        state: ExporterState,\r\n        primitive: IMeshPrimitive\r\n    ): void {\r\n        let indicesToExport = null;\r\n\r\n        primitive.mode = GetPrimitiveMode(fillMode);\r\n\r\n        // Flip indices if triangle winding order is not CCW, as glTF is always CCW.\r\n        const flip = sideOrientation !== Material.CounterClockWiseSideOrientation && IsTriangleFillMode(fillMode);\r\n        if (flip) {\r\n            if (fillMode === Material.TriangleStripDrawMode || fillMode === Material.TriangleFanDrawMode) {\r\n                throw new Error(\"Triangle strip/fan fill mode is not implemented\");\r\n            }\r\n\r\n            const newIndices = is32Bits ? new Uint32Array(count) : new Uint16Array(count);\r\n\r\n            if (indices) {\r\n                for (let i = 0; i + 2 < count; i += 3) {\r\n                    newIndices[i] = indices[start + i] + offset;\r\n                    newIndices[i + 1] = indices[start + i + 2] + offset;\r\n                    newIndices[i + 2] = indices[start + i + 1] + offset;\r\n                }\r\n            } else {\r\n                for (let i = 0; i + 2 < count; i += 3) {\r\n                    newIndices[i] = i;\r\n                    newIndices[i + 1] = i + 2;\r\n                    newIndices[i + 2] = i + 1;\r\n                }\r\n            }\r\n\r","sourceCodeStart":1352,"sourceCodeEnd":1388,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/serializers/src/glTF/2.0/glTFExporter.ts#L1352-L1388","documentation":"glTF only supports triangle lists (index order CCW). When a Babylon mesh uses TriangleStrip or TriangleFan fill mode with clockwise (back-facing) side orientation, the exporter would need to flip the triangle winding, but flipping strip/fan index sequences is not implemented, so it throws instead of producing wrong geometry.","triggerScenarios":"Exporting a mesh whose material.fillMode is Material.TriangleStripDrawMode or Material.TriangleFanDrawMode AND whose sideOrientation is not Material.CounterClockWiseSideOrientation (e.g. Mesh.DEFAULTSIDE/sideOrientation set to ClockWiseSideOrientation or DOUBLESIDE handled via flip).","commonSituations":"Ribbon/strips or procedurally generated meshes built with triangle strips exported to glTF; meshes with sideOrientation explicitly set to clockwise for back-face rendering; converting scenes authored for Babylon's strip modes into glTF pipelines.","solutions":["Set the mesh's sideOrientation to Mesh.COUNTERCLOCKWISE_SIDE_ORIENTATION (or use Mesh.DEFAULTSIDE which is CCW) before exporting","Convert the strip/fan geometry into a triangle list (expand indices via _ToTriangleList / CreateGreedyMesh-like conversion) so fillMode is the default TriangleFillMode","Change material.fillMode to Material.TriangleFillMode before export and restore afterwards","Catch the error and skip or pre-convert such meshes"],"exampleFix":"// before\nmesh.material.fillMode = Material.TriangleStripDrawMode;\nmesh.sideOrientation = Mesh.CLOCKWISE_SIDE_ORIENTATION;\nawait GLTF2Export.GLTFAsync(scene, \"scene\"); // throws\n// after\nmesh.material.fillMode = Material.TriangleFillMode;\nmesh.sideOrientation = Mesh.COUNTERCLOCKWISE_SIDE_ORIENTATION;\nawait GLTF2Export.GLTFAsync(scene, \"scene\");","handlingStrategy":"validation","validationCode":"function isExportableFillMode(mesh: Mesh): boolean {\n    const fm = (mesh.material as Material)?.fillMode ?? Material.TriangleFillMode;\n    const ccw = mesh.sideOrientation === Mesh.COUNTERCLOCKWISE_SIDE_ORIENTATION;\n    return ccw || (fm !== Material.TriangleStripDrawMode && fm !== Material.TriangleFanDrawMode);\n}","typeGuard":null,"tryCatchPattern":"try {\n    await GLTF2Export.GLTFAsync(scene, \"scene\");\n} catch (e) {\n    if (e instanceof Error && e.message === \"Triangle strip/fan fill mode is not implemented\") {\n        // convert strip/fan geometry to triangle list or set CCW orientation, then retry\n    } else { throw e; }\n}","preventionTips":["Default meshes to CCW side orientation in projects that export to glTF","Avoid TriangleStrip/TriangleFan fill modes on meshes destined for export, or pre-convert them to triangle lists","Run a pre-export scan of material.fillMode values across the scene","Keep a conversion helper that expands strip indices before exporting"],"tags":["gltf","export","fill-mode","triangle-strip","serialization"],"backgroundTag":"unsupported-fill-mode","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}