History: AI-driven alternate-history simulator
Pax Historia-style sim where the LLM is the world engine.
- React 19 + Vite 6 + Tailwind v4 + shadcn/ui frontend
- Express single-port backend (/api + /sse + built client + SPA fallback)
- SQLite (better-sqlite3) persistence, one row per game
- MapLibre choropleth map (OpenFreeMap dark + ISO_A3 regions)
- Defensive turn loop: strip fences, balanced-{} extract, parse, clamp 0-100,
retry-once nudge, generic 'unclear' fallback; never crashes on bad output
- 5 seed presets (wwii-1939, coldwar-1955, modern-2025, no-wwii-1940, aegis-2400)
- LLM client over native fetch w/ injectable transport (mesh-bot pattern);
LLM_STUB=1 deterministic transport for tests/e2e
- Unit (vitest, 19) + deterministic Playwright e2e
- Multi-stage node:22-slim Docker + Traefik (history.dev.kkhost.pl:4321)
Co-Authored-By: OpenCode <opencode@users.noreply.github.com>
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
// Domain types — the single source of truth shared by the frontend (src/), the
|
||||
// backend (server/), and the LLM prompt contract. No runtime dependencies here.
|
||||
|
||||
/** A nation's 0–100 status indices. Every value is clamped to 0–100 by the engine. */
|
||||
export interface NationStats {
|
||||
military: number;
|
||||
economy: number;
|
||||
stability: number;
|
||||
population: number;
|
||||
}
|
||||
|
||||
export const STAT_KEYS = ['military', 'economy', 'stability', 'population'] as const;
|
||||
export type StatKey = (typeof STAT_KEYS)[number];
|
||||
|
||||
export type NationType = 'major' | 'minor' | 'power' | 'alliance' | 'faction';
|
||||
|
||||
/** Direction of a bilateral diplomatic relationship. */
|
||||
export type RelationStatus = 'ally' | 'neutral' | 'rival' | 'hostile' | 'war';
|
||||
|
||||
export const RELATION_STATUSES: RelationStatus[] = [
|
||||
'ally',
|
||||
'neutral',
|
||||
'rival',
|
||||
'hostile',
|
||||
'war',
|
||||
];
|
||||
|
||||
/**
|
||||
* A single nation in the world. `territory` holds ISO_A3 codes; the map colors
|
||||
* each of those regions with this nation's stable color (see protocol.nationColor).
|
||||
*/
|
||||
export interface Nation {
|
||||
id: string;
|
||||
name: string;
|
||||
type: NationType;
|
||||
stats: NationStats;
|
||||
territory: string[];
|
||||
relations: Record<string, RelationStatus>;
|
||||
}
|
||||
|
||||
/** Categories a narrative event can take. */
|
||||
export type EventType =
|
||||
| 'military'
|
||||
| 'diplomatic'
|
||||
| 'economic'
|
||||
| 'political'
|
||||
| 'social'
|
||||
| 'disaster'
|
||||
| 'scientific'
|
||||
| 'cultural';
|
||||
|
||||
export const EVENT_TYPES: EventType[] = [
|
||||
'military',
|
||||
'diplomatic',
|
||||
'economic',
|
||||
'political',
|
||||
'social',
|
||||
'disaster',
|
||||
'scientific',
|
||||
'cultural',
|
||||
];
|
||||
|
||||
export type EventOutcome = 'success' | 'failure' | 'partial' | 'neutral';
|
||||
|
||||
/** A narrative event the simulation emitted on some turn. */
|
||||
export interface EventEntry {
|
||||
id: string;
|
||||
turn: number;
|
||||
date: string;
|
||||
nation: string; // nation id the event concerns
|
||||
type: EventType;
|
||||
title: string;
|
||||
text: string;
|
||||
outcome: EventOutcome;
|
||||
}
|
||||
|
||||
/** The full, persisted state of one game. Saved to SQLite by id. */
|
||||
export interface GameState {
|
||||
id: string;
|
||||
presetId: string;
|
||||
presetTitle: string;
|
||||
playerNationId: string;
|
||||
turn: number;
|
||||
date: string;
|
||||
nations: Record<string, Nation>;
|
||||
events: EventEntry[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A scenario the player can start. One JSON file per preset (presets/<id>.json).
|
||||
* `worldBackground` + `simulationRules` become the LLM system prompt.
|
||||
*/
|
||||
export interface Preset {
|
||||
id: string;
|
||||
title: string;
|
||||
startDate: string;
|
||||
summary: string;
|
||||
worldBackground: string;
|
||||
simulationRules: string[];
|
||||
nations: Nation[];
|
||||
}
|
||||
|
||||
/** The lightweight manifest entry used to render the preset picker cards. */
|
||||
export interface PresetMeta {
|
||||
id: string;
|
||||
title: string;
|
||||
startDate: string;
|
||||
summary: string;
|
||||
}
|
||||
Reference in New Issue
Block a user