From 9fdbdd72d951f14dee82c4bacb9a69753e76fc53 Mon Sep 17 00:00:00 2001 From: iliya Date: Sat, 28 Mar 2026 12:39:50 +0200 Subject: [PATCH] feat(graph): centered column headers + member avatar letters - Column headers centered horizontally over pill area (not column edge) - Member/lead nodes show first letter of name inside hexagon as avatar (bold, sized proportionally to node radius, colored in member color) - Lead gets slightly smaller font (0.6r vs 0.7r) to fit context ring --- .../agent-graph/src/canvas/draw-agents.ts | 22 +++++++++++++++++++ .../agent-graph/src/layout/kanbanLayout.ts | 6 ++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/agent-graph/src/canvas/draw-agents.ts b/packages/agent-graph/src/canvas/draw-agents.ts index fcfa1234..bc353adc 100644 --- a/packages/agent-graph/src/canvas/draw-agents.ts +++ b/packages/agent-graph/src/canvas/draw-agents.ts @@ -44,6 +44,9 @@ export function drawAgents( // Hexagonal body with interior fill drawHexBody(ctx, x, y, r, color, node.state, time, isSelected, isHovered); + // Avatar: first letter of name centered inside hexagon + drawAvatar(ctx, x, y, r, node.label, color, node.kind === 'lead'); + // Breathing animation + spawn/waiting effects drawBreathing(ctx, x, y, r, node.state, time, node.spawnStatus); @@ -207,6 +210,25 @@ function drawBreathing( } } +function drawAvatar( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + r: number, + name: string, + color: string, + isLead: boolean, +): void { + const letter = name.charAt(0).toUpperCase(); + const fontSize = isLead ? Math.round(r * 0.6) : Math.round(r * 0.7); + + ctx.font = `bold ${fontSize}px sans-serif`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = hexWithAlpha(color, 0.9); + ctx.fillText(letter, x, y + 1); +} + function drawLabel( ctx: CanvasRenderingContext2D, x: number, diff --git a/packages/agent-graph/src/layout/kanbanLayout.ts b/packages/agent-graph/src/layout/kanbanLayout.ts index e822afcc..1c5a2623 100644 --- a/packages/agent-graph/src/layout/kanbanLayout.ts +++ b/packages/agent-graph/src/layout/kanbanLayout.ts @@ -8,7 +8,7 @@ */ import type { GraphNode } from '../ports/types'; -import { KANBAN_ZONE } from '../constants/canvas-constants'; +import { KANBAN_ZONE, TASK_PILL } from '../constants/canvas-constants'; /** Column header info for rendering */ export interface KanbanColumnHeader { @@ -125,10 +125,10 @@ export class KanbanLayoutEngine { const colX = baseX + colIdx * columnWidth; const config = COLUMN_LABELS[col.name] ?? { label: col.name, color: '#888' }; - // Column header + // Column header — centered over pill area headers.push({ label: config.label, - x: colX + columnWidth / 2, // centered in column + x: colX + TASK_PILL.width / 2, // horizontally centered over pills y: baseY, color: config.color, });