Architecture
Architecture
The technical architecture for Cynario — a client-side, static web app with a Builder and a Player over one shared scenario document, plus import/export and local storage.
On this page
Design doc, evolving. This page captures the system design. Some implementation details below reflect an earlier proposed stack; the live app is built on Astro + Svelte + Svelte Flow (see the tech stack in the repo). The load-bearing shape is a client-side Builder and Player over one scenario document. Optional sharing, collaboration, catalogs, and protected sources add network infrastructure around that local-first core without making it a central plaintext scenario service.
High-level architecture
┌─────────────────────────────────────────────────────────────────┐
│ CYNARIO WEB APP │
│ (Client-Side / Static) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ PLAYER │ │ BUILDER │ │ SHARED STATE │ │
│ │ MODE │ │ MODE │ │ │ │
│ │ │ │ │ │ │ │
│ │ • Narrative │ │ • Graph │ │ • Current scenario │ │
│ │ display │ │ editor │ │ • Player position │ │
│ │ • Choices │ │ • Node │ │ • History │ │
│ │ • Progress │ │ editor │ │ • Settings │ │
│ │ • Score │ │ • Edge │ │ │ │
│ │ │ │ editor │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ SCENARIO DATA │ │
│ │ (JSON Schema) │ │
│ │ │ │
│ │ • Nodes[] │ │
│ │ • Edges[] │ │
│ │ • Metadata │ │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │
│ │ Import │ │ Local │ │ Export │ │
│ │ (JSON) │ │ Storage │ │ (JSON) │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Tech stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Astro | Static site generation |
| UI | Svelte | Single UI framework |
| Graph UI | Svelte Flow | Builder graph editor |
| Language | TypeScript | Type safety |
| Styling | Tailwind CSS | Utility-first CSS |
| Collaboration | Trystero / WebRTC | Encrypted links and live peer sessions |
| Encryption | Web Crypto API | AES-256-GCM |
| Storage | localStorage + export | Persistence |
| Hosting | Cloudflare Pages | Static hosting |
Data flow
Player mode
┌──────────────┐ ┌───────────────┐ ┌─────────────────┐
│ Load JSON │────▶│ Parse & Store │────▶│ Render Start │
│ Scenario │ │ in state │ │ Node │
└──────────────┘ └───────────────┘ └────────┬────────┘
│
┌──────────────────────────────┘
▼
┌─────────────┐
│ User clicks │
│ choice │
└──────┬──────┘
│
┌────────────▼────────────┐
│ Update current node │
│ Push to history stack │
│ Update score │
└────────────┬────────────┘
│
┌────────▼────────┐
│ Is ending? │
└────────┬────────┘
│
┌───────────┴───────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ Render │ │ Show │
│ next node │ │ ending │
└───────────┘ └───────────┘
Builder mode
┌─────────────────────────────────────────────────────────────┐
│ Graph Canvas │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ A │───▶│ B │───▶│ C │ │
│ └──┬──┘ └─────┘ └─────┘ │
│ │ │
│ On node click ─────────────────────────────────────────────┼───┐
└─────────────────────────────────────────────────────────────┘ │
│
┌──────────────────────────────┘
▼
┌───────────────────┐
│ Node Editor │
│ Sidebar │
│ │
│ • Title │
│ • Content (MD) │
│ • Type │
│ • Score/Badge │
│ │
│ [Save] [Delete] │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Scenario Store │
│ (nodes, edges) │
└─────────┬─────────┘
│
┌─────────────────┴─────────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Re-render │ │ Auto-save │
│ graph │ │ to localStorage│
└───────────────┘ └───────────────┘
URL structure
/ - Home (scenario list, import)
/builder - Builder (visual graph editor)
/player - Player (narrative interface)
Security considerations
- XSS in Markdown: Rendered content is sanitized before display.
- JSON import: Validate against the schema before loading.
- Local storage: No sensitive data stored beyond the scenario you opened.
- Local-first core: Builder and Player do not require a central application database. Static hosts, catalog sources, signaling, relays, and containers remain ordinary network trust surfaces.
See the full trust model on the Security & trust page.
Performance considerations
- Large graphs: Svelte Flow handles many nodes; virtualize where needed.
- Markdown rendering: Memoize parsed content.
- Bundle size: Tree-shake unused components.
- Offline: Cache scenario files for offline play (PWA).
Related
- Data model — the scenario JSON schema everything compiles to.
- The Scene (the Scene source) — the author-facing model for what a node actually contains.