diff --git a/packages/web/src/fpv/FirstPerson.svelte b/packages/web/src/fpv/FirstPerson.svelte index 9b70ca3..3e43fab 100644 --- a/packages/web/src/fpv/FirstPerson.svelte +++ b/packages/web/src/fpv/FirstPerson.svelte @@ -455,7 +455,13 @@ const screenX = W / 2 + (side / depth) * (W / 2) / Math.tan(FOV / 2); const wallH = H / depth; const size = wallH * b.scale; - const wide = size * (b.aspect ?? 1); + // Vertical pixels scale by H/depth, horizontal by focal/depth — and + // they differ. A sprite that declares an aspect means WORLD width + // (a hedge one cell wide must touch both posts), so its width uses + // the horizontal scale; plain square sprites keep their pixel shape. + const wide = b.aspect + ? size * b.aspect * (((W / 2) / Math.tan(FOV / 2)) / H) + : size; const bottom = half + wallH / 2 - b.rise * wallH; return { src: b.src, depth: depth - (b.bias ?? 0), warped: b.warped, diff --git a/packages/web/src/fpv/raycast.ts b/packages/web/src/fpv/raycast.ts index 102ea79..6823c4a 100644 --- a/packages/web/src/fpv/raycast.ts +++ b/packages/web/src/fpv/raycast.ts @@ -339,7 +339,7 @@ export function billboards( if (content.kind === "thornbush" || content.kind === "rosebush") { out.push({ ...at, src: `/terrain3d/${content.kind}.png`, fallback: content.kind, - scale: 0.5, aspect: 2.35, rise: 0, bias: 0.18, label: content.kind, + scale: 0.5, aspect: 2.1, rise: 0, bias: 0.18, label: content.kind, }); } else if (content.kind === "ooze") { out.push({