From fe9ea67f56847859b4fb4fa4f747022f0a2e5a70 Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Wed, 1 Oct 2025 10:15:43 -0500 Subject: [PATCH] fix: prevent premature passenger display during route transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix bug where new route passengers would appear on train cars before all cars from the previous route had exited through the tunnel. The issue occurred because passengers were switched when trainPosition < 0 (locomotive exits), but train cars trail behind by up to 35% (5 cars × 7% spacing). This caused new passengers to briefly appear on the old cars that were still fading out (positions 65-97%). Solution: Calculate the last car's position and only switch passengers when: 1. Train has reset to start position (trainPosition < 0), OR 2. All cars have fully faded out (lastCarPosition >= 97%) Changes: - useTrackManagement: Added maxCars and carSpacing parameters - Updated passenger display logic to check lastCarPosition >= fadeOutEnd - SteamTrainJourney: Pass maxCars and carSpacing from useTrainTransforms 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .claude/settings.local.json | 3 +- .../RaceTrack/SteamTrainJourney.tsx | 18 ++++++----- .../hooks/useTrackManagement.ts | 31 ++++++++++++------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 28870682..84164fc5 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -169,7 +169,8 @@ "Bash(open http://localhost:6006)", "Bash(open http://localhost:3002/games/matching)", "Bash(open http://localhost:3002/create)", - "Bash(open http://localhost:3002/games/complement-race/practice)" + "Bash(open http://localhost:3002/games/complement-race/practice)", + "Bash(open http://localhost:3002/games/complement-race)" ], "deny": [], "ask": [] diff --git a/apps/web/src/app/games/complement-race/components/RaceTrack/SteamTrainJourney.tsx b/apps/web/src/app/games/complement-race/components/RaceTrack/SteamTrainJourney.tsx index 10afaab6..38f82624 100644 --- a/apps/web/src/app/games/complement-race/components/RaceTrack/SteamTrainJourney.tsx +++ b/apps/web/src/app/games/complement-race/components/RaceTrack/SteamTrainJourney.tsx @@ -98,6 +98,13 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi const pathRef = useRef(null) const [trackGenerator] = useState(() => new RailroadTrackGenerator(800, 600)) + // Train transforms (extracted to hook) - called first to get maxCars and carSpacing + const { trainTransform, trainCars, locomotiveOpacity, maxCars, carSpacing } = useTrainTransforms({ + trainPosition, + trackGenerator, + pathRef + }) + // Track management (extracted to hook) const { trackData, tiesAndRails, stationPositions, landmarks, landmarkPositions, displayPassengers } = useTrackManagement({ currentRoute: state.currentRoute, @@ -105,14 +112,9 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi trackGenerator, pathRef, stations: state.stations, - passengers: state.passengers - }) - - // Train transforms (extracted to hook) - const { trainTransform, trainCars, locomotiveOpacity, maxCars, carSpacing } = useTrainTransforms({ - trainPosition, - trackGenerator, - pathRef + passengers: state.passengers, + maxCars, + carSpacing }) // Passenger animations (extracted to hook) diff --git a/apps/web/src/app/games/complement-race/hooks/useTrackManagement.ts b/apps/web/src/app/games/complement-race/hooks/useTrackManagement.ts index 21b089d2..e44e113f 100644 --- a/apps/web/src/app/games/complement-race/hooks/useTrackManagement.ts +++ b/apps/web/src/app/games/complement-race/hooks/useTrackManagement.ts @@ -10,6 +10,8 @@ interface UseTrackManagementParams { pathRef: React.RefObject stations: Station[] passengers: Passenger[] + maxCars?: number + carSpacing?: number } export function useTrackManagement({ @@ -18,7 +20,9 @@ export function useTrackManagement({ trackGenerator, pathRef, stations, - passengers + passengers, + maxCars = 5, + carSpacing = 7 }: UseTrackManagementParams) { const [trackData, setTrackData] = useState | null>(null) const [tiesAndRails, setTiesAndRails] = useState<{ @@ -68,23 +72,26 @@ export function useTrackManagement({ // Manage passenger display during route transitions useEffect(() => { - // If we're starting a new route (position < 0) or passengers haven't changed, update immediately - if (trainPosition < 0 || passengers === previousPassengersRef.current) { + // Calculate the position of the last train car + const lastCarPosition = trainPosition - maxCars * carSpacing + const fadeOutEnd = 97 // Position where cars are fully faded out + + // Only switch to new passengers when: + // 1. Train has reset to start position (< 0), OR + // 2. All cars (including the last one) have exited (last car position >= fadeOutEnd) + const allCarsExited = lastCarPosition >= fadeOutEnd + const trainReset = trainPosition < 0 + + if (trainReset || allCarsExited || passengers === previousPassengersRef.current) { setDisplayPassengers(passengers) previousPassengersRef.current = passengers } // Otherwise, if we're mid-route and passengers changed, keep showing old passengers - else if (trainPosition > 0 && passengers !== previousPassengersRef.current) { - // Keep displaying old passengers until train exits + else if (passengers !== previousPassengersRef.current) { + // Keep displaying old passengers until all cars exit // Don't update displayPassengers yet } - - // When train resets to beginning, switch to new passengers - if (trainPosition < 0 && passengers !== previousPassengersRef.current) { - setDisplayPassengers(passengers) - previousPassengersRef.current = passengers - } - }, [passengers, trainPosition]) + }, [passengers, trainPosition, maxCars, carSpacing]) // Update display passengers during gameplay (same route) useEffect(() => {