Skip to content

Repository files navigation

Rippl

Geopolitical cascade simulator. Model real-world events, trace how consequences propagate through global systems, and compare possible futures.

What this is

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.

Key capabilities

  • 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 (Global or 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

Architecture

┌─────────────────────────────────────────────────────────┐
│  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.

Tech stack

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

Getting started

Prerequisites

  • Node.js 20+
  • Python 3.10+
  • npm

Install and run

# Install frontend dependencies
npm install

# Set up Python backend
npm run backend:venv
npm run backend:install

# Start both services
npm run dev

This launches:

  • Python backend at http://127.0.0.1:8001
  • Next.js frontend at http://127.0.0.1:4175

Frontend only

npm run dev:frontend

The app works without the Python backend — API routes fall back to the TypeScript baseline engine.

Environment variables

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.

Project structure

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

Domain model

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.

Data pipeline

Country baselines (175 countries)

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)

Active geopolitical events

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.

Live data ingestion

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

Stress status formula

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.

Current status

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

Recent implementation status

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 dependsOn instead 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 Global or 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 countries lists
  • 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 shock versus relief, 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.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages