Geopolitical cascade simulator. Model real-world events, trace how consequences propagate through global systems, and compare possible futures.
Rippl connects a live data baseline (economic indicators, conflict signals, energy markets, shipping routes) to a simulation engine that models how shocks cascade through countries, sectors, and entities. Users author "what-if" scenarios, run them forward in time, and watch downstream consequences emerge across a dependency graph.
The core idea: events don't happen in isolation. A sanctions package ripples through trade dependencies, energy markets, and shipping routes. Rippl makes those ripple chains visible and explorable.
- Live baseline — real-time country scores derived from World Bank, GDELT, EONET, and other public feeds
- Scenario authoring — start with a natural-language briefing, review the generated event chain, and keep a manual fallback path for constrained authoring
- Cascade propagation — dependency graph engine that traces consequences across entities, sectors, and borders
- Branch comparison — run multiple scenarios side by side with confidence bands
- Interactive map — MapLibre-powered world map with country stress, shipping routes, hazard overlays, and propagation visualization
- Consequence ledger — structured log of downstream effects with severity, confidence, and causal chains
- Scenario summary reports — dedicated post-run report pages with return-to-dashboard flow and PDF/DOCX export
- Scenario workspace — left-rail scenario panel centered on new scenarios, live/demo seeds, saved scenarios, and prior summaries
- Scope-first top strip — the upper workspace now carries the current scope (
Globalor the selected country) while the right panel behaves as a drill-in surface instead of the default country header - Metric inspector drill-ins — domain cards and country KPI cards open a granular right-panel inspector that explains scale meaning, compositional drivers, and source-backed evidence
- Animated baseline loading state — the initial load now uses a Rippl-native animated scanner with short rotating status lines instead of a static text-heavy placeholder
- Public preview guardrails — AI-assisted scenario generation is capped at two architected scenarios per hour per visitor, with a user-facing reset-time modal and expectation-setting in the entry flow
- Inference transparency — each saved scenario can disclose how much of its construction was user-stated versus engine-inferred
- Hazard-aware simulation roadmap — evolving toward asset-level, weather-aware, and local pass-through simulation across energy, transport, infrastructure, and public-safety scenarios
┌─────────────────────────────────────────────────────────┐
│ Browser (Next.js client) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ WorldMap │ │ Scenario │ │ Dep. │ │ Consequence│ │
│ │ (MapLibre)│ │ Branches │ │ Graph │ │ Ledger │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
│ │ │ │ │ │
│ └────────────┴────────────┴────────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ │ Simulation Engine │ │
│ │ (lib/simulation.ts) │ │
│ └───────────┬───────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ │ Live Baseline Data │ │
│ └───────────┬───────────┘ │
└──────────────────────────┼───────────────────────────────┘
│
┌────────────┴────────────┐
│ Next.js API Routes │
│ (BFF / proxy layer) │
└────────────┬────────────┘
│
┌────────────┴────────────┐
│ Python Backend │
│ (FastAPI + SQLite) │
│ Scoring, ingestion, │
│ snapshot persistence │
└─────────────────────────┘
Frontend (Next.js) — single-page client app. All simulation state, visualization, and interaction live here. Components under components/simulator/ handle the map, scenario workspace, summary history surfaces, dependency graph, ledger, and comparison views.
Simulation engine (lib/simulation.ts) — pure TypeScript, no React dependency. Takes a scenario branch, modifiers, and baseline data; produces a full SimulationSnapshot with country states, entity stress, propagation logs, consequence ledger, and confidence bands.
API routes — thin BFF layer. /api/live-baseline and /api/live-overlays proxy to the Python backend when available, falling back to the TypeScript implementation.
Python backend (backend/) — FastAPI service owning live data ingestion, scoring, and snapshot persistence. Designed to progressively replace the TypeScript baseline pipeline. See backend/README.md for details.
| Layer | Technology |
|---|---|
| Framework | Next.js 16, React 19, TypeScript 5.7 |
| Styling | Tailwind CSS v4, Radix UI primitives |
| Maps | MapLibre GL |
| Charts | Recharts |
| Graphs | @xyflow/react |
| Forms | react-hook-form, zod |
| Backend | Python, FastAPI, SQLite |
| Dev orchestration | Custom scripts/dev-stack.mjs |
- Node.js 20+
- Python 3.10+
- npm
# Install frontend dependencies
npm install
# Set up Python backend
npm run backend:venv
npm run backend:install
# Start both services
npm run devThis launches:
- Python backend at
http://127.0.0.1:8001 - Next.js frontend at
http://127.0.0.1:4175
npm run dev:frontendThe app works without the Python backend — API routes fall back to the TypeScript baseline engine.
| Variable | Required | Description |
|---|---|---|
RIPPL_PYTHON_BACKEND_URL |
No | Python backend URL. Set automatically by dev-stack.mjs. Default: http://127.0.0.1:8001 |
RIPPL_AISSTREAM_API_KEY |
No | AISStream key for live maritime vessel tracking |
FRED_API_KEY |
No | Federal Reserve Economic Data API key |
EIA_API_KEY |
No | U.S. Energy Information Administration API key |
All keys are optional. The system degrades gracefully with fallback/seeded data when keys are absent.
rippl/
├── app/ # Next.js App Router
│ ├── page.tsx # Main simulator page (client component)
│ ├── layout.tsx # Root layout, fonts, dark theme
│ └── api/ # API routes (BFF layer)
│ ├── live-baseline/ # Proxies to Python or TS fallback
│ ├── live-overlays/ # Map overlay data
│ └── country-observed/ # Per-country observable detail
├── components/
│ ├── simulator/ # Feature UI (26 components)
│ │ ├── world-map.tsx # MapLibre world map
│ │ ├── map-inner.tsx # Map internals (layers, interactions)
│ │ ├── global-metrics.tsx # Top-level KPI bar
│ │ ├── scenario-branches.tsx # Scenario workspace panel
│ │ ├── dependency-graph.tsx # @xyflow entity dependency graph
│ │ ├── consequence-ledger.tsx# Structured consequence log
│ │ ├── country-detail.tsx # Country drill-in panel
│ │ └── ...
│ └── ui/ # Shared UI primitives (shadcn/Radix)
├── lib/ # Domain logic (no React dependency)
│ ├── simulation.ts # Core simulation engine
│ ├── sim-types.ts # TypeScript type definitions
│ ├── sim-data.ts # Seed data and initial branches
│ ├── live-baseline.ts # Live baseline models
│ ├── live-baseline-server.ts # Server-side baseline aggregation
│ ├── observations.ts # Observation normalization
│ ├── world-state.ts # Entity graph construction
│ ├── source-registry.ts # Data source metadata
│ └── ...
├── backend/ # Python FastAPI service
│ ├── app/
│ │ ├── main.py # FastAPI routes
│ │ ├── scoring.py # Baseline scoring pipeline
│ │ ├── adapters.py # External data adapters
│ │ ├── models.py # Pydantic response models
│ │ ├── seed.py # Seed country data
│ │ └── storage.py # SQLite snapshot persistence
│ └── README.md
├── scripts/
│ └── dev-stack.mjs # Launches backend + frontend together
└── public/ # Static assets
The simulation operates on these core concepts:
- Branches — scenario timelines. The baseline branch reflects the live world state. User-created branches add events and time horizons.
- Events — discrete shocks (military action, cyber attack, economic disruption) with severity, onset, and duration.
- Tracks — phased escalation sequences within a branch (e.g., "Initial Strike" → "Blockade" → "Residual Effects").
- Entities — nodes in the dependency graph: countries, sectors, routes, chokepoints, resources, institutions, cities.
- Dependencies — weighted, typed edges between entities (trade, energy, supply chain, military, financial, narrative).
- Propagation rules — how stress transmits along dependency edges, with lag, persistence, reversibility, and confidence.
- Interventions — policy responses that dampen specific stress channels.
- Consequence ledger — the structured output: what happened, when, how severe, how confident, and the causal chain that led to it.
Every sovereign nation has a seed baseline in backend/app/seed.py with:
- Population, GDP, military spend, trade exposure, energy import dependence, cyber resilience
- Alliance block classification (NATO, CSTO, other)
- 9-dimension metric scores (economy, infrastructure, stability, military, social, trust, alliances, technology, escalation)
The scoring engine (backend/app/scoring.py) maintains ACTIVE_EVENTS — a curated list of ongoing geopolitical events with per-country role assignments (primary/secondary/tertiary) and per-class intensity scores. Current events include US-Iran conflict, Ukraine-Russia war, Israel-Gaza/Lebanon, Sudan civil war, Red Sea/Houthi disruption, Sahel instability, Taiwan Strait tensions, and more.
External adapters (backend/app/adapters.py) pull real-time signals from:
- FRED — VIX, high-yield spreads → market/sentiment adjustments
- EIA — WTI crude oil prices → energy/maritime/market adjustments
- CISA KEV — known exploited vulnerabilities → cyber/governance adjustments
- GDELT — conflict/news articles (24h window) → per-country conflict, humanitarian, sentiment, governance adjustments
Country status on the live map (app/page.tsx) uses a weighted composite:
- Sentiment pulse: 30%
- Energy pulse: 20%
- Logistics pulse: 20%
- Markets pulse: 15%
- Escalation metric: 15%
Thresholds: ≥52 = critical, ≥35 = elevated, below = stable.
v0.2.0 — full-coverage baseline with real-time geopolitical intelligence.
- Frontend: substantially implemented (map, scenarios, graph, ledger, compare, history, snapshots)
- Interaction model: selected countries now persist as the active workspace scope in the top strip, while the right panel opens for deeper metric/entity/conflict inspection instead of auto-opening on every country selection
- Metric drill-ins: both global domain cards and country KPI cards now feed the same right-panel inspector, with composition and evidence replacing the old default country-leaderboard treatment
- Simulation engine: rich domain model with propagation, confidence bands, branch comparison
- Python backend: 175-country baselines, 10 active geopolitical events, GDELT live conflict feed, multi-source scoring pipeline
- Data persistence: client-side (localStorage) for scenarios/runs; server-side (SQLite) for baseline snapshots
- Live feeds: FRED, EIA, CISA KEV, GDELT integrated with graceful degradation
- Baseline trust contract: provenance-weighted source metadata, explicit required/critical feed counts, baseline/scenario-start confidence, and intelligence-gap summaries
Scenario authoring and execution have moved beyond the earlier placeholder contract:
- generated scenario specs now go through shared schema validation and normalization before execution
- authored event metadata such as provenance, dependency links, and target annotations now survive
ScenarioSpec -> SimulationBranch - runtime event activation now respects
dependsOninstead of treating authored event chains as flat timed lists - regenerate now preserves matching manual review edits and remembers intentional event removals
The live baseline contract has also been tightened:
- source registry entries now distinguish authority tier, verification mode, bias risk, and baseline/scenario-start importance
- source snapshots now expose explicit gap state instead of collapsing everything into a single trust number
- baseline-facing data source summaries now report required-feed health, critical gaps, and confidence for both current baseline quality and scenario start quality
- the Python backend owns those confidence/gap calculations, and the TypeScript fallback mirrors the same contract when the backend is absent
The workspace interaction model has also sharpened:
- the top strip is the primary scope summary surface for
Globalor the selected country - the right panel is a contextual drill-in surface rather than the default country header
- metric panels now focus on composition, score interpretation, and evidence instead of generic
most affected countrieslists - the initial loading state stays visually alive while still waiting for the first honest baseline snapshot
The cascade graph is also being repositioned as a left-to-right propagation view rather than a generic network cloud:
- origin should anchor on the left
- downstream branches should unfold toward the right
- graph readability should optimize for causal path-following first
The next engine priority is improving multi-hop propagation and explicit path attribution so higher-order ripples are not just visually implied but actually simulated and explainable.
That next engine slice is now underway:
- propagation logs now carry
rippleOrder,parentLogId,rootEntityId,pathScore, and branch classification (primary,secondary,spillover) - consequence ledger entries and dependency traces now surface ripple order and path-share information instead of flattening everything into undifferentiated downstream impact
- the world graph now includes global chokepoint and market nodes such as Hormuz and crude-market entities as real traversable nodes, which unlocks true multi-hop propagation instead of first-order-only country-sector echoes
- focused engine tests now verify that a regional initiating shock can produce second-, third-, and fourth-order ripple chains through the backend simulation model
- scenario events can now express
shockversusrelief, which lets Rippl model reopening, restoration, and de-escalation as real engine inputs instead of only showing the initial disruption - the engine now tracks lagged and sticky transmission profiles so upstream normalization can appear before downstream retail or local pass-through catches up
- a first explicit energy pass-through chain now exists for
Hormuz -> crude market -> U.S. Gulf refining -> East Coast terminals -> Mid-Atlantic rack pricing -> Northern Virginia retail fuel - the simulation runtime now derives and surfaces activated capability modules so a user-created scenario can show which parts of the Rippl toolbox were actually invoked
- compound and natural-disaster event families now have explicit infrastructure, logistics, and sentiment propagation rules instead of falling through generic handling
- the first real hazard module runtime is now active: chemical release plus weather modifier events can emit plume-style hazard forecasts, estimated exposed population and evacuation counts, and local subnational impact entries that feed the map and country detail surfaces
- hazard modules now accept explicit module context, and the app can fetch no-key Open-Meteo wind/precipitation forecast context for active chemical-release events before falling back to scenario text or deterministic baseline assumptions
- prebuilt scenarios have been reduced to a single demo seed so Rippl stays capability-first rather than growing into a library of canned runs
- the left scenario rail now leads with scenario creation, treats saved scenario reports as the primary history artifact, and demotes lower-level runtime storage concepts behind cleaner accordion sections
What is explicitly not surfaced right now:
- user-facing intervention controls are intentionally deferred
- Rippl should first become stronger at shock definition, propagation realism, and explanation before it asks users to model responses
- a likely future premium direction is AI-assisted response-option generation as alternate scenario branches, not manual intervention toggles in the core product
See Granular Simulation Roadmap for the fidelity roadmap and Simulation Capability Modules for the modular architecture direction behind it. See Definition Of Done for the current v1 finish-line criteria, including the required post-run scenario summary page.