{"record":{"id":"724edf23b3563629","repo":"moeru-ai/airi","slug":"airi-failed-to-patch-built-in-mtoon-outline-shad-724edf","errorCode":null,"errorMessage":"[AIRI] Failed to patch built-in MToon outline shader: outlineNormal is missing on geometry.","messagePattern":"\\[AIRI\\] Failed to patch built-in MToon outline shader: outlineNormal is missing on geometry\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui-three/src/composables/vrm/outline.ts","lineNumber":510,"sourceCode":"  return {\n    onDispose({ vrm }) {\n      disposeVrmOutlineRuntime(vrm)\n    },\n    onLoad({ vrm }) {\n      prepareVrmOutlineRuntime(vrm)\n    },\n    onMaterial(context) {\n      const { material } = context\n\n      if (!isMToonMaterial(material) || material.isOutline === true)\n        return\n\n      const meshTarget = findVrmOutlineMeshTarget(context)\n      if (!meshTarget)\n        return\n\n      if (!meshTarget.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)) {\n        console.warn(\n          '[AIRI] Failed to patch built-in MToon outline shader: outlineNormal is missing on geometry.',\n          meshTarget.mesh.name,\n        )\n        return\n      }\n\n      patchBuiltInOutlineMaterial(meshTarget.builtInOutlineMaterial)\n    },\n  }\n}\n","sourceCodeStart":492,"sourceCodeEnd":521,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui-three/src/composables/vrm/outline.ts#L492-L521","documentation":"The outline material patch requires a custom outlineNormal geometry attribute (AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME) that an earlier pipeline stage is supposed to have computed. In the onMaterial hook, if the target mesh's geometry lacks that attribute, the patch is skipped with this warn naming the mesh — the built-in outline keeps its normal-based (potentially lower quality) behavior for that mesh only.","triggerScenarios":"A mesh that bypassed the geometry-preparation pass (added/swap after registration), a geometry whose attribute computation failed silently, or non-standard geometry without the attributes the computation needs.","commonSituations":"Models with mixed rigging where some meshes skip the prepare hook; runtime mesh swapping; geometries missing normals so outlineNormal derivation was skipped.","solutions":["Verify the mesh went through the geometry pass that adds the attribute (register it the same way as working meshes).","Ensure the geometry has valid normals before the pass runs (geometry.computeVertexNormals() if needed).","Treat single-mesh warns as cosmetic; if all meshes warn, the pipeline ordering is broken — fix registration order."],"exampleFix":"// before\nmesh.geometry.setAttribute('outlineNormal', attr) // skipped for late-added meshes\n\n// after\n// recompute when geometry is (re)assigned\nfunction ensureOutlineNormal(mesh: SkinnedMesh) {\n  if (!mesh.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME))\n    computeOutlineNormalAttribute(mesh.geometry)\n}","handlingStrategy":"validation","validationCode":"if (!mesh.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)) {\n  computeOutlineNormalAttribute(mesh.geometry) // re-run the geometry stage\n}","typeGuard":"function hasOutlineNormal(geometry: BufferGeometry): boolean {\n  return !!geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)\n}","tryCatchPattern":null,"preventionTips":["Compute the attribute in one geometry-preparation pass and assert coverage for every registered mesh.","Re-derive attributes whenever geometry is swapped at runtime.","Log mesh names (as the warn does) to pinpoint which meshes bypass the pipeline."],"tags":["vrm","mtoon","outline","geometry","attribute"],"backgroundTag":"missing-geometry-attribute","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}