diff --git a/src/web/templates/index.html b/src/web/templates/index.html
index e15c7a2..677b9e9 100644
--- a/src/web/templates/index.html
+++ b/src/web/templates/index.html
@@ -506,6 +506,9 @@ function initCourtScene() {
courtScene.add(new THREE.AmbientLight(0xffffff, 0.8));
+ // Physical camera marker: 1m from net, center, 1m height
+ addCameraMarker(courtScene, 7.7, 3.05, 1);
+
// Load existing calibration cameras
fetch('/api/calibration/data')
.then(function(r) { return r.json(); })
@@ -604,6 +607,9 @@ function initTrajectoryScene() {
trajScene.add(new THREE.AmbientLight(0xffffff, 0.8));
+ // Physical camera marker: 1m from net, center, 1m height
+ addCameraMarker(trajScene, 7.7, 3.05, 1);
+
function animateTraj() {
requestAnimationFrame(animateTraj);
controls.update();
@@ -620,6 +626,33 @@ function initTrajectoryScene() {
});
}
+// ===================== Camera marker =====================
+function addCameraMarker(scene, x, y, z) {
+ // Camera body (box)
+ var body = new THREE.Mesh(
+ new THREE.BoxGeometry(0.2, 0.15, 0.15),
+ new THREE.MeshBasicMaterial({ color: 0x44aaff })
+ );
+ body.position.set(x, y, z);
+ scene.add(body);
+
+ // Lens (cone pointing toward net at x=6.7)
+ var lens = new THREE.Mesh(
+ new THREE.ConeGeometry(0.06, 0.15, 8),
+ new THREE.MeshBasicMaterial({ color: 0x2288dd })
+ );
+ lens.rotation.z = Math.PI / 2; // point along -X toward net
+ lens.position.set(x - 0.17, y, z);
+ scene.add(lens);
+
+ // Pole from ground to camera
+ var poleGeo = new THREE.BufferGeometry().setFromPoints([
+ new THREE.Vector3(x, y, 0),
+ new THREE.Vector3(x, y, z)
+ ]);
+ scene.add(new THREE.Line(poleGeo, new THREE.LineBasicMaterial({ color: 0x666666 })));
+}
+
// ===================== Draw court lines =====================
function drawCourtLines(scene) {
var mat = new THREE.LineBasicMaterial({ color: 0xffffff });