diff --git a/packages/web/src/fpv/fx3d.ts b/packages/web/src/fpv/fx3d.ts index c536226..4786b77 100644 --- a/packages/web/src/fpv/fx3d.ts +++ b/packages/web/src/fpv/fx3d.ts @@ -114,9 +114,21 @@ export function fpFxForEvents( if ((e.type === "moved" || e.type === "creatureMoved") && "direction" in e) { const via = e.type === "moved" ? e.via : "step"; const key = edgeKey(e.from, e.direction); - if (via === "step" && view.board.edges[key] === "door") { + const edgeState = view.board.edges[key] ?? "open"; + if (via === "step" && edgeState === "door") { out.push({ fx: { id: nextId++, kind: "door", edge: key, t0: 0, dur: 1100 }, delay: 0 }); } + if (via === "step" && edgeState === "wall") { + // A body just stepped through what THIS viewer holds solid — an + // illusion the mover disbelieves. The viewer keeps their false + // belief, but the crossing must read as magic, not a glitch: + // shimmer both faces, and wash the screen if these are the eyes. + out.push({ fx: { id: nextId++, kind: "impact", art: "shimmer", at: { x: e.from.x + 0.5, y: e.from.y + 0.5 }, t0: 0, dur: 500 }, delay: 0 }); + out.push({ fx: { id: nextId++, kind: "impact", art: "shimmer", at: { x: e.to.x + 0.5, y: e.to.y + 0.5 }, t0: 0, dur: 500 }, delay: 200 }); + if (e.type === "moved" && e.player === povId) { + out.push({ fx: { id: nextId++, kind: "flash", color: "#9a8fb0", peak: 0.35, t0: 0, dur: 450 }, delay: 0 }); + } + } if (e.type === "moved" && e.via === "passWall") { out.push({ fx: { id: nextId++, kind: "impact", art: "shimmer", at: { x: e.from.x + 0.5, y: e.from.y + 0.5 }, t0: 0, dur: 500 }, delay: 0 }); out.push({ fx: { id: nextId++, kind: "impact", art: "shimmer", at: { x: e.to.x + 0.5, y: e.to.y + 0.5 }, t0: 0, dur: 500 }, delay: 200 });