← Cycles
Qflow · c7

layouts

archivedcreated 2026-03-23· last activity 2026-08-15

New in this cycle: Layout system — arc packing, radial destinations, growth relayout

What changed

1. Rename ArcLayout → RadialLayout

The old ArcLayout with fullCircle: true was actually radial distribution (concentric rings), not arc packing. Renamed to RadialLayout for clarity. Both exported from @qpoint-io/qflow. Stage.js now uses RadialLayout for endpoints.

2. New ArcLayout — true bounded-arc packing

Positions items along an arc segment between configurable startAngle and endAngle. Each item's angular footprint is 2 * arcsin(radius / arcRadius), so larger items consume more arc space and smaller items fill gaps naturally. Overflows to outer rings when the arc fills.

3. Growth-based relayout

Nodes grow via updateNodeSize() as traffic arrives, but layout previously only refreshed on new node discovery — causing overlaps over time.

The problem: When a node's radius increases from 5px to 15px, it now occupies 3x the space but its neighbors haven't moved. With dozens of nodes growing simultaneously, the layout becomes a mess of overlapping circles.

How it works:

  • Every call to updateNodeSize() accumulates |newRadius - oldRadius| into a running growthDelta counter
  • When growthDelta >= growthThreshold, a relayout is triggered and the counter resets to 0
  • A growthCooldown timer prevents back-to-back relayouts during traffic bursts

Two types of relayout, different triggers:

  • Discovery relayout — fires immediately when a new node appears (needs positioning)
  • Growth relayout — throttled by both threshold and cooldown (cosmetic fix for overlap)

Controls:

  • Growth Threshold (default 30px) — cumulative radius delta before relayout fires. Lower = more frequent relayouts (tighter spacing, more motion). Higher = tolerates more overlap before correcting.
  • Cooldown (default 500ms) — minimum time between growth relayouts. Prevents thrashing when many nodes resize in a burst.
  • Cumulative Delta — live readout of current accumulated radius change. Shows how close you are to the next growth relayout.

4. Layout interface refactor — computePositions

All layouts now expose computePositions(items) returning {positions: {key: {x,y}}, width, height} — pure data, no container side effects. A separate applyPositions(playerMap, positions, animated) utility handles tweening existing nodes and snapping new ones. This separation enables layout composition (ZonedLayout) and makes testing easier.

5. ZonedLayout stub

Documented interface for a future composite layout:

  • Ingress traffic in an arc on the left
  • Internal services in a packed cluster in the center
  • Egress traffic in an arc on the right

Design questions documented in source: item classification, zone sizing, pulse routing, reclassification animation.

6. Experiment controls

Added to toolbar:

  • Dest layout: Radial (renamed), Arc (new), Grid
  • Arc controls (visible when dest=arc): start angle, end angle, radius, ring gap sliders
  • Relayout section: growth threshold slider, cooldown slider, live cumulative delta display
  • New "Arc Demo" preset showcasing the bounded-arc layout
  • All existing c6 controls preserved

Visual record

9 captures — heroes, page slices, and full-page renders. Click to view.

Radial destinations (the new default) after ~9s
Radial destinations (the new default) after ~9s
Radial at ~20s — growth relayout has fired
Radial at ~20s — growth relayout has fired
Arc destinations at defaults
Arc destinations at defaults
Arc swept wide: −180°…180°, radius 300
Arc swept wide: −180°…180°, radius 300
Tight arc: −45°…45°, radius 150
Tight arc: −45°…45°, radius 150
The Arc Demo preset — the cycle's showcase configuration
The Arc Demo preset — the cycle's showcase configuration
Back to radial with pink pulses
Back to radial with pink pulses
Agent Sprawl preset under the new layout engine
Agent Sprawl preset under the new layout engine
c7 hero

Artifacts

/experiments/c7.layouts/ (local dev)

Qpoint Brand Style Guide