← Cycles
Qmap · c15
QMap V1 — Production Component
archivedcreated 2025-03-18· last activity 2026-03-23
Promote 14 cycles of experimental work to a clean, consumable `src/` component
Why
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 src/ — which still rendered a spinning dodecahedron. The goal: create a clean v1 component that other projects can import and pass reactive data to.
What Changed
This is not an experiment cycle — it's a promotion cycle. No new features were invented. Instead, c14's battle-tested code was reorganized, cleaned, and wired into a props-driven Vue component.
New src/ Structure (37 files)
src/
├── index.js # Public exports
├── components/QMap.vue # Props → scene (full rewrite)
├── composables/
│ ├── useQMap.js # Extended with entity animation loop
│ ├── useSceneLoader.js # From c14, stripped test scenarios
│ ├── useActorSelection.js # From c14, options object pattern
│ └── useSceneReactivity.js # NEW: watches props → reconciler → transitions
├── core/
│ ├── SceneManager.js # Existing (documented)
│ ├── CameraControls.js # Existing (added public isDragging/updateFrustum)
│ ├── SceneReconciler.js # From c14 (pure, unchanged)
│ ├── TransitionOrchestrator.js # From c14 (RAF leak fixed)
│ ├── LayoutEngine.js # From c14
│ ├── ViewOrchestrator.js # From c14
│ ├── GroupingStrategy.js # From c14
│ ├── animation.js # From c14
│ └── cameraAnimation.js # From c14 (uses public API now)
├── entities/ # All 7 files from c14
├── flows/ # 3 files from c14
├── boundaries/GroupRug.js # From c14
├── layout/ # 4 files from c14
├── styles/ # colorScheme, labelMetrics
└── utils/transitionHelpers.js # Defensive copy utilities
Props API
defineProps({
actors: { type: Array, default: () => [] },
connections: { type: Array, default: () => [] },
groupBy: { type: Object, default: () => ({}) },
width, height, backgroundColor, frustumSize, selectable, autoStart, faviconProxy
})
Events
defineEmits(['ready', 'error', 'actor-select', 'actor-deselect', 'transition-start', 'transition-end'])
Reactivity Model
Props change → useSceneReactivity watches → LayoutEngine.compute() → SceneReconciler.reconcile() → TransitionOrchestrator.execute() (4-phase) → fit camera → refresh selection
- First load: direct build (no transition)
- Subsequent: animated reconciliation
- During transition: queue pending update, apply after completion
Public Exports
export { QMap } from './components/QMap.vue'
export { useQMap } from './composables/useQMap.js'
export { SceneManager } from './core/SceneManager.js'
export { CameraControls } from './core/CameraControls.js'
export { computeGrouping, getAvailableTags, getAvailableTagsByType } from './core/GroupingStrategy.js'
Bugs Fixed During Promotion
- Race condition: dual load paths — The
isReadywatcher manually calledloadData(), ANDuseSceneReactivity's deep watch also fired on initial props. Fixed with explicitactivate()/deactivate()lifecycle so the watcher doesn't register until afterinitialize(). - RAF leak in TransitionOrchestrator._phaseMove — The
syncFlowsRAF loop wasn't stored or cancelled on abort. Wrapped in try/finally withcancelAnimationFrame(). - Render target leak in SceneManager.captureImage — If
readRenderTargetPixels()threw, the WebGLRenderTarget was never disposed. Wrapped in try/finally. - Private API access —
_isDraggingand_updateFrustumaccessed from outside CameraControls. Added publicisDragging()andupdateFrustum()methods. Updated all callers. - freezeTransitionData unused — Imported but never applied in useSceneReactivity. Now used on connection updates and pending update queuing.
Documentation Pass
Added module-level docs and JSDoc to all core/public API files:
- SceneManager, CameraControls, TransitionOrchestrator, ViewOrchestrator, GroupingStrategy
- GroupRug (extracted magic numbers to named constants)
- GroupItem (documented skyline bin-packing algorithm)
- LineFlow (documented LINE_CONFIG values with units)
- LayoutEngine, useQMap
Design Project Integration
Updated /visualization/qmap.vue in ../design with:
- 18 actors (apps, services, databases, vendors, agents, users)
- Scenario switcher (Full / Small / Empty)
- Grouping mode buttons (Flat / By Type / By Cloud / By Team)
- Selection event display
- Transition indicator
Known Debt (acceptable for v1)
- Rug creation duplication between ViewOrchestrator and TransitionOrchestrator
- Deep watch on large actor arrays — optimize with identity-based comparison if >500 actors
LayoutEnginenot yet exposed as a public export (internal to composable)