diff --git a/public/boardViewer.html b/public/boardViewer.html
index df3864e..491bb09 100644
--- a/public/boardViewer.html
+++ b/public/boardViewer.html
@@ -366,6 +366,11 @@ function buildSkeletonFK(robot, angles) {
const corner0W = posWorld.clone().add(ptrDir.multiplyScalar(markerSizeM * Math.SQRT1_2));
gArmMarkers.add(makeLine(posWorld, corner0W, col, 0.9));
gArmMarkers.add(makeSphere(corner0W, 0.0008, col));
+
+ // Modell-Normale (Pfeil, gleiche Link-Farbe, halbtransparent)
+ const modelNormalEnd = posWorld.clone().add(normalW.clone().multiplyScalar(markerSizeM * 1.5));
+ gArmMarkers.add(makeLine(posWorld, modelNormalEnd, col, 0.5));
+ gArmMarkers.add(makeSphere(modelNormalEnd, 0.0005, col));
}
}
}
@@ -391,8 +396,28 @@ function buildSkeletonFK(robot, angles) {
const [lx, ly, lz] = modelM.position;
const modelPosW = new THREE.Vector3(lx * S, lz * S, -ly * S).applyMatrix4(frames[obsLink]);
const obsPosW = r2vArr(obs.position_mm);
+ const obsCol = LINK_COLORS[obsLink] ?? 0x3b82f6;
gArmMarkers.add(makeLine(modelPosW, obsPosW, 0xff8800, 0.85));
- gArmMarkers.add(makeSphere(obsPosW, 0.007, LINK_COLORS[obsLink] ?? 0x3b82f6));
+ gArmMarkers.add(makeSphere(obsPosW, 0.007, obsCol));
+
+ // Beobachtungs-Ecke 0: Orientierungszeiger für Spin-Vergleich
+ // corners_m sind Weltkoordinaten in Metern → direkt in Three.js (Y↑=Z, Z↑=-Y)
+ const c0 = obs.corners_m?.[0];
+ if (c0) {
+ const obsCorner0W = new THREE.Vector3(c0[0], c0[2], -c0[1]);
+ gArmMarkers.add(makeLine(obsPosW, obsCorner0W, obsCol, 0.85));
+ gArmMarkers.add(makeSphere(obsCorner0W, 0.006, obsCol));
+ }
+
+ // Beobachtungs-Normale (weißer Pfeil)
+ if (obs.normal) {
+ const [on0, on1, on2] = obs.normal;
+ const obsNormalW = new THREE.Vector3(on0, on2, -on1).normalize();
+ const arrowLen = (modelM.size ?? 25) * S * 1.5;
+ const obsNormalEnd = obsPosW.clone().add(obsNormalW.multiplyScalar(arrowLen));
+ gArmMarkers.add(makeLine(obsPosW, obsNormalEnd, 0xffffff, 0.55));
+ gArmMarkers.add(makeSphere(obsNormalEnd, 0.005, 0xffffff));
+ }
}
}
}