← Cycles
Qmap · c2

entity-meshes

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

New in this cycle: Four distinguishable actor mesh archetypes with states and labels

Summary

Established a solid OOP foundation for actor entity meshes with distinct visual identities, state management, and animation systems.


Architecture

Class Hierarchy

BaseMesh (abstract)
├── AppMesh      - Dodecahedron, full tumble spin
├── ServiceMesh  - Hexagonal prism, grounded spin
├── DatabaseMesh - Stacked octagon slabs, grounded spin
└── VendorMesh   - Octahedron + favicon sprite, full tumble

Key Patterns

1. Animation Config Merging Subclasses define their defaults, then spread incoming options on top:

const animation = {
  bob: false,
  spin: true,
  spinMode: "grounded",  // subclass default
  ...options.animation,   // caller can override
};

This ensures type-specific behaviors persist even when callers provide partial options.

2. State Material Registration Materials that should respond to state changes register via registerStateMaterial(). The base setState() iterates and updates color/opacity. Materials that should stay constant (like vendor favicons) simply don't register.

3. Disposable Resource Tracking All geometries, materials, and textures call registerDisposable(). The dispose() method cleans up everything - prevents GPU memory leaks.

4. Edge Line HelperscreateEdgeLines(geometry, options) centralizes the LineMaterial/LineSegments2 boilerplate. Supports optional material reuse for efficiency (DatabaseMesh shares one edge material across 3 slabs).

5. Canvas Texture Redrawing Labels and favicons store their canvas/context for dynamic updates. On state change, redraw the canvas and set texture.needsUpdate = true.


Entity Shapes & Behaviors

TypeGeometrySpin ModeVisual Meaning
AppDodecahedronfull (tumble)Complex, multi-faceted internal app
ServiceHexagonal prismgrounded (Y-axis)Modular, stable backend service
Database3 stacked octagonsgrounded (Y-axis)Layered data storage
VendorOctahedron (diamond)full (tumble)External, valuable third-party

State System

Four states with distinct visual treatments:

StateMesh ColorMesh OpacityLabel OpacityLabel Border
activePurple1.01.0Purple
highlightedTeal1.01.0Teal
warningRed1.01.0Red
ignoredWhite0.350.3White

Vendor favicons: icon fades to 0.3 when ignored, white background stays full opacity.


What Works Well

  1. Clean separation - BaseMesh handles lifecycle/animation, subclasses define geometry
  2. Semantic shapes - Each type is instantly distinguishable
  3. Grounded vs full spin - Services/databases feel "infrastructure-like", apps/vendors feel "dynamic"
  4. State reactivity - Single setState() call updates everything consistently
  5. Factory pattern - createEntity(type, options) for runtime type selection

Lessons Learned

Animation override trap: Initially subclasses overrode update() just to skip spin. Wasteful - the base class already checks animState.spin. Removed overrides, used config flags instead.

Options merging matters: Using options.animation ?? defaults completely replaces defaults. Using { ...defaults, ...options.animation } preserves type-specific behaviors.

Canvas textures need explicit updates: Three.js caches textures. After redrawing a canvas, must set texture.needsUpdate = true or changes won't appear.

Favicon state handling: Registering favicon as a state material caused unwanted color tinting. Solution: don't register it, handle opacity separately in _drawFavicon() using ctx.globalAlpha.


Technical Debt / Future Work

  1. Label text truncation - Long labels overflow the canvas. Consider auto-sizing or ellipsis.
  2. Edge line resolution - LineMaterial needs window resolution. Currently set at creation time - won't adapt to window resize.
  3. Favicon error states - Failed favicon loads silently. Could show a placeholder icon.
  4. Performance at scale - Each entity creates its own canvas texture. For 100+ entities, consider texture atlasing.
  5. Animation easing - Current bob uses raw Math.sin(). Could add easing functions for more organic motion.

Files

entities/
├── index.js         - Factory + exports
├── BaseMesh.js      - Base class (~285 lines)
├── AppMesh.js       - Dodecahedron (~63 lines)
├── ServiceMesh.js   - Hexagon (~64 lines)
├── DatabaseMesh.js  - Stacked slabs (~90 lines)
└── VendorMesh.js    - Diamond + favicon (~185 lines)

shared/
├── testData.js      - Sample actors + state colors
├── colorScheme.js   - Color definitions
└── ExperimentBase.js - Three.js scene setup

Ready for Next Cycle

The entity system is production-ready for connecting actors with traffic flows. Next logical step: traffic lines/flows between entities (c3?).

Visual record

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

The four archetypes at rest (spin frozen)
The four archetypes at rest (spin frozen)
Active state markers
Active state markers
Highlighted state
Highlighted state
Warning state
Warning state
Ignored — dimmed out of the story
Ignored — dimmed out of the story
Low ambient, low direct — the moody read
Low ambient, low direct — the moody read
Everything at 2.0 — flat and bright
Everything at 2.0 — flat and bright
Grid intensity at 3
Grid intensity at 3
c2 legacy

Artifacts

/experiments/c2.entity-meshes/ (local dev)

Qpoint Brand Style Guide