diff --git a/html/js/render/isoRenderer.js b/html/js/render/isoRenderer.js
index a87371b..763fd0b 100644
--- a/html/js/render/isoRenderer.js
+++ b/html/js/render/isoRenderer.js
@@ -313,7 +313,7 @@
p = this._project(e.x, e.y, originX, originY);
items.push({ type: 'entity', e: e, sx: p.x, sy: p.y, depth: e.x + e.y + 0.55 });
// Sticky camera target (keep last if the player is momentarily absent).
- if (e.you || e.kind === 'player') this.focusPoint = { x: p.x, y: p.y + this.tileH };
+ if (e.you || e.kind === 'player') { this.focusPoint = { x: p.x, y: p.y + this.tileH }; this._plx = e.x; this._ply = e.y; }
}
items.sort(function (a, b) { return a.depth === b.depth ? (a.y || 0) - (b.y || 0) : a.depth - b.depth; });
@@ -325,8 +325,17 @@
if (WALLISH[tileKind]) tileKind = this._wallVariant(scene, it.x, it.y, tileKind);
else tileKind = this._floorVariant(tileKind, it.x, it.y);
var rec = this._load(this._tileUrl(tileKind));
+ // Cutaway: fade the walls sitting between the camera and the player (higher x+y, toward
+ // the SE camera, within a few cells) so they don't hide the player or the openings right
+ // in front of them. Iso occlusion otherwise makes near hallways impossible to read.
+ var cut = WALLISH[it.kind] && this._plx != null &&
+ it.x >= this._plx && it.y >= this._ply &&
+ (it.x + it.y) > (this._plx + this._ply) &&
+ ((it.x - this._plx) + (it.y - this._ply)) <= 3;
+ if (cut) ctx.globalAlpha = 0.28;
if (rec && rec.ready) this._drawImage(rec.img, it.sx, it.sy + this.tileH, this.imageW, this.imageH);
else if (it.kind !== 'dark') this._diamond(it.sx, it.sy + this.tileH * 0.5, (legend[it.kind] && legend[it.kind].color) || '#3a4048');
+ ctx.globalAlpha = 1;
} else if (it.type === 'prop') {
this._contactShadow(it.sx, it.sy + this.tileH * 1.4, 22, 9);
rec = this._load(this._tileUrl(it.kind));
diff --git a/html/js/render/spGameRenderer.js b/html/js/render/spGameRenderer.js
index 76d94d6..2fbce27 100644
--- a/html/js/render/spGameRenderer.js
+++ b/html/js/render/spGameRenderer.js
@@ -112,13 +112,23 @@
host._rkZoomBound = true;
host.addEventListener('wheel', function (ev) {
ev.preventDefault();
- SP._zoom = Math.max(0.6, Math.min(4, (SP._zoom || 1.7) * Math.exp(-ev.deltaY * 0.0015)));
+ // Base the step on the CURRENT effective zoom (mode-aware default if not yet set),
+ // NOT a hardcoded 1.7 — otherwise the first scroll on iso (default 1.0) jumped up to
+ // 1.7 and BOTH directions read as "zoom in".
+ var base = (SP._zoom != null) ? SP._zoom : SP._defaultZoom();
+ SP._zoom = Math.max(0.4, Math.min(4, base * Math.exp(-ev.deltaY * 0.0015)));
SP._applyCamera();
}, { passive: false });
}
return SP._renderer;
};
+ // Mode-aware default zoom: iso tiles are large (84px) so they want less magnification than the
+ // small tiled/ascii cells (~24px).
+ SP._defaultZoom = function () {
+ return (SP._renderer && SP._renderer.name === 'iso') ? 1.0 : 1.7;
+ };
+
// Centre the (whole-scene) canvas on the player via a CSS transform, clipped to the host —
// renderer-agnostic (works for tiled / iso / 3d, each of which reports its own focusPoint).
SP._applyCamera = function () {
@@ -133,9 +143,7 @@
r.canvas.style.top = '0';
return;
}
- // Default zoom is mode-aware: iso tiles are large (84px), so a lower default frames a sensible
- // number of them; tiled/ascii cells are small (~24px) so they want more magnification.
- var scale = SP._zoom || (r.name === 'iso' ? 1.0 : 1.7);
+ var scale = (SP._zoom != null) ? SP._zoom : SP._defaultZoom();
var fp = r.focusPoint;
// ROBUSTNESS: if the renderer hasn't reported a focus this frame — a race at game start, or a
// camera tick reading a just-(re)created renderer instance before its first render — derive the