Fall the light off across the run-off, so it reads as ground and not margin
Riding the court up left a wide band below the near baseline, and `pal.out` is one flat colour — so the perspective visibly stopped partway down the screen and the rest read as dead margin rather than as the back of a court. A gradient from the baseline to the bottom edge fixes it: the band gets depth, the rack gets a frame, and what darkens is exactly the area the thumb covers anyway. Starts at alpha 0 on the baseline, so there is no seam. A procedural "trodden ground" variant (scuffs and drag marks) was built and cut: random ellipses read as unexplained puddles, not as wear. That idea wants authored detail and gore that accumulates over a run, not noise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0fe8f37a81
commit
75936d3324
1 file changed
+19
@@ -161,6 +161,24 @@ export function proj(x, y, z) {
|
||||
return { x: W / 2 + x * s, y: TUNE.horizon + (TUNE.camY + aimCam * TUNE.aimCamY - y) * s, s };
|
||||
}
|
||||
|
||||
// The run-off apron below the near baseline. Raising the court to make room for the pull (see
|
||||
// fitViewport) left a wide band down there, and `pal.out` is a single flat colour — so the
|
||||
// perspective visibly stopped partway down the screen and the rest read as dead margin. This falls
|
||||
// the light off toward you, which gives the band depth, frames the rack, and darkens exactly the
|
||||
// area the thumb covers anyway. Starts at alpha 0 on the baseline, so there is no seam to see.
|
||||
// NOT a near backstop: at camZ 48 with the baseline at z 23.77 a real one would sit between the
|
||||
// camera and the player and draw enormous. You are looking OVER it, which is why a broadcast frame
|
||||
// never shows one either. Wear and props at the margins are the next layer, not this.
|
||||
function drawRunOff() {
|
||||
const top = proj(0, 0, COURT.L).y;
|
||||
if (top >= H) return; // landscape has no apron at all — the baseline projects off the bottom
|
||||
const g = ctx.createLinearGradient(0, top, 0, H);
|
||||
g.addColorStop(0, 'rgba(6,10,6,0)');
|
||||
g.addColorStop(1, 'rgba(6,10,6,0.72)');
|
||||
ctx.fillStyle = g;
|
||||
ctx.fillRect(0, top, W, H - top);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- sprites ----
|
||||
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
|
||||
const SPRV = 78; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
@@ -831,6 +849,7 @@ export function render() {
|
||||
line(-COURT.W / 2, COURT.svcNear, COURT.W / 2, COURT.svcNear, 1);
|
||||
line(0, COURT.svcFar, 0, COURT.svcNear, 1);
|
||||
line(0, 0, 0, 0.35, 1); line(0, COURT.L - 0.35, 0, COURT.L, 1); // center marks
|
||||
drawRunOff(); // light falls off across the apron below the baseline
|
||||
|
||||
// gore decals: what remains of the visiting team (flat ground layer, then far-side mounds)
|
||||
for (const d of gore) {
|
||||
|
||||
Reference in new issue
Block a user