style(client): widen the agent card grid
The natural cell pitch was 208px, which left the two-line titles on a subagent's card hugging the edge. Every card takes the same, larger pitch — 276px — so the graph stays one grid and no card claims room its neighbour does not get. A stage narrower than the pitch still compresses it, so the family never overflows horizontally.
This commit is contained in:
1 parent
38fe279213
commit
cd26173459
3 files changed
+18
-14
No files matched your search
@@ -87,8 +87,9 @@ export const AGENT_TREE_LIMIT = 25
|
||||
* exit point (card bottom) and entry point (card top) always land on the card's edge. */
|
||||
export const AGENT_CARD_H = 104
|
||||
/** Horizontal cell pitch adapts to the stage width between these bounds; each node owns one
|
||||
* cell and the card fills it minus a 12px gutter, so a card never clips a neighbor or the stage edge. */
|
||||
const SLOT_MAX = 208
|
||||
* cell and the card fills it minus a 12px gutter, so a card never clips a neighbor or the stage edge.
|
||||
* Every card shares one pitch — the graph reads as a grid, and a card never claims extra room. */
|
||||
const SLOT_MAX = 276
|
||||
const SLOT_MIN = 150
|
||||
const CARD_GUTTER = 12
|
||||
/** Vertical pitch between depth levels: card height + a dedicated 40px link channel below it. */
|
||||
|
||||
@@ -524,6 +524,9 @@ describe('subagentCostFoldOf', () => {
|
||||
})
|
||||
|
||||
describe('layoutForest', () => {
|
||||
/** The natural cell pitch (agentTree.ts SLOT_MAX) — the width a roomy stage settles on. */
|
||||
const SLOT = 276
|
||||
|
||||
function forestOf(ids: [string, string?][]): AgentForest {
|
||||
const nodes = ids.map(([id, parent], i) => ({
|
||||
id,
|
||||
@@ -572,19 +575,19 @@ describe('layoutForest', () => {
|
||||
assert.equal(layout.points.length, 1)
|
||||
assert.equal(layout.points[0].depth, 0)
|
||||
assert.equal(layout.links.length, 0)
|
||||
assert.equal(layout.width, 208)
|
||||
assert.equal(layout.width, SLOT)
|
||||
assert.equal(layout.height, 48 + 104 + 24)
|
||||
assert.equal(layout.cardW, 208 - 12)
|
||||
assert.equal(layout.cardW, SLOT - 12)
|
||||
})
|
||||
|
||||
test('levels follow depth, siblings claim leaf slots, parents center over children', () => {
|
||||
const layout = layoutForest(forestOf([['root'], ['a', 'root'], ['b', 'root'], ['g', 'a']]))
|
||||
const pointOf = new Map(layout.points.map(p => [p.id, p]))
|
||||
// Two leaf cells (g under a, then b); root centers between them.
|
||||
assert.equal(pointOf.get('g')?.x, 104)
|
||||
assert.equal(pointOf.get('a')?.x, 104)
|
||||
assert.equal(pointOf.get('b')?.x, 104 + 208)
|
||||
assert.equal(pointOf.get('root')?.x, 104 + 104)
|
||||
assert.equal(pointOf.get('g')?.x, SLOT / 2)
|
||||
assert.equal(pointOf.get('a')?.x, SLOT / 2)
|
||||
assert.equal(pointOf.get('b')?.x, SLOT / 2 + SLOT)
|
||||
assert.equal(pointOf.get('root')?.x, SLOT)
|
||||
// One row per depth level.
|
||||
assert.equal(pointOf.get('root')?.y, 48)
|
||||
assert.equal(pointOf.get('a')?.y, 48 + 144)
|
||||
@@ -602,15 +605,15 @@ describe('layoutForest', () => {
|
||||
assert.equal(linkG.color, familyHue(0))
|
||||
assert.equal(layout.links.find(l => l.to === 'b')?.color, familyHue(1))
|
||||
assert.equal(layout.links.length, 3)
|
||||
assert.equal(layout.width, 2 * 208)
|
||||
assert.equal(layout.width, 2 * SLOT)
|
||||
assert.equal(layout.height, 48 + 2 * 144 + 104 + 24)
|
||||
})
|
||||
|
||||
test('responsive: a wide stage keeps the natural pitch', () => {
|
||||
const forest = forestOf([['root'], ['a', 'root'], ['b', 'root'], ['c', 'root']])
|
||||
const layout = layoutForest(forest, 4000)
|
||||
assert.equal(layout.width, 3 * 208)
|
||||
assert.equal(layout.cardW, 208 - 12)
|
||||
assert.equal(layout.width, 3 * SLOT)
|
||||
assert.equal(layout.cardW, SLOT - 12)
|
||||
})
|
||||
|
||||
test('responsive: a tighter stage compresses the slot pitch to fit exactly', () => {
|
||||
|
||||
@@ -173,11 +173,11 @@ describe('AgentGraph — the family tree', () => {
|
||||
assert.ok(query(m.container, '[data-agent="worker"]').querySelector('.lc-agent-self-badge') === null)
|
||||
|
||||
// Links join both children as bezier curves out of the root card's foot
|
||||
// (x=208: root centers over the two leaf slots) with joint plugs at both ends;
|
||||
// the running one layers a flowing pulse over the solid lineage stroke.
|
||||
// (x=276: the natural slot pitch, with the root centered over the two leaf slots)
|
||||
// with joint plugs at both ends; the running one layers a flowing pulse over the solid lineage stroke.
|
||||
const links = queryAll(m.container, 'path.lc-agents-link')
|
||||
assert.equal(links.length, 2)
|
||||
assert.ok(links.every(l => l.getAttribute('d')?.startsWith('M 208 ')))
|
||||
assert.ok(links.every(l => l.getAttribute('d')?.startsWith('M 276 ')))
|
||||
assert.ok(links.every(l => l.getAttribute('d')?.includes(' C ')))
|
||||
assert.equal(queryAll(m.container, 'path.lc-agents-link-live').length, 1)
|
||||
assert.equal(queryAll(m.container, 'path.lc-agents-flow').length, 1)
|
||||
|
||||
Reference in new issue
Block a user