Frame Design System

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