Brand Hub

Chart Guidelines

The design system behind Composio chart cards — surface, type, color, the dither engine, chrome rules, and how each template implements them.

agent.json

Every chart card is a 1200×675 dark surface rendered from a JSON config — by the API (POST /api/chart), by an agent following /api/chart/instructions, or by the standalone templates in standalone/. The tokens below are the single system all of them share; standalone/gen.mjs is the source of truth that generates the templates and the API's copies of them.

01Anatomy

Anatomy — the tokens on a real card

Placeholder cards rendered by the real engine, one concern per figure. Red spans are measurements (px in the 1200×675 frame); red tags name the rule at that exact spot.

Spacing & margins
pt 323232y-axis 60gap 16plot top 44plot bottom 44Δ gutter 100bar 44pb 16footer ≥ 57.5
Typography
title · Geist Sans 40/500 · capitalizecaption · mono 16 · white/60 · uppercasebest/worst · sans 12/500y ticks · mono 18 · white/80Δ ratio · sans 26/600 · tabularx labels · mono 14 · white/80meta · mono 14 · white/60 · uppercase
02Surface & spacing

Surface & spacing

Card
1200 × 675 px, black (#000), sharp corners, overflow hidden
Export
2400 × 1350 PNG — the card at device pixel ratio 2
Body padding
32px left/right · 32px top · 16px bottom
Title row
title + caption on one baseline row, 24px gap; chart starts 16px below
Footer
1px top border white/10 · 16px vertical padding · min-height 57.5px, pinned so branding toggles never move the chart
Panel gap
64px between panels (small-multiples, composed)
03Typography

Typography

Two faces only: Geist Sans for names and titles, JetBrains Mono for every number, unit, and piece of chrome. Sans never exceeds weight 600; mono carries all uppercase+tracking treatments. Specimens below render in the real faces on the card ground.

Card title
Geist Sans · 40 · 500 · −0.01em · capitalize · leading 1
Shell title on every template
Success rate
Panel title
Geist Sans · 20 · 500 · −0.01em · capitalize
small-multiples & composed panel headers
Cost per success
Row / legend / callout name
Geist Sans · 19 · 500
horizontal-bar rows, pie legends & callouts
Claude Code
Caption
JetBrains Mono · 16 · uppercase · +0.05em · white/60
Top-right unit line
% of tasks passed
Meta line
JetBrains Mono · 14 · uppercase · +0.05em · white/60
Footer — left when unbranded, right with the wordmark
Source: Composio agentic eval
Badge pill
JetBrains Mono · 13 · 500 · uppercase · +0.05em · 2×8 padding · 1px border
Footer, opt-in only
BENCH
Value labels
JetBrains Mono · 600 · tabular — 18 bar ends · 16 legend · 12 mini bars
Wherever a number names a mark
+2,059%
Axis ticks
JetBrains Mono · 400 — 18 y-axis (vertical bars) · 14 x labels · 12 h-bar axis · 10 mini panels
All axes; color rides the white-alpha ladder
0% 20% 40% 60%
Stat / donut-center value
Geist Sans · 500 · −0.02em · tabular — 64 stat tile · 24–44 donut center
composed stat panels, pie center
48.2M
Footnote
Geist Sans · 12 · italic · white/45
Full-width line above the footer
Numbers show verifier checks cleared
04Color

Color

Seven dither seeds carry every mark. A series owns one color; the engine varies only its alpha (the “color vs opacity” rule), which is why the same chart reads correctly at any density. Each swatch below is painted live with the engine's own Bayer math — solid origin accent, dissolving fade.

green
40 210 110
blue
53 143 243
purple
150 110 255
pink
240 90 190
orange
255 150 50
red
240 70 70
grey
92 92 100
worst · “Other” · no-data
Badge (default)
emerald-400 border + text — bench-family cards
Badge (sky)
sky-400/70 border, sky-300 text, 12px icon (timer / trending) — time & growth cards
Matrix pass
seed green at k 0.45, α 0.98 — dark enough for white text
Matrix fail
seed red at α 0.28, text red-300/85
Grid lines
#2c2c2c dashed 3·3 (vertical-bars) · white/6 dotted guides (h-bars)
White-alpha ladder
80 axis text · 60 captions/meta · 55 callout shares · 50 ticks/subs · 45 footnote · 40 mini ticks & leaders · 10 hairlines
05The dither engine

The dither engine

Bayer 4×4
ordered-dither thresholds (v+0.5)/16 — the only randomness-free scatter in every fill
Cell
2 css px → 4 device px at export; backing canvases scale up with image-rendering: pixelated
Color vs opacity
each series paints one fill color and varies only alpha — lit cells α 1 (or 0.3+0.7·density stacked), off-tier cells ×0.32–0.4. No lighter shades, ever
The fade
density 1 at the origin edge → 0 at the value edge: bars dissolve toward their tips, pies from hub to rim
Value edge
BORDER_ALPHA 0.72 accent at the measured edge — bar caps, the pie rim arc
Origin edge
solid leading accent — h-bar left edge, pie hub, stat strip
Separators
3px black lines between pie wedges keep pixel boundaries crisp
No bloom
capture surfaces never use the hover glow
06Data & chrome rules

Data & chrome rules

  • Sort largest-first; the vertical-bars Δ bracket reads best from the first row and worst from the last.
  • Distinct items take distinct hues; the same item keeps its hue across every panel of a card.
  • grey is reserved for “Other”, worst, and no-data.
  • Titles in sentence case — CSS title-cases them and preserves existing caps (DeepSeek, V4).
  • Formatters are declarative JSON ({prefix, suffix, decimals, locale, plus}), never code.
  • Logos come from the embedded asset: library or data: URIs; external URLs are dropped.
  • Footer branding (wordmark, badge pill) is hidden by default and opt-in per card.
07How the templates achieve it

How the templates achieve it

Six templates implement the system; each one's job is to spend the tokens above on its data shape. Numbers here are the implementation constants in standalone/gen.mjs.

vertical-bars
  • Plot margins 44 / 100 / 44 / 60 (right drops to 24 when `delta: false`).
  • d3 band scale — paddingInner 0.6, paddingOuter 0.28, bar = 90% of band.
  • d3-nice domain; y-axis ticks(5) at 18px mono, dashed #2c2c2c grid at ticks(4).
  • Stacked-density dither (0.5→1) so bars read solid at the base, dissolving to a 0.72-alpha cap.
  • 28px logos float 8px above bar tips; Δ marker: emerald best line, white/40 worst, 26/600 ratio, Δ 11px.
horizontal-bars
  • 220px label column (overridable) · 44px bars · 30px axis · 24px gutter.
  • Nice-round ticks target 6; plotRightPad 72–130 reserves room for 18px mono 600 value labels.
  • Fade runs left→right from a solid CELL-wide origin accent; white/6 dotted guides at each tick.
  • 24px row logos on white/5 tiles beside 19px medium names.
small-multiples
  • Three panels, 64px gap; 44px axis gutter; 30px bars centered per slot.
  • Panel header: 20px title + higher/lower chip (emerald ↑ / white-40 ↓), hairline divider.
  • Values 12px mono 600 above 20px logos above bars; names 10px mono, word-stacked.
  • y-axis = even divisions of an explicit yMax so all panels get clean top ticks.
matrix
  • Grid: 170px row labels + equal columns, 8×5px gaps; header row of 20px logos + 13px semibold names.
  • Pass cells: dark-emerald dense dither (k 0.45, α 0.98) under white 13px mono fractions.
  • Fail cells: low-alpha red (0.28) under red-300/85 text; check/× at 14px, stroke 3.
pie
  • Radial fade — solid hub → sparse rim, capped by a 2px rim arc at 0.72 alpha per slice; 3px black separators.
  • inner 0–0.85 opens the donut; center stat = mono 11 label over ≤44px sans value.
  • Legends: right (19px names, values, share %), bottom (wrapped), callout, or none.
  • Callout mode: labels on rails 84px past the rim, 2px elbow leaders, 28px logos on the pie side, 56px rhythm with collision nudging, and near-vertical slices (±23°) rebalance to the light side.
composed
  • A flex row of panels (weights via `flex`, 64px gap) inheriting every rule above.
  • Panels carry the small-multiples header treatment; primitives: bars, mini bars, matrix, pie, stat.
  • Stat tiles: 64px value over an optional 12px dither accent strip in the item's hue.
08For agents

For agents

POST /api/chart
config JSON in, 2400×1350 PNG out — rendered by headless Chromium server-side
GET /api/chart?c=…
base64url config in the URL; the response is edge-cached immutably, so a URL is a permanent chart
/api/chart/instructions
the living agent instructions — schemas, these rules, and working example configs, versioned with the app
standalone/
the same templates as self-contained HTML, plus capture.mjs for browser-local rendering with no server