Frame Design System

Frame’s Purpose

  • Experience: An elegant design language and clear structure let the product speak for itself.
  • Collaboration: A design language that people and AI can read, reuse, verify, and evolve together.
  • Assurance: Design principles → AI-readable rules → installable components → automated design checks → validation in real products.
  • Community: The public design foundation is open source, with components validated in real products available to install. View on GitHub
  • Agent Plugin candidate: Design and audit reliable conversational and agentic AI products—from chat and voice to tool use, citations, confirmations, failure and recovery, and human-in-the-loop control—using Frame principles, released components, implementation rules, and verifiable checks. Privacy · Support
  • Built for: Designers, developers, and product teams creating reliable conversational and agentic AI products.

Operating Model

One system, shared across products. Use this guide to find the right source, see how each product uses the system, and understand how design work is checked before release.

One source, many consumers

  • Frame Design System

    Shared across products

    • WorkPal (Workspace)

      WorkPal interface preview showing the desktop workspace and mobile assistant.
    • Wingman (Dating Space)

      Wingman interface preview showing desktop dating preferences and the mobile companion.

What the design system and products each own

Shared design system

  • Design principles and shared documentation content
  • Color, typography, spacing, radius, motion, and theme tokens
  • Reusable primitives, promoted patterns, and their shared variants
  • The company catalog examples that explain those shared definitions

Product code

WorkPal and Wingman directly use the shared components, layouts, and variants provided by packages/design-system; each product configures which ones to use and how they appear, then connects its own features, data, routing, and business logic.

How Codex and Claude Code execute design work

  1. Read the project-level AGENTS.md or CLAUDE.md, then the repository design guidance and applicable product specification.
  2. Check the Component Library first and reuse a shared component wherever possible.
  3. If nothing fits, register and showcase the new shared primitive in the package and company catalog. For WorkPal-originated gaps, also add it to WorkPal's Review Queue for approval.
  4. Run design-lint, relevant tests, and builds; visually verify the affected page, responsive states, and both themes when applicable.

Automated assurance

The assurance model has three layers. Each catches a different kind of risk, from code-level rules to the final page.

Layer 1 — Static rules

Active today. design-lint enforces selected hard rules on new UI changes: token and typography discipline, no emoji in product UI, and touch-target risk warnings. Build validation confirms affected applications compile.

Layer 2 — Component and accessibility contracts

Product-level coverage is active today: tests already verify shared component behavior and accessibility in the applications that use them. Next, this coverage will be consolidated into a consistent design-system contract layer.

Layer 3 — Visual regression

Planned. Repeatable screenshot comparisons will protect stable pages across themes, states, and responsive layouts from unintended visual change.

Public AI implementation resources

Use the public guide and rules to implement with Frame. They support alignment but do not certify design quality, accessibility, correct behavior, or complete compliance; human review remains necessary.

Principles

These 13 principles guide every UI design decision made by designers and Coding Agents, with DESIGN_SYSTEM.md §3 as the single source of truth. Five also map to mandatory implementation rules in the repository-root AGENTS.md, with the corresponding rule number shown on each principle.

The 11 hard implementation rules live separately in the repository-root AGENTS.md §2; the two sets complement each other, and overlapping entries cross-reference both ways. Principle #7’s “13 text styles” counts typography tiers — a coincidence, not these 13 principles.

  1. 1
    Shared-first

    Build reusable UI in packages/design-system/src/shared.tsx, then import into pages. Never copy component code inline. Implementation rule: AGENTS.md §2 #5.

    Why: One source of truth means token changes propagate everywhere automatically.

    See Component Library →
  2. 2
    Tokens-first

    Use CSS variables and utility classes for every color, size, and spacing. Never hardcode hex, px font sizes, or arbitrary spacing values. Implementation rule: AGENTS.md §2 #1.

    Why: Tokens are the only way light/dark mode and future rebrands stay coherent.

    See Foundations →
  3. 3
    One Primary button per view

    Use PrimaryButton (gradient CTA) at most once per view. Multiple gradient CTAs dilute the focal point.

    Why: The gradient is a visual anchor — duplicating it creates ambiguity about the primary action.

  4. 4
    1–2% gradient budget

    The brand gradient (#7652B9 → #B46470 → #CA9D8C) is reserved for the single focal element per view: the primary CTA, a hover affordance, or a hero title.

    Why: Gradient saturation breaks the hierarchy and reads as decorative rather than meaningful.

  5. 5
    Callouts are blue, not gradient

    Use --color-accent-blue (#3171FF) for selected chips, links, progress, and focus rings. Never substitute the brand gradient for these signals.

  6. 6
    StatusTag success green is unique

    The success tokens (--color-accent-green / --color-accent-green-bg) appear only inside StatusTag variant="success". Do not repurpose them for other UI.

    Why: Reserving the color keeps "success" visually unambiguous across the product.

  7. 7
    13 text styles only

    Use .type-display-xl, .type-display, .type-h1, .type-h1--emphasized, .type-body, .type-body-emphasized, .type-h2, .type-h2-emphasized, .type-h3, .type-detail, .type-detail-emphasized, .type-caption, .type-footnote. Never use raw px sizes or Tailwind’s native type/weight scale (text-sm, text-base, font-bold, font-medium …). Forbidden running-text sizes: 9, 10, 13, 17, 18, 24, 28, 32 px. 11/12 are valid only via .type-footnote / .type-caption. ("13" here counts the text-style tiers — it is a coincidence that there are also 13 principles.) Implementation rule: AGENTS.md §2 #2.

    See Foundations →
  8. 8
    Icons = lucide-react

    All icons come from lucide-react. No emoji in product UI. Never render letters or abbreviations as icon stand-ins. Never import another icon library or inline SVG. Implementation rule: AGENTS.md §2 #6.

    See Foundations →
  9. 9
    Dark-mode is automatic

    All colors must come from CSS variables bound to :root / .dark. Monochrome PNG assets use .icon-theme for auto-inversion. Lucide SVGs inherit currentColor.

  10. 10
    Three-panel shell

    Every feature is a slot inside NavPanel, ConversationPanel, or InspectorPanel. Do not introduce new top-level chrome.

    See Layout →
  11. 11
    Review queue for new components

    If an existing shared component cannot satisfy a need, build the new one in packages/design-system/src/shared.tsx and add it to the company viewer catalog. When the candidate originates in WorkPal, also register its promotion status in WorkPal's Review Queue tab. Approved components stay in shared.tsx; rejected ones revert to the closest existing primitive.

  12. 12
    Bg fill or border, not both

    A card / panel uses EITHER a background fill (bg-bg-hover, bg-bg-page, bg-card, etc.) OR a border (border-stroke-outline) — never both on the same surface. Pick whichever creates the right visual separation in the surrounding context. Default for an inline mini-preview, intro card, or hover zone is bg fill; default for a free-standing card on the page background is border-only. Exception: dashed borders (border-dashed) carry placeholder/skeleton/drop-zone semantics and may coexist with bg fills. Implementation rule: AGENTS.md §2 #4.

    Why: Stacking bg-change + border on the same element produces a redundant double-frame — either signal alone is enough to lift the element from its surroundings. Doubling competes with surrounding chrome and breaks the design's quiet hierarchy.

  13. 13
    Tab structure — Pattern A or Pattern B

    Documentation tabs follow one of two structures. Pattern A: Intro card → L2 SectionTitle (OUT of box) → content WRAPPED in a single border-only box (rounded-2xl border-stroke-outline p-5); use it for Foundations, Components, Review, Layouts, and AI Interaction Patterns. Pattern B: Intro card → flat list of cards (no L2 wrapper) → each card has IN-box L3 title (16px); use it for Principles, Agent Videos, and Voice & Tone. Same-level content must look identical across tabs: every Pattern A section content uses the same box chrome; every Pattern B card uses the same chrome.

    Why: Without this rule, sections drift between in-box and out-of-box across tabs (cf. App Shell vs Color Palette vs 8.X Pattern), and same-level content uses different sizes (Principles 16px vs Agent Videos 22px). The border-box wrap on Pattern A also gives the section visual closure — a SectionTitle followed by bare paragraphs reads as "loose copy", not "section content".

AI Interaction Patterns

Composed flows for AI surfaces — one level above components: a pattern says "for problem X, here's the canonical shape we converge on." Single source: content/aiPatterns.tsx.

Read the standalone AI interaction patterns guide
Pattern status:Shippedraw material exists in componentsPartialpieces exist, gaps remainspec reserved, no component yet

Conversation layout — Prompt / Reply / Grow

Shipped

Every AI conversation unit follows a three-segment skeleton. This is the macro layout — the per-segment patterns below are how each segment fills in. All gaps are tokens from Foundations → Spacing: inter-segment --space-6 (24px), intra-segment --space-4 (16px).

Prompt — user bubble
Reply — text answer (markdown)
Reply — card / image / citation (optional)
Grow — text suggestion with bold optionsGrow — answer toolbar (TTS · Copy · Share · Upvote · Downvote · Regenerate)

↓ ChatInput area (separate from the message above) — `Message.chips` renders here automatically:

Don't

  • Stack two MessageCards in one Reply — pick the primary deliverable.
  • Render AI's follow-up options as inline buttons in the message body — write them as bold spans inside the markdown, and emit clickable shortcuts via message.chips: ActionChip[] so ChatInput shows them above the textarea (one canonical interaction pattern).
  • Skip the Toolbar on assistant messages — Retry is the "model misread me" escape hatch.

Anatomy

ChatMessage covers both the user and assistant variants; ArtifactCard is one alternative Reply payload. renderMarkdownBlocks is a shared module, not a gallery component. MessageCard · TypingIndicator · WebSourceChips · ImageResultsGrid · VideoResultsGrid · FeedbackBar are app-local (WorkPal's ChatMessage.tsx / its own MessageCard.tsx, which is a different component from the shared gallery's MessageCard despite the shared name), not shared primitives — there is no gallery entry to link. Action chips: message.chips → ChatInput renders via the existing <Chip /> primitive.

Streaming

Shipped

Problem

The model produces tokens incrementally (200ms–10s). Users need to (a) see progress immediately, (b) stop generation, (c) trust that "no movement" means done, not stuck.

Pattern

  • Render tokens as they arrive (no buffer-then-flush) inside the ChatMessage assistant bubble.
  • Show a 3-dot brand-gradient loader (.loading-dot) when the stream hasn’t started yet (network round-trip).
  • Token arrival itself signals liveness — no extra blinking caret needed during active streaming.
  • Show a Stop affordance in the composer while streaming; collapses to Send when done.
  • Entry animation uses var(--motion-duration-normal) var(--motion-ease-decelerate) — see .message-appear.

Don't

  • Don’t buffer tokens to render whole sentences. Buffering looks frozen and breaks the trust loop.

Anatomy

Assistant variant of ChatMessage, with the 3-dot .loading-dot ahead of the first token and a Stop affordance in ChatInput while the stream runs.

Citation

Partial

Problem

Model output makes claims that need to be traceable to source material (a doc, an email, a meeting transcript, a URL). Without citations, every AI claim has the same trust level — which means none.

Pattern

  • Inline citation: a .type-footnote chip with a leading source-type icon (File, Mail, Calendar, Link). Click → opens the source in DetailPanel.
  • Multiple citations stack with gap-1, never wrap mid-sentence — push the entire group to end-of-paragraph if needed.
  • Source preview: hovering surfaces a Tooltip (dark, --color-tooltip-bg) with the source title + 1-line excerpt.
  • Use --color-accent-blue for the citation chip text — consistent with link styling, marks it as a navigation affordance.

Anatomy

The chip itself is still ad-hoc: a .type-footnote span + a lucide source icon, with Tooltip carrying the source preview. Promote to <Citation /> in shared.tsx when a second consumer appears.

Confirmation

Shipped

Problem

The agent is about to take a side-effecting action (create ticket, send email, run script). Doing it silently breaks user agency; asking before every action breaks the autonomy promise.

Pattern

  • Side-effecting actions render a MessageCard variant (ticket, schedule, meeting) with a preview + explicit confirm/cancel pair.
  • Confirm = PrimaryButton (gradient — one per card). Cancel = TertiaryButton.
  • Reversible read-only actions (search, summarize, draft) skip confirmation — go directly to result.
  • After confirm, the card collapses to a StatusTag row showing the result.
  • "Don’t ask again for X" is reserved for repeated identical actions in the same session — never persist across sessions without explicit consent.

Anatomy

MessageCard is app-local (WorkPal's own MessageCard.tsx, not the shared gallery's MessageCard of the same name) — no gallery entry to link.

Undo

Problem

Even with confirmation, the agent’s action lands in the real world (ticket created in Linear, email drafted in Gmail). User needs a way to back out within seconds without going to the source system.

Pattern

  • After a side-effecting action lands, the resulting MessageCard shows an Undo affordance for N seconds (default 10s for low-stakes; 30s for irreversible-ish like sending email).
  • Undo countdown uses a token-exempt loop duration (10s/30s — like progressFill bespoke timing).
  • Undo collapses the card to "Reverted" StatusTag (neutral variant).
  • After the window expires, the Undo affordance is replaced by a permanent link to the action source ("View ticket in Linear").

Anatomy

No shared component yet.

Placeholder. Spec reserved here so when the Undo flow ships it converges on this shape.

Confidence / Status

Shipped

Problem

Not every AI output is a finished result — some are guesses, some are partial, some are awaiting user input. A flat list of messages hides this distinction; users default to either over-trusting or never trusting.

Pattern

  • Use StatusTag (8 variants) on every AI-produced artifact card to signal where it sits.
  • Map: generating → in-progress (blue). Finished, awaiting user → in-review (amber). Approved → success (green). Rejected/failed → failed (red). Sent to external system → submitted (violet). Blocked on missing input → pending (orange).
  • Never use raw probability numbers ("87% confident") — they imply false precision. Use the categorical pills.
  • Insight-level content uses InsightCard ("Maya’s insight") as a higher-confidence signal — reserved for synthesized observations, not raw output.

Anatomy

StatusTag carries the semantic state; InsightCard marks insight-grade content.

Tool transparency

Problem

The agent calls tools (search docs, query Calendar, run code). When something goes wrong — or even when it goes right — the user needs to know what the agent did, not just the final answer. Black-box agents collapse trust the moment they’re wrong once.

Pattern

  • Every tool call emits a collapsed TaskProgressCard-like row inside the ChatMessage: tool icon + tool name + 1-line input summary + status.
  • Default state: collapsed. Expanded view shows full input + output (truncated to 200 lines, "View raw" link for the full payload).
  • Multiple tool calls in one turn stack vertically inside a single card with StepIndicator glyphs (done/in-progress/pending).
  • Failed tool calls surface inline immediately (red StatusTag), not folded into the agent’s natural-language response.
  • Use --color-accent-violet for the agent’s "calling tool X" header to distinguish from user-initiated actions.

Anatomy

Placeholder. TaskProgressCard has the structural pieces (collapsible, step list); needs a tool-call-specific variant.

Hallucination / Uncertainty disclosure

Problem

The model produces confident-sounding output even when its source coverage is thin or it’s interpolating. A flat assistant bubble makes "confident facts" and "best guesses" look identical — users either over-trust everything or learn to under-trust everything.

Pattern

  • Three uncertainty grades, three visual signals — Cited fact: claim has a Citation chip per the Citation pattern. Default trust level.
  • Synthesis: model’s interpretation of cited material (no chip needed). Standard body text.
  • Inference / guess: model has no source and is interpolating. Render in text-text-tertiary with an inline marker chip (StatusTag neutral variant + ? icon) immediately preceding the inferred sentence/clause.
  • "I don’t know" mode: when the model can’t answer with reasonable confidence, the assistant message is a single short paragraph naming the gap and offering a path forward (e.g. "I don’t have access to that calendar yet — connect it on Connectors to ask again."). Voice from Voice & Tone → Style guide; ladders into the Refusal & safety pattern.
  • Never show probability numbers ("87% confident"); they imply false precision. Categorical pills only — same rule as Confidence / Status.

Don't

  • Rendering inferred content in standard body text without any marker. Better to over-disclose and break user immersion than over-trust into a hallucination loop.

Anatomy

StatusTag neutral is the uncertain marker and text-text-tertiary renders the inferred segment; cited segments carry Citation chips (see the Citation pattern), and synthesis stays in the standard ChatMessage body.

Status

Placeholder. No component yet. The pieces (StatusTag, citation chip prototype, tertiary text token) all exist; spec reserved here so the first hallucination-aware flow converges on this shape rather than re-inventing.

Memory surface

Shipped

Problem

An assistant that "remembers you" is hostile if the memory is invisible. Users can’t verify what’s stored, can’t correct stale facts, can’t remove sensitive entries — and silently-applied memory feels manipulative even when it’s working.

Pattern

  • Dedicated MemoryPage (src/components/MemoryPage.tsx) lists every stored memory grouped by kind. Three kinds: Core — always-on user facts (role, language, locale). Preference — how-to-collaborate guidance ("reply in Chinese", "skip the summary"). Project — facts scoped to a specific project.
  • CRUD must be inline + immediate. Add via inline MemoryForm, edit/delete on each row, no modal indirection. Memory writes that need protection pop a PasswordModal; never silent.
  • In-conversation reference: when the assistant uses a memory in its reply, surface the trigger inline as a citation-style chip (same pattern as Citation) so users can click → MemoryPage → verify or edit. (Not yet shipped — see status note below.)
  • Filter chip row: FilterChip for All / Core / Preference / Project lets users browse what’s stored without a search. Empty state per Voice & Tone → Empty-state copy.

Don't

  • Silent memory writes ("I’ll remember that for next time") with no visible record. Always confirm or surface what’s being saved within the same turn.

Anatomy

FilterChip drives both the kind filter and the kind selector inside the inline MemoryForm. MemoryPage.tsx (CRUD shell), MemoryForm and PasswordModal (write gate) are app-local, not shared primitives.

Status

Shipped — see src/components/MemoryPage.tsx. The in-conversation memory citation chip is the next gap; promote alongside the Citation pattern when the second consumer of the chip primitive appears.

Retry / Regenerate / Fork

Partial

Problem

The model’s first attempt isn’t always right — wrong tone, missed constraint, hallucinated detail. Users need a low-friction escape to "try again" without re-typing the prompt or losing the original.

Pattern

  • Retry button sits on the assistant message toolbar (FeedbackBar in ChatMessage.tsx, far right after Bad). Clicking re-runs the same prompt with fresh sampling. Always present on assistant messages — see the locked toolbar order in Conversation layout.
  • Regenerate-with-mode (proposed): a small caret next to Retry expands a popover with single-tap mode shifts — more concise / more detail / change tone / try a different angle. Each prepends a system instruction to the regen call. Closing the popover defaults to plain Retry.
  • Fork, not replace: a regenerated reply lands as a sibling of the original assistant message, with both reachable through a 1/2 ▸ 2/2 navigator at the top of the bubble. Never destroy the prior reply — users often want it back after seeing a worse regeneration.
  • Regen counter cap: after 5 sibling regens for the same prompt, surface a hint to refine the prompt instead. Prevents low-value churn.

Don't

  • In-place replacement that destroys the rejected reply. Loses the user’s anchor for "I didn’t like the part where you said X."

Anatomy

The Retry button lives in the app-local FeedbackBar inside apps/workpal/src/components/ChatMessage.tsx. Still proposed: the sibling-thread navigator and the regen-mode popover.

Status

Partial. Toolbar Retry button is rendered but no regenerate handler is wired up; click is a no-op today. Promote when the first regen flow ships.

Refusal & safety

Problem

Sometimes the assistant can’t or won’t help — out-of-scope task, missing connector, destructive action, sensitive content. A flat "I can’t help with that" feels dismissive and severs the conversation. Refusals are part of the trust loop, not error states.

Pattern

  • Refusal copy follows the Voice & Tone chapter — name the gap, offer the next step. Categories: Capability gap (no tool): "I can’t run shell commands yet — let me know what you’re trying to do and I’ll suggest the steps." · Permission gap (need user to connect): "I don’t have access to your calendar yet. Connect it on Connectors to ask again." · Policy refusal (destructive / irreversible): "I can’t move money for you, but I can draft the steps if you’d like." · Safety refusal (could harm user): handled with the same calm-structured tone — never lecturing, never moralizing.
  • Visually a normal assistant message, no special chrome. Refusals are part of the conversation, not error states. Do not wrap in a red error card — that conflates "I refused" with "system broke."
  • Optional StatusTag neutral with label "Out of scope" if a downstream surface needs to filter refusal turns later (e.g. analytics dashboard).
  • Never expose: stack traces, policy names, model IDs, or "as an AI language model…" preambles. The user needs the gap and the path forward, nothing else.

Don't

  • Terse "I can’t help with that" with no reason and no path forward. Drops the user into a dead end and breaks the Voice & Tone → Brand philosophy promise of empathetic + structured.

Anatomy

A standard assistant-variant ChatMessage with the voice templates pinned in Voice & Tone. StatusTag neutral is optional, for surface-level classification.

Status

Placeholder. No component-level affordance needed (it’s a copy/voice pattern). Voice templates pinned here; promote to a dedicated Voice & Tone section ("Refusal copy templates") when a second refusal surface appears.

Voice & Tone

Two layers: a shared baseline both products inherit, plus a per-product personality profile. Single source: content/voiceTone.tsx.

Shared baseline

Tone — by situation

The baseline shifts subtly with the emotional weight of the moment. Never drop the calm-structured floor; only flex the warmth dial.

Situation
Tone style
Example response
✅ Task completed
Warm, affirming, lightly celebratory
"All done! You can relax now, I’ve got this 😊"
⚠️ User made a mistake
Gentle, non-judgmental, supportive
"Looks like we’re missing a file — no worries, let’s fix it together."
❓ Uncertainty / hesitation
Clear, helpful, reassuring
"I’ve got a few options. Want to take a look and choose what fits best?"
📈 Offering suggestions
Logical, structured, calm
"Here are three key insights: 1. Time usage, 2. Repetitive tasks, 3. Collaboration gaps."
Voice personality traits

The five baseline traits below describe how WorkPal speaks before any user personalization. They are the floor, not the ceiling.

Trait
Description
Inclusive
Welcomes users of all levels. Never rushes, never pressures.
Kind
Speaks like a trusted colleague — professional yet human.
Structured
Provides clarity with clean, step-by-step responses.
Reliable
Remembers your progress, fills in gaps, never lets you do extra work.
Calm
Stays steady during chaos, offering logic and composure.
Style guide for language
  • Avoid cold or technical jargon. "Error 404" → "Can’t find the file, want to retry?"
  • Friendly use of emojis (context-dependent): 😊 👍. At most once per message; never in error/warning copy.
  • Keep sentences short, smart, and clear. One idea per sentence.
  • Never cutesy or forced — just steady, helpful, and warm.
Sample phrases (UI / system surfaces)
Context
Phrase
Starting
"Ready when you are."
Task done
"All done. What’s next?"
Processing
"I’m on it. Just a sec."
Error hint
"Looks like we’re missing a file."
Error message templates

Pattern: identify the issue + offer the next step. Never just "Error" or a status code. Never expose HTTP codes, stack traces, or model names to the user.

Situation
Avoid
Use
Required field empty
"This field is required."
"Add a name so we can save it."
Network failure
"Network error."
"Couldn’t reach the network. I’ll retry — or you can."
Permission denied
"403 Forbidden."
"I don’t have access to that yet. Connect it on the Connectors page?"
Model overloaded
"503 Service Unavailable."
"Servers are busy right now. Try again in a moment."
Unsaved changes
"You have unsaved changes."
"You have unsaved edits — save before leaving?"
Unknown / catch-all
"Something went wrong."
"Something didn’t go through. Want me to try again?"

Product profiles

Brand philosophy

Born from the best people you've worked with.

WorkPal is a calm, structured, and empathetic AI assistant — built not just to execute tasks, but to understand your pace, lighten your load, and always be there when you need support.

Personalization philosophy

Personalization builds on the baseline — it enhances, but doesn't replace the core identity.

  • Parasocial bonding. When users assign traits they admire, they project the warmth and trust they associate with real people — deepening trust and acceptance.
  • Participation builds connection. When users shape the assistant's tone or appearance, that involvement strengthens emotional connection and creates ownership and belonging.

12 personality traits — drag 3 into "important" zone (top-3 carry extra weight; the rest still shape the agent at lower weight). Lives in src/components/Onboarding.tsx.

StableOrganizedKindCalmOpen-mindedPeople-firstAlways smilingHas a sense of humorEnergeticMinimalFormalNot sure yet
UX strategy matrix — by task state

What the interaction surface does in each state. Decisions ladder up to the AI Interaction Patterns tab.

Task state
UX interaction strategy
✅ Task completed
1. Proactive suggestion of next steps based on inferred intent (uses MessageCard follow-up chips)
❌ Task incomplete / failed
1. Intent clarification & input reconstruction · 2. Alternative action suggestion · 3. Progressive disclosure (show error reason on demand, not by default)
Empty-state copy templates

For the EmptyState component. Title is short and action-oriented; description optional.

Surface
Title
Description
No chats yet
Ready when you are.
Start a conversation — I’ll keep track of where we left off.
No projects
Nothing here yet.
Create a project to bring tasks, files, and conversations together.
No search results
Nothing matched.
Try a different word, or browse recent items.
Connector not connected
Not connected yet.
Connect to bring your data into WorkPal.
No tasks pending
All caught up. ✨
Nothing waiting on you. Take a moment.
No notifications
All quiet.
I’ll let you know when something needs your attention.
Agent tags (role-title)

Shown after the name in the welcome carousel's centered pill — e.g. "Lily-The Research Partner".

MattThe Creative Teammate"Tell me the whole story."
MayaThe Project Driver"The more we talk, I'll understand you better, and you'll understand yourself better—helping your relationships thrive."
LilyThe Research Partner"Honest conversations create better connections."

Foundations

Color tokens

#

CSS variables with light + dark themes baked in. Toggle the moon/sun to compare. Each token shows its var name, the resolved value at the current theme, the canonical Tailwind class, and the primitives that consume it (click the eye toggle to expand).

Surface

bg-page

--color-bg-page

—

bg-bg-page

9 primitives
  • PageLayout
  • SearchBox
  • StepIndicator
  • StatusTag
  • DarkToggle
  • SidebarSectionToggle
  • ConnectorCard
  • AttachmentChip
  • ChatPanel

bg-message

--color-bg-message

—

bg-bg-message

7 primitives
  • DarkToggle
  • AgentRequiredHint
  • ChatMessage
  • VoiceWaveform
  • AttachmentChip
  • ChatInput
  • ChatWelcomeState

bg-hover

--color-bg-hover

—

bg-bg-hover

21 primitives
  • SearchBox
  • SectionCount
  • ProgressBar
  • HeaderIconButton
  • MenuRow
  • IconBadge
  • StatusStrip
  • DarkToggle
  • AvatarMenu
  • AddRowButton
  • TextField
  • AutocompleteField
  • Chip
  • SolutionRow
  • ChoiceCard
  • InsightCard
  • TaskProgressCard
  • EmptyState
  • AttachmentChip
  • ChatInput
  • ChatWelcomeState

sidebar

--color-sidebar-bg

—

bg-bg-sidebar

no primitive uses

card-panel

--color-card-panel-bg

—

bg-bg-card

3 primitives
  • ArtifactCard
  • AgentRequiredHint
  • MessageCard

Text

text-primary

--color-text-primary

—

text-text-primary

52 primitives
  • HeaderBar
  • SearchBox
  • SidePanelHeader
  • SideCard
  • ToolbarPill
  • ToolbarIconButton
  • ToolbarSegmented
  • Switch
  • Checkbox
  • SectionCount
  • SectionTitle
  • ProgressBar
  • CategoryBreakdown
  • StepIndicator
  • TertiaryButton
  • GhostPillButton
  • HeaderIconButton
  • IconButton
  • MenuRow
  • IconBadge
  • TextButton
  • UserAvatar
  • DarkToggle
  • AvatarMenu
  • TextField
  • AutocompleteField
  • RangeSlider
  • DualRangeSlider
  • NavItem
  • SidebarSectionToggle
  • ConnectorCard
  • FilterChip
  • Chip
  • UtilityChip
  • SolutionRow
  • SummaryFooter
  • MetricCard
  • InsightCard
  • AreaChart
  • TaskProgressCard
  • HealthDimensionRow
  • ReviewItemCard
  • ArtifactCard
  • EmptyState
  • VersionRow
  • AgentRequiredHint
  • ChatMessage
  • AttachmentChip
  • ChatInput
  • ChatPanel
  • ChatWelcomeState
  • MessageCard

text-secondary

--color-text-secondary

—

text-text-secondary

24 primitives
  • Switch
  • Checkbox
  • CategoryBreakdown
  • HeaderIconButton
  • MessageActions
  • SegmentedToggle
  • MenuRow
  • StatusStrip
  • TextButton
  • ResourceLinkCard
  • AvatarMenu
  • AddRowButton
  • TextField
  • AutocompleteField
  • RangeSlider
  • DualRangeSlider
  • ConnectorCard
  • ChoiceCard
  • EmptyState
  • VersionRow
  • ChatMessage
  • AttachmentChip
  • ChatInput
  • MessageCard

text-tertiary

--color-text-tertiary

—

text-text-tertiary

4 primitives
  • MenuRow
  • ConnectorCard
  • VersionRow
  • ChatInput

Stroke

stroke-outline

--color-stroke-outline

—

border-stroke-outline

18 primitives
  • ToolbarPill
  • ToolbarSegmented
  • Switch
  • Checkbox
  • StepIndicator
  • StatusTag
  • TertiaryButton
  • GhostPillButton
  • SegmentedToggle
  • AvatarMenu
  • RangeSlider
  • DualRangeSlider
  • ConnectorCard
  • FilterChip
  • Chip
  • UtilityChip
  • ChoiceCard
  • AttachmentChip

Selected

selected-bg

--color-selected-bg

—

bg-selected-bg

9 primitives
  • ToolbarSegmented
  • Switch
  • Checkbox
  • IconButton
  • SegmentedToggle
  • FilterChip
  • Chip
  • ChoiceCard
  • ChatMessage

selected-text

--color-selected-text

—

text-selected-text

9 primitives
  • ToolbarSegmented
  • Switch
  • Checkbox
  • IconButton
  • SegmentedToggle
  • FilterChip
  • Chip
  • ChoiceCard
  • ChatMessage

Accent

accent-blue

--color-accent-blue

—

text-accent-blue

4 primitives
  • SampleWorkspaceLabel
  • ResourceLinkCard
  • ChatInput
  • ChatWelcomeState

accent-green

--color-accent-green

—

text-accent-green

1 primitive
  • ChatWelcomeState

accent-red

--color-accent-red

—

text-accent-red

no primitive uses

accent-amber

--color-accent-amber

—

text-accent-amber

no primitive uses

accent-orange

--color-accent-orange

—

text-accent-orange

no primitive uses

accent-violet

--color-accent-violet

—

text-accent-violet

no primitive uses

accent-neutral

--color-accent-neutral

—

text-accent-neutral

no primitive uses

Status

warning

--color-warning

—

text-warning

1 primitive
  • ChatWelcomeState

error

--color-error

—

text-error

3 primitives
  • DangerButton
  • TextField
  • ChatInput

Overlay glass surface

#

One treatment for every surface that floats OVER content — dialog, dropdown, menu, popover, overlay navigation, overlay Inspector. In dark mode it is pure black at 50% AND a 10px backdrop blur, applied together by the .overlay-surface class; the colour is not exposed as a Tailwind class on its own, so a consumer cannot take the fill and miss the blur. Light mode keeps the opaque fill overlays already shipped with. It is a background fill, so the fill-or-border rule applies: no border by default. Not for inline panes, page canvases, passive cards, on-media controls or tooltips.

.overlay-surface

Foreground stays fully opaque — backdrop-filter only touches what is behind.

Computed background

—

Computed backdrop-filter

—

Light mode is unchanged: .overlay-surface keeps the opaque sidebar fill and declares no backdrop-filter at all. Flip the moon to compare.

Brand gradient

#

Three-stop signature gradient — every CTA, app shell, nav highlight and chip-hover border resolves through these stops. Equal-status with color tokens, not a color sub-group.

Stops

start

--brand-grad-start

—

mid

--brand-grad-mid

—

end

--brand-grad-end

—

Utility classes

Gradient text

.gradient-text
.gradient-btn
.chip-gradient-hover
Active nav
.gradient-ring
.app-bg — outer shell background

Typography

#

Use the .type-* helper classes — never hardcode font-size / line-height / letter-spacing. Token change in one place propagates everywhere.

The quick brown fox.type-display-xlDisplay XL — oversized stat
The quick brown fox.type-displayDisplay — page title
The quick brown fox.type-h1--emphasizedH1 emphasized — section banner
The quick brown fox.type-h1H1 — section banner (regular)
The quick brown fox.type-h2-emphasizedH2 emphasized — card title
The quick brown fox.type-h2H2 — header label
The quick brown fox.type-h3H3 — sub-heading
The quick brown fox.type-body-emphasizedBody emphasized — markdown bold
The quick brown fox.type-bodyBody — chat bubble copy
The quick brown fox.type-detail-emphasizedDetail emphasized — list label
The quick brown fox.type-detailDetail — meta description
The quick brown fox.type-captionCaption — meta line / counter
The quick brown fox.type-footnoteFootnote — tooltip / hint

Shadow

#

Sparse on purpose — only two semantic depths plus the gradient-btn lift. Light mode shadows turn into 1px gradient rings on dark canvas (shadows read as muddy glows on dark).

thumb

--shadow-thumb

Slider thumb / draggable knob

Hover me

card-hover

--shadow-card-hover

.card-hover-shadow

Card hover lift (light only — dark uses gradient ring instead)

gradient-btn

.gradient-btn

Brand gradient CTA — internal box-shadow lift on hover/active

Light mode active — toggle the sun/moon to see how dark mode swaps shadows for gradient rings.

Radius

#

Five-step radius scale. The shell radius (40px) is the outer app rounding; pill (9999px) is for tags and gradient CTAs.

sm

--radius-sm

8px

Pills, small cards, inputs

md

--radius-md

12px

Section cards, modal panels

lg

--radius-lg

16px

Composer, chat-input panel

pill

--radius-pill

9999px

Tags, status pills, gradient buttons

shell

--radius-shell

40px

Outer app shell rounded corner

Spacing

#

Use Tailwind spacing scale. Common rhythms: 1.5 (6px), 2 (8px), 3 (12px), 4 (16px), 6 (24px), 8 (32px).

gap-1.56px
gap-28px
gap-312px
gap-416px
gap-624px
gap-832px

Layout

How a whole screen is assembled, and the parts it is assembled from — every surface plugs into one three-panel shell, and each part below carries its spec and a live demo in the same place. Single source: content/layoutTemplates.tsx.

App Shell — Three-Panel Structure

App.tsx

Every WorkPal view composes into a single three-panel shell: NavPanel (global navigation), ConversationPanel (primary working surface), and InspectorPanel (contextual detail). Foundations tokens flow through all three; edit a color once and every panel updates.

NavPanel
260 / 64 px
ConversationPanel
flex-1
InspectorPanel
280 / 504 px
NavPanel260 / 64 px

Global navigation, view switching, recents, profile

SidebarMiniSidebar
Sidebar · 260px (drag 220–400) · sidebar-bg
MiniSidebar · 64px · collapsed
ConversationPanelflex-1

The user’s primary working surface — chat, page content, forms

ChatPanelPageLayout (+ any page)
flex-1 · centered content max-w-[863px]
InspectorPanel280 / 504 px

Contextual detail to the right: document, task context, side cards

DetailPanelTaskContextPanelSplitView side
DetailPanel · 504px
TaskContextPanel · 280px
Overlays on narrow viewports

Rule: a new feature is a slot in one of these three panels — never a new top-level chrome element. If you need a new panel primitive, build it in shared.tsx and register it under the relevant panel here.

PageLayout

#MasterUsed in: Wingman 26 · WorkPal 15

Page shell — pinned single-row header (toggle + title + rightSlot/actions) that the filters + body scroll beneath (frosted, like the header on this site) + optional pinned footer. Wraps HeaderBar internally.

PageLayout owns the title + filters + scrollable body. Pass a `footer` for a pinned ChatInput.

Demo content row.
Demo content row.
Demo content row.
Demo content row.
Demo content row.
Demo content row.
Demo content row.
Demo content row.

Spec

shared.tsx

Canonical page shell. A pinned single-row header (sidebar toggle · title · flexible gap · rightSlot search/actions · onNewChat · headerRight · onBack) stays pinned at the top as a frosted layer while the body scrolls beneath it, and an optional footer stays pinned to the bottom. The title lives on the pinned row and is truncated to one line — pass a short label, not prose. Edit the spec in shared.tsx once — every page updates.

Pinned header row: px-4 sm:px-8 · pt-6 pb-3 · title inline (truncated) · .frosted-header
Horizontal pad: px-4 sm:px-8
Header → body: header pb-3 + body pt-3
filters → content: mb-8
maxWidth 'full': no limit
maxWidth 'reading': 863px centered
maxWidth 'wide': 1040px centered
Used by · WorkPal
OverviewPageLibraryPageConnectorsPageDesignSystemPageOnboardingProjectPageComingSoonPage
Used by · Wingman
AboutPageAdminObservabilityPageAgentConfirmPageAgentVoicePreviewPageChatPageCheckoutCompletePageCheckoutPageDateArrangePageDateDetailPageDatesPageDesignSystemPageMatchDetailPageMatchesPageNotFoundPagePrivacySettingsPageProfilePhotosPageSSOCallbackPageSelfSnapshotPageSettingsPageSignInPageSignUpPageTokenSettingsPageVideoFeedbackPageVideoInvitePageVideoRoomPage

HeaderBar

#MasterUsed in: Wingman 6 · WorkPal 2

Canonical top toolbar. Sidebar toggle (when closed) + optional left/right slots. Used by every top-level shell.

Project · Wingman
Page content lives below the header.

Spec

shared.tsx

The pinned top row. Bare — as ChatPanel and the Wingman chat/quiz shells use it — it's just the sidebar-toggle button (only when the sidebar is closed) + optional left/right slots. DS-029: the toggle glyph is not fixed; each product supplies it through NavToggleIconProvider (WorkPal shows a panel-left icon, Wingman a hamburger). DS-080: PageLayout renders through HeaderBar, passing title / rightSlot / widthClass / padX so the page title sits inline on the pinned row; bare consumers pass none of these and render exactly the toolbar they always did.

Props: sidebarOpen, onToggleSidebar, headerRight, title, titleAs, rightSlot, widthClass, padX
Used by · WorkPal
ChatPanel
Used by · Wingman
ChatPageChatsPageDesignSystemPageOnboardingPageQuizChatPageQuizPageSelfTestChatPage

SplitView

#MasterUsed in: Wingman 0 · WorkPal 4

Two-column shell that flips inline ↔ overlay based on container width (ResizeObserver, not viewport). Used by ProjectPage, ChatPanel + DetailPanel, TaskContextPanel.

Main column

Resize this card horizontally to see the panel collapse to overlay.

Side panel

SplitView decides inline ↔ overlay based on container width.

Spec

shared.tsx

Main column + collapsible side column. Auto-switches to overlay mode when the CONTAINER is too narrow to fit both inline — DS-029: this used to say "viewport". It is measured with a ResizeObserver on SplitView's own element, which is deliberately agnostic of viewport size, sidebar width and collapsed state.

Props: side, sideOpen, onCloseSide, sideWidth, mainMinWidth
Used by · WorkPal
ProjectPageLibraryPage (detail panel)
Used by · Wingman
DesignSystemPage (showcase)

SidePanelHeader

#MasterUsed in: Wingman 0 · WorkPal 5

Canonical header row for a side panel. Title + optional children + close button (X or panel-right collapse icon).

Inspector

Collapsible

Spec

shared.tsx

Shared header row for any side panel. Unifies close-button size (40px rounded-xl), hover, and typography across every panel.

Props: title, onClose, closeIcon ('x' | 'panel-right'), closeLabel
Used by · WorkPal
ProjectPage side panelTaskContextPanelDetailPanel
Used by · Wingman
DesignSystemPage (showcase)

SidePanelBody

#MasterUsed in: Wingman 0 · WorkPal 3

Scrollable conversation inspector body with spacing and an automatic scrollbar.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Scrollable body container — pairs with SidePanelHeader. Holds a vertical stack of SideCards.

Side panel

notes.md · 4 KB

Spec

shared.tsx

Scrollable body that pairs with SidePanelHeader and holds a vertical stack of SideCards. Single source of truth for right-panel L/R padding (px-3) and inter-card gap (gap-4) — switching between project view and task view no longer shifts content horizontally.

Props: children. Padding / gap are intentionally not configurable — that's the point.
Used by · WorkPal
ProjectPage side panelTaskContextPanel
Used by · Wingman
No pages yet

SideCard

#MasterUsed in: Wingman 0 · WorkPal 6

Collapsible section inside a right-column side panel — no panel fill, border or radius; sections are separated by a fading 1px rule. Pairs with SidePanelHeader / SidePanelBody.

Pre-fetch the user's calendar and reference last week's meeting notes.

Spec

shared.tsx

Collapsible section inside a right-column side panel. DS-029: this used to say "card" — it has no panel fill, no border and no radius; sections are separated by a 1px rule along the bottom edge that fades out at both ends (side-card-divider, with last:bg-none on the final one). Header with title + optional icon + optional add affordance + chevron.

Props: title, icon, hasAdd, defaultOpen
Used by · WorkPal
ProjectPage (Instructions/Scheduled/Files/Context)TaskContextPanel
Used by · Wingman
DesignSystemPage (showcase)

ShellGlow

#MasterUsed in: Wingman 1 · WorkPal 1

Dark-mode background glow: one rotating field carrying all three color gradients, turning together around the screen center — never changing brightness, color or size. Mount once per app root — never per `.app-shell-bg` surface — so every dark-mode shell shares one animation clock instead of a second instance rotating out of phase.

Purple · --shell-glow-purple
25%
Orange · --shell-glow-orange
30%
Blue · --shell-glow-blue
20%

% is today's brightness — a ceiling that never changes. The three glows keep their positions relative to each other and rotate together as one field around the screen center, 60 seconds per full turn, clockwise, at a constant speed. prefers-reduced-motion freezes the field at today's rest position (0° = 360°, so the freeze frame is never mid-turn).

ResizeHandle

#MasterUsed in: Wingman 1 · WorkPal 2

User-draggable column width (useResizableWidth + ResizeHandle). The products' NavPanel defaults to 260px, drags 220–400px and is remembered per product; this demo uses a smaller range. Drag the right edge, or focus it and use ←/→, Home/End; Enter or double-click resets.

Navigation

160px

Main content

Buttons

PrimaryButton

#MasterUsed in: Wingman 29 · WorkPal 14

Tier 1 — gradient background, white text, strongest CTA. Use sparingly: one per surface.

Variant × state matrix (1×4 = 4 cells)
variant ↓ / state →defaulthoveractivedisabled
default

hover / active force-state mirror the .gradient-btn box-shadow lift; live :hover still owns the precise pixel definition.

SecondaryButton

#MasterUsed in: Wingman 6 · WorkPal 4

Secondary action button for prompt or workflow decisions.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Tier 2 — solid inverted surface (black in light mode, white in dark).

Variant × state matrix (1×4 = 4 cells)
variant ↓ / state →defaulthoveractivedisabled
default

AppleSignInButton

#MasterUsed in: Wingman 0 · WorkPal 1

DS-162 — Apple's own Continue with Apple button: black in light mode, white in dark, Apple's logo, title 43% of height. Use only for Sign in with Apple; never restyle it.

TertiaryButton

#MasterUsed in: Wingman 26 · WorkPal 15

Outlined action button for quieter conversation and workflow actions.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Tier 3 — bordered, default text color. Lightest-weight option.

Variant × state matrix (1×4 = 4 cells)
variant ↓ / state →defaulthoveractivedisabled
default

GhostPillButton

#MasterUsed in: Wingman 6 · WorkPal 13

Pill-shaped secondary action with optional icon and disabled state.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Pill-shaped bordered secondary — used in page headers next to FilterChip rows. size='sm' gives a tighter ~32px pill (pair with a 12px glyph) for inline Edit / Reveal-in-Finder actions; default 'md' is unchanged.

HeaderIconButton

#MasterUsed in: Wingman 4 · WorkPal 11

Named icon action for conversation headers; size the mobile hit area to at least 44 pixels.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Named icon button for page headers: 44×44 on mobile, 40×40 on desktop (sidebar toggle, panel close, modal close).

IconButton

#MasterUsed in: Wingman 12 · WorkPal 9

Square / round icon-only button, 24–44px — the mid/small inline buttons between ToolbarIconButton (composer) and HeaderIconButton (44px mobile / 40px desktop). Four tones: default (transparent→hover), filled (MiniSidebar keys), overlay (white glyph on a dark bg-scrim, for buttons on photos/video), inverted (dark glyph on a light bg-scrim-inverted). Consumer sizes the glyph ≈ box×0.5; className is the escape hatch for responsive sizing + one-off active rings.

tone="default" · sizes 24 / 28 / 32 / 40 / 44 (square)
shape="round" · active · filled · disabled · secondary glyph
tone="overlay" / "inverted" — shown on a sample media surface

ToolbarIconButton

#MasterUsed in: Wingman 0 · WorkPal 1

Composer-scale icon button (uses --toolbar-btn-h token), pairs with ToolbarPill / ToolbarSegmented in the same row.

AddRowButton

#MasterUsed in: Wingman 1 · WorkPal 2

Inline 'add a new row' affordance — sits at the end of an editable list (file list, tag list).

existing-file.md

TextButton

#MasterUsed in: Wingman 1 · WorkPal 12

Quiet text action with disabled and disclosure attributes.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Bare text-link button — no border / fill, secondary text → primary on hover. The lightest action (Not now, clear, Replace…). tone='primary' for a stronger primary-text link.

Inputs

TextField

#MasterUsed in: Wingman 11 · WorkPal 3

Filled labeled text input. Pass `error` for inline validation. `autoComplete` for browser keychain hints.

Variant × state matrix (2×3 = 6 cells)
variant ↓ / state →defaultfocuserror
empty
filled

focus state shows the canonical 2px ring; live focus inside the input is identical.

AutocompleteField

#MasterUsed in: Wingman 3 · WorkPal 0

Filled combobox with suggested options and custom-value fallback. Use when the system can help match entries but should not block freeform input.

RangeSlider

#MasterUsed in: Wingman 2 · WorkPal 0

Token-styled native sliders. Use RangeSlider for a single value and DualRangeSlider for bounded ranges.

Age range25-40
Distance25 miles

Switch

#MasterUsed in: Wingman 1 · WorkPal 4

Binary radio-pill toggle. Generic over the value type. Use for two mutually exclusive choices that aren't toolbar-scale.

Variant × state matrix (2×2 = 4 cells)
variant ↓ / state →defaultdisabled
left
right

SegmentedToggle

#MasterUsed in: Wingman 0 · WorkPal 4

Compact pill segmented control for 2–4 mutually-exclusive options (language EN/中, view mode). Separated-pill style — distinct from ToolbarSegmented (composer connected segments) and Switch (binary). variant='flat' (selected-bg) or 'gradient' (brand fill).

DarkToggle

#MasterUsed in: Wingman 1 · WorkPal 1

Recessed-track + raised-thumb switch — a filled inset groove (no border) with the active option lifted onto a near-surface pill. The 'stands on its own layer' style; use for a single, emphasized binary control (e.g. light/dark mode). For same-layer or repeated/batch controls (e.g. per-row priority) use the lighter bordered SegmentedToggle instead.

Recessed track + raised thumb — a filled inset groove, no border (bg-XOR-border).

When to use which toggle

A · Visual layer

Sits on the SAME layer as content → bordered SegmentedToggle. Needs its OWN / a receded layer → inset DarkToggle.

B · Quantity

Many / repeated (e.g. per-row priority) → bordered (lighter). Single / emphasized → inset.

Inset · single / emphasis
Bordered · batch / same layer

Checkbox

#MasterUsed in: Wingman 0 · WorkPal 3

Independent boolean (NOT a radio group). Multiple can be checked at once.

Variant × state matrix (2×2 = 4 cells)
variant ↓ / state →defaultdisabled
unchecked
checked

Pills & Tags

StatusTag

#MasterUsed in: Wingman 20 · WorkPal 7

Semantic status pill for pending, processing, review and completed states.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

THE canonical pill component. Every tag/badge/pill renders through this. 8 semantic variants × 2 sizes × icon override.

pendingin-progressin-reviewsuccessfailedexpiredneutral
pendingin-progressin-reviewsuccessfailedexpiredneutral
OutlineOutline failed
Variant × state matrix (6×1 = 6 cells)
variant ↓ / state →default
pending
pending
in-progress
in-progress
in-review
in-review
success
success
failed
failed
neutral
neutral

Tag

#MasterUsed in: Wingman 5 · WorkPal 3

Compact neutral label with an optional outline and tooltip.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Thin alias — neutral StatusTag at size='sm' with no icon. Inline labels: emoji chips, n/3 counters, type labels.

Betan/3OutlineTooltip

Chip

#MasterUsed in: Wingman 7 · WorkPal 4

Compact rounded-full chip for inline suggestions, selections, draggable trait pickers.

Removable
Variant × state matrix (2×3 = 6 cells)
variant ↓ / state →defaulthoverdisabled
label only
icon + label

FilterChip

#MasterUsed in: Wingman 6 · WorkPal 5

Filter-bar chip — distinct from Chip (uses `type-detail` not `type-h2`, supports a count badge).

Variant × state matrix (2×3 = 6 cells)
variant ↓ / state →defaulthoverdisabled
default
active

UtilityChip

#MasterUsed in: Wingman 0 · WorkPal 2

Compact context action with optional pressed state for prompt toolbars.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Mono-text utility pill for paths, IDs, tool-surface labels. Solid bg-bg-hover on hover (not gradient).

IconBadge

#MasterUsed in: Wingman 16 · WorkPal 1

Decorative icon badge for message context or workflow groups; not an interactive control.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Decorative icon-in-circle badge (non-interactive, aria-hidden) — a round bg-bg-hover plate behind a glyph, used next to list items / section headers. For a CLICKABLE round icon use IconButton.

StatusStrip

#MasterUsed in: Wingman 0 · WorkPal 1

DS-147. One-line passive status above a content area — a bg-bg-hover strip (fill only, no border) with a 16px secondary glyph and a type-caption line. Not a control, no dismiss. Pass role='status' when it appears or changes after load.

Couldn’t reach this folder’s remote — working from its local copy for now.

With role="status" — announced when it appears.

TimePill

#MasterUsed in: Wingman 0 · WorkPal 1

Compact time or effort label using the shared status presentation.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Thin alias — StatusTag (in-progress, sm) with a User icon. 'time estimate' semantics at call sites.

~3 minjust now

SampleWorkspaceLabel

#MasterUsed in: Wingman 0 · WorkPal 2

DS-145. Passive blue label saying the data on screen is a sample. placement='inline' sits to the right of a page title on the same line and wraps under it on narrow screens (WorkPal guest mode: label 'Sample data' with a sign-in tooltip, on every page that would show the user's own content); placement='edge' is the ribbon pulled flush to a panel's left edge (default label).

OverviewSample data
Sample workspace

Cards

MetricCard

#MasterUsed in: Wingman 0 · WorkPal 2

Large centered number with title and subtitle. Used in stat dashboards.

Emotional value
10
/10
Time gained
+2h
this week
API spend
$1.02
under budget

InsightCard

#MasterUsed in: Wingman 0 · WorkPal 1

AI-generated summary card. Sparkle icon + body + action buttons.

INSIGHT

Your focus time dropped 40% this week. Want me to protect morning blocks?

TaskProgressCard

#MasterUsed in: Wingman 0 · WorkPal 1

Clickable card showing current step + elapsed time. Expands to show full step list.

ReviewItemCard

#MasterUsed in: Wingman 0 · WorkPal 5

Presentational review-result row with type, time and completed state; does not implement a review workflow.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Passive row with type icon, title and type/time metadata. Enable the chevron only inside a button or link that owns a real action.

UX meeting summary — 6 action items
Document · 3 min ago
Weekly stakeholder email draft
Email · 2h ago
Bug triage tickets
Tickets · yesterday

ConnectorCard

#MasterUsed in: Wingman 0 · WorkPal 4

Compact row card for an integration. Logo slot + name + Connect / Connected pill (with optional Disconnect dropdown).

G
Gmail
S
Slack
Codex

Reads the published agreement and sends anything that needs you into Needs You.

ArtifactCard

#MasterUsed in: Wingman 0 · WorkPal 2

Compact file card with icon derived from fileType. Click-to-open via onClick or external link via href.

report.html

deck.pptx

photo.png

ChoiceCard

#MasterUsed in: Wingman 5 · WorkPal 0

Selectable title and description card for choosing a prompt or workflow option.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Selectable card with icon + title + description. Radio-style selection — one active at a time.

Toolbars

ToolbarPill

#MasterUsed in: Wingman 0 · WorkPal 1

Slim pill control sitting in a ChatInput toolbar row — folder pickers, branch pickers, worktree checkboxes.

ToolbarSegmented

#MasterUsed in: Wingman 1 · WorkPal 1

Connected-segment pill for mode selection. Selected segment shows label; unselected segments are icon-only with Tooltip.

SectionTitle

#MasterUsed in: Wingman 0 · WorkPal 4

Lucide icon + bold title + optional count badge. Use across shared section headers.

Needs Your Eyes3
Agents at Work
Big section

SectionCount

#MasterUsed in: Wingman 0 · WorkPal 5

Compact count label for grouped messages, references or workflow steps.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

The count badge beside a section title. SectionTitle renders it for its `count` prop; import it directly when a surface builds its own heading row (a collapsible section with a chevron, a heading that needs its own semantic level) so the markup is never re-spelled.

112140

Tooltip

#MasterUsed in: Wingman 4 · WorkPal 1

Dark hover tooltip — appears above the trigger. Shows on group-hover AND group-focus-within (WCAG 1.4.13).

?

PopoverMenu

#MasterUsed in: Wingman 0 · WorkPal 3

The shell for a small menu that pops out of a trigger (DS-159): portaled, placed below or above the anchor, and dismissed by a press outside, Escape (focus back to the trigger), a resize, or a scroll that moves the anchor. Overlay glass + popup shadow, no border. The caller supplies the rows.

EmptyState

#MasterUsed in: Wingman 14 · WorkPal 3

Icon and explanation for an empty message, result or reference area.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Centered icon + title + optional description. No CTA, no illustration — reads as 'nothing here yet, that's expected'.

No files yet
Drop a file or paste a link to get started.

VersionRow

#MasterUsed in: Wingman 0 · WorkPal 2

Version comparison and update-status presentation without a network or update client.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Single row in the Software Update dashboard — component name, current version, latest version, status tag.

WorkPal Agent

0.4.2 → 0.4.3

Update available

Wingman

0.0.1

Up to date

Unknown peer

0.0.0

AgentRequiredHint

#MasterUsed in: Wingman 0 · WorkPal 6

Notice shown on mobile when a surface depends on the local WorkPal Agent (Mac-only). Two variants: 'card' (inline assistant message) and 'tip' (compact pill near disabled button).

This needs WorkPal Agent on your Mac. Open the page on your computer to use it.

Open this on your Mac to use Agent tools.

StepIndicator

#MasterUsed in: Wingman 1 · WorkPal 1

Visual pending, active and completed workflow step marker; pair with a text label.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Three states: done (check), in-progress (filled dot), pending (empty circle). Used inside TaskProgressCard.

Done
In progress
Pending

Data viz

AreaChart

#MasterUsed in: Wingman 0 · WorkPal 1

Responsive SVG area chart with Catmull-Rom smoothing. Auto-sizes to container width via ResizeObserver.

MonTueWedThuFriSatSun

CategoryBreakdown

#MasterUsed in: Wingman 0 · WorkPal 2

Stacked-percentage bar + color-dot legend. One visual unit for breakdowns where every category sums to a whole.

Deadline pressure35%
Keeping up with AI28%
Cross-team alignment22%
Context switching15%

ProgressBar

#MasterUsed in: Wingman 1 · WorkPal 2

Track + filled bar. Optional `showLabel` for inline percentage. Color override via `color` prop.

32%
78%

HealthDimensionRow

#MasterUsed in: Wingman 0 · WorkPal 1

Lucide icon + label/desc + auto-colored status pill. Color/icon derived from value/target ratio.

Focus Time
9–11am blocked & protected
2/2h
Movement
Stand-up reminder every hour
5/8
Family time
No family time yet today
0/2h

Chat primitives

MessageCard

#Master + extendedUsed in: Wingman 1 · WorkPal 0

Inline event notice with information, success or warning tone and an optional action slot.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Inline card-style message for meta-events in a chat stream — distinct from a regular ChatMessage bubble. Three tones: info / success / warning.

Heads up

A new agent version is available.

Branch merged

Pushed claude/loving-khorana to origin/main.

Conflict detected

Two of your tasks reference the same file. Resolve before continuing.
Extension details (1 fork)
  • WorkPal fork: apps/workpal/src/components/MessageCard.tsx

ChatMessage

#Master + extendedUsed in: Wingman 1 · WorkPal 1

User and assistant message presentation with a visual streaming state.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Single chat bubble. role='user' (right, no avatar) or role='assistant' (left, default Sparkles avatar; showAvatar={false} renders none — WorkPal's configuration). Optional streaming dots.

Help me plan dinner for two on Saturday.
On it — I'll cross-reference your past picks and the weather forecast.
Drafting suggestions
2 sources
No avatar — WorkPal's configuration.

Product extensions

WingmanAttachment record + conversational GIF reaction
profile-photo.jpg
profile-photo.jpg
842.0 KB
Does this photo feel like me?
Warm reaction GIF

Wingman may append a replaceable GIF after an assistant turn.

WorkPalNo assistant avatar + primary artifact delivery

I finished the research pass and created the requested report.

market-brief.html

WorkPal composes the shared bubble with showAvatar={false} — assistant messages carry no avatar. Its wrapper keeps rich content (the one primary artifact it selects, web-source chips, media grids, feedback bar) below the bubble, outside the primitive.

Extension details (2 forks)
  • Wingman fork: apps/wingman/src/components/ChatMessage.tsx
  • WorkPal fork: apps/workpal/src/components/ChatMessage.tsx

MessageActions

#MasterUsed in: Wingman 0 · WorkPal 3

THE shared answer toolbar under an AI reply. Two abilities are built in — read-aloud (plays the whole answer, click again to stop) and copy (glyph flips to a check on success). Everything else — thumbs-up/down, retry, share — is optional and injected by the host through `actions`, laid out in the locked order: read-aloud · copy · injected. Used by the viewer's Ask-AI panel and WorkPal's chat. Read-aloud runs on the browser Web-Speech engine by default; a host can pass a `readAloud` transport (the viewer routes it to a server-side `/api/tts` so no key reaches the frontend).

On it — I'll cross-reference your past picks and the weather forecast.

Read-aloud + copy are built in; share / thumbs-up / thumbs-down / retry are optional actions the host wires up — shown here as no-op placeholders. Read-aloud uses the browser Web-Speech engine, so the demo makes no server call.

With a timestamp

Help me plan dinner for two on Saturday.
On it — I'll cross-reference your past picks and the weather forecast.

Pass `timestamp` and the row shows when the message was sent — a relative time refreshed once a minute, full local time on hover. An AI answer puts it after the buttons; a user message puts it first (`timestampPosition="start"`) in a right-aligned row with Copy. Omit it and the row is unchanged.

ChatWelcomeState

#MasterUsed in: Wingman 2 · WorkPal 1

Shared agent carousel, greeting, commit/cancel behavior, and collapsed return state. Products configure identity copy and optional capabilities; they do not fork the carousel.

The product-owned production strings “What should we work on?” and “Customize” stay in English. Viewer annotations and explicitly localized demo labels follow the selected language.

WorkPalRole tags · fixed work prompt · video eligibility filter

Hi, Beibei

What should we work on?

Product owns the greeting, role-title tags, selected agent, and which videos are eligible.

WingmanPersona tags · dating prompt · custom-avatar action

Hi, friend

What’s on your mind? Let’s figure it out together.

Product owns custom-avatar persistence, the Customize flow, dating copy, and returning-user collapse state.

Long-name marqueeNarrow phone (~320px)

Hi, Beibei

What should we work on?

The long Latin name is focused on load; tap the avatar to its right for the 20-character CJK name. Names that fit stay static; only a name that overflows its track scrolls — a continuous one-direction ticker loop, no hover needed. Under prefers-reduced-motion the name wraps instead of scrolling (WCAG 2.3.3). Toggle the theme to check dark mode.

ChatInput

#Master + extendedUsed in: Wingman 5 · WorkPal 6

Prompt composer with callback-based sending, optional attachments and mentions. No model provider is included.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Bottom composer — the brand-gradient pill **both Wingman and WorkPal render**, via a thin wrapper (`apps/{wingman,workpal}/src/components/ChatInput.tsx`) that opts into the features each call site needs through `features={{…}}`: attach, voice mode, voice input, action chips, @mentions, send overrides, and draft per-key. (A `features`-less baseline mode — controlled `value`/`onChange`, plain textarea — also exists for callers that just need a bare composer; no product uses it in V0.1.)

All 7 feature groups opted in — the same rich composer Wingman + WorkPal both render. Try: type a message, type @ to mention, click +, click the mic, hover chips.

@ references and / commands

Default off. Pass an async mentions.source for @ (e.g. files) and features.commands for / at the start of the input. The master debounces, aborts stale requests and shows loading / empty states; the product owns the data and what a command does. Sample data below is a viewer demo, not a real product source. Use the sun/moon toggle to check dark mode.

Events appear here — picked commands and sent messages.

Suggested reply

Optional suggestion prop. While the input is empty the predicted reply shows in grey as the placeholder; Tab (or → in the empty input) fills it, and a touch device gets a Use chip instead of the Tab hint. Tab keeps its normal focus behaviour with no suggestion or with text in the box. Wingman does not pass it.

useSuggestedReply

useSuggestedReply (@beibei/design-system/suggest) produces it: one request per finished turn you watched; the host supplies its messages and the request. Demo: a static suggestion.

Suggested reply: Yes, use this version and replace it on the About page. Press Tab to use it.

Actual product configurations

Same master primitive, visibly different product choices. The profiles below are imported by the real wrappers and welcome call sites, so this comparison changes with the products instead of duplicating a Wingman or WorkPal specification in the viewer.

WorkPal

Real welcome configuration

workpal
Voice entry
Emphasized
Chip model
Quick + action
@ mentions
Not configured
Busy gate
Product-controlled

Source: apps/workpal/src/components/ChatInput.tsx · apps/workpal/src/components/ChatPanel.tsx

Wingman

Real welcome configuration

wingman
Voice entry
Emphasized
Chip model
Quick only
@ mentions
Match picker
Busy gate
Not exposed

Source: apps/wingman/src/components/ChatInput.tsx · apps/wingman/src/pages/ChatsPage.tsx

Both still share attachments (10 files, up to 2 MB each), voice transcription, per-chat drafts, AI-response gating, and the same responsive shell. Try @ in Wingman to open its product-only mention picker; WorkPal intentionally has no mention configuration.

Extension details (2 forks, 9 flag uses)
  • Wingman fork: apps/wingman/src/components/ChatInput.tsx
  • WorkPal fork: apps/workpal/src/components/ChatInput.tsx
  • Wingman feature flag: apps/wingman/src/components/ChatInput.tsx (actionChips + attach + draft + forceSendActive + isAiResponding + mentions + voice + voiceInput)
  • Wingman feature flag: apps/wingman/src/components/chatInputMentionsCommands.test.tsx (commands + mentions)
  • Wingman feature flag: apps/wingman/src/components/chatInputTooltipAria.test.tsx (attach + voice + voiceInput)
  • Wingman feature flag: apps/wingman/src/pages/QuizChatPage.tsx (actionChips + draft)
  • Wingman feature flag: apps/wingman/src/pages/SelfTestChatPage.tsx (actionChips + draft)
  • WorkPal feature flag: apps/workpal/src/components/liveDictation.test.tsx (attach + voiceInput)
  • WorkPal feature flag: apps/workpal/src/components/nestedOverlayPopovers.test.tsx (attach)
  • WorkPal feature flag: apps/workpal/src/components/voiceComposerFuse.test.tsx (attach + voice + voiceInput)
  • WorkPal feature flag: apps/workpal/src/components/voiceErrorFused.test.tsx (attach + voice + voiceInput)

AttachmentChip

#MasterUsed in: Wingman 0 · WorkPal 1

One attached-file pill — 48×48 thumbnail or icon area + filename (truncates at `maxNameWidth`, default 160px) + size, on a `bg-bg-message` surface. Two optional affordances: `onRemove` (hover-revealed ×, used in the input pending strip) or `showDownload` (Download icon at the right edge, used in sent message bubbles paired with an `<a download>` wrapper). PR #54 unified the visual chrome — same chip across input + bubble.

Input strip — narrow, × on hover:

已生成图像 3.png
已生成图像 3.png
1.7 MB
Beibei Zhang Resume.pdf
224.8 KB
a-very-long-attachment-filename-that-should-truncate.docx
48.0 KB

Sent in bubble — wider, Download icon:

Beibei Zhang Resume (2).pdf
224.8 KB

ChatPanel

#Master + extendedUsed in: Wingman 3 · WorkPal 0

Conversation layout with message and composer slots and near-bottom scrolling.

View source

Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.

Container for a chat surface — optional toolbar + header (one frosted sticky layer the messages scroll beneath) + scrollable message list + pinned input. Auto-scrolls to bottom when content grows (unless user scrolled up).

Saturday plans

Hi Beibei — what would you like to work on today?
Help me plan a date for Saturday evening.
Got it. I'll suggest a few options based on weather + your past picks.
Option 1: rooftop dinner at 7, then a walk by the water.
Something indoors in case it rains?
Sure — a small jazz bar nearby has seats at 9.
Extension details (1 fork)
  • WorkPal fork: apps/workpal/src/components/ChatPanel.tsx

Voice & realtime

Voices

#

Hear every shared voice in one place — the ten OpenAI Realtime voices in the shared catalogue, grouped by gender, with the agent that speaks in each. Play a short fixed sample to compare timbre before choosing one.

Female voices

5
  • Neutral

    Neutral, versatile

    No agent yet · auditionable

  • Bright

    Bright, friendly

    Used by Maya · Beibei

  • Measured

    Measured, thoughtful

    Used by Lily

  • Crisp

    Crisp, upbeat

    Used by Happy

  • Natural

    Natural, expressive

    No agent yet · auditionable

Male voices

5
  • Deep

    Deep, grounded

    No agent yet · auditionable

  • Warm

    Warm, soft

    No agent yet · auditionable

  • Smooth

    Smooth, calm

    No agent yet · auditionable

  • Expressive

    Expressive, lively

    Used by Matt

  • Resonant

    Resonant, grounded

    No agent yet · auditionable

Each sample plays a short fixed sentence in the page language.

VoiceMode

#Master + extended

The shared inline realtime control bar. It owns connection, mute, live-session feedback, voice choice, and recoverable error presentation; products provide authentication, metering, tools, and persistence callbacks.

Shared master anatomy

Static anatomy preview — the viewer never starts a realtime session or requests microphone access.

Shared state contract

Each state is the real fused composer, driven by the switcher — a static preview; the viewer never starts a realtime session.

Product extensions

Master + extended

These cards document integration boundaries. They intentionally do not run task dispatch, auth, quota, or billing logic in the viewer.

The product-owned production strings “Not now” and “Sign in” stay in English. Viewer annotations and explicitly localized demo labels follow the selected language.

WorkPalDirect master composition

Task-enabled conversation

WorkPal supplies start-task, status-check, live context, notice injection, and idle wind-down callbacks.

Queued supplements

Pending typed text and images stay visible until the realtime writer can accept them.

WingmanProduct wrapper around VoiceMode

Guest soft nudge

A dismissible, value-framed sign-in prompt lives outside the shared voice bar.

Quota hard nudge

Wingman maps an exhausted session to sign-in or upgrade; billing copy never enters the master.

Other

SolutionRow

#MasterUsed in: Wingman 0 · WorkPal 1

Row with a lucide icon + title + description + right-aligned category tag. Used in Overview solution lists.

AI 趋势速报 — 每天 3 分钟音频
针对:AI
Focus Block — 自动拦截非紧急会议
针对:Deadline

70 of 91 renderable exports have a viewer representation.

Coverage is calculated at build time from shared.tsx exports and explicit viewer sections. New exports appear below until represented or classified as non-visual.

Not yet represented as standalone viewer entries

AvatarMenu · DangerButton · NavToggleIconProvider · RESIZABLE_NAV_DEFAULT_WIDTH · RESIZABLE_NAV_KEYBOARD_STEP · RESIZABLE_NAV_MAX_WIDTH · RESIZABLE_NAV_MIN_WIDTH · UserAvatar · VoiceWaveform · adoptUserEdit · applyFinal · applyPartial · beginDictation · clampWidth · discardDraft · mapPosition · readStoredWidth · settleDraft · useAnchoredAbove · useResizableWidth · writeStoredWidth

Source of truth: packages/design-system/src/shared.tsxTokens: packages/design-system/src/index.css

Product-only components

Generated from production components/*.tsx files. Tests and specs are excluded; wrappers, flows, shells, full-page surfaces, and reusable product components are labeled separately.

Wingman-only

#Wingman-only20 components

Production components with no shared export. Extensions intentionally wrap a master; product flows and surfaces stay local unless a second product needs the same reusable shape.

Shared-master extensions

2
  • ChatInputWithCreditCap

    Product orchestration around a shared master primitive

    apps/wingman/src/components/ChatInputWithCreditCap.tsx

  • VoiceModeWithFunnel

    Product orchestration around a shared master primitive

    apps/wingman/src/components/VoiceModeWithFunnel.tsx

Product flows

9
  • AvatarPicker

    Product-specific interaction flow

    apps/wingman/src/components/AvatarPicker.tsx

  • BetaIntroModal

    Product-specific interaction flow

    apps/wingman/src/components/BetaIntroModal.tsx

  • ChatUnlockGate

    Product-specific interaction flow

    apps/wingman/src/components/ChatUnlockGate.tsx

  • PostCallFeedbackModal

    Product-specific interaction flow

    apps/wingman/src/components/PostCallFeedbackModal.tsx

  • SignInModal

    Product-specific interaction flow

    apps/wingman/src/components/SignInModal.tsx

  • VideoSlotPicker

    Product-specific interaction flow

    apps/wingman/src/components/VideoSlotPicker.tsx

  • VoicePicker

    Product-specific interaction flow

    apps/wingman/src/components/VoicePicker.tsx

  • VoicePromptModal

    Product-specific interaction flow

    apps/wingman/src/components/VoicePromptModal.tsx

  • WingmanVideoConference

    Product-specific interaction flow

    apps/wingman/src/components/WingmanVideoConference.tsx

Shell & navigation

3
  • MiniSidebar

    Product navigation or app-shell composition

    apps/wingman/src/components/MiniSidebar.tsx

  • Sidebar

    Product navigation or app-shell composition

    apps/wingman/src/components/Sidebar.tsx

  • VideoBookingPanel

    Product navigation or app-shell composition

    apps/wingman/src/components/VideoBookingPanel.tsx

Product components

6
  • DateCard

    Product-specific reusable component

    apps/wingman/src/components/DateCard.tsx

  • MatchCard

    Product-specific reusable component

    apps/wingman/src/components/MatchCard.tsx

  • ReferralInviteCta

    Product-specific reusable component

    apps/wingman/src/components/ReferralInviteCta.tsx

  • WingmanAvatar

    Product-specific reusable component

    apps/wingman/src/components/WingmanAvatar.tsx

  • WingmanFallbackBanner

    Product-specific reusable component

    apps/wingman/src/components/WingmanFallbackBanner.tsx

  • WingmanParticipantTile

    Product-specific reusable component

    apps/wingman/src/components/WingmanParticipantTile.tsx

WorkPal-only

#WorkPal-only50 components

Production components with no shared export. Extensions intentionally wrap a master; product flows and surfaces stay local unless a second product needs the same reusable shape.

Product flows

9
  • AboutLayoutGate

    Product-specific interaction flow

    apps/workpal/src/components/AboutLayoutGate.tsx

  • AuthGate

    Product-specific interaction flow

    apps/workpal/src/components/AuthGate.tsx

  • CompleteSessionModal

    Product-specific interaction flow

    apps/workpal/src/components/CompleteSessionModal.tsx

  • ConfirmActionModal

    Product-specific interaction flow

    apps/workpal/src/components/ConfirmActionModal.tsx

  • ModelPicker

    Product-specific interaction flow

    apps/workpal/src/components/ModelPicker.tsx

  • NewProjectDialog

    Product-specific interaction flow

    apps/workpal/src/components/NewProjectDialog.tsx

  • Onboarding

    Product-specific interaction flow

    apps/workpal/src/components/Onboarding.tsx

  • OnboardingSurface

    Product-specific interaction flow

    apps/workpal/src/components/OnboardingSurface.tsx

  • PlainFolderSaveModal

    Product-specific interaction flow

    apps/workpal/src/components/PlainFolderSaveModal.tsx

Shell & navigation

5
  • AboutSidePanel

    Product navigation or app-shell composition

    apps/workpal/src/components/AboutSidePanel.tsx

  • AgreementDraftPanel

    Product navigation or app-shell composition

    apps/workpal/src/components/AgreementDraftPanel.tsx

  • DetailPanel

    Product navigation or app-shell composition

    apps/workpal/src/components/DetailPanel.tsx

  • Sidebar

    Product navigation or app-shell composition

    apps/workpal/src/components/Sidebar.tsx

  • TaskContextPanel

    Product navigation or app-shell composition

    apps/workpal/src/components/TaskContextPanel.tsx

Full-page surfaces

17
  • AboutPage

    Product-level route or full-page surface

    apps/workpal/src/components/AboutPage.tsx

  • AgreementDetailPage

    Product-level route or full-page surface

    apps/workpal/src/components/AgreementDetailPage.tsx

  • AgreementDraftPage

    Product-level route or full-page surface

    apps/workpal/src/components/AgreementDraftPage.tsx

  • AiManagerPage

    Product-level route or full-page surface

    apps/workpal/src/components/AiManagerPage.tsx

  • ArtifactPage

    Product-level route or full-page surface

    apps/workpal/src/components/ArtifactPage.tsx

  • BoardPage

    Product-level route or full-page surface

    apps/workpal/src/components/BoardPage.tsx

  • ComingSoonPage

    Product-level route or full-page surface

    apps/workpal/src/components/ComingSoonPage.tsx

  • ConnectorsPage

    Product-level route or full-page surface

    apps/workpal/src/components/ConnectorsPage.tsx

  • DesignSystemPage

    Product-level route or full-page surface

    apps/workpal/src/components/DesignSystemPage.tsx

  • DocViewerPage

    Product-level route or full-page surface

    apps/workpal/src/components/DocViewerPage.tsx

  • LibraryPage

    Product-level route or full-page surface

    apps/workpal/src/components/LibraryPage.tsx

  • LoginScreen

    Product-level route or full-page surface

    apps/workpal/src/components/LoginScreen.tsx

  • MemoryPage

    Product-level route or full-page surface

    apps/workpal/src/components/MemoryPage.tsx

  • OverviewPage

    Product-level route or full-page surface

    apps/workpal/src/components/OverviewPage.tsx

  • ProjectPage

    Product-level route or full-page surface

    apps/workpal/src/components/ProjectPage.tsx

  • SettingsPage

    Product-level route or full-page surface

    apps/workpal/src/components/SettingsPage.tsx

  • SoftwareUpdatePage

    Product-level route or full-page surface

    apps/workpal/src/components/SoftwareUpdatePage.tsx

Product components

19
  • AgreementOutline

    Product-specific reusable component

    apps/workpal/src/components/AgreementOutline.tsx

  • AgreementPreview

    Product-specific reusable component

    apps/workpal/src/components/AgreementPreview.tsx

  • AppAuthHandoff

    Product-specific reusable component

    apps/workpal/src/components/AppAuthHandoff.tsx

  • BoardProjectSwitcher

    Product-specific reusable component

    apps/workpal/src/components/BoardProjectSwitcher.tsx

  • BoardRow

    Product-specific reusable component

    apps/workpal/src/components/BoardRow.tsx

  • CommitDiffView

    Product-specific reusable component

    apps/workpal/src/components/CommitDiffView.tsx

  • DesktopAgentSection

    Product-specific reusable component

    apps/workpal/src/components/DesktopAgentSection.tsx

  • DocViewer

    Product-specific reusable component

    apps/workpal/src/components/DocViewer.tsx

  • FolderProjectCard

    Product-specific reusable component

    apps/workpal/src/components/FolderProjectCard.tsx

  • HistorySyncAnnouncer

    Product-specific reusable component

    apps/workpal/src/components/HistorySyncAnnouncer.tsx

  • NeedsYouInbox

    Product-specific reusable component

    apps/workpal/src/components/NeedsYouInbox.tsx

  • PermissionPrompt

    Product-specific reusable component

    apps/workpal/src/components/PermissionPrompt.tsx

  • ProjectActivityModules

    Product-specific reusable component

    apps/workpal/src/components/ProjectActivityModules.tsx

  • ProjectBoardModules

    Product-specific reusable component

    apps/workpal/src/components/ProjectBoardModules.tsx

  • ProjectDutyCard

    Product-specific reusable component

    apps/workpal/src/components/ProjectDutyCard.tsx

  • ProjectOptionsMenu

    Product-specific reusable component

    apps/workpal/src/components/ProjectOptionsMenu.tsx

  • PullRequestCard

    Product-specific reusable component

    apps/workpal/src/components/PullRequestCard.tsx

  • SourceOfTruthCard

    Product-specific reusable component

    apps/workpal/src/components/SourceOfTruthCard.tsx

  • TodoRow

    Product-specific reusable component

    apps/workpal/src/components/TodoRow.tsx