2026 02 12_architecture_reconciliation - mark-ik/graphshell GitHub Wiki
Two incompatible architectural proposals exist in the design docs:
Document: 2026-02-12_unified_architecture_plan.md
Core Idea: Single continuous spatial canvas where you zoom into nodes to see their web content rendered as textures ON the node surface.
Far zoom: [●]──[●]──[●] (nodes as icons)
Mid zoom: [preview] (thumbnail visible)
Near zoom: [┌────────┐] (webview fills viewport, rendered on node)
[│ content │]
[└────────┘]
Key Features:
- Thermal states (Active/Warm/Cold) based on camera distance
- Webviews rendered to textures composited onto node geometry
- No separate "views" — just zoom levels
- Nodes own their
Option<WebView>directly
Problem: This was NOT what the user proposed. This was my interpretation without verification.
Document: 2026-02-12_servoshell_inheritance_analysis.md
Core Idea: Use egui_tiles for layout management. Graph is one pane/tile, webviews are separate panes/tiles that can be arranged/docked.
┌─────────────┬─────────────┐
│ Graph │ WebView │
│ [●]──[●] │ ┌────┐ │
│ │ │ │page│ │
│ [●]──[●] │ └────┘ │
├─────────────┼─────────────┤
│ WebView │ WebView │
│ ┌────┐ │ ┌────┐ │
│ │page│ │ │page│ │
└─────────────┴─────────────┘
Key Features:
- Graph and webviews are sibling tiles in egui_tiles layout
- Drag-and-drop tiling/docking comes free
- Tab management automatic
- Multiple simultaneous webviews in separate panes
- Each webview tile gets its own
OffscreenRenderingContext
Alignment: This matches what the user actually asked for ("viewports containing webviews within the context of the graph view").
From archived docs (2026-02-10_crate_refactor_plan.md):
- "Replace exclusive view toggle with
egui_tilestiled layout" - "egui_tiles enables: graph AND detail view (simultaneous)"
From README.md:
- "Split view: egui_tiles for graph + detail simultaneously (Phase 2)"
From ARCHITECTURAL_OVERVIEW.md:
- "Split view (egui_tiles)" listed as future work
Conclusion: egui_tiles has been the plan all along.
The user said:
"I guess what I think makes sense is to use egui_tiles to organize viewports containing webviews within the context of the graph view. those viewports would reuse servoshell's tab ui although everything would be wired through the graph ultimately."
This explicitly describes:
- ✅ egui_tiles for organization
- ✅ Viewports (separate panes/tiles) containing webviews
- ✅ Reusing servoshell's tab UI
- ✅ Graph as source of truth (wiring)
Proposal A (continuous zoom) does NONE of these. It:
- ❌ Doesn't use egui_tiles
- ❌ Doesn't have separate viewport panes — just zooming into nodes
- ❌ No opportunity to reuse servoshell's tab UI (no separate tabs/panes)
- ❌ Fundamentally different interaction model
-
Rendering webviews as textures on nodes: Possible but requires exposing
OffscreenRenderingContext::texture_id(currently private) or implementing customRenderingContextthat exposes it - Smooth zoom UX: Every node at "warm" zoom needs a webview → resource intensive
- Interaction: How do you click links on a zoomed node while also dragging the graph? Input routing becomes complex
- ✅ egui_tiles 0.14.x compatible with egui 0.33.3 (confirmed)
- ✅ Multiple
OffscreenRenderingContexts supported by Servo API (verified in source) - ✅
render_to_parent_callback()pattern works per-tile (servoshell already uses it) - ✅
browser_tab()widget directly reusable inBehavior::tab_ui() - ✅ Graph can be one pane while webviews are other panes
Decision: Pursue Proposal B. It matches:
- The user's explicit request
- Historical documentation direction
- Technical feasibility analysis
- Minimal divergence from existing codebase
2026-02-12_unified_architecture_plan.md should be:
- Archived or marked as "Alternative approach — not pursued"
- Or replaced with an egui_tiles-aligned plan
The continuous zoom approach might be interesting future work, but it's not what was requested and not what the historical docs point toward.
pub struct Gui {
tiles_tree: egui_tiles::Tree<TileKind>,
tile_behavior: GraphshellTileBehavior,
// One rendering context per visible webview tile
rendering_contexts: HashMap<NodeKey, Rc<OffscreenRenderingContext>>,
// Favicon cache remains per-webview
favicon_textures: HashMap<WebViewId, (TextureHandle, SizedTexture)>,
// Graph state
graph_app: GraphBrowserApp,
// ... other state ...
}
pub enum TileKind {
Graph, // The force-directed spatial canvas
WebView(NodeKey), // A webview displaying this node's content
}
impl egui_tiles::Behavior<TileKind> for GraphshellTileBehavior {
fn tab_title_for_pane(&mut self, pane: &TileKind) -> WidgetText {
match pane {
TileKind::Graph => "Graph".into(),
TileKind::WebView(node_key) => {
// Query graph_app.graph.get_node(node_key) for title
}
}
}
fn pane_ui(&mut self, ui: &mut Ui, tile_id: TileId, pane: &mut TileKind) -> UiResponse {
match pane {
TileKind::Graph => {
// Existing render::render_graph(ctx, graph_app)
}
TileKind::WebView(node_key) => {
// Get or create OffscreenRenderingContext for this node
// Get webview from graph_app via node_key
// Call webview.paint()
// Register egui PaintCallback with render_to_parent_callback()
}
}
}
fn tab_ui(&mut self, tiles, ui, id, tile_id, state) -> Response {
// Reuse existing browser_tab() function
// Pull data from graph_app.graph instead of WebViewCollection
}
}- Add egui_tiles dependency (Cargo.toml)
- Define TileKind enum (Graph + WebView variants)
-
Implement minimal Behavior:
-
pane_ui()dispatches to graph rendering or webview rendering -
tab_title_for_pane()queries graph for node title
-
-
Per-tile rendering contexts:
- Create one
OffscreenRenderingContextper visible WebView tile - Wire
paint()+render_to_parent_callback()per tile
- Create one
-
Graph-driven tile management:
- Clicking a graph node creates/focuses its WebView tile
- Navigation in a webview creates new node + new tile
- Closing a tile updates graph state
| Current | egui_tiles |
|---|---|
View enum (Graph/Detail) exclusive toggle |
egui_tiles::Tree with multiple simultaneous tiles |
Monolithic update() with view branching |
Behavior::pane_ui() dispatch per tile |
Single shared OffscreenRenderingContext
|
One context per visible webview tile |
| Tab bar only in detail view | Tab bar per container, managed by egui_tiles |
webview_controller.rs manage_lifecycle |
Tile creation/destruction via egui_tiles API |
-
All Servo integration:
running_app_state.rs,window.rs -
Graph data structures:
graph/mod.rs,GraphBrowserApp - Persistence: fjall + redb + rkyv unchanged
- Physics: Worker thread, KD-tree, all intact
-
Platform layer:
headed_window.rs,platform/unchanged
-
Archive or deprecate
2026-02-12_unified_architecture_plan.md - Update INDEX.md to list the new docs under implementation_strategy
-
Rename
2026-02-12_servoshell_inheritance_analysis.mdto something like2026-02-12_egui_tiles_architecture.md(since it's now the official plan) - Create a spike: Minimal egui_tiles integration to prove the concept
Without reconciliation, future work could go in the wrong direction. The continuous zoom idea (Proposal A) is architecturally interesting but:
- Not what was requested
- More complex to implement
- Doesn't align with historical documentation
- Requires more Servo API changes
The egui_tiles approach (Proposal B):
- Matches the explicit user request
- Aligns with historical docs
- Technically verified as feasible
- Reuses more existing code
- Clearer migration path from current codebase