← Cycles

Default: apps by team, vendors by continent, datasets by kind 
Apps regrouped by criticality — mid-morph identity 
Apps by language 
Apps by datacenter 
Apps by pod — the finest grain 
Vendors regrouped by security policy 
Datasets by sensitive-data flag 
Curve height 8 over the regrouped field 
Qmap · c5
boundary-morphing
archivedcreated 2026-03-23· last activity 2026-08-15
New in this cycle: Runtime tag-based regrouping with animated boundary morphs
Goal
Explore dynamic boundary grouping based on actor tags, with animated transitions when groupings change.
Focus
- Tag-based data model for actors (Apps, Vendors, Datasets)
- Dynamic re-grouping at runtime
- Animated morphing between grouping configurations
- Visual "rug" boundaries beneath each group
Approach
- Each actor type has props and tags (key-value pairs)
- UI dropdowns let user select which tag to group by per actor type
- When grouping changes:
- Compute new layout positions
- Animate actors to new positions
- Fade out old rugs, fade in new rugs
- Update flow connections
Data Model
Apps
{
id: "app-api-gateway",
type: "app",
name: "API Gateway",
tags: {
criticality: "production",
language: "node",
datacenter: "AWS East",
pod: "gateway-7f8d9c",
team: "platform",
}
}
Vendors
{
id: "vendor-stripe",
type: "vendor",
name: "Stripe",
url: "stripe.com",
tags: {
securityPolicy: "critical-data",
continent: "N. America",
}
}
Datasets
{
id: "db-users",
type: "dataset",
name: "Users DB",
tags: {
kind: "Postgres",
pii: true,
sensitiveData: true,
criticality: "production",
}
}
Connections
{ id: "conn-1", origin: "app-api-gateway", destination: "vendor-stripe", timestamp: 1706900000000 }
Key Files
| File | Purpose |
|---|---|
shared/testData.js | Tagged actor data (8 Apps, 6 Vendors, 6 Datasets, 16 Connections) |
shared/layoutEngine.js | Computes positions for grouped actors and rug bounds |
shared/morphAnimation.js | Animation system for smooth transitions |
boundaries/GroupRug.js | Rug boundary visualization with labels |
components/GroupingControls.vue | UI dropdowns for selecting groupings |
entities/ | Reused from c3 (AppMesh, VendorMesh, DatabaseMesh) |
flows/ | Reused from c3 (LineFlow for connections) |
Test Data
| Actor Type | Count | Groupable Tags |
|---|---|---|
| Apps | 8 | criticality, language, datacenter, pod, team |
| Vendors | 6 | securityPolicy, continent |
| Datasets | 6 | kind, pii, sensitiveData, criticality |
Connections: 16 (linking apps to vendors, apps to datasets, apps to apps)
Learnings
Animation System Architecture
- Singleton AnimationController - Central controller manages all active animations via
requestAnimationFrameloop; prevents multiple competing loops - Promise-based API -
animateValue()returns Promise for clean async/await sequencing; enables "wait for X then do Y" patterns - Easing functions -
easeInOutCubicfor position morphing (smooth start/end),easeOutCubicfor fades (quick start, gentle landing)
Morph Transition Coordination
- Parallel where possible - Rug fades, actor visibility changes, and position animations run concurrently via
Promise.all - Real-time flow updates - Flow connections update every frame during actor position animation, not just at start/end
- Visibility-first filtering - Determine which actors have target positions; skip animating hidden elements entirely
Layout Engine Design
- Two-pass algorithm: (1) compute each group's internal grid layout and bounds, (2) arrange groups in a row and apply global offsets
- Grid positioning -
Math.ceil(Math.sqrt(count))columns gives roughly square grids - Type-specific Z offsets - Actors separated by type (datasets: -4, apps: 0, vendors: +4) for visual clarity without overlap
GroupRug Implementation
- Actor-type coloring - Blue/purple/green by type creates instant visual association
- Canvas label coloring - Label text uses same hex color as rug, maintaining cohesion
- Depth buffer settings -
depthWrite: false,polygonOffset: true,renderOrderhierarchy prevents z-fighting between overlapping transparent surfaces
Tag-Based Data Model
- Flat actors + rich metadata - No nested hierarchies; grouping is derived from tag queries at runtime
- "Unknown" fallback group - Actors missing the selected tag go to a catch-all group rather than disappearing
- Runtime flexibility - Same data, different views—grouping by
team,datacenter, orcriticalitywithout restructuring
What Worked Well
- Reusing c3 entity meshes and c4's ContainerRug pattern saved significant time
- Animation system is composable—can animate any value, not just specific properties
- Layout engine is deterministic (same inputs → same outputs), which simplifies debugging
Open Questions Answered
- Missing tags → "unknown" group (implemented)
- "No grouping" option → not implemented, but trivial (group all by constant key)
- Cross-boundary flows → flows animate correctly but don't yet visually emphasize boundary crossing
Relationship to Other Cycles
- c1.border-grouping: Rug visualization patterns reused here
- c2.entity-meshes: N/A (skipped to c3)
- c3.data-flows: Entity meshes and flow rendering reused
- c4.semantic-zoom: Morphing animation patterns informed by cube-to-rug transitions
Progress
- Create cycle structure
- Tag-based test data
- Layout engine for grouped actors
- GroupRug boundary visualization
- Morph animation system
- Grouping controls UI
- Wire up ExperimentsApp.vue
- Test and iterate
- Document learnings
Open Questions
- How should actors with missing tags be grouped? (Currently: "unknown" group)
- Should there be a "no grouping" option showing all actors flat?
- How do flows look when they cross group boundaries?
Visual record
9 captures — heroes, page slices, and full-page renders. Click to view.









Artifacts
/experiments/c5.boundary-morphing/ (local dev)