Compare commits

...

4 Commits

Author SHA1 Message Date
semantic-release-bot
28fc0a14be chore(release): 4.67.2 [skip ci]
## [4.67.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.67.2) (2025-10-23)

### Performance Improvements

* **complement-race:** increase train position update frequency to 60fps ([fffaf1d](fffaf1df1d))
2025-10-23 11:24:24 +00:00
Thomas Hallock
fffaf1df1d perf(complement-race): increase train position update frequency to 60fps
Increased update intervals from 50ms (20fps) to 16ms (60fps) for smoother
train movement without using react-spring animations. Changes applied to:

- Game logic loop (useSteamJourney.ts)
- Momentum/position updates (Provider.tsx)
- Position broadcasts for multiplayer (Provider.tsx)

This resolves the regression where react-spring animations caused guest
players' trains to freeze at their starting position in multiplayer games.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 06:23:02 -05:00
semantic-release-bot
09df96922e chore(release): 4.67.1 [skip ci]
## [4.67.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.0...v4.67.1) (2025-10-22)

### Bug Fixes

* **complement-race:** fix react-spring interpolation TypeScript errors ([0add9e4](0add9e4ef1))
2025-10-22 19:06:35 +00:00
Thomas Hallock
0add9e4ef1 fix(complement-race): fix react-spring interpolation TypeScript errors
Fixed TypeScript errors in transform interpolation by using correct react-spring
syntax: to([spring1, spring2, spring3], (a, b, c) => ...) instead of the
incorrect spring1.to((a, b, c) => ..., spring2, spring3) syntax.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 14:05:21 -05:00
5 changed files with 32 additions and 15 deletions

View File

@@ -1,3 +1,17 @@
## [4.67.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.67.2) (2025-10-23)
### Performance Improvements
* **complement-race:** increase train position update frequency to 60fps ([fffaf1d](https://github.com/antialias/soroban-abacus-flashcards/commit/fffaf1df1d4d55c811bf634c957691e3564470d6))
## [4.67.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.0...v4.67.1) (2025-10-22)
### Bug Fixes
* **complement-race:** fix react-spring interpolation TypeScript errors ([0add9e4](https://github.com/antialias/soroban-abacus-flashcards/commit/0add9e4ef1d69e4e92ffe279cce09c68efa43714))
## [4.67.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.66.2...v4.67.0) (2025-10-22)

View File

@@ -1,6 +1,6 @@
'use client'
import { useSpring, useSprings, animated } from '@react-spring/web'
import { useSpring, useSprings, animated, to } from '@react-spring/web'
import { useMemo, useRef } from 'react'
import type { PlayerState } from '@/arcade-games/complement-race/types'
import type { RailroadTrackGenerator } from '../../lib/RailroadTrackGenerator'
@@ -146,10 +146,9 @@ export function GhostTrain({
<g ref={ghostRef} data-component="ghost-train" data-player-id={player.id}>
{/* Ghost locomotive - animated */}
<animated.g
transform={locomotiveSpring.x.to(
(x, y, rot) => `translate(${x}, ${y}) rotate(${rot}) scale(-1, 1)`,
locomotiveSpring.y,
locomotiveSpring.rotation
transform={to(
[locomotiveSpring.x, locomotiveSpring.y, locomotiveSpring.rotation],
(x, y, rot) => `translate(${x}, ${y}) rotate(${rot}) scale(-1, 1)`
)}
opacity={locomotiveSpring.opacity}
>
@@ -208,10 +207,9 @@ export function GhostTrain({
{carSprings.map((spring, index) => (
<animated.g
key={`car-${index}`}
transform={spring.x.to(
(x, y, rot) => `translate(${x}, ${y}) rotate(${rot}) scale(-1, 1)`,
spring.y,
spring.rotation
transform={to(
[spring.x, spring.y, spring.rotation],
(x, y, rot) => `translate(${x}, ${y}) rotate(${rot}) scale(-1, 1)`
)}
opacity={spring.opacity}
>

View File

@@ -34,7 +34,7 @@ const MOMENTUM_DECAY_RATES = {
const MOMENTUM_GAIN_PER_CORRECT = 15 // Momentum added for each correct answer
const SPEED_MULTIPLIER = 0.15 // Convert momentum to speed (% per second at momentum=100)
const UPDATE_INTERVAL = 50 // Update every 50ms (~20 fps)
const UPDATE_INTERVAL = 16 // Update every 16ms (~60 fps for smooth animation)
const GAME_DURATION = 60000 // 60 seconds in milliseconds
export function useSteamJourney() {

View File

@@ -365,7 +365,7 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
const MOMENTUM_GAIN_PER_CORRECT = 15
const MOMENTUM_LOSS_PER_WRONG = 10
const SPEED_MULTIPLIER = 0.15 // momentum * 0.15 = % per second
const UPDATE_INTERVAL = 50 // 50ms = ~20fps
const UPDATE_INTERVAL = 16 // 16ms = ~60fps for smooth animation
// Transform multiplayer state to look like single-player state
const compatibleState = useMemo((): CompatibleGameState => {
@@ -486,7 +486,12 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
if (multiplayerState.gamePhase !== 'playing') {
hasInitializedPositionRef.current = false
}
}, [multiplayerState.gamePhase, multiplayerState.config.style, multiplayerState.players, localPlayerId])
}, [
multiplayerState.gamePhase,
multiplayerState.config.style,
multiplayerState.players,
localPlayerId,
])
// Initialize game start time when game becomes active
useEffect(() => {
@@ -636,7 +641,7 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
console.log('[POS_BROADCAST] Starting position broadcast interval')
// Send position update every 100ms for smoother ghost trains (reads from refs to avoid restarting interval)
// Send position update every 16ms (~60fps) for smoother ghost trains (reads from refs to avoid restarting interval)
const interval = setInterval(() => {
const currentPos = clientPositionRef.current
broadcastCountRef.current++
@@ -659,7 +664,7 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
userId: viewerId || '',
data: { position: currentPos },
} as ComplementRaceMove)
}, 100)
}, 16)
return () => {
console.log(`[POS_BROADCAST] Stopping interval (sent ${broadcastCountRef.current} updates)`)

View File

@@ -1,6 +1,6 @@
{
"name": "soroban-monorepo",
"version": "4.67.0",
"version": "4.67.2",
"private": true,
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
"workspaces": [