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);
}
+1 -1
View File
@@ -57,7 +57,7 @@ export function processTick(state: GameState): Partial<GameState> {
const capacity = computeCapacity(state, infrastructure, researchBonuses);
const market = processMarket(stateWithModels, capacity.tokensPerSecondCapacity, capacity.effectiveInferenceFlops, researchBonuses);
const compute = finalizeCompute(capacity, market.totalTokenDemand);
const compute = finalizeCompute(capacity, market.totalTokenDemand, state.compute.computeHistory, state.meta.tickCount);
const talent = processTalent(stateWithModels);
const stateWithTalent = { ...stateWithModels, talent };
@@ -10,6 +10,8 @@ export const AUTO_SAVE_INTERVAL_TICKS = 60;
export const FINANCIAL_SNAPSHOT_INTERVAL = 60;
export const MAX_FINANCIAL_HISTORY = 1000;
export const MAX_REPUTATION_HISTORY = 500;
export const COMPUTE_SNAPSHOT_INTERVAL = 60;
export const MAX_COMPUTE_HISTORY = 500;
export const STARTING_MONEY = 600_000;
export const BASE_ENERGY_COST_PER_FLOP = 0.001;
+12
View File
@@ -1,3 +1,13 @@
export interface ComputeSnapshot {
tick: number;
totalFlops: number;
effectiveTrainingFlops: number;
effectiveInferenceFlops: number;
inferenceUtilization: number;
tokensPerSecondCapacity: number;
tokensPerSecondDemand: number;
}
export interface ComputeState {
totalFlops: number;
totalTrainingFlops: number;
@@ -10,6 +20,7 @@ export interface ComputeState {
inferenceUtilization: number;
tokensPerSecondCapacity: number;
tokensPerSecondDemand: number;
computeHistory: ComputeSnapshot[];
}
export const INITIAL_COMPUTE: ComputeState = {
@@ -24,4 +35,5 @@ export const INITIAL_COMPUTE: ComputeState = {
inferenceUtilization: 0,
tokensPerSecondCapacity: 0,
tokensPerSecondDemand: 0,
computeHistory: [],
};
+1 -1
View File
@@ -52,4 +52,4 @@ export const INITIAL_SETTINGS: GameSettings = {
musicVolume: 0.5,
};
export const SAVE_VERSION = 9;
export const SAVE_VERSION = 10;