[{"data":1,"prerenderedAt":463},["ShallowReactive",2],{"$fr2bHN_Ocbbe-1aq7W7vx_RZe54CQDRNuxDUN403tPv4":3},{"newThing":4,"project":5,"cycle":9,"sections":21,"threads":418,"otherDocs":419,"documents":420,"images":421,"archiveItems":460,"links":461},"Layout system — arc packing, radial destinations, growth relayout",{"id":6,"label":7,"liveBase":8},"qflow","Qflow",null,{"id":10,"num":11,"dir":12,"name":13,"title":13,"focus":8,"status":14,"statusNote":8,"created":15,"completed":8,"mode":8,"report":8,"recordless":16,"thumbnail":17,"imageCount":18,"artifactCount":19,"lastActivity":20,"hasPickup":16,"hasInitialPrompt":16},"c7",7,"c7.layouts","layouts","archived","2026-03-23",false,"\u002Fcycles\u002Fqflow\u002Fc7-agent-sprawl.png",9,0,"2026-08-15",[22],{"key":23,"title":24,"empty":16,"ast":25},"extra","What changed",{"type":26,"children":27},"root",[28,37,91,97,126,132,145,156,164,223,231,254,262,295,301,330,336,341,359,364,370,375],{"type":29,"tag":30,"props":31,"children":33},"element","h3",{"id":32},"_1-rename-arclayout-radiallayout",[34],{"type":35,"value":36},"text","1. Rename ArcLayout → RadialLayout",{"type":29,"tag":38,"props":39,"children":40},"p",{},[41,43,50,52,58,60,66,68,74,76,82,84,89],{"type":35,"value":42},"The old ",{"type":29,"tag":44,"props":45,"children":47},"code",{"className":46},[],[48],{"type":35,"value":49},"ArcLayout",{"type":35,"value":51}," with ",{"type":29,"tag":44,"props":53,"children":55},{"className":54},[],[56],{"type":35,"value":57},"fullCircle: true",{"type":35,"value":59}," was actually radial distribution (concentric rings), not arc packing. Renamed to ",{"type":29,"tag":44,"props":61,"children":63},{"className":62},[],[64],{"type":35,"value":65},"RadialLayout",{"type":35,"value":67}," for clarity. Both exported from ",{"type":29,"tag":44,"props":69,"children":71},{"className":70},[],[72],{"type":35,"value":73},"@qpoint-io\u002Fqflow",{"type":35,"value":75},". ",{"type":29,"tag":44,"props":77,"children":79},{"className":78},[],[80],{"type":35,"value":81},"Stage.js",{"type":35,"value":83}," now uses ",{"type":29,"tag":44,"props":85,"children":87},{"className":86},[],[88],{"type":35,"value":65},{"type":35,"value":90}," for endpoints.",{"type":29,"tag":30,"props":92,"children":94},{"id":93},"_2-new-arclayout-true-bounded-arc-packing",[95],{"type":35,"value":96},"2. New ArcLayout — true bounded-arc packing",{"type":29,"tag":38,"props":98,"children":99},{},[100,102,108,110,116,118,124],{"type":35,"value":101},"Positions items along an arc segment between configurable ",{"type":29,"tag":44,"props":103,"children":105},{"className":104},[],[106],{"type":35,"value":107},"startAngle",{"type":35,"value":109}," and ",{"type":29,"tag":44,"props":111,"children":113},{"className":112},[],[114],{"type":35,"value":115},"endAngle",{"type":35,"value":117},". Each item's angular footprint is ",{"type":29,"tag":44,"props":119,"children":121},{"className":120},[],[122],{"type":35,"value":123},"2 * arcsin(radius \u002F arcRadius)",{"type":35,"value":125},", so larger items consume more arc space and smaller items fill gaps naturally. Overflows to outer rings when the arc fills.",{"type":29,"tag":30,"props":127,"children":129},{"id":128},"_3-growth-based-relayout",[130],{"type":35,"value":131},"3. Growth-based relayout",{"type":29,"tag":38,"props":133,"children":134},{},[135,137,143],{"type":35,"value":136},"Nodes grow via ",{"type":29,"tag":44,"props":138,"children":140},{"className":139},[],[141],{"type":35,"value":142},"updateNodeSize()",{"type":35,"value":144}," as traffic arrives, but layout previously only refreshed on new node discovery — causing overlaps over time.",{"type":29,"tag":38,"props":146,"children":147},{},[148,154],{"type":29,"tag":149,"props":150,"children":151},"strong",{},[152],{"type":35,"value":153},"The problem:",{"type":35,"value":155}," 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.",{"type":29,"tag":38,"props":157,"children":158},{},[159],{"type":29,"tag":149,"props":160,"children":161},{},[162],{"type":35,"value":163},"How it works:",{"type":29,"tag":165,"props":166,"children":167},"ul",{},[168,197,210],{"type":29,"tag":169,"props":170,"children":171},"li",{},[172,174,179,181,187,189,195],{"type":35,"value":173},"Every call to ",{"type":29,"tag":44,"props":175,"children":177},{"className":176},[],[178],{"type":35,"value":142},{"type":35,"value":180}," accumulates ",{"type":29,"tag":44,"props":182,"children":184},{"className":183},[],[185],{"type":35,"value":186},"|newRadius - oldRadius|",{"type":35,"value":188}," into a running ",{"type":29,"tag":44,"props":190,"children":192},{"className":191},[],[193],{"type":35,"value":194},"growthDelta",{"type":35,"value":196}," counter",{"type":29,"tag":169,"props":198,"children":199},{},[200,202,208],{"type":35,"value":201},"When ",{"type":29,"tag":44,"props":203,"children":205},{"className":204},[],[206],{"type":35,"value":207},"growthDelta >= growthThreshold",{"type":35,"value":209},", a relayout is triggered and the counter resets to 0",{"type":29,"tag":169,"props":211,"children":212},{},[213,215,221],{"type":35,"value":214},"A ",{"type":29,"tag":44,"props":216,"children":218},{"className":217},[],[219],{"type":35,"value":220},"growthCooldown",{"type":35,"value":222}," timer prevents back-to-back relayouts during traffic bursts",{"type":29,"tag":38,"props":224,"children":225},{},[226],{"type":29,"tag":149,"props":227,"children":228},{},[229],{"type":35,"value":230},"Two types of relayout, different triggers:",{"type":29,"tag":165,"props":232,"children":233},{},[234,244],{"type":29,"tag":169,"props":235,"children":236},{},[237,242],{"type":29,"tag":149,"props":238,"children":239},{},[240],{"type":35,"value":241},"Discovery relayout",{"type":35,"value":243}," — fires immediately when a new node appears (needs positioning)",{"type":29,"tag":169,"props":245,"children":246},{},[247,252],{"type":29,"tag":149,"props":248,"children":249},{},[250],{"type":35,"value":251},"Growth relayout",{"type":35,"value":253}," — throttled by both threshold and cooldown (cosmetic fix for overlap)",{"type":29,"tag":38,"props":255,"children":256},{},[257],{"type":29,"tag":149,"props":258,"children":259},{},[260],{"type":35,"value":261},"Controls:",{"type":29,"tag":165,"props":263,"children":264},{},[265,275,285],{"type":29,"tag":169,"props":266,"children":267},{},[268,273],{"type":29,"tag":149,"props":269,"children":270},{},[271],{"type":35,"value":272},"Growth Threshold",{"type":35,"value":274}," (default 30px) — cumulative radius delta before relayout fires. Lower = more frequent relayouts (tighter spacing, more motion). Higher = tolerates more overlap before correcting.",{"type":29,"tag":169,"props":276,"children":277},{},[278,283],{"type":29,"tag":149,"props":279,"children":280},{},[281],{"type":35,"value":282},"Cooldown",{"type":35,"value":284}," (default 500ms) — minimum time between growth relayouts. Prevents thrashing when many nodes resize in a burst.",{"type":29,"tag":169,"props":286,"children":287},{},[288,293],{"type":29,"tag":149,"props":289,"children":290},{},[291],{"type":35,"value":292},"Cumulative Delta",{"type":35,"value":294}," — live readout of current accumulated radius change. Shows how close you are to the next growth relayout.",{"type":29,"tag":30,"props":296,"children":298},{"id":297},"_4-layout-interface-refactor-computepositions",[299],{"type":35,"value":300},"4. Layout interface refactor — computePositions",{"type":29,"tag":38,"props":302,"children":303},{},[304,306,312,314,320,322,328],{"type":35,"value":305},"All layouts now expose ",{"type":29,"tag":44,"props":307,"children":309},{"className":308},[],[310],{"type":35,"value":311},"computePositions(items)",{"type":35,"value":313}," returning ",{"type":29,"tag":44,"props":315,"children":317},{"className":316},[],[318],{"type":35,"value":319},"{positions: {key: {x,y}}, width, height}",{"type":35,"value":321}," — pure data, no container side effects. A separate ",{"type":29,"tag":44,"props":323,"children":325},{"className":324},[],[326],{"type":35,"value":327},"applyPositions(playerMap, positions, animated)",{"type":35,"value":329}," utility handles tweening existing nodes and snapping new ones. This separation enables layout composition (ZonedLayout) and makes testing easier.",{"type":29,"tag":30,"props":331,"children":333},{"id":332},"_5-zonedlayout-stub",[334],{"type":35,"value":335},"5. ZonedLayout stub",{"type":29,"tag":38,"props":337,"children":338},{},[339],{"type":35,"value":340},"Documented interface for a future composite layout:",{"type":29,"tag":165,"props":342,"children":343},{},[344,349,354],{"type":29,"tag":169,"props":345,"children":346},{},[347],{"type":35,"value":348},"Ingress traffic in an arc on the left",{"type":29,"tag":169,"props":350,"children":351},{},[352],{"type":35,"value":353},"Internal services in a packed cluster in the center",{"type":29,"tag":169,"props":355,"children":356},{},[357],{"type":35,"value":358},"Egress traffic in an arc on the right",{"type":29,"tag":38,"props":360,"children":361},{},[362],{"type":35,"value":363},"Design questions documented in source: item classification, zone sizing, pulse routing, reclassification animation.",{"type":29,"tag":30,"props":365,"children":367},{"id":366},"_6-experiment-controls",[368],{"type":35,"value":369},"6. Experiment controls",{"type":29,"tag":38,"props":371,"children":372},{},[373],{"type":35,"value":374},"Added to toolbar:",{"type":29,"tag":165,"props":376,"children":377},{},[378,388,398,408,413],{"type":29,"tag":169,"props":379,"children":380},{},[381,386],{"type":29,"tag":149,"props":382,"children":383},{},[384],{"type":35,"value":385},"Dest layout",{"type":35,"value":387},": Radial (renamed), Arc (new), Grid",{"type":29,"tag":169,"props":389,"children":390},{},[391,396],{"type":29,"tag":149,"props":392,"children":393},{},[394],{"type":35,"value":395},"Arc controls",{"type":35,"value":397}," (visible when dest=arc): start angle, end angle, radius, ring gap sliders",{"type":29,"tag":169,"props":399,"children":400},{},[401,406],{"type":29,"tag":149,"props":402,"children":403},{},[404],{"type":35,"value":405},"Relayout section",{"type":35,"value":407},": growth threshold slider, cooldown slider, live cumulative delta display",{"type":29,"tag":169,"props":409,"children":410},{},[411],{"type":35,"value":412},"New \"Arc Demo\" preset showcasing the bounded-arc layout",{"type":29,"tag":169,"props":414,"children":415},{},[416],{"type":35,"value":417},"All existing c6 controls preserved",[],[],[],[422,429,433,437,441,445,449,453,456],{"src":423,"kind":424,"order":425,"caption":426,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-radial-warm.png","hero",57,"Radial destinations (the new default) after ~9s","2026-08-15T23:39:22.618Z","\u002Fexperiments\u002Fc7.layouts\u002F",{"src":430,"kind":424,"order":431,"caption":432,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-radial-rich.png",58,"Radial at ~20s — growth relayout has fired",{"src":434,"kind":424,"order":435,"caption":436,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-arc.png",59,"Arc destinations at defaults",{"src":438,"kind":424,"order":439,"caption":440,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-arc-wide.png",60,"Arc swept wide: −180°…180°, radius 300",{"src":442,"kind":424,"order":443,"caption":444,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-arc-tight.png",61,"Tight arc: −45°…45°, radius 150",{"src":446,"kind":424,"order":447,"caption":448,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-arc-demo-preset.png",62,"The Arc Demo preset — the cycle's showcase configuration",{"src":450,"kind":424,"order":451,"caption":452,"capturedAt":427,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-pink-radial.png",63,"Back to radial with pink pulses",{"src":17,"kind":424,"order":454,"caption":455,"capturedAt":427,"route":428},64,"Agent Sprawl preset under the new layout engine",{"src":457,"kind":424,"order":458,"capturedAt":459,"route":428},"\u002Fcycles\u002Fqflow\u002Fc7-layouts.png",4999,"2026-08-15T19:12:09.496Z",[],[462],{"route":428,"href":8},1794599436051]