Nondominium UI Design Vision

MVP

This section describes the minimalistic UI for MVP Layer 0 — NDO Identity (stable anchor; only lifecycle_stage evolves after creation; REQ-NDO-L0-*). The MVP UI implements the concepts of Lobby, Groups, and NDO view.

Lobby → Groups → NDOs three-level hierarchy — DNA architecture, identity progression, and navigation flow

Lobby discovers Groups (via GroupAnnouncement in the shared Lobby DHT) — not NDOs. Groups discover NDOs via SoftLink entries in each Group's own cloned-cell DHT. The Lobby's NdoBrowser shows only NDOs from the agent's own groups, not a global public registry. NDOs can only be created from within a Group. Identity: localStorage nickname → per-group profile → Person DHT entry on first NDO action.


Lobby

The Lobby is a permissionless digital environment that anyone can join. It is the persistent outer shell of the application, always visible regardless of which route is active.

Implemented:

  • Persistent left sidebar present on all routes, containing:
    • Browse NDOs link → root page (/) listing all unique NDOs across all the user's groups, with filter chips (Lifecycle Stage, Resource Nature, Property Regime)
    • Groups list — links to each group the user has created or joined (/group/:id)
    • + New Group — inline form: user enters a group name and confirms; they become the group creator
    • → Join Group — inline form: user pastes an invite code or link
    • My Profile / Edit profile — at the bottom of the sidebar; opens the profile modal
  • First-time profile modal — triggered automatically on first app launch when no lobby profile exists; requires at least a nickname; all other fields (real name, bio, email) are optional and stored in localStorage

Groups

Groups are organizational contexts for NDOs. A user can create a solo Group or join an existing one. Groups are DNA-backed: each group is a cloned Group DNA cell (clone_cell, zome_group) with its own isolated DHT, announced for discovery via the Lobby DNA. Only the Level 2 presentation choice (GroupMemberProfile — anonymous vs. selected fields) remains in localStorage; membership and NDO associations live on the DHT (SoftLinks).

Implemented:

  • Group panel (/group/:id): shows group name, list of NDO cards, member list, and a "Create NDO" button
  • Group profile prompt: on first visit to a group the user is asked how they wish to present themselves (anonymous / custom); stored in localStorage
  • NDO cards in group: each card shows name, lifecycle-stage badge, property-regime badge, resource-nature badge, and description excerpt; clicking a card navigates to the NDO detail page
  • Switching groups: navigating from one group to another correctly reloads the group name and NDO list
  • Invite links (multi-member groups): generateInviteLink encodes { network_seed, group_dna_hash, group_name } as ?group=<base64>; Sidebar and GroupView expose "Copy invite"; joinGroup provisions the clone cell and calls join_group
  • Group members from DHT: MemberList is wired to groupService.getMembers(cellId) on the group clone cell (each member is the action author of a GroupMembership entry linked from the group hash)
  • Reactive join: a joined group appears in the sidebar immediately. joinGroup polls get_my_group (fetchGroupProfileWithRetry) to absorb DHT gossip latency, and falls back to an invite-payload GroupDescriptor if the profile has not yet synced, so no page reload is needed. TODO(signals): replace polling with a Holochain remote signal once available.
  • Membership self-heal: because joinGroup's membership commit is best-effort (it can take the payload-fallback path before the group profile gossips, and the join_group call is non-fatal), opening a group runs an idempotent lobbyService.ensureMembership(groupId) (resolve group hash → is_memberjoin_group if missing). This guarantees a joined agent is eventually a committed member and appears in everyone's member list, even if the original join missed.
  • Pull-based reactivity for shared items: while a group is open, GroupView silently re-fetches it (members + NDOs via groupStore.refreshCurrentGroup()) on tab focus / visibility change and on a gentle ~8s poll (paused when the tab is hidden). New items gossiped from other members therefore surface without a manual reload. TODO(signals): replace this pull layer with Holochain remote signals (focus/poll kept only as an offline/missed-signal fallback).

Not yet implemented:

  • Group-level governance
  • Push-based reactivity via Holochain signals (currently pull-based: focus + poll + per-open reconciliation). Cross-member changes appear within the poll interval / on focus / on reload rather than instantly.

NDO Creation

NDOs can only be created from within a Group. The "Create NDO" button in a Group panel opens a creation form. NDO identity data is stored on the Holochain DHT as a NondominiumIdentity (Layer 0) entry; the action_hash of that entry is the NDO's permanent stable identity.

Implemented fields:

FieldControlNotes
nametext inputrequired; uniqueness warning shown if name already exists in the lobby
property_regimeselect4 variants: Private, Commons, Nondominium, CommonPool; tooltip per option
resource_natureselect5 variants: Physical, Digital, Service, Hybrid, Information; tooltip per option
lifecycle_stageselectseven creatable-at-registration stages: Ideation, Specification, Development, Prototype, Stable, Distributed, Active (matches create_ndo validation); Hibernating and terminal stages (Deprecated, EndOfLife) are not selectable here — only via lifecycle transitions after registration
descriptiontextareaoptional

Note: the original spec listed 6 property-regime variants (including Collective and Pool) and 4 initial lifecycle stages (including Prototype). Both have been revised — see the Rust PropertyRegime enum and LifecycleStage for current canonical values.


NDO View

Clicking an NDO card navigates to /ndo/:hash.

Implemented:

  • NDO name displayed in header (populated immediately from in-memory cache on card click; refreshed from DHT in the background)
  • Truncated hash shown below the name
  • Detail card: labeled fields for Description, Property Regime, Resource Nature, Lifecycle Stage, and Created date
  • Identity badges: lifecycle-stage color badge, property-regime badge, resource-nature badge
  • Lifecycle transition button (visible to NDO initiator only): advances the lifecycle stage
  • Join NDO button — placeholder; toggles inline "Coming soon"; no backend call yet
  • Associate with a group button — always shown in the header; opens a modal that lists groups the user has created or joined that are not already linked to this NDO (multi-select); if the user has no groups, the modal explains that case; confirming writes associations to localStorage (ndo_groups_v1 keyed like other group data — see group.store.svelte.ts); the NDO card then appears in the selected group(s)
  • Fork this NDO button — opens the fork friction modal; visible only when the Holochain conductor is connected and the UI has resolved the user's agent key
  • Tabs: Resources, Governance, Composition, Activity (stubs for post-MVP content)

Browse NDOs

Implemented:

  • "Browse NDOs" in sidebar → root page showing all unique NDOs from all groups the user has created or joined
  • Filter chips by Lifecycle Stage, Resource Nature, and Property Regime (4 variants)
  • NDO cards with name, badges, description excerpt, and truncated hash
  • "No NDOs yet" state when the user has no groups or no NDOs

User / Agent Identity

At the Lobby level the User can be anyone. At this level the User creates a Lobby Profile, stored in localStorage. At the Group level the User also has a profile, linked to the Lobby profile but customizable per group. As the User creates or links to an NDO, their identity is distilled into a Holochain Agent (as implemented in zome_person). Since NDOs are public and permissionless, no personal information is revealed at the NDO level — only a pseudonymous agent key address is shown. Access to personal data (e.g. PPR — Personal Participation Receipts) is selective and governed by the Governance zome.

Implemented:

  • First-time Lobby profile modal: nickname required; realName, bio, email optional; stored in localStorage
  • "Edit profile" in sidebar for returning users
  • Group profile prompt on first group visit: user can choose how to present themselves (anonymous or with selected fields from their Lobby profile)
  • Agent public key shown on the NDO initiator line when Holochain is connected

MVP ToDos

Status (2026-06): All eight MVP ToDos below are implemented. Groups are DNA-backed via cloned Group cells (clone_cell, zome_group); NDO lists use SoftLink entries on the group DHT. Join NDO is UI + API contract only (backend stub).

  1. Multi-member groups — invite linkgenerateInviteLink encodes {network_seed, group_dna_hash, group_name}; Sidebar and GroupView expose copy-invite; joinGroup provisions clone cell and calls join_group.

  2. NDO fork frictionForkNdoModal.svelte displays negotiation → consensus → Unyt stake notice before copy-pubkey CTA.

  3. NDO detail page — DHT refresh reliability/ndo/[hash] calls resource.getNdo(hash) directly via getNdoDescriptorForSpecActionHash; cache is fallback only.

  4. Group member listMemberList wired to groupService.getMembers(cellId) from group clone cell.

  5. Browse NDOs onboardingNdoBrowser empty state distinguishes no-groups vs no-NDOs with create/join CTAs.

  6. Update agent.md ✅ Three-tier identity model documented (§2.0); Level 2 profiles remain localStorage; groups are DHT-backed.

  7. NDO–Group association DHT propagationcreate_soft_link on group cell; lobby/group NDO lists resolve from SoftLinks.

  8. Join NDO ✅ UI flow in NdoView.svelte; API contract in documentation/zomes/resource_zome.md § NDO membership (planned); joinNdo/getNdoMembers stub in ndo.service.ts.

Post MVP

This section is about UI improvements after a functional MVP.

Core Design Philosophy

  • Perspective-centric design: Interface adapts to agent's role and context
  • Landscape as fundamental pattern: Natural spatial metaphor for resource organization
  • Parallax 3D depth: Isometric perspective with 3-4 layers creating intuitive navigation
  • Horizontal navigation: Primary movement left-right through parallax layers
  • Intuitive interaction: Natural gestures and spatial awareness
  • Symbolic representation: Resources/entities as round icons with peripheral state indicators

Three-Layer Depth System

🔬 Micro Layer (z-index: 300)

  • Purpose: Detailed resource view (modal/overlay)
  • Trigger: Click/tap on resource entity
  • Opacity: 1.0, no blur
  • Content: Full resource details, actions, history
  • Navigation: Close to return to meso, or jump to related entities

🎯 Meso Layer (z-index: 200) - DEFAULT

  • Purpose: Contextual workspace, agent's primary focus
  • Scope: Local context relevant to agent's role/location
  • Opacity: 0.9-1.0, no blur
  • Content: 10-20 most relevant resources/entities (4-5 on screen, but we can circle them while staying in meso view)
  • Interaction: Full interactive capabilities

🌍 Macro Layer (z-index: 100)

  • Purpose: Global landscape, broader system context
  • Scope: All entities less directly related to agent
  • Opacity: 0.4-0.7, 2-4px blur
  • Content: Overview of entire resource network
  • Interaction: Hover preview, click to refocus meso layer

Perspective Types

👷 Role Perspective

Agent sees resources relevant to their role/capabilities

maintainer_role:
  focus_filter: needs_maintenance = true
  priority_order: urgency_level
  color_scheme: earth_tones
  layout: spatial_proximity

📦 Resource Perspective

Focus on specific resource types or categories

resource_view:
  focus_filter: resource_type = selected
  group_by: category | location | status
  color_scheme: resource_type_colors
  layout: cluster_hierarchy

👥 Agent Perspective

Social/collaborative view of other agents

social_view:
  focus_filter: collaboration_potential
  relationship_mapping: trust_network
  color_scheme: relationship_strength
  layout: network_graph

📍 Geographic Perspective

Location-based resource organization

geographic_view:
  focus_filter: spatial_proximity
  center_point: agent_location
  radius: role_responsibility_area
  layout: concentric_circles

Visual Design System

Entity Representation

.resource-entity {
  shape: circle | rounded-square | hexagon;
  size: calc(proximity_score * base_size);
  background: resource_type_color;
  border: 2px solid state_color;

  /* Peripheral indicators */
  .state-badges: action_indicators[];
  .glow-effect: urgency_level;
  .pulse-animation: activity_state;
}

State Indicators

  • 🟢 Available/Healthy: Ready for use, optimal condition
  • 🟡 Needs Attention: Maintenance required, low priority
  • 🔴 Critical/Blocked: Urgent action needed, system risk
  • 🔵 In Use/Reserved: Currently engaged, not available
  • Dormant/Archive: Inactive, background status
  • 🟣 Pending: Awaiting approval/assignment

Concentric Layout Pattern

  • Center: Agent's current focus/role context
  • Inner Ring: High-relevance resources (meso layer)
  • Outer Ring: Background context (macro layer, blurred)
  • Smooth Transitions: Elastic zoom and pan between layers

Proximity Calculation Algorithm

function calculateProximity(entity, agent_context) {
  const weights = {
    role_relevance: 0.4, // Match to agent's role/skills
    geographic_distance: 0.2, // Physical/logical proximity
    interaction_frequency: 0.2, // Historical engagement
    temporal_urgency: 0.1, // Time-sensitive needs
    governance_access: 0.1, // Permission/capability level
  };

  const proximity_score =
    weights.role_relevance * entity.roleMatch(agent_context.role) +
    weights.geographic_distance *
      (1 - entity.distance(agent_context.location)) +
    weights.interaction_frequency *
      entity.interactionHistory(agent_context.id) +
    weights.temporal_urgency * entity.urgencyScore() +
    weights.governance_access * entity.accessLevel(agent_context.capabilities);

  return Math.min(1.0, Math.max(0.0, proximity_score));
}

// Layer assignment
function assignLayer(proximity_score) {
  if (proximity_score >= 0.7) return "micro_candidate";
  if (proximity_score >= 0.4) return "meso";
  return "macro";
}

Dynamic View Composition

Filter System

const meso_composition = {
  keywords: ["maintenance", "urgent", "mechanical"],
  tags: ["infrastructure", "public"],
  date_range: "last_30_days",
  proximity_threshold: 0.6,
  max_entities: 20,
  sort_by: "urgency_desc",
};

Adaptive Personalization

  • Learning: System learns from agent's interaction patterns
  • Preferences: Custom color themes, entity sizes, layout density
  • Context Switching: Quick perspective toggles based on current task

Primary Navigation (Horizontal)

  • Left/Right Scrolling: Move through perspective layers
  • Parallax Effect: Different scroll speeds per layer (macro slower than meso)
  • Momentum Scrolling: Natural deceleration with bounce effects
  • Breadcrumb Trail: Visual path showing navigation history

Secondary Navigation (Vertical)

  • Zoom In: Meso → Micro (entity details)
  • Zoom Out: Meso → Macro (broader landscape)
  • Elastic Transitions: Smooth scaling with momentum physics
  • Quick Return: One-click return to default meso view

Interaction Gestures

  • Click/Tap: Open micro view or refocus meso
  • Double-Click: Quick action (depends on entity type)
  • Long Press: Context menu with available actions
  • Pinch/Zoom: Layer transition control
  • Swipe: Navigate between related entities

Use Case Examples

🌲 Forester Agent Example

Role: Forest maintenance specialist Meso View: Trees/forest sections under their responsibility

  • Focus: Trees needing attention (disease, damage, scheduled maintenance)
  • Layout: Geographic clusters by forest section
  • Priority: Health status and maintenance urgency

Micro View: Individual tree details

  • Health metrics, species info, maintenance history
  • Available actions: Schedule maintenance, mark for removal, update status

Macro View: Entire forest ecosystem

  • All forest resources beyond immediate responsibility
  • Ability to see broader patterns and request assistance

🔧 Maintenance Coordinator Example

Role: Equipment and infrastructure maintenance Meso View: Equipment requiring maintenance within their jurisdiction

  • Priority filter: Critical systems first, then scheduled maintenance
  • Status indicators: Operational, needs attention, critical failure
  • Timeline view: Maintenance schedules and deadlines

🏗️ Resource Allocation Agent Example

Role: Optimizing resource distribution across projects Meso View: Available resources and current allocations

  • Filter by: Resource type, availability, location, project needs
  • Visual flow: Resource movement between projects
  • Optimization indicators: Efficiency metrics, bottlenecks

Responsive Design Considerations

Mobile Adaptation

  • Single Layer Focus: Simplified view with layer swipe transitions
  • Larger Touch Targets: Minimum 44px touch areas for entities
  • Simplified Indicators: Essential state information only
  • Gesture Navigation: Swipe for layers, tap for details

Desktop Enhancement

  • Full Parallax Experience: All three layers simultaneously visible
  • Keyboard Shortcuts: Layer navigation, entity selection, quick actions
  • Multi-Selection: Batch operations on multiple entities
  • Rich Hover States: Detailed tooltips and preview information

Accessibility Features

  • High Contrast Mode: Enhanced visual differentiation
  • Screen Reader Support: Semantic markup and ARIA labels
  • Keyboard Navigation: Full functionality without mouse
  • Motion Preferences: Respect user's motion sensitivity settings

Technical Implementation Notes

  • Rendering: Canvas-based or WebGL for smooth 3D transitions
  • Data Binding: Real-time updates from Holochain DHT
  • Performance: Virtualized rendering for large entity sets
  • Caching: Intelligent prefetching based on proximity scores
  • State Management: Maintain layer states and user preferences