This document defines the shared vocabulary and final layout architecture for Seed frontend app surfaces. It describes the desired system as the stable reference point for new features, layout refactors, and AI-agent implementation work.
If you want to check the current app layout state, you can see it here.
Core Vocabulary
Platform Shell
A platform shell is the outermost app frame owned by a specific runtime.
Seed has two platform shells:
DesktopShell for Electron-specific app chrome and local runtime affordances.
WebShell for browser and Remix-specific app chrome.
The platform shell owns runtime integration. It does not own feature content.
App Frame
The app frame is the shared layout boundary inside a platform shell. It provides the structural contract that feature routes render into.
The app frame owns:
Route viewport sizing.
Main content boundaries.
Optional route right panel placement.
Shared route-level action slots.
Intentional scroll containers.
Route Frame
A route frame is the reusable layout component used by a route when it needs a main content area and optional contextual right panel.
A route frame has two regions:
RouteFrame
MainContent
RightPanel? optionalRoutes render content into MainContent and provide panel descriptors for RightPanel.
Main Content
Main content is the primary route surface. It is the only region where route body content renders.
Examples:
Document content.
Feed.
Library.
Notifications.
Settings.
Agents.
Right Panel
A right panel is contextual UI attached to the active route.
Examples:
Comments.
Activity.
Directory.
Collaborators.
Document options.
Document versions.
Inspector/debug details.
Right panels are optional, route-addressable when their state affects navigation, independently scrollable, and resizable on desktop-class layouts.
App Panel
An app panel is a platform-level panel outside the route frame.
Example:
Desktop assistant panel.
App panels are not route right panels. They are owned by the platform shell.
System Layers
Seed frontend layout is organized into three layers.
Platform Shell
App Frame
Route Frame
Feature ContentPlatform Shell Layer
The platform shell layer owns runtime-specific chrome and capabilities.
Desktop shell responsibilities:
Electron window chrome.
Titlebar and native window controls.
Desktop sidebar.
Footer/status affordances.
Assistant app panel.
IPC-backed platform actions.
Web shell responsibilities:
Remix root document integration.
Server/client route loading boundaries.
Site host banners.
Web-only header/actions.
Browser navigation integration.
Platform shell code provides platform capabilities to shared code through adapters, context, or explicit props. Shared layout code does not import Electron APIs, Remix loaders, or browser-only globals directly.
Shared App Layout Layer
The shared app layout layer owns structure that behaves the same across platforms:
App frame.
Route frame.
Main content scroll container.
Optional right panel.
Panel headers and close affordances.
Panel sizing and persistence interfaces.
Route action slot placement.
Layout-level responsive behavior.
Shared app layout lives in @shm/ui and remains feature-agnostic.
Feature Layer
Feature code owns route content and feature state:
Documents.
Feed.
Comments.
Activity.
Directory.
Collaborators.
Settings.
Agents.
Notifications.
Feature code does not recreate platform shells or app frames. It provides content, actions, and optional right-panel descriptors to the shared layout layer.
Layout Regions
Desktop Layout
Desktop-specific shell regions are Titlebar, Sidebar, and AppPanel. The shared region is AppFrame.
Web Layout
Web does not implement the desktop sidebar, titlebar, or assistant app panel. Web still uses the shared AppFrame and RouteFrame concepts for main content and right-panel behavior.
Code Organization
The shared layout system uses these conceptual modules:
@shm/ui
app-frame
AppFrame
route-frame
RouteFrame
RouteFrameMain
RouteFramePanel
RouteFrameActions
resizable
ResizableGroup
ResizablePanel
ResizableHandle
PanelSizeStorage
shell-slots
ActionSlot
HeaderSlot
PanelSlot
Platform apps compose those modules through platform-owned wrappers:
frontend/apps/desktop
DesktopShell
DesktopTitlebar
DesktopSidebar
DesktopAssistantPanel
DesktopPlatformProvider
frontend/apps/web
WebShell
WebSiteBanner
WebHeaderActions
WebPlatformProvider
Feature routes consume the shared layout through stable imports from @shm/ui.
Route Contract
A route provides content and optional slots. It does not manage shell structure.
Canonical route shape:
<RouteFrame panel={panelDescriptor} actions={routeActions}>
<RouteContent />
</RouteFrame>The RouteFrame contract:
export type RouteFramePanel = {
key: string
title: string
content: React.ReactNode
width?: PanelSize
minWidth?: PanelSize
maxWidth?: PanelSize
onClose?: () => void
}
export type RouteFrameProps = {
children: React.ReactNode
panel?: RouteFramePanel | null
actions?: React.ReactNode
}Routes own:
Data loading and feature state.
Feature-specific providers.
Route-specific actions.
Choosing the active right panel.
Rendering panel content.
The route frame owns:
Main/right-panel split.
Panel header placement.
Close affordance placement.
Resize handle placement.
Scroll behavior.
Responsive behavior.
Slot layout.
Right Panel Contract
Right panels are described as data plus content.
export type RightPanelDescriptor = {
key: string
title: string
content: React.ReactNode
routeState?: unknown
size?: PanelSize
minSize?: PanelSize
maxSize?: PanelSize
}Rules:
key identifies the panel type.
title is displayed by the shared panel header.
content is feature-owned.
Navigation-relevant panel state is encoded in shared route state.
Ephemeral panel state, such as width, is persisted through panel-size storage.
Panel content scrolls independently from main content.
Resizable Layout Contract
Resizable behavior is exposed through Seed-owned layout primitives, not directly through third-party panel libraries.
<ResizableGroup direction="horizontal" storageKey="document-route">
<ResizablePanel id="main" minSize={50}>
<MainContent />
</ResizablePanel>
<ResizableHandle />
<ResizablePanel id="right-panel" minSize={20} maxSize={50} collapsible>
<RightPanel />
</ResizablePanel>
</ResizableGroup>Resizable layout rules:
Panel sizes are explicit percentages or named presets.
Panel size persistence is injected through a small storage interface.
Nested panel groups are scoped by group identity.
Route code does not call imperative resize methods.
Collapse and restore behavior is represented as layout state.
Complex coordination uses a local state machine inside the resizable layout implementation.
Scroll Model
Seed app layout uses intentional scroll containers.
Rules:
Platform root fills the viewport.
Platform shell does not scroll.
App frame does not scroll.
Route frame does not scroll.
Main content scrolls.
Right-panel content scrolls.
Sidebar content scrolls on desktop.
App panels scroll internally when their content overflows.
Required Tailwind layout patterns:
h-screen
h-full
min-h-0
min-w-0
overflow-hidden
overflow-y-auto
shrink-0
flex-1Every flex child that contains a scroll region includes min-h-0. Every horizontal flex child that contains route content includes min-w-0.
Platform Capability Boundary
Shared layout code accesses platform behavior through a platform capability interface.
export type PlatformLayoutCapabilities = {
platform: 'desktop' | 'web'
openExternalUrl?: (url: string) => void
windowControls?: {
minimize(): void
maximize(): void
close(): void
}
}Rules:
Platform capabilities are optional unless a platform wrapper requires them.
Shared layout components guard optional capabilities.
Shared layout components do not import Electron modules.
Shared layout components do not import Remix server APIs.
Browser globals are accessed at platform edges or through injected callbacks.
UI Primitive Boundary
The app/layout scaffold consumes UI through @shm/ui public wrappers.
Rules:
Feature and layout code import UI components from @shm/ui.
Feature and layout code do not import Radix, React Aria, or Ariakit directly.
Primitive-library choices remain hidden behind @shm/ui wrappers.
Layout architecture and primitive implementation are separate concerns.
This boundary allows the UI primitive implementation to evolve without changing the app/layout architecture vocabulary.
Naming Rules
Use these names consistently:
PlatformShell for runtime-owned outer shell concepts.
DesktopShell for the Electron shell.
WebShell for the browser/Remix shell.
AppFrame for the shared platform-inside layout boundary.
RouteFrame for a route's main content plus optional right panel.
MainContent for the primary route body.
RightPanel for contextual route UI.
AppPanel for platform-level side panels such as the assistant.
ResizableGroup, ResizablePanel, and ResizableHandle for Seed-owned resizing primitives.
Avoid using panel without a qualifier in new architecture docs or public APIs. Prefer RightPanel, AppPanel, or ResizablePanel.
Architecture Decisions
Seed shares the app frame and route frame across desktop and web.
Seed does not force desktop-only chrome into the web app.
Platform shells own platform chrome and runtime integration.
Feature routes provide content and slots; they do not recreate shell layout.
Right-panel identity is route-addressable when it affects navigation.
Panel dimensions are persisted separately from route identity.
Resizable behavior is hidden behind Seed-owned layout primitives.
UI primitive libraries are hidden behind @shm/ui wrappers.
Document-content styling is outside the app/layout scaffold.
Guidance for Developers and AI Agents
Before implementing layout-related work:
Name the layer being changed: platform shell, shared app layout, or feature.
Use the vocabulary in this document.
Prefer adding a slot or descriptor over duplicating layout structure.
Keep scroll containers explicit.
Keep route state and ephemeral layout state separate.
Do not combine primitive implementation changes with app/layout scaffold work.
Update this document when the vocabulary or final architecture changes.
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime