ARCHITECTURE_MODULAR_ANALYSIS - mark-ik/graphshell GitHub Wiki
This architecture analysis has been archived. See the archived copy below for the original detailed modular architecture notes.
Archived copy: archive_docs/ARCHITECTURE_MODULAR_ANALYSIS.md
For the current modular decisions and short architecture summary see README.md and GRAPH_INTERFACE.md.
The crate split and trait-heavy architecture sketched in this document represent a long-term target rather than the immediate implementation plan.
- Phase 1 (MVP) keeps Graphshell as a single application crate that embeds graph, camera, UI, and Servo integration.
- Within that crate, graph/physics/camera/serialization modules are designed to be Servo-agnostic so they can later be extracted into
graphshell-graph-core. - A dedicated
wgpurendering pipeline,BrowserEnginetrait, andUIBackendtrait are introduced only after the MVP graph browser is stable and in regular use.
The sections below remain useful as guidance for that later refactor, but they should not be treated as requirements for the initial migration from tabs to a graph interface.
graphshell-servo-browser (binary crate - consumes graphshell-graph-core) βββ browser/ (Servo integration) βββ ui/ (egui overlay for chrome/menus) βββ main.rs
graphshell-chrome-extension (binary crate - consumes graphshell-graph-core) βββ browser/ (Chrome tab API integration) βββ ui/ (native Chrome extension UI)
graphshell-visualization (library crate - consumes graphshell-graph-core) βββ (Generic spatial graph visualization for any data)
**Characteristics**:
- Graph core is **platform-agnostic, pure library**
- Browser engine abstracted via traits
- UI framework swappable (egui β GPUI β Xilem)
- Reusable in extensions, other apps, data visualization tools
- Multiple targets (desktop, extension, library consumers)
---
## Key Architectural Decisions
### 1. **Graph Core β Browser Engine** π₯ **MAJOR CHANGE**
**Current plan**: Graph engine lives in `src/graph/` alongside Servo integration.
**Proposed**: Extract graph core into separate `graphshell-graph-core` crate with:
- **Zero dependencies** on:
- Servo, WebRender, compositor logic
- Platform-specific window code
- UI frameworks
- **Pure dependencies**:
- `wgpu` (GPU rendering)
- `nalgebra` or `glam` (math)
- `serde` (serialization)
- Standard library
**Advantage**: Graph library can be published on crates.io, used independently.
**Trade-off**: Requires architectural discipline; can't import Servo types into core.
---
### 2. **Browser Engine as Trait** π₯ **MAJOR CHANGE**
**Proposed trait**:
```rust
// graphshell-graph-core/src/browser.rs
pub trait BrowserEngine {
type WebView;
fn create_webview(&mut self, node_id: NodeId, url: &str) -> Result<Self::WebView>;
fn load_url(&mut self, webview: &mut Self::WebView, url: &str) -> Result<()>;
fn render_to_texture(&mut self, webview: &Self::WebView) -> TextureHandle;
fn cleanup_webview(&mut self, webview: Self::WebView) -> Result<()>;
}
Implementations:
| Engine | Crate | Status |
|---|---|---|
| Servo | graphshell-servo-browser |
MVP (current plan) |
| Chrome Tab API | graphshell-chrome-extension |
Phase 3+ |
| Firefox Tab API | graphshell-firefox-extension |
Phase 3+ |
| Headless (testing) |
graphshell-graph-core (test) |
MVP (for unit tests) |
Advantage: Same graph code works with different browser engines.
Trade-off: Requires abstracting Servo-specific APIs (Constellation messages, embedder_traits, etc.)
Current plan: WebRender compositor β Graphshell window.
Proposed:
-
graphshell-graph-coreuses wgpu for graph rendering (independent of Servo) - WebRender still renders webpages to textures (Servo responsibility)
- Graph core composes its own quad-based rendering (nodes + edges + HUD)
- UI framework (egui) renders chrome/menus on top
Benefit: Graph core doesn't depend on Servo's WebRender; can work with Chrome's rendering pipeline too.
Implementation:
// graphshell-graph-core/src/renderer.rs
pub struct GraphRenderer {
wgpu_device: wgpu::Device,
wgpu_queue: wgpu::Queue,
render_pipeline: wgpu::RenderPipeline,
// ...
}
impl GraphRenderer {
pub fn render_frame(
&mut self,
graph: &Graph,
camera: &Camera,
node_textures: &HashMap<NodeId, TextureHandle>,
) -> wgpu::Texture {
// Render nodes (as quads with node_textures)
// Render edges (as lines)
// Render HUD (text, FPS counter, etc.)
}
}Current plan: Graphshell's chrome/menus are closely tied to one UI system.
Proposed: Define traits for UI operations:
// graphshell-graph-core/src/ui_traits.rs
pub trait UIBackend {
fn render_search_bar(&mut self) -> Option<SearchQuery>;
fn render_settings_dialog(&mut self) -> Option<SettingsUpdate>;
fn render_menu(&mut self) -> Option<MenuAction>;
fn render_status_bar(&mut self, stats: &Stats) -> Result<()>;
}Implementations:
-
graphshell-ui-egui: egui-based (MVP, initial PoC) -
graphshell-ui-gpui: GPUI-based (future) -
graphshell-ui-xilem: Xilem-based (future) -
graphshell-ui-web: Web-based (browser extension)
Advantage: Swap UI frameworks without changing graph logic.
-
Publishable graph library
-
graphshell-graph-coreon crates.io - General-purpose spatial graph visualization
- Not browser-specific; anyone can use it
-
-
Browser extension pathway
- Chrome/Firefox extensions can consume graph core
- Reuse physics + rendering + graph structure
- Use browser's native tab API instead of Servo
-
Testability
- Graph core has zero dependencies (except math/serde)
- Can unit test physics, algorithms, serialization in isolation
- No need to spin up Servo to test graph logic
-
Code reuse
- Same graph library in desktop app + extension + other projects
- Reduces duplication
-
Swappable components
- Could use different browser engines (headless Chrome, Firefox, etc.)
- Could use different UI frameworks (egui β GPUI)
- Not locked into one choice
-
Architecture overhead
- Requires careful trait design upfront
- Abstraction costs (trait dispatch, error handling)
- More complex to reason about than monolithic design
-
Delayed MVP
- Current plan targets working Graphshell app in ~8 weeks
- Modular design adds 2-4 weeks of architecture work
- Traits need to be designed correctly; wrong design = painful refactor
-
Servo integration complexity
- Servo's APIs are deeply tied to its compositor/constellation
- Abstracting
CompositorMsg,WebViewDelegate, etc. behind traits is non-trivial - May require creating wrapper types
-
Testing trade-offs
- Headless testing easier with modular design
- But browser-specific testing (Servo integration) still requires full stack
-
Maintenance burden
- More crates to maintain
- Trait stability becomes critical (breaking changes affect all implementers)
Phases:
-
Phase 1 (Weeks 1β4): Extract graph-core
- Create
graphshell-graph-corecrate (pure library) - Implement graph engine, physics, wgpu rendering
- Define
BrowserEngineandUIBackendtraits - Create headless test harness
- Create
-
Phase 1 (Weeks 5β8): Implement Servo as trait
- Create
graphshell-servo-browsercrate - Implement
BrowserEnginefor Servo - Create
graphshell-ui-eguicrate - Integrate graph-core + Servo + egui into working app
- Create
-
Phase 2 (Weeks 9β16): Features
- Add features to graph-core (clustering, filtering, persistence)
- Keep feature logic in core; UI implementations per framework
-
Phase 3 (Weeks 17β24): Extensions
- Implement
graphshell-chrome-extensionusing graph-core - Implement
graphshell-firefox-extensionusing graph-core - Tokenization/P2P research (can be framework-agnostic)
- Implement
Timeline: Same 8-week MVP window, but modular structure in place.
Outcome:
-
graphshell-graph-coreis publishable library -
graphshell-servo-browseris desktop app - Extensions are possible in Phase 3
Phases:
-
Phase 1β2 (Weeks 1β16): Current migration plan (monolithic)
- Build graph, rendering, Servo integration tightly coupled
- Ship working app
-
Phase 2β3 transition: Modularization refactor
- Extract graph-core from monolithic codebase
- Create traits for browser/UI
- Separate Servo integration into wrapper crate
- ~4 weeks of careful refactoring
-
Phase 3: Extension development
- Now can build extensions using extracted graph-core
Outcome:
- Working app sooner (no upfront architecture design)
- More refactoring work later (higher risk of breaking things)
- Library extraction delayed to ~week 18β22
Phase 1 (Weeks 1β8): Build modular core, but ship monolithic app
-
Weeks 1β2: Design + prototype traits
-
BrowserEngine,UIBackendtraits (on paper) - Validate they work for Servo + egui
-
-
Weeks 2β5: Implement graph-core
- Pure
graphshell-graph-corecrate with physics, graph, wgpu rendering - Zero Servo/UI dependencies
- Headless test binary (validates core logic)
- Pure
-
Weeks 5β8: Integrate into monolithic Graphshell app
- Create
graphshellbinary that uses graph-core - Integrate Servo via trait (rough implementation OK for MVP)
- Integrate egui via trait (rough implementation OK for MVP)
- Ship working app
- Create
Phase 2: Keep monolithic; stabilize features
Phase 2β3 transition (~week 16β18): Clean-up refactor
- Formalize
BrowserEngineandUIBackendtraits - Move Servo code into separate
graphshell-servo-browsercrate - Extract egui code into separate
graphshell-ui-eguicrate - Library becomes publish-ready
Phase 3: Extensions
- Build
graphshell-chrome-extensionon graph-core - Build
graphshell-firefox-extensionon graph-core
Benefits:
- MVP still ships in 8 weeks (not delayed)
- Architecture is sound from the start (not a surprise refactor)
- Graph-core is ready for publication by week 16β18
- Extension pathway is clear from the beginning
- Less risk than full upfront modularization
New crates:
graphshell/
βββ graphshell-graph-core/ (NEW - pure library)
β βββ Cargo.toml
β βββ src/
β β βββ lib.rs
β β βββ graph/ (nodes, edges, graph container)
β β βββ physics/ (force simulation)
β β βββ renderer/ (wgpu rendering)
β β βββ traits/ (BrowserEngine, UIBackend)
β β βββ camera.rs
β β βββ types.rs (common types)
β βββ examples/
β βββ headless.rs (test harness without browser/UI)
β
βββ graphshell/ (existing, now uses graphshell-graph-core)
β βββ Cargo.toml (add graphshell-graph-core dependency)
β βββ src/
β β βββ main.rs
β β βββ browser/ (Servo BrowserEngine impl)
β β βββ ui/ (egui UIBackend impl)
β β βββ app.rs (wires graph-core + browser + UI)
β βββ ...
β
βββ graphshell-ui-egui/ (NEW - UI framework impl)
β βββ ...
β
βββ graphshell-servo-browser/ (FUTURE - separate Servo app)
βββ ...
Key design documents:
- Update
GRAPH_BROWSER_MIGRATION.mdwith new architecture section - Create
ARCHITECTURE.mdexplaining trait design + module responsibilities - Document
BrowserEngineandUIBackendtraits
The sketch notes propose a library-first, reusable approach vs. the current monolithic app approach.
| Aspect | Current Plan | Sketch Notes |
|---|---|---|
| Core artifact | Graphshell browser app | graphshell-graph-core library |
| Reusability | Graphshell-specific only | General spatial graph lib + extensions |
| Browser engines | Servo only (hardcoded) | Pluggable (Servo, Chrome API, Firefox API, headless) |
| UI frameworks | Single framework | Swappable (egui, GPUI, Xilem) |
| Extension path | Deferred; would require rewrite | Enabled from start; reuse graph-core |
| MVP timeline | 8 weeks | 8 weeks (with hybrid approach) |
| Testability | Full stack required | Graph core testable in isolation |
| Code reuse | None (monolithic) | High (library + multiple consumers) |
Recommendation: Adopt the hybrid approachβdesign modular traits upfront, implement graph-core as pure library (weeks 1β5), integrate into monolithic Graphshell app (weeks 5β8), then clean up separation in Phase 2β3 transition.
This adds minimal MVP delay (maybe 1 week for architecture upfront) but unlocks extension pathway and general-purpose library by Phase 3 start.