Skip to main content
When your tool returns, the model narrates the data. A glance card is the visual half of that answer: native blocks — headers, lists, stats, charts — rendered by VoiceOS’s own components. It’s the same block language the VoiceOS agent itself answers with, so your card is automatically on-brand, dark-glass themed, and restyle-proof.

Design target: a two-second read. Not a dashboard — the one thing the user wants to see.

Attaching a card

Spread glanceResult([...]) into your tool’s JSON result:
That adds a _voiceos_glance: { blocks } key to your payload. VoiceOS lifts it out before the model sees the result — the model reads your data, never your UI JSON.
Never put information only in the card. The model narrates from the JSON data. A card-only fact is a fact the agent can’t say out loud.

The budget

Your folder’s bun verify.ts catches shape mistakes before users do.

The vocabulary

Every prop, cap, and edge case: glance block reference.

Four patterns that work

The lookup — header + list

The bread and butter.

Rows carry a subtitle and a trailing value — enough to scan, never enough to read.

The metric card — header + stats + one chart

The full three-block budget: identity, the numbers, the shape of the numbers.

The status glance — a row

Puts a ring beside its caption.

One block, two things side by side — the smallest card worth showing.

The composition — splitBar

What something is made of.

Segment colors are assigned by index, never by you — so composition can't read as good or bad.

Tones, glyphs, and app icons

  • tone is a meaning, not a color. good, bad, or neutral — the renderer owns the hues. You never pick colors; that’s how every card stays on-brand.
  • Glyphs come from a fixed allowlist of 34 names (calendar, clock, mail, globe, coffee, sparkle, …) — see the full list. Unknown names invalidate the block.
  • appIcon renders a real app logo (e.g. "notion") in headers and list rows, and wins over icon. It only renders when the row’s visible title starts with that app’s name — so one brand can never masquerade as another.
  • Numbers are strings you format. stats.value caps at 20 chars — send "5 hr 56 min", not 21360. Deltas color by sign: leading - is red, + is green.

How cards behave

  • Blocks animate in with the notch’s staggered blur-in; charts rise and wipe. All motion respects prefers-reduced-motion.
  • clock and countdown tick once per second. Prefer until (an ISO timestamp) over seconds — an absolute target survives re-renders.
  • Cards render in the notch’s answer column and scroll internally if the viewport is tight. On small screens, less is more.
  • One failing block never sinks the card — every block renders inside its own error boundary.

Next: Confirmation cards

Tools that act need approval first — declare the card the user approves on.