Skip to content

P1b: tan-first course identity — Chambers reads as a links (+ eng-review re-architecture) - #39

Merged
rroojrooj merged 6 commits into
mainfrom
claude/p1b-tan-palette
Jul 7, 2026
Merged

rroojrooj merged 6 commits into
mainfrom
claude/p1b-tan-palette

Conversation

@rroojrooj

Copy link
Copy Markdown
Owner

Phase P1b of the Reality Master Plan. Full pipeline: sub-plan → /plan-eng-review (+ outside voice) → build → live-verify.

The problem

The sim rendered every course as lush green striped parkland. Real Chambers Bay is a firm tan-gold links (fescue rough dominates, minimal stripes) — the #1 gap both assessors flagged.

What the review saved us from

The naive plan was "paint the base splat tan." The outside voice (10 findings, all verified against code) proved that doesn't work: the splat is 1 of 4 color sources, and the other three override it —

  • foreground grass blades hard-ref the green COLORS (scene.js:890),
  • an unconditional shader warm-mix (turf.js:226) double-counts a tan base,
  • the far-photo crossfade (turf.js:135) washes the tan back to the green aerial at overview.

It also caught that a courseDry JSON field is silently dropped in transit (server.js / lib/course.js return fixed allow-lists) — tests green, feature dead.

What shipped

One manual courseDry scalar (0 lush parkland → 1 dry links) drives all four sources coherently:

  • course-character.js — COLORS (moved here), a dry DRY_PALETTE, a client-side COURSE_DRY map (not JSON), and blendPalette (grass zones only; greens excluded; courseDry=0 byte-identical).
  • scene.js — paints the splat AND retints the _fairwayZoneColor blades from this._pal.
  • turf.js — uCourseDry uniform (v32, on base + HD-patch materials): pulls the warm-mix endpoint toward neutral, floors the stripes for links, and lowers the far-photo weight so dry courses show lit tan turf at overview.
  • Tests: test/course-character.test.mjs + updated hd-turf. 301/301 green.

Live-verified

  • Chambers (courseDry=0.85): the play view is a convincing tan-gold fescue links with the putting green staying green and no blade seam; the overview reads clearly warmer/tan.
  • Sawgrass (courseDry=0): proven byte-unchanged — blendPalette returns COLORS identically (palRough=#4a8038) and every shader edit is a no-op at uCourseDry=0.

Tuning knob for a tanner overview later: COURSE_DRY['Chambers Bay'] + DRY_PALETTE. The auto-detector (fairway-warmth) is a deferred stretch (T5). Plan carries the full GSTACK review report.

🤖 Generated with Claude Code

rroojrooj and others added 6 commits July 7, 2026 15:54
Course-aware dryness (uCourseDry) auto-detected from fairway-grass warmth
drives a shader dry-bias (rebuild chroma toward gold-tan on rough/base,
gated off greens + mown fairway) + course-aware stripe strength. Chambers
-> firm tan links, Sawgrass -> lush parkland. Grounded: COLORS all lush
(scene.js), shader has noise-driven lush<->tan mix (turf.js:226) + fixed
stripes (:247); detector goes in _buildMacroTint (:490) where m.avg is set
(sidesteps splat-before-aerial ordering). Task 0 GATE: validate a
fairway-warmth metric separates links vs parkland (memory: greenness is
BACKWARDS) or fall back to a manual courseDry field. Ready for eng review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… colour sources

Outside voice (10 findings, all verified) proved "paint the splat tan" does
NOT achieve tan-links: the splat is 1 of 4 colour sources. Blades hard-ref
COLORS (scene.js:890), the shader warm-mix (turf.js:226) double-counts, and
the far-photo (turf.js:135) washes the tan back to the green aerial at
overview. Re-architected: one manual courseDry scalar (client-side map, NOT
JSON -- dropped in transit at server.js:276/course.js:392) drives splat +
blades + warm-mix endpoint + far-photo weight, greens excluded, lush===COLORS.
Manual first, auto-detector a gated stretch. GSTACK REVIEW REPORT appended.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
course-character.js holds the lush COLORS palette (moved from scene.js, no
circular import), a dry tan-links DRY_PALETTE, a manual per-course COURSE_DRY
map (client-side, NOT the course JSON which drops unknown fields in transit),
and blendPalette (grass zones only; greens/sand/water pinned; courseDry=0 is
byte-identical). scene.js computes this._pal at load from geo.name and paints
BOTH the splat AND the _fairwayZoneColor blades from it (blades previously
hard-ref'd COLORS -> would leave green tufts on tan ground). 300/300 green
(test/course-character.test.mjs added). Shader coordination is T3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oto (T3)

uCourseDry uniform (passed via _turfInputs so it hits BOTH base + HD-patch
materials) coordinates the 3 shader colour sources the splat alone can't:
(1) pull the noise warm-mix endpoint toward neutral so a tan base doesn't
double-count/overshoot; (2) scale mow-stripe strength toward a low floor for
links; (3) lower the far-photo weight so dry courses show lit tan turf at
overview instead of the green summer aerial. Cache key v31->v32. 300/300 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cache-key assertions v31->v32 (both variants) + a new test that courseDry
passes through to the uCourseDry uniform and appears in the shader. 301/301.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sub-plan/TODO/HANDOFF: P1b shipped + verified. Chambers courseDry=0.85 reads
tan-gold links at play (greens green, no seam) + warmer overview; Sawgrass
courseDry=0 proven byte-unchanged (palette + shader no-ops). Tuning knob =
COURSE_DRY['Chambers Bay'] + DRY_PALETTE.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rroojrooj
rroojrooj merged commit fe8e677 into main Jul 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant