Strata approved layouts

The product app’s macro layout doctrine lives in apps/web-v2/docs/AGENT_APP_UI_CONVENTIONS.md (chat ↔ canvas ↔ sheets — read it for anything touching the chat surface). This doc is the index of approved page-level shapes; if the shape you need isn’t here, propose a new one — don’t improvise a bespoke layout.

The surface model

The product surface is chat + canvas + sheets. Chat is text and buttons only; everything else renders on the canvas as sheets. The chat column is the bounded resizable element (min 280, max 816); the canvas takes the rest.

Sheet types — pick by contract

SurfaceComponentUse for
Canvas sheetCanvasSheetAn artifact rendered full on the canvas. Stacks up to 3 deep with progressive recede; base sheet stays mounted.
Inspector panelWindowSheetRight-anchored resizable inspector/editor (min 400px).
WallDialog / AlertDialogAuth, paywall, destructive confirm — blocking, no artifact behind it.
Fullscreen editorFullscreenModalCreative builders and editors.

Stock shadcn Sheet is never used directly.

CanvasSheet — the law

  • Overlays are stacked CanvasSheets. Any overlay/detail view in a product area is a sibling CanvasSheet stacked above the base sheet — never a modal, never a nested child. stackedDepth on the sheet below controls the recede.
  • Headers are the standard sub-components, never hand-rolled JSX:
    • CanvasSheetChrome — sticky header for tabbed/toolbar sheets (NavTabs + optional CanvasSheetToolbar).
    • CanvasSheetHeader — eyebrow + title + actions for chrome-less sheets.
    • Vertical rhythm between chrome, toolbar, and CanvasSheetBody is automatic — never add manual pt-*/pb-*/gap-* between them.
  • Which sheet is open lives in URL search params or layout state, not in the page component.
  • No close behavior destroys underlying state — dismissing a top sheet lands exactly where the user left the sheet below.

WindowSheet — the composition

Right-anchored resizable inspector on Base UI Dialog (drag the left edge; defaultWidth/minWidth/maxWidth on WindowSheetContent, max defaults to 90% of viewport).

  • WindowSheetHeader children are the LEFT side (tabs or title); the actions prop is the RIGHT side (icon-only buttons). Header and footer are both 64px min-height, content centered.
  • WindowSheetBody is the scroll region — always use it, never a hand-rolled flex-1 overflow-y-auto. WindowSheetSection provides the padding; variant="secondary" tints a region. Forms inside are bare <form> + FieldSet.
  • WindowSheetTitle is required by the a11y contract — className="sr-only" when the header shows tabs instead of a visible title.

Area pages (product app)

  • Area navigation is NavTabs inside CanvasSheetChrome; filters are toolbar controls bound to URL search params (shareable state), all size="sm" (32px). Filter selects are text label + chevron only (no icons inside SelectTrigger); view toggles are TabsList size="sm" with text labels when an icon alone would be ambiguous.

  • DataTable is the one table. Every tabular surface uses it (sticky header, mono uppercase <th>, keyset-paginated data underneath — list APIs are cursor-based, never offset).

  • Grids use the shared grid classes — never a new one-off grid:

    ClassLives inMin columnContext
    content-gridpackages/ui/src/css/canvas-sheet.css240pxGenerations page, content picker sheet
    library-gridweb-v2 client/css/influencer-card.css272pxLibrary pages (influencers, media, products)
    builder-grid / builder-grid-smweb-v2 client/css/creative-builder.css240px / 180pxBuilder detail views inside FullscreenModal

Sheet footers

At most two actions: the primary (does the thing the sheet is about) and Discuss with Elle (always secondary, right-aligned, mono uppercase subtle style — closes the sheet and drops the artifact into the composer as context).

Marketing pages

Page shells and section building blocks are listed in brand.md — content pages compose from ContentLayout + the section kit, never bespoke section scaffolding.

Raw markdown for agents: /docs/layouts.md