A cut is not a stride

The wraith reel still ended in a wall, and the ledger showed why: its
final step CUTS home from the cutaway at the summon site — a nine-cell
leap — and the camera read that leap as a walk, faced along it into
the masonry, and counted itself aimed, which silenced the closing-shot
rescue. Leaps no longer set facing: any step that will cut computes
willCut first, strides only turn the eyes within a stride's reach, and
a cut that lands with nothing aimed always re-picks its view from the
new position. The wraith turn now closes down a corridor with the
wraith itself in frame.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-23 19:19:33 -04:00
co-authored by Claude Fable 5
parent 59c25f42f0
commit a94ab5c6f5
+10 -6
View File
@@ -253,12 +253,13 @@
} }
return null; return null;
})(); })();
// A leap the legs cannot explain (first frame, teleport, the return
// from a cutaway) is a CUT, and a cut is not a stride: the direction
// of travel means nothing at the far end.
const willCut = !camReady || (dist > 1.6 && !hurled);
let targetFacing = camF; let targetFacing = camF;
let aimed = false; let aimed = false;
// A stride turns the eyes along it — but only a REAL stride: on the if (camReady && !willCut && dist > 0.05 && !hurled) { targetFacing = Math.atan2(dy, dx); aimed = true; }
// 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) { else if (aim) {
const ax = aim.x + 0.5, ay = aim.y + 0.5; const ax = aim.x + 0.5, ay = aim.y + 0.5;
const toAim = Math.hypot(ax - tx, ay - ty); const toAim = Math.hypot(ax - tx, ay - ty);
@@ -316,7 +317,10 @@
for (const t of v.treasures) if (t.position && !t.carriedBy) score += bonus(t.position, 3); for (const t of v.treasures) if (t.position && !t.carriedBy) score += bonus(t.position, 3);
return score; return score;
}; };
const staring = castRay(v, tx, ty, targetFacing).dist < (atEnd ? 1.2 : 0.8); // A cut lands with whatever stale facing it carried, so a cut with
// nothing aimed always re-picks its view from the new position.
const staring = willCut ||
castRay(v, tx, ty, targetFacing).dist < (atEnd ? 1.2 : 0.8);
if (staring) { if (staring) {
const current = viewScore(targetFacing); const current = viewScore(targetFacing);
let bestA = targetFacing, bestScore = current; let bestA = targetFacing, bestScore = current;
@@ -329,7 +333,7 @@
targetFacing = bestA; targetFacing = bestA;
} }
} }
if (!camReady || (dist > 1.6 && !hurled)) { if (willCut) {
// First frame, or a leap the legs cannot explain: cut. // First frame, or a leap the legs cannot explain: cut.
cam.x = tx; cam.y = ty; cam.facing = targetFacing; cam.x = tx; cam.y = ty; cam.facing = targetFacing;
camReady = true; camReady = true;