Skip to content

Visual Vocabulary

"Every map picks the right visual tools for its story. Not stamped from a template."

Node shapes

All shapes use fluid, rounded edges. No sharp corners, no angular boxes, no Visio look.

Available shapes

Shape SVG element Best for Look
Pill <rect rx="20"> Branch categories, plan names [ Teams ] rounded rectangle
Circle <circle> Root node, leaf detail dots organic, mind-map feel
Soft card <rect rx="12"> + multi-line text Nodes needing description Rounded box with title + subtitle
Tag <rect rx="8"> small + uppercase text Metadata: "New", "$30/mo", "Preview" Tiny coloured badge
Icon + label <image> + <text> Product nodes: Teams, Excel, Defender Logo + name side by side

What's actually implemented (v2 renderer)

Shape Implementation Used for
Root rectangle <rect rx="16"> dark slate (#1E293B), white text, drop shadow Central anchor — map title
Branch pill <rect rx="16"> solid vibrant fill, white text, drop shadow L1 categories
Leaf pill <rect rx="12"> tinted fill (88% white blend), coloured stroke L2 items — the detail content
Connector dot <circle r="3.5"> solid branch colour Junction between link and leaf pill
Tag badge <rect rx="8"> solid branch colour, white uppercase text, 8px font Metadata: "New", "Most used", "Popular"

Not yet implemented

Shape Planned for
Soft card Nodes needing multi-line description (future maps with more context)
Icon + label Product nodes with Microsoft logos (requires icon pipeline)

Choose shapes based on what the node represents:

Node role Recommended shape Why
Root (map title) Large circle or prominent pill Anchors the visual, draws the eye first
Branch heading Pill Scannable, clear category grouping
Detail item Small pill or circle dot + text Compact, doesn't compete with branches
Comparison item Soft card Needs more text (e.g., "E3: Desktop apps, Intune, DLP")
Status/price Tag Glanceable metadata that supplements, not dominates

All links use curves. No straight lines, no angular elbows.

Style D3 method Best for Feel
Organic Bezier curveBasis / curveBundle Default — most maps Smooth, natural, flowing
S-curve Custom cubic Bezier Top-down waterfall layouts Clean vertical cascade
Tapered Custom <path> with varying stroke-width Directional flow (deployment steps) Shows progression
Gradient <linearGradient> on stroke Multi-colour branch transitions Colour flows parent → child

Rules

  1. All links are curvedcurveBasis is the default
  2. Link colour inherits from parent branch at reduced opacity (30-40%)
  3. Hover state: none — maps are static, no interaction
  4. Minimum stroke-width: 1px — never thinner (disappears on screens)
  5. Maximum stroke-width: 3px — thicker = more important connection

Grouping techniques

Entra.news groups related nodes with soft coloured backgrounds. This is better than boxes because it feels organic rather than rigid.

Available grouping

Technique Implementation Best for
Background region <rect rx="16"> with 5-8% opacity fill Grouping branch clusters
Connector dots Small <circle r="3"> at junction points Feeling of organic connection
Colour banding All nodes in a branch share a colour family Visual grouping without explicit containers
Whitespace Increased gap between branch clusters Simplest grouping — just space

Preference order

  1. Colour banding (default) — nodes in same branch share colour
  2. Whitespace — space between branches creates natural groups
  3. Background region — only when branches would otherwise merge visually
  4. Connector dots — sparingly, for organic feel at junction points

Sutheesh's design preferences (captured for all future work)

✅ Use ❌ Avoid
Fluid Bezier curves Straight angular lines
Rounded corners (high rx/ry) Sharp corners on anything
Organic, flowing feel Rigid grid/box layouts
Multiple vibrant colours per map Monochrome/washed-out single-colour
Whitespace as a design tool Cramming elements together
Purpose-built per map Template-stamped sameness
Readable at first glance Requiring zoom/interaction to read

Shape examples (SVG snippets)

Pill node

<rect x="0" y="0" width="120" height="36" rx="18" ry="18"
      fill="#6366F1" fill-opacity="0.1"
      stroke="#6366F1" stroke-width="1.5" />
<text x="60" y="23" text-anchor="middle"
      font-family="'Plus Jakarta Sans'" font-weight="600" font-size="13"
      fill="#4F46E5">Teams</text>

Tag badge

<rect x="0" y="0" width="40" height="18" rx="9" ry="9"
      fill="#10B981" />
<text x="20" y="13" text-anchor="middle"
      font-family="'DM Sans'" font-weight="600" font-size="9"
      fill="#FFFFFF" text-transform="uppercase">NEW</text>
d3.link(d3.curveBasis)
  .x(d => d.x)
  .y(d => d.y)