[{"data":1,"prerenderedAt":453},["ShallowReactive",2],{"$fn8scehs_Cmq78MIa9HS_1iM9t0YDFIRTxVOSBBGY44w":3},{"newThing":4,"project":5,"cycle":8,"sections":22,"threads":445,"otherDocs":446,"documents":448,"images":450,"archiveItems":451,"links":452},null,{"id":6,"label":7,"liveBase":4},"qmap","Qmap",{"id":9,"num":10,"dir":11,"name":12,"title":13,"focus":14,"status":15,"statusNote":4,"created":16,"completed":4,"mode":4,"report":4,"recordless":17,"thumbnail":4,"imageCount":18,"artifactCount":19,"lastActivity":20,"hasPickup":17,"hasInitialPrompt":21},"c15",15,"c15.production-component","production-component","QMap V1 — Production Component","Promote 14 cycles of experimental work to a clean, consumable `src\u002F` component","archived","2025-03-18",false,0,1,"2026-03-23",true,[23,46,168,327,364,417],{"key":24,"title":25,"empty":17,"ast":26},"why","Why",{"type":27,"children":28},"root",[29],{"type":30,"tag":31,"props":32,"children":33},"element","p",{},[34,37,44],{"type":35,"value":36},"text","QMap has 14 cycles of experiments culminating in c14 with 6 actor types, animated transitions, layout engine, flow visualization, and grouping strategies. None of this had been promoted to ",{"type":30,"tag":38,"props":39,"children":41},"code",{"className":40},[],[42],{"type":35,"value":43},"src\u002F",{"type":35,"value":45}," — which still rendered a spinning dodecahedron. The goal: create a clean v1 component that other projects can import and pass reactive data to.",{"key":47,"title":48,"empty":17,"ast":49},"extra","What Changed",{"type":27,"children":50},[51,64,71,83,89,100,106,114,120,129,149,155,163],{"type":30,"tag":31,"props":52,"children":53},{},[54,56,62],{"type":35,"value":55},"This is not an experiment cycle — it's a ",{"type":30,"tag":57,"props":58,"children":59},"strong",{},[60],{"type":35,"value":61},"promotion cycle",{"type":35,"value":63},". No new features were invented. Instead, c14's battle-tested code was reorganized, cleaned, and wired into a props-driven Vue component.",{"type":30,"tag":65,"props":66,"children":68},"h3",{"id":67},"new-src-structure-37-files",[69],{"type":35,"value":70},"New src\u002F Structure (37 files)",{"type":30,"tag":72,"props":73,"children":77},"pre",{"className":74,"code":76,"language":35},[75],"language-text","src\u002F\n├── index.js                          # Public exports\n├── components\u002FQMap.vue               # Props → scene (full rewrite)\n├── composables\u002F\n│   ├── useQMap.js                    # Extended with entity animation loop\n│   ├── useSceneLoader.js             # From c14, stripped test scenarios\n│   ├── useActorSelection.js          # From c14, options object pattern\n│   └── useSceneReactivity.js         # NEW: watches props → reconciler → transitions\n├── core\u002F\n│   ├── SceneManager.js               # Existing (documented)\n│   ├── CameraControls.js             # Existing (added public isDragging\u002FupdateFrustum)\n│   ├── SceneReconciler.js            # From c14 (pure, unchanged)\n│   ├── TransitionOrchestrator.js     # From c14 (RAF leak fixed)\n│   ├── LayoutEngine.js               # From c14\n│   ├── ViewOrchestrator.js           # From c14\n│   ├── GroupingStrategy.js           # From c14\n│   ├── animation.js                  # From c14\n│   └── cameraAnimation.js            # From c14 (uses public API now)\n├── entities\u002F                         # All 7 files from c14\n├── flows\u002F                            # 3 files from c14\n├── boundaries\u002FGroupRug.js            # From c14\n├── layout\u002F                           # 4 files from c14\n├── styles\u002F                           # colorScheme, labelMetrics\n└── utils\u002FtransitionHelpers.js        # Defensive copy utilities\n",[78],{"type":30,"tag":38,"props":79,"children":81},{"__ignoreMap":80},"",[82],{"type":35,"value":76},{"type":30,"tag":65,"props":84,"children":86},{"id":85},"props-api",[87],{"type":35,"value":88},"Props API",{"type":30,"tag":72,"props":90,"children":95},{"className":91,"code":92,"language":93,"meta":80,"style":94},"language-js","defineProps({\n  actors:      { type: Array, default: () => [] },\n  connections: { type: Array, default: () => [] },\n  groupBy:     { type: Object, default: () => ({}) },\n  width, height, backgroundColor, frustumSize, selectable, autoStart, faviconProxy\n})\n","js","undefined",[96],{"type":30,"tag":38,"props":97,"children":98},{"__ignoreMap":80},[99],{"type":35,"value":92},{"type":30,"tag":65,"props":101,"children":103},{"id":102},"events",[104],{"type":35,"value":105},"Events",{"type":30,"tag":72,"props":107,"children":109},{"className":91,"code":108,"language":93,"meta":80,"style":94},"defineEmits(['ready', 'error', 'actor-select', 'actor-deselect', 'transition-start', 'transition-end'])\n",[110],{"type":30,"tag":38,"props":111,"children":112},{"__ignoreMap":80},[113],{"type":35,"value":108},{"type":30,"tag":65,"props":115,"children":117},{"id":116},"reactivity-model",[118],{"type":35,"value":119},"Reactivity Model",{"type":30,"tag":72,"props":121,"children":124},{"className":122,"code":123,"language":35},[75],"Props change → useSceneReactivity watches → LayoutEngine.compute() → SceneReconciler.reconcile() → TransitionOrchestrator.execute() (4-phase) → fit camera → refresh selection\n",[125],{"type":30,"tag":38,"props":126,"children":127},{"__ignoreMap":80},[128],{"type":35,"value":123},{"type":30,"tag":130,"props":131,"children":132},"ul",{},[133,139,144],{"type":30,"tag":134,"props":135,"children":136},"li",{},[137],{"type":35,"value":138},"First load: direct build (no transition)",{"type":30,"tag":134,"props":140,"children":141},{},[142],{"type":35,"value":143},"Subsequent: animated reconciliation",{"type":30,"tag":134,"props":145,"children":146},{},[147],{"type":35,"value":148},"During transition: queue pending update, apply after completion",{"type":30,"tag":65,"props":150,"children":152},{"id":151},"public-exports",[153],{"type":35,"value":154},"Public Exports",{"type":30,"tag":72,"props":156,"children":158},{"className":91,"code":157,"language":93,"meta":80,"style":94},"export { QMap } from '.\u002Fcomponents\u002FQMap.vue'\nexport { useQMap } from '.\u002Fcomposables\u002FuseQMap.js'\nexport { SceneManager } from '.\u002Fcore\u002FSceneManager.js'\nexport { CameraControls } from '.\u002Fcore\u002FCameraControls.js'\nexport { computeGrouping, getAvailableTags, getAvailableTagsByType } from '.\u002Fcore\u002FGroupingStrategy.js'\n",[159],{"type":30,"tag":38,"props":160,"children":161},{"__ignoreMap":80},[162],{"type":35,"value":157},{"type":30,"tag":164,"props":165,"children":166},"style",{},[167],{"type":35,"value":80},{"key":47,"title":169,"empty":17,"ast":170},"Bugs Fixed During Promotion",{"type":27,"children":171},[172],{"type":30,"tag":173,"props":174,"children":175},"ol",{},[176,234,258,276,317],{"type":30,"tag":134,"props":177,"children":178},{},[179,184,186,192,194,200,202,208,210,216,218,224,226,232],{"type":30,"tag":57,"props":180,"children":181},{},[182],{"type":35,"value":183},"Race condition: dual load paths",{"type":35,"value":185}," — The ",{"type":30,"tag":38,"props":187,"children":189},{"className":188},[],[190],{"type":35,"value":191},"isReady",{"type":35,"value":193}," watcher manually called ",{"type":30,"tag":38,"props":195,"children":197},{"className":196},[],[198],{"type":35,"value":199},"loadData()",{"type":35,"value":201},", AND ",{"type":30,"tag":38,"props":203,"children":205},{"className":204},[],[206],{"type":35,"value":207},"useSceneReactivity",{"type":35,"value":209},"'s deep watch also fired on initial props. Fixed with explicit ",{"type":30,"tag":38,"props":211,"children":213},{"className":212},[],[214],{"type":35,"value":215},"activate()",{"type":35,"value":217},"\u002F",{"type":30,"tag":38,"props":219,"children":221},{"className":220},[],[222],{"type":35,"value":223},"deactivate()",{"type":35,"value":225}," lifecycle so the watcher doesn't register until after ",{"type":30,"tag":38,"props":227,"children":229},{"className":228},[],[230],{"type":35,"value":231},"initialize()",{"type":35,"value":233},".",{"type":30,"tag":134,"props":235,"children":236},{},[237,242,243,249,251,257],{"type":30,"tag":57,"props":238,"children":239},{},[240],{"type":35,"value":241},"RAF leak in TransitionOrchestrator._phaseMove",{"type":35,"value":185},{"type":30,"tag":38,"props":244,"children":246},{"className":245},[],[247],{"type":35,"value":248},"syncFlows",{"type":35,"value":250}," RAF loop wasn't stored or cancelled on abort. Wrapped in try\u002Ffinally with ",{"type":30,"tag":38,"props":252,"children":254},{"className":253},[],[255],{"type":35,"value":256},"cancelAnimationFrame()",{"type":35,"value":233},{"type":30,"tag":134,"props":259,"children":260},{},[261,266,268,274],{"type":30,"tag":57,"props":262,"children":263},{},[264],{"type":35,"value":265},"Render target leak in SceneManager.captureImage",{"type":35,"value":267}," — If ",{"type":30,"tag":38,"props":269,"children":271},{"className":270},[],[272],{"type":35,"value":273},"readRenderTargetPixels()",{"type":35,"value":275}," threw, the WebGLRenderTarget was never disposed. Wrapped in try\u002Ffinally.",{"type":30,"tag":134,"props":277,"children":278},{},[279,284,286,292,294,300,302,308,309,315],{"type":30,"tag":57,"props":280,"children":281},{},[282],{"type":35,"value":283},"Private API access",{"type":35,"value":285}," — ",{"type":30,"tag":38,"props":287,"children":289},{"className":288},[],[290],{"type":35,"value":291},"_isDragging",{"type":35,"value":293}," and ",{"type":30,"tag":38,"props":295,"children":297},{"className":296},[],[298],{"type":35,"value":299},"_updateFrustum",{"type":35,"value":301}," accessed from outside CameraControls. Added public ",{"type":30,"tag":38,"props":303,"children":305},{"className":304},[],[306],{"type":35,"value":307},"isDragging()",{"type":35,"value":293},{"type":30,"tag":38,"props":310,"children":312},{"className":311},[],[313],{"type":35,"value":314},"updateFrustum()",{"type":35,"value":316}," methods. Updated all callers.",{"type":30,"tag":134,"props":318,"children":319},{},[320,325],{"type":30,"tag":57,"props":321,"children":322},{},[323],{"type":35,"value":324},"freezeTransitionData unused",{"type":35,"value":326}," — Imported but never applied in useSceneReactivity. Now used on connection updates and pending update queuing.",{"key":47,"title":328,"empty":17,"ast":329},"Documentation Pass",{"type":27,"children":330},[331,336],{"type":30,"tag":31,"props":332,"children":333},{},[334],{"type":35,"value":335},"Added module-level docs and JSDoc to all core\u002Fpublic API files:",{"type":30,"tag":130,"props":337,"children":338},{},[339,344,349,354,359],{"type":30,"tag":134,"props":340,"children":341},{},[342],{"type":35,"value":343},"SceneManager, CameraControls, TransitionOrchestrator, ViewOrchestrator, GroupingStrategy",{"type":30,"tag":134,"props":345,"children":346},{},[347],{"type":35,"value":348},"GroupRug (extracted magic numbers to named constants)",{"type":30,"tag":134,"props":350,"children":351},{},[352],{"type":35,"value":353},"GroupItem (documented skyline bin-packing algorithm)",{"type":30,"tag":134,"props":355,"children":356},{},[357],{"type":35,"value":358},"LineFlow (documented LINE_CONFIG values with units)",{"type":30,"tag":134,"props":360,"children":361},{},[362],{"type":35,"value":363},"LayoutEngine, useQMap",{"key":47,"title":365,"empty":17,"ast":366},"Design Project Integration",{"type":27,"children":367},[368,389],{"type":30,"tag":31,"props":369,"children":370},{},[371,373,379,381,387],{"type":35,"value":372},"Updated ",{"type":30,"tag":38,"props":374,"children":376},{"className":375},[],[377],{"type":35,"value":378},"\u002Fvisualization\u002Fqmap.vue",{"type":35,"value":380}," in ",{"type":30,"tag":38,"props":382,"children":384},{"className":383},[],[385],{"type":35,"value":386},"..\u002Fdesign",{"type":35,"value":388}," with:",{"type":30,"tag":130,"props":390,"children":391},{},[392,397,402,407,412],{"type":30,"tag":134,"props":393,"children":394},{},[395],{"type":35,"value":396},"18 actors (apps, services, databases, vendors, agents, users)",{"type":30,"tag":134,"props":398,"children":399},{},[400],{"type":35,"value":401},"Scenario switcher (Full \u002F Small \u002F Empty)",{"type":30,"tag":134,"props":403,"children":404},{},[405],{"type":35,"value":406},"Grouping mode buttons (Flat \u002F By Type \u002F By Cloud \u002F By Team)",{"type":30,"tag":134,"props":408,"children":409},{},[410],{"type":35,"value":411},"Selection event display",{"type":30,"tag":134,"props":413,"children":414},{},[415],{"type":35,"value":416},"Transition indicator",{"key":47,"title":418,"empty":17,"ast":419},"Known Debt (acceptable for v1)",{"type":27,"children":420},[421],{"type":30,"tag":130,"props":422,"children":423},{},[424,429,434],{"type":30,"tag":134,"props":425,"children":426},{},[427],{"type":35,"value":428},"Rug creation duplication between ViewOrchestrator and TransitionOrchestrator",{"type":30,"tag":134,"props":430,"children":431},{},[432],{"type":35,"value":433},"Deep watch on large actor arrays — optimize with identity-based comparison if >500 actors",{"type":30,"tag":134,"props":435,"children":436},{},[437,443],{"type":30,"tag":38,"props":438,"children":440},{"className":439},[],[441],{"type":35,"value":442},"LayoutEngine",{"type":35,"value":444}," not yet exposed as a public export (internal to composable)",[],[447],"initial-prompt.md",[449],{"file":447,"title":4},[],[],[],1794599442926]