Markdown Converter
Agent skill for markdown-converter
**Purpose:** This document provides mandatory guidelines for AI agents and developers working on this codebase to ensure maintainable, modular, and high-quality code.
Sign in to like and favorite skills
Purpose: This document provides mandatory guidelines for AI agents and developers working on this codebase to ensure maintainable, modular, and high-quality code.
GlobeScene), narrative events (FlashpointModal), and global condition trackers (pandemic, fog of war, diplomacy) to immerse players in high-stakes decision making.useFlashpoints, usePandemic, useFogOfWar) that expose deterministic state transitions and side-effects for UI orchestration.GlobeScene, PandemicPanel, NewsTicker, TutorialOverlay) coordinated by page-level containers like pages/Index.tsx. Each module owns its styling and state wiring.useCallback, useMemo, and controlled refs to stabilise game loops and side effects, keeping render cycles predictable even with randomised event payloads.All code MUST be modular to minimize future refactoring.
Example Structure:
// ā GOOD: Modular approach src/utils/calculations/ āāā economicCalculations.ts // Only economic math āāā combatCalculations.ts // Only combat math āāā resourceCalculations.ts // Only resource math // ā BAD: Monolithic approach src/utils/ āāā allCalculations.ts // 2000+ lines mixing everything
Files MUST NOT mix data definitions and business logic.
/data/, /constants/, or /types/ directories*.data.ts, *.constants.ts, *.types.ts/utils/, /services/, or /lib/ directoriesExample:
// ā GOOD: Separated data and logic // techTree.data.ts (ONLY DATA) export const TECH_TREE_DATA = { "cybersecurity": { cost: 1000, prereqs: [] }, "quantum": { cost: 2000, prereqs: ["cybersecurity"] } }; // techTree.utils.ts (ONLY LOGIC) import { TECH_TREE_DATA } from './techTree.data'; export function canResearchTech(techId: string, nation: Nation): boolean { const tech = TECH_TREE_DATA[techId]; return nation.science >= tech.cost; } // ā BAD: Mixed data and logic in one file export const TECH_TREE_DATA = { /* ... */ }; export function canResearchTech() { /* ... */ } export function researchTech() { /* ... */ } export function getTechCost() { /* ... */ }
src/ āāā components/ # React components ONLY ā āāā ui/ # Pure UI components (buttons, cards, etc.) ā āāā game/ # Game-specific components ā āāā layout/ # Layout components ā āāā data/ # Pure data definitions ā āāā techTree.data.ts ā āāā units.data.ts ā āāā nations.data.ts ā āāā types/ # TypeScript interfaces and types ā āāā game.types.ts ā āāā api.types.ts ā āāā utils/ # Pure utility functions ā āāā calculations/ # Math and calculation functions ā āāā validation/ # Validation functions ā āāā formatting/ # Formatting functions ā āāā services/ # Business logic and services ā āāā gameEngine/ ā āāā api/ ā āāā state/ ā āāā hooks/ # React custom hooks ā āāā constants/ # App-wide constants
*.data.ts (e.g., techTree.data.ts)*.types.ts (e.g., game.types.ts)*.utils.ts (e.g., combat.utils.ts)use*.ts (e.g., useGameState.ts)TechTree.tsx)Example:
// ā GOOD: Modular functions export function processEndTurn(gameState: GameState): GameState { const afterEconomy = processEconomy(gameState); const afterCombat = processCombat(afterEconomy); const afterDiplomacy = processDiplomacy(afterCombat); return afterDiplomacy; } function processEconomy(state: GameState): GameState { /* ... */ } function processCombat(state: GameState): GameState { /* ... */ } function processDiplomacy(state: GameState): GameState { /* ... */ } // ā BAD: Monolithic function export function processEndTurn(gameState: GameState): GameState { // 500 lines of mixed economy, combat, and diplomacy logic }
type for unions and simple aliasesinterface for object shapes and classesany type (use unknown if type is truly unknown)anyReact.memo() for expensive componentsuseMemo() and useCallback() for expensive calculationsOrder imports logically:
// 1. External libraries import React, { useState, useEffect } from 'react'; import { Canvas } from '@react-three/fiber'; // 2. Internal types import type { GameState, Nation } from '@/types/game.types'; // 3. Internal data import { TECH_TREE_DATA } from '@/data/techTree.data'; // 4. Internal utilities import { calculateCombat } from '@/utils/calculations/combat.utils'; // 5. Internal components import { TechTree } from '@/components/game/TechTree';
React.memo() for expensive componentsuseMemo() and useCallback() for expensive calculationsExample:
/** * Calculates combat damage between attacker and defender * * @param attacker - The attacking nation's stats * @param defender - The defending nation's stats * @param terrain - Battlefield terrain type * @returns Damage dealt to defender (0-100) * * @example * const damage = calculateCombatDamage(usa, china, 'mountain'); */ export function calculateCombatDamage( attacker: Nation, defender: Nation, terrain: TerrainType ): number { // Implementation }
If you encounter these patterns, REFACTOR IMMEDIATELY:
When refactoring large files:
Example workflow:
# Before refactoring src/components/Game.tsx (3000 lines) # After refactoring src/components/Game.tsx (200 lines - main component) src/data/game.data.ts (data definitions) src/types/game.types.ts (interfaces) src/utils/game/ āāā combat.utils.ts āāā economy.utils.ts āāā diplomacy.utils.ts src/components/game/ āāā CombatPanel.tsx āāā EconomyPanel.tsx āāā DiplomacyPanel.tsx
src/hooks/__tests__/ or parallel component test foldersnpm run test locally before opening a PRuseFlashpoints' template-driven optionsusePandemicuseFogOfWar, revealing map intel progressivelypages/Index.tsxGlobeScene using @react-three/fiberuse-toast) and ticker updates to narrate systemic changespublic/ or are generated procedurallysrc/components/The Agent System provides intelligent, voice-enabled advisors that guide players through strategic decisions, react to game events, and provide dynamic commentary. This system uses ElevenLabs for text-to-speech and implements an adaptive personality framework.
Voice: Roger (EXAVITQu4vr4xnSDxMaL) - Deep, authoritative Personality: Hawkish, direct, action-oriented Triggers:
Sample Lines:
"DEFCON 3 confirmed, Mr. President. Recommend immediate alert posture." "Enemy missile silos operational. We should strike first while we have the advantage." "Our ABM systems intercepted 12 warheads. Defense grid holding... for now." "Intelligence shows massive troop movements. This is it."
Personality Traits:
Voice: Sarah (EXAVITQu4vr4xnSDxMaL) - Calm, analytical Personality: Rational, cautious, long-term thinker Triggers:
Sample Lines:
"Research complete: Titan-Class Weaponization. I pray we never use it." "Nuclear winter projections are... catastrophic. 80% crop failure within six months." "Radiation levels in sector 7 are lethal. Evacuation recommended immediately." "Our satellite network is now operational. Knowledge is our greatest weapon."
Personality Traits:
Voice: Charlotte (XB0fDUnXU5powFXDhCwa) - Diplomatic, measured Personality: Patient, persuasive, idealistic Triggers:
Sample Lines:
"Mr. President, the UN General Secretary is on the line. They're proposing a ceasefire." "Breaking a treaty now would destroy our credibility. We must honor our word." "I've secured a non-aggression pact with France. It's fragile, but it holds." "The world is watching. How we respond here defines our legacy."
Personality Traits:
Voice: Daniel (onwK4e9ZLuTAKqWW03F9) - Measured, cryptic Personality: Paranoid, secretive, pragmatic Triggers:
Sample Lines:
"Our asset in Moscow confirms: they're preparing a first strike." "Sir, we've been compromised. Someone leaked our launch codes." "Satellite recon shows something... unusual. Underground construction, massive scale." "Trust no one, Mr. President. Even our allies have secrets."
Personality Traits:
Voice: Bill (pqHfZKP75CvOlQylNhV4) - Practical, numbers-focused Personality: Pragmatic, cautious with resources Triggers:
Sample Lines:
"Mr. President, we're burning through uranium reserves at an unsustainable rate." "The economy is in freefall. We need trade agreements, not more missiles." "Production quotas exceeded. Our industrial might is unmatched." "Sanctions are crippling their economy. Another month and they'll collapse."
Personality Traits:
Voice: Jessica (cgSgspJ2msm6clMCkdW9) - Urgent, media-savvy Personality: Image-conscious, politically aware Triggers:
Sample Lines:
"Mr. President, the press is going wild. We need a statement NOW." "Public approval just dropped 15 points. The people want peace." "Protests in every major city. They're burning flags and calling for your resignation." "Our propaganda campaign is working. National morale is soaring."
Personality Traits:
Advisors comment based on:
Priority Levels:
Rules:
When multiple advisors want to speak:
// Priority: Military > Intel > Diplomatic > Science > Economic > PR if (multiplePendingLines) { const priorityOrder = ['military', 'intel', 'diplomatic', 'science', 'economic', 'pr']; const selectedAdvisor = priorityOrder.find(role => hasPendingLine(role)); playLine(selectedAdvisor); }
const ADVISOR_VOICES = { military: { voiceId: 'CwhRBWXzGAHq8TQ4Fs17', // Roger model: 'eleven_turbo_v2_5', stability: 0.7, similarityBoost: 0.8, style: 0.6, // More expressive }, science: { voiceId: 'EXAVITQu4vr4xnSDxMaL', // Sarah model: 'eleven_turbo_v2_5', stability: 0.9, similarityBoost: 0.7, style: 0.3, // More neutral }, diplomatic: { voiceId: 'XB0fDUnXU5powFXDhCwa', // Charlotte model: 'eleven_turbo_v2_5', stability: 0.8, similarityBoost: 0.8, style: 0.5, }, intel: { voiceId: 'onwK4e9ZLuTAKqWW03F9', // Daniel model: 'eleven_turbo_v2_5', stability: 0.8, similarityBoost: 0.6, style: 0.4, }, economic: { voiceId: 'pqHfZKP75CvOlQylNhV4', // Bill model: 'eleven_turbo_v2_5', stability: 0.85, similarityBoost: 0.7, style: 0.35, }, pr: { voiceId: 'cgSgspJ2msm6clMCkdW9', // Jessica model: 'eleven_turbo_v2_5', stability: 0.75, similarityBoost: 0.8, style: 0.7, // Very expressive } };
class AdvisorVoice { private audioQueue: AudioBuffer[] = []; private currentlyPlaying: boolean = false; async speak(text: string, advisorRole: string, priority: 'critical' | 'urgent' | 'important' | 'routine') { const voiceConfig = ADVISOR_VOICES[advisorRole]; // Generate speech via ElevenLabs API const audioBuffer = await this.generateSpeech(text, voiceConfig); if (priority === 'critical') { this.interrupt(); this.playImmediately(audioBuffer); } else { this.enqueue(audioBuffer, priority); } } private async generateSpeech(text: string, config: VoiceConfig): Promise<AudioBuffer> { // Call ElevenLabs API through edge function const response = await fetch('/api/text-to-speech', { method: 'POST', body: JSON.stringify({ text, ...config }) }); return await response.arrayBuffer(); } }
| Event | Military | Science | Diplomatic | Intel | Economic | PR |
|---|---|---|---|---|---|---|
| DEFCON Change | ā Primary | ā ļø Warns | ā ļø Urges calm | ā¹ļø Context | ā | ā¹ļø Public |
| Research Done | ā¹ļø Military tech | ā Primary | ā | ā¹ļø Applications | ā¹ļø Costs | ā |
| Treaty Signed | ā ļø Skeptical | ā¹ļø Benefits | ā Primary | ā ļø Verification | ā¹ļø Trade | ā PR win |
| Intel Success | ā¹ļø Strategic | ā | ā¹ļø Diplomatic use | ā Primary | ā | ā¹ļø Leak risk |
| Resource Low | ā ļø Readiness | ā ļø Limits | ā¹ļø Trade | ā | ā Primary | ā ļø Rationing |
| Morale Drop | ā ļø Unrest | ā¹ļø Causes | ā ļø Stability | ā¹ļø Threats | ā ļø Economy | ā Primary |
| Nuclear Launch | ā Tactical | ā Consequences | ā ļø War crime | ā¹ļø Counterstrike | ā | ā Crisis |
| Enemy Buildup | ā Primary | ā ļø Arms race | ā¹ļø Negotiate | ā Primary | ā¹ļø Costs | ā¹ļø Spin |
Legend:
const DIALOGUE_TEMPLATES = { defconEscalation: { military: [ "DEFCON ${level}. All forces on alert. Ready to strike on your command.", "We've moved to DEFCON ${level}. Our response time is now ${seconds} seconds.", "Escalation to DEFCON ${level} complete. God help us all." ], science: [ "DEFCON ${level}... the probability of nuclear exchange just jumped to ${percent}%.", "We're at DEFCON ${level}. At this rate, we'll trigger nuclear winter by month's end.", ], diplomatic: [ "DEFCON ${level} sends a dangerous message. We should pursue de-escalation immediately.", "Mr. President, going to DEFCON ${level} closes diplomatic doors. Reconsider." ] }, // ... 100+ event templates };
Advisors reference specific game state:
function generateAdvice(event: GameEvent, advisor: Advisor): string { const template = DIALOGUE_TEMPLATES[event.type][advisor.role]; const selected = selectRandomWeighted(template, advisor.personality); // Inject dynamic data return selected .replace('${level}', event.data.defcon) .replace('${nation}', event.data.nationName) .replace('${count}', event.data.missileCount) .replace('${percent}', Math.round(event.data.probability * 100)); }
interface AdvisorState { role: string; trustLevel: number; // 0-100 correctPredictions: number; wrongPredictions: number; timesIgnored: number; timesFollowed: number; }
Trust Affects:
Trust Changes:
Advisors can disagree publicly:
MILITARY: "We must strike now while we have superiority!" DIPLOMATIC: "General, that's madness. Negotiations are progressing." MILITARY: "Negotiations are stalling tactics. They're buying time to build more warheads!" SCIENCE: "Both of you are ignoring the real threat: nuclear winter. ANY major exchange ends civilization."
<type>: <description>feat, fix, refactor, docs, style, test, choreExamples:
feat: Add quantum computing tech tree branch fix: Resolve RNG undefined error in endTurn callback refactor: Split canvasDrawingFunctions.ts into modular components docs: Update agents.md with modular code guidelines
Before submitting new code, verify:
tsc --noEmit (implicit via Vite build) or local IDE diagnosticsnpm run lint if lint rules are added/updatednpm run test and ensure coverage for new gameplay logic"Write code that is easy to delete, not easy to extend."
The goal is to create small, independent modules that can be:
Modular code is maintainable code. When each file has a single, clear purpose, bugs are easier to find, features are easier to add, and refactoring becomes rare.
log.md for refactoring examples and lessons learnedLast Updated: 2026-01-14 Maintained By: Development Team Status: Living Document (update as project evolves)