Skip to content

perf: cull ground-level CityLights accent lights on the low quality tier - #3423

Merged
atomantic merged 1 commit into
mainfrom
claim/issue-3397
Aug 3, 2026
Merged

perf: cull ground-level CityLights accent lights on the low quality tier#3423
atomantic merged 1 commit into
mainfrom
claim/issue-3397

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

CityLights mounted 12 dynamic lights unconditionally. A mounted light costs a per-fragment iteration in the lighting loop of every MeshStandardMaterial in the scene regardless of its intensity, so the adaptive-quality low tier could not shed that cost by fading lights toward zero — only by not mounting them.

The two ground-level accent point lights are now gated behind cityShowDetail(settings) — the existing medium-tier-and-up gate that already governs rooftop kits, street furniture and transit trams, and which reads settings.effectiveTier with the legacy particleDensity fallback. Low tier drops from 11 dynamic point lights to 9.

Scope decisions made in this PR (unattended run, no gold-plating):

  • Which lights: the green accent (intensity 0.2, distance 25) and the red warning accent (intensity 0.15, distance 22) — the pair the issue names as the starting point, and the least visually significant of the set. They tint a small patch of street that the low tier already renders without its set dressing.
  • What is untouched: the overhead key/fill pair, the broad night glow, the two animated side accents, the purple back light, the warm orange ground accent (distance 35), the searchlight, and the hemisphere/ambient fill all still mount on every tier.
  • Which gate: reused cityShowDetail rather than writing a new effectiveTier !== 'low' predicate. It is the same semantics, keeps the tier ranking in one place, and inherits the fallback that keeps older payloads (and any caller that never sets effectiveTier) rendering exactly as before.
  • Medium/high/ultra output is byte-for-byte unchanged.

Closes #3397

Test plan

  • New client/src/components/city/CityLights.test.jsx (4 tests): the low tier mounts exactly two fewer point lights than the full tier; medium and ultra match high; an absent settings keeps every light; and the low tier still carries its 9 point lights plus the ambient, hemisphere and spot lights (so the cull can't silently widen).
  • cd client && npx vitest run src/components/city/ — 10 files, 92 tests, all passing.
  • npx eslint clean on both touched files.

Verification

Low-tier visual confirmation is still pending a human screenshot check. Headless WebGL cannot render in this environment, so the "no obvious visual regression on the low tier" half of the acceptance criteria has not been observed — only the light-count half is verified, by unit test. The change is deliberately conservative and trivially revertible (two lights wrapped in one conditional); if the low tier looks wrong in that corner of the street, reverting this commit restores the previous behavior with no other side effects.

@atomantic
atomantic merged commit 9efe7f7 into main Aug 3, 2026
6 checks passed
@atomantic
atomantic deleted the claim/issue-3397 branch August 3, 2026 20:16
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.

Cull CityLights accent lights on the low quality tier

1 participant