Narrative universe interface where agentic storytelling, visual craft, and operational reliability are engineered together.
Most story products optimize for either experience quality or runtime reliability, rarely both. StoryVerse was built with a deliberate triple-axis model:
- Axis A — Immersive narrative UX: A visually rich, modern 2D interface where users explore and connect stories across Movies, History, and Novels through AI-powered narrative bridges.
- Axis B — Agentic intelligence: A multi-agent pipeline (Parser → Navigator → Storyteller) that resolves natural-language queries, traverses a Neo4j knowledge graph, and synthesizes cross-domain "What-If" scenarios.
- Axis C — Operational transparency: A live health footer, route-level diagnostics, explicit fallback policies, and auditable failure codes — so degradation is surfaced, not hidden.
This matters because API health can appear green while public routes silently degrade. StoryVerse treats narrative quality and SRE quality as one inseparable product.
Deliver a compelling, AI-driven narrative universe that lets anyone discover hidden connections between the stories that shape our world — while remaining operationally transparent under continuous deployment.
StoryVerse aims to become a reusable blueprint for agentic content systems where:
- Creative modules are composable and domain-portable
- The story catalog grows autonomously through AI generation
- User-path reliability is measurable at every route
- Fallback policy behavior is auditable, not accidental
- Visual design, accessibility, and engineering rigor reinforce each other
Every narrative — whether a Hollywood blockbuster, a pivotal historical event, or a classic novel — exists in relation to others. Characters echo across centuries, power structures recur in new costumes, and moral dilemmas reappear in every genre. StoryVerse makes these invisible threads visible by modeling stories as nodes in a knowledge graph and letting AI synthesize the bridges between them.
The system doesn't just "generate text." It decomposes the problem into specialized agents — a Parser that understands what the user is asking (in English or Korean), a Navigator that traverses the graph for thematic neighbors, and a Storyteller that weaves a plausible cross-domain scenario with timeline beats and risk assessment. Each agent's contribution is transparent and individually testable.
The initial 8 hand-curated stories are a seed, not a ceiling. StoryVerse includes an AI-powered catalog generator (backed by Ollama) that periodically creates new story entries balanced across domains, persists them to Neo4j (with a JSON file fallback), and makes them immediately available to users. The goal: a living, expanding universe that rewards repeat visits.
The visual layer isn't a skin over functionality — it's part of the product's argument. The dark cosmic theme, domain-specific color coding (Movie blue, History green, Novel pink), glassmorphism cards, and micro-animations all serve information hierarchy and emotional resonance. Every hover glow, gradient border, and timeline dot is a deliberate design decision.
Power users get a full shortcut system (search focus, quick filters, history browsing, one-key copy/share actions); assistive-tech users get skip links, live-region announcements, labeled recovery actions, and visible focus states. Neither is an afterthought — recent development has treated accessibility as a shipping feature, commit by commit.
A beautiful frontend with silent failures is a broken product. StoryVerse embeds operational diagnostics as a first-class concern: a live health footer that polls the API and flags stale data, route-level status codes, endpoint fail ratios, latency context, and explicit fallback policies. When something degrades, the system tells you — it doesn't pretend everything is fine.
| Phase | Description | Status |
|---|---|---|
| Agentic Pipeline | Parser → Navigator → Storyteller agent chain with Neo4j GraphRAG | Done |
| Query Resolution | Bilingual (EN/KO) natural-language parsing with 5 resolution strategies, confidence levels, and one-click clarification choices (Korean particle-aware) | Done |
| 3D Universe (v1) | Three.js-based 3D visualization with interactive CommandDeck | Done (retired) |
| 2D Redesign (v2) | Complete UX/UI overhaul to modern card-based 2D layout with glassmorphism dark theme | Done |
| Dynamic Catalog | AI auto-generation via Ollama, Neo4j + file persistence, cron-triggerable API endpoint | Done |
| Ops Diagnostics | Route/API status codes, fail ratios, latency metrics, tunnel churn detection | Done |
| Live Health Footer | /api/health endpoint + footer that polls it every 15s with manual refresh, staleness detection, and screen-reader announcements |
Done |
| Universe Command Surface | Catalog search + medium lane filters, shareable deep links (q/medium/source/target), recent bridge pairs, and a page-wide keyboard shortcut system |
Done |
| Marketing Quick Nav | Sticky landing-page section navigator with fuzzy filter, pinned sections, recent trail, and a built-in shortcut guide | Done |
| Accessibility Layer | Skip links, focusable landmarks, aria-live status regions, labeled empty-state recovery actions, visible focus states |
Done |
- Neo4j graph seeding automation (
RELATED_TOrelationships for generated stories) - Story detail pages with full bridge visualization
- Server-side session persistence and favorites (client-side persistence of selections, filters, recent queries/pairs already ships via
localStorage) - Multi-language marketing UI (the universe surface is already bilingual EN/KO)
| Token | Value | Usage |
|---|---|---|
| Background | cosmos-950 (#020617) |
Page and card backgrounds |
| Foreground | cosmos-100 (#dbeafe) |
Primary text |
| Panel | #0b1228 |
Elevated panel surfaces |
| Muted | #8aa0d1 |
Secondary text |
| Accent Cyan | neon-cyan (#22d3ee) |
CTAs, source selection, links |
| Accent Violet | neon-violet (#a855f7) |
Target selection, decorative |
| Accent Rose | neon-rose (#f472b6) |
Risk badges, alerts |
| Domain Movie | #60a5fa |
Movie badges, borders, glows |
| Domain History | #34d399 |
History badges, borders, glows |
| Domain Novel | #f472b6 |
Novel badges, borders, glows |
| Display Font | Orbitron | Headings, logos, labels |
| Body Font | Space Grotesk | Body text, descriptions |
Supporting tokens: cosmos 900/800/700/200 shades, nebula/movie/history/novel glow box-shadows, and a faint space-grid background pattern.
- Glassmorphism: Cards use
backdrop-blur-xlwith semi-transparent backgrounds and subtle borders - Domain color coding: Every story is immediately identifiable by its medium through gradient top-borders, colored badges, and themed glow effects
- Micro-animations:
fade-in,slide-up, andfloatkeyframes for entrance effects and decorative motion (pulse-glowandshimmerare defined in the design system for future use) - Hover dynamics: Cards scale to 1.02x with domain-colored box-shadows; primary buttons carry a neon glow shadow
- Constellation motif: A decorative SVG overlay on the hero page evokes a star-map aesthetic — nodes connected by faint lines, slowly floating
┌─────────────────────────────────────────────┐
│ Header (fixed, glassmorphism nav bar) │
│ · Skip link · Home/Universe links with │
│ active state (aria-current) │
├─────────────────────────────────────────────┤
│ Marketing Quick Nav (sticky command bar) │
│ · Section progress bar + prev/next/resume │
│ · Fuzzy section filter (?nav= URL sync) │
│ · Pinned sections (max 4) + recent trail │
│ · "?" shortcut guide, keys 1-4 jump │
├─────────────────────────────────────────────┤
│ Hero Section │
│ · Constellation SVG background (animated) │
│ · Gradient headline: "Explore Stories │
│ Across Worlds" │
│ · Domain badges (Movie / History / Novel) │
│ · Dual CTA: "Start Exploring" + │
│ "See How It Works" │
├─────────────────────────────────────────────┤
│ How It Works (3 step cards) │
│ · Pick Two Stories → AI Builds the Bridge │
│ → Explore Connections │
├─────────────────────────────────────────────┤
│ Story Catalog Preview (filterable grid) │
│ · Medium lane filters synced to ?medium= │
│ · Per-domain counts + live status text │
│ · Empty-state "Clear lane filter" reset │
│ · Click → /universe?story={id} │
├─────────────────────────────────────────────┤
│ CTA Section + Live Health Footer │
│ · "Ready to Bridge Worlds?" call-to-action │
│ · API status: live/degraded · fresh/stale │
└─────────────────────────────────────────────┘
Desktop:
┌──────────────────────────────────────────────┐
│ Header │
├────────────────────┬─────────────────────────┤
│ Story Grid (55%) │ Bridge Panel (45%) │
│ │ │
│ Search + quick │ Command Deck header │
│ filter chips │ Shortcut guide (?) │
│ Medium lanes │ Selected Pair Bar │
│ [Story Card] │ Recent Pairs (1-5) │
│ [Story Card] │ Query Input + Prompts │
│ ...2-col grid │ Clarification Panel │
│ Empty-state │ Bridge Result Card │
│ recovery actions │ Timeline Beats │
│ │ Risk Badge │
│ │ Neighbor Suggestions │
│ │ Chat History (toggle) │
├────────────────────┴─────────────────────────┤
Mobile: vertical stack (grid → panel)
State: URL params (q / medium / source / target)
+ localStorage persistence
| Component | Responsibility |
|---|---|
StoryCard |
Domain-colored card with SOURCE/TARGET selection badges, glow states, hover scale |
StoryGrid |
Responsive grid with result counts, filter chips, and labeled empty-state recovery actions |
SelectedPairBar |
Source → Target display with swap/clear/copy-link/open-link/copy-prompt actions and Generate Bridge CTA |
QueryInput |
240-char query box with starter prompts, recent-query chips, and inline history browsing |
BridgeResultCard |
Scenario title + bridge narrative with four copy actions (summary, brief, timeline, next hops) |
TimelineBeats |
Vertical timeline with neon dots and staggered fade-in |
RiskBadge |
Neon-rose warning card with pulse animation |
NeighborSuggestions |
Clickable suggestion cards with domain-colored borders |
ClarificationPanel |
One-click corrected prompts (Korean particle-aware) plus source/target candidate pickers |
ChatHistory |
Collapsible query log with role filter, text search, and copy-log action |
BridgePanel |
Right-side orchestrator composing all bridge sub-components, recent pairs, and the shortcut guide |
useUniverseState |
Central state hook: selection, queries, results, recent pairs, and localStorage persistence |
The universe page is fully keyboard-operable. Highlights (press ? in either surface for the built-in guide):
| Surface | Keys | Action |
|---|---|---|
| Universe page | / |
Focus catalog search |
| Universe page | 1–4 |
Quick filter picks (Sherlock / galaxy / dynasty / rebellion) |
| Universe page | A M H N |
Medium lane filter: All / Movie / History / Novel |
| Universe page | L / Shift+L / O |
Copy filtered-view link / copy selection link / open in new tab |
| Universe page | Esc |
Cascade: clear selection → clear filters → blur search |
| Query input | Ctrl/Cmd+K |
Focus query input (/ is taken by catalog search on this page) |
| Query input | Ctrl/Cmd+Enter |
Submit immediately |
| Query input | ↑ ↓ (or Ctrl/Cmd+P/N) |
Browse recent-query history; Esc restores the draft |
| Pair bar | Enter / S / C / O / P |
Generate bridge / swap / copy link / open link / copy prompt |
| Result card | B / T / N |
Copy full brief / timeline beats / next hops |
| Recent pairs | 1–5 |
Resume a saved pair (remove/copy/open variants listed in the in-app ? guide) |
| Landing quick nav | 1–4, [/], /, ?, r, f, 5–8, 9 |
Jump sections, filter, resume last stop, pin/recall sections |
- Skip-to-content links in the root layout and header, targeting a keyboard-focusable
mainlandmark aria-currentnav states (including nested routes) and labeled icon buttons throughoutaria-livestatus regions for: universe result summaries, catalog filter status, query character counter, history-browsing state, and footer health announcementsaria-pressedselection state on filter chips, medium lanes, and clarification candidates- Labeled empty-state recovery actions and visible
focus-visiblerings on catalog controls - Decorative SVGs and spinners marked
aria-hidden; IME-safe Enter handling for Korean input - WCAG 2.2 SC 2.1.4: single-character shortcuts can be turned off via a persisted toggle in the Bridge Panel shortcut guide (the
?guide and Escape stay active so it's always reachable). Overlapping keys resolve by context — recent-pair slots own their digits, and the page yieldsN/Owhen a result card or selected pair is present, so one keypress never triggers two actions
flowchart LR
User[Browser] --> Web[storyverse-web]
Web --> Actions[Server Actions]
Actions --> Orchestrator[Agent Orchestrator]
Orchestrator --> Parser[Query Parser]
Orchestrator --> Navigator[Navigator Agent]
Orchestrator --> Storyteller[Storyteller Agent · LangGraph]
Navigator --> Neo4j[(Neo4j Graph)]
Storyteller -.->|"optional: OPENAI_API_KEY"| OpenAI[gpt-4o-mini]
Navigator -.->|"optional re-rank"| OpenAI
Web --> CatalogAPI["/api/catalog"]
CatalogAPI --> Neo4j
CatalogAPI -.->|fallback| FileStore[("data/generated-catalog.json")]
Web --> GenerateAPI["/api/catalog/generate"]
GenerateAPI --> Ollama[Ollama LLM]
GenerateAPI --> Neo4j
GenerateAPI -->|backup write| FileStore
Footer[Health Footer · 15s poll] --> HealthAPI["/api/health"]
Ops[ops-check] -->|HTTP probes| Web
Ops --> Metrics[Route codes · fail ratios · latency · tunnel churn]
Every external dependency degrades gracefully: without Neo4j the catalog serves the seed + file fallback and the navigator suggests real catalog neighbours (never synthetic nodes, so every suggestion stays selectable); without OPENAI_API_KEY the storyteller uses deterministic templates. The storyteller is grounded in the navigator's neighbours — the bridge references a real related story rather than an invented one. Low-confidence queries abstain — the parser returns a clarification instead of fabricating a bridge. The app boots and demos with zero external services configured.
| Endpoint | Method | Behavior |
|---|---|---|
/api/health |
GET | Liveness + readiness: ok, service, version, nodeEnv, uptimeSec, timestamp, plus ready and checks.neo4j (a cached, short-timeout Neo4j probe; unconfigured graph is skipped and still ready); served with Cache-Control: no-store |
/api/catalog |
GET | Full story catalog { count, catalog[] } (seed + generated), force-dynamic |
/api/catalog/generate |
POST | AI catalog generation; body { countPerDomain } (clamped 1–10, default 4); bearer auth if CATALOG_GENERATE_SECRET is set. Required in production — refused when NODE_ENV=production and no secret is set; in development, localhost requests are allowed (Host-header check). 60s max duration |
Server actions wrap the agent pipeline with a 15s timeout (timeouts fail fast; other failures get one retry with 150ms backoff), returning explicit failure codes: EMPTY_QUERY, INVALID_SELECTION, TIMEOUT, EXECUTION_FAILED.
| Component | Role |
|---|---|
storyverse-web |
Next.js web client, API routes, agent pipeline, ops diagnostics |
storyverse-web/src/lib/agents/ |
Agentic narrative pipeline (parser, navigator, storyteller, clarification, catalog + generator) |
storyverse-web/src/components/ |
UI components (universe, marketing, layout, ui) |
storyverse-web/scripts/ops-check.sh |
Route/API status, fail counts, ratios, latency, tunnel churn (npm run ops:check) |
scripts/ops-check.sh |
Root wrapper that runs the web checker and emits a Policy-A JSON summary on success |
OPERATIONS_PLAN.md / SESSION_MEMORY.md |
Multi-project ops roadmap and session working notes |
Deep-dive docs: storyverse-web/README.md (implementation and design-system detail) · storyverse-web/agents.md (contributor guide for the agent pipeline).
The project follows a fallback-allowing operational policy (Policy A) under primary-route instability:
ops-checkprobes/,/universe, and/api/healthon the primary URL first, then falls back to localhost- Primary degradation is surfaced as warning/degraded while fallback success is still captured for continuity
- Strict-fail transitions are policy-controlled, not accidental (
OPERATIONS_REQUIRE_PRIMARYis ignored by design under Policy A) - Metrics include per-route status codes, fail counts/ratios, health-probe latency, retry totals, and PM2 tunnel restart churn; set
OPERATIONS_REPORT_FILEfor a machine-readable JSON report - Server action failures return explicit codes:
EMPTY_QUERY,INVALID_SELECTION,TIMEOUT,EXECUTION_FAILED - The live footer surfaces health freshness to end users: snapshots older than 20s are labeled stale/over SLA
cd storyverse-web
cp .env.example .env.local # optional — every variable is optional
npm ci
npm run devOpen http://localhost:16100 — no external services are required for a degraded-mode demo (seed catalog + deterministic agents). See storyverse-web/.env.example for the full configuration surface.
| Variable | Required | Description |
|---|---|---|
NEO4J_URI |
Optional | Neo4j connection URI — all three NEO4J_* vars must be set to enable graph mode; otherwise the app runs on the seed catalog and the navigator suggests real catalog neighbours |
NEO4J_USERNAME |
Optional | Neo4j username |
NEO4J_PASSWORD |
Optional | Neo4j password |
OPENAI_API_KEY |
Optional | Enables gpt-4o-mini bridge narration and suggestion re-ranking; deterministic templates otherwise |
OLLAMA_BASE_URL |
For generation | OpenAI-compatible Ollama endpoint, e.g. http://localhost:11434/v1 (the code default points at an internal lab host — set your own) |
OLLAMA_MODEL |
Optional | Ollama model name (default: qwen3:32b) |
CATALOG_GENERATE_SECRET |
Prod required | Bearer token for the generation API. Required in production (generation is refused when NODE_ENV=production and it is unset); in development, localhost requests are allowed without it |
QUERY_PREFERRED_MEDIA |
Optional | Comma list: Movie,History,Novel — steers ambiguous-query resolution |
QUERY_AMBIGUITY_MARGIN |
Optional | Integer 1..40 (default 15) — clarification sensitivity |
OPERATIONS_* |
Optional | ops-check tuning: base URLs, retries, report file, tunnel process name |
# Trigger AI catalog generation (4 stories per domain = 12 new stories)
curl -X POST http://localhost:16100/api/catalog/generate
# With custom count (clamped to 1..10 per domain)
curl -X POST http://localhost:16100/api/catalog/generate \
-H "Content-Type: application/json" \
-d '{"countPerDomain": 6}'
# Example cron schedule (weekly, Monday 3 AM)
# 0 3 * * 1 curl -X POST http://localhost:16100/api/catalog/generatecd storyverse-web
npm run check # lint + test:parser + build
npm run ops:check # live route/API diagnosticstest:parser compiles the agent library and runs 79 tests (parser, orchestrator, clarification choices, and the action command-runner) on Node's built-in test runner.
Found a vulnerability? Please report it privately — see SECURITY.md. Note that catalog generation must be locked down with CATALOG_GENERATE_SECRET in any deployed environment.
Released under the MIT License.