diff --git a/frontend/src/capture/PhotoStage.svelte b/frontend/src/capture/PhotoStage.svelte index f0ef731..a542d4f 100644 --- a/frontend/src/capture/PhotoStage.svelte +++ b/frontend/src/capture/PhotoStage.svelte @@ -147,6 +147,10 @@ let pinchStartAngle = 0; let pinchStartTilt = 0; + const PAN_DAMP = 0.4; // Keep pointer pan movement deliberate without changing keyboard nudges. + const ROTATE_DAMP = 0.4; // Soften two-finger and rotation-handle tilt changes. + const PINCH_ZOOM_DAMP = 0.4; // Blend pinch distance changes toward 1 to avoid zoom jumps. + const stagePoint = (clientX: number, clientY: number): { x: number; y: number } => { const el = tapeWrap; if (!el) return { x: 0, y: 0 }; @@ -209,17 +213,23 @@ const dx = pts[1].x - pts[0].x; const dy = pts[1].y - pts[0].y; const dist = Math.hypot(dx, dy) || 1; - const z = Math.min(3, Math.max(0.5, pinchStartZoom * (dist / pinchStartDist))); + const ratio = dist / pinchStartDist; + const softenedRatio = 1 + (ratio - 1) * PINCH_ZOOM_DAMP; + const z = Math.min(3, Math.max(0.5, pinchStartZoom * softenedRatio)); // Screen y-down atan2 delta matches CSS rotate (positive = clockwise). const angle = Math.atan2(dy, dx); const deltaDeg = ((angle - pinchStartAngle) * 180) / Math.PI; - emit({ ...live, zoom: z, tiltDeg: clampTiltDeg(pinchStartTilt + deltaDeg) }); + emit({ ...live, zoom: z, tiltDeg: clampTiltDeg(pinchStartTilt + deltaDeg * ROTATE_DAMP) }); return; } if (!drag) return; const p = stagePoint(e.clientX, e.clientY); if (drag.kind === 'pan') { - emit({ ...live, panX: drag.panX0 + (p.x - drag.x0), panY: drag.panY0 + (p.y - drag.y0) }); + emit({ + ...live, + panX: drag.panX0 + (p.x - drag.x0) * PAN_DAMP, + panY: drag.panY0 + (p.y - drag.y0) * PAN_DAMP, + }); } else if (drag.kind === 'tickA' || drag.kind === 'tickB') { const pair = drag.kind === 'tickA' ? clampTickPair(p.y, live.tickB) @@ -231,7 +241,7 @@ const a0 = Math.atan2(drag.y0 - cy, drag.x0 - cx); const a1 = Math.atan2(p.y - cy, p.x - cx); const delta = ((a1 - a0) * 180) / Math.PI; - emit({ ...live, tiltDeg: clampTiltDeg(drag.tilt0 + delta) }); + emit({ ...live, tiltDeg: clampTiltDeg(drag.tilt0 + delta * ROTATE_DAMP) }); } };