Overhaul dashboard into command center with compute tracking, era-gated sections
CI / build-and-push (push) Successful in 37s

Add compute history time-series (capacity vs demand chart), revenue vs expenses
dual-line chart, enhanced system status (training allocation, network uptime,
model freshness), active operations panel, market position bars, and competitor
snapshot. Stat cards expand from 3 to 6 as player progresses through eras.
Graceful v9→v10 save migration preserves existing games.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 13:45:16 -04:00
parent 901db02a6b
commit 283c7c7932
7 changed files with 487 additions and 103 deletions
@@ -1,5 +1,5 @@
import type { GameState, ComputeState, InfrastructureState } from '@ai-tycoon/shared';
import { FLOPS_TO_TOKENS_MULTIPLIER } from '@ai-tycoon/shared';
import { FLOPS_TO_TOKENS_MULTIPLIER, COMPUTE_SNAPSHOT_INTERVAL, MAX_COMPUTE_HISTORY } from '@ai-tycoon/shared';
import type { ResearchBonuses } from './researchBonuses';
export interface CapacityResult {
@@ -43,19 +43,36 @@ export function computeCapacity(state: GameState, infrastructure: Infrastructure
};
}
export function finalizeCompute(capacity: CapacityResult, totalTokenDemand: number): ComputeState {
export function finalizeCompute(capacity: CapacityResult, totalTokenDemand: number, prevHistory: ComputeState['computeHistory'], tickCount: number): ComputeState {
const inferenceUtilization = capacity.tokensPerSecondCapacity > 0
? Math.min(1, totalTokenDemand / capacity.tokensPerSecondCapacity)
: (totalTokenDemand > 0 ? 1 : 0);
const computeHistory = [...prevHistory];
if (tickCount % COMPUTE_SNAPSHOT_INTERVAL === 0) {
computeHistory.push({
tick: tickCount,
totalFlops: capacity.totalFlops,
effectiveTrainingFlops: capacity.effectiveTrainingFlops,
effectiveInferenceFlops: capacity.effectiveInferenceFlops,
inferenceUtilization,
tokensPerSecondCapacity: capacity.tokensPerSecondCapacity,
tokensPerSecondDemand: totalTokenDemand,
});
if (computeHistory.length > MAX_COMPUTE_HISTORY) {
computeHistory.shift();
}
}
return {
...capacity,
tokensPerSecondDemand: totalTokenDemand,
inferenceUtilization,
computeHistory,
};
}
export function processCompute(state: GameState, infrastructure: InfrastructureState): ComputeState {
const cap = computeCapacity(state, infrastructure);
return finalizeCompute(cap, state.compute.tokensPerSecondDemand);
return finalizeCompute(cap, state.compute.tokensPerSecondDemand, state.compute.computeHistory, state.meta.tickCount);
}