diff --git a/src/scenes/drawer.ts b/src/scenes/drawer.ts index 0a96a3c..4d42ba3 100644 --- a/src/scenes/drawer.ts +++ b/src/scenes/drawer.ts @@ -355,15 +355,16 @@ export class DrawerView implements View { const pz = t.z + this.tmp.z; // A spring, not a joint: a snagged piece has to fight the ones on top of it - // and lose, rather than tunnel through them. + // and lose, rather than tunnel through them. Soft K + heavy damping so it + // EASES toward the cursor; a snagged piece builds no catapult tension. const v = p.body.linvel(); const m = p.body.mass(); - const K = 165 * m; - const C = 13 * m; + const K = 55 * m; + const C = 22 * m; const fx = (this.target.x - px) * K - v.x * C; const fy = (this.target.y - py) * K - v.y * C; const fz = (this.target.z - pz) * K - v.z * C; - const cap = 90 * m; + const cap = 22 * m; const mag = Math.hypot(fx, fy, fz); const s = mag > cap ? cap / mag : 1; p.body.wakeUp(); @@ -372,6 +373,15 @@ export class DrawerView implements View { { x: px, y: py, z: pz }, true, ); + // The real anti-catapult: the held piece can NEVER move fast enough to bat + // the pile across the room. Clamp its speed hard — everything downstream + // (momentum into neighbours) is bounded by this one line. + const MAXV = 3.2; + const sp = Math.hypot(v.x, v.y, v.z); + if (sp > MAXV) { + const k = MAXV / sp; + p.body.setLinvel({ x: v.x * k, y: v.y * k, z: v.z * k }, true); + } } dispose(): void {