From d560aa44c32b97af24c11b7e9b0cfb685db827fd Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sun, 23 Aug 2026 17:00:30 -0400 Subject: [PATCH] The opening shot stops facing its own teleport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two more camera flaws, read straight out of A9WK's clip against its ledger. The reel's first run measured the leap from the camera's uninitialized origin as a stride and FACED ALONG IT — an arbitrary heading that landed nose-first in a wall, and counted as aimed, so the corridor fallback never ran. A stride only turns the eyes once the camera is real. And idle beats are rescued generally: whenever nothing aims the eyes and they would sit staring at a wall closer than a stride, they turn down the deepest corridor instead — so pacing into a dead-end cell no longer parks the whole screen inside brick. Co-Authored-By: Claude Fable 5 --- packages/web/src/Replay.svelte | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/web/src/Replay.svelte b/packages/web/src/Replay.svelte index 401827b..02e2eb3 100644 --- a/packages/web/src/Replay.svelte +++ b/packages/web/src/Replay.svelte @@ -220,7 +220,10 @@ })(); let targetFacing = camF; let aimed = false; - if (dist > 0.05 && !hurled) { targetFacing = Math.atan2(dy, dx); aimed = true; } + // A stride turns the eyes along it — but only a REAL stride: on the + // reel's first run the camera sits at its uninitialized origin, and + // that phantom distance must not pick the opening shot's direction. + if (camReady && dist > 0.05 && !hurled) { targetFacing = Math.atan2(dy, dx); aimed = true; } else if (aim) { targetFacing = Math.atan2(aim.y + 0.5 - ty, aim.x + 0.5 - tx); aimed = true; @@ -236,9 +239,10 @@ aimed = true; } } - if (!camReady && !aimed) { - // The reel opens on a wizard standing still: face the longest - // corridor rather than whatever wall the default heading found. + if (!aimed && castRay(v, tx, ty, targetFacing).dist < 0.8) { + // Nothing aims the eyes and they'd idle nose-to-brick (the opening + // cut, or a beat after pacing into a dead end): face the deepest + // corridor from where the wizard stands instead. let deepest = -1; for (const a of [0, Math.PI / 2, Math.PI, -Math.PI / 2]) { const h = castRay(v, tx, ty, a);