From 10b27e37fa0a57fa8c5d9d38558f8e4c4f84277b Mon Sep 17 00:00:00 2001 From: type-two Date: Sun, 19 Jul 2026 13:31:30 +1000 Subject: [PATCH] Drawer drag: soften the grab spring + clamp held-piece velocity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grabbing a buried piece built up spring tension against the pieces on top, then broke free at ~9g (force cap 90*m, no speed limit) and batted the whole pile out of the drawer. Softened the spring (K 165->55, damping 13->22, force cap 90->22) so it EASES toward the cursor, and added the real fix: a hard velocity clamp (3.2 u/s) on the held piece so it can never become a projectile — every downstream momentum transfer is bounded by that one line. Verified (harness drives the identical dragGrabbed path): a violent yank now peaks the pile at 2.89 u/s with ZERO pieces flung out (was: everything flew off screen); a controlled lift still raises a piece to y=2.09 over the 1.47 rim and commits it out. Fishing still works, catapult gone. Co-Authored-By: Claude Fable 5 --- src/scenes/drawer.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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 {