Skip to content

Perceptual color pair system for user identity #58

Description

@jonesd

Vision

Replace the current single-color hash-based user identity system with a perceptual color pair system. Each user gets two complementary colors (primary + secondary) that create a unique two-tone gradient identity across all UI elements.

Current Problem

  • authorColor() uses FNV-1a hash → 25 fixed colors → frequent collisions
  • "alice" and "david" can get visually similar colors
  • Single colors don't scale — only 25 possible identities
  • Attribution panel colors don't stand out between authors
  • Colors scattered across CSS, canvas, and TypeScript with no central registry

Design Principles

Principle Implementation
Complementary hues Primary and secondary on opposite sides of color wheel — maximum internal contrast
Even hue distribution N users get hues at 360°/N spacing — no two users close on the wheel
Lightness split Primary lighter (65% L), secondary darker (40% L) — gradient always visible
Server-assigned Stored with user identity, not recomputed from hash — stable and unique
Perceptual distance New assignments maximize ΔE (CIELAB) to all existing pairs

Color Pair Structure

interface ColorPair {
  primary: string;    // lighter hue (65% lightness) — top of pill
  secondary: string;  // darker complementary (40% lightness) — bottom of pill
}

Example Pairs (5 users)

User 1: top=#4A90D9 (blue)      bottom=#D97A4A (orange)
User 2: top=#D94A8B (pink)      bottom=#4AD994 (green)
User 3: top=#9B4AD9 (purple)    bottom=#A5D94A (lime)
User 4: top=#4AD9C8 (teal)      bottom=#D94A5B (red)
User 5: top=#D9C84A (gold)      bottom=#4A5BD9 (indigo)

Each pair has maximum internal contrast (opposite hues) and maximum external distance (evenly spaced around the wheel).

UI Usage Guidelines

Awareness Pills (top bar)

background: linear-gradient(180deg, primary 40%, secondary 60%);
border-radius: 12px;

Top portion shows primary, bottom shows secondary, smooth blend on sides.

Attribution Spans (canvas overlay)

  • Background fill: primary at 15% opacity
  • Bottom border: secondary at 60% opacity
  • Creates a two-tone effect that matches the pill

Remote Cursors

  • Caret line: primary
  • Name label background: gradient(primary, secondary)

Timeline (Attribution Panel)

  • Author dot: split circle (top half primary, bottom half secondary)
  • Range bar: gradient from primary to secondary

Transclusion Source Badges

  • Background: secondary at 20% opacity
  • Border: primary at 50% opacity
  • Links back to the source author's identity

Implementation Plan

Phase 1: Color Pair Engine (backend + frontend)

Backend:

  • Add color_pair: Option<(u32, u32)> to Club struct (stores HSL hue pair)
  • Assignment algorithm: when a user registers, find the complementary hue pair that maximizes minimum perceptual distance to all existing pairs
  • HSL → RGB → hex conversion
  • Expose via wire protocol (club info / who-am-i response)

Frontend:

  • New ColorPairRegistry — fetches all users's color pairs, caches locally
  • Replace authorColor(name) with authorColorPair(name): ColorPair
  • Backward compatible: if no pair assigned, derive from FNV-1a hash (old behavior)

Phase 2: UI Updates

Component Change
AwarenessIndicators Gradient pill using color pair
CollaborativeEditor canvas Attribution spans use pair (primary fill + secondary underline)
RemoteCursors Caret uses primary, label uses gradient
AttributionPanel Author dots use split-circle, timeline bars use gradient
CompoundPanel Transclusion source badges use pair
VirtualizedEditor Same canvas overlay changes

Phase 3: Color System Documentation

  • docs/color-system.html — visual guide showing all UI elements with color pairs
  • Design guidelines: when to use primary vs secondary, opacity levels, accessibility
  • Colorblind-safe alternatives (patterns/icons in addition to color)

Migration

Existing users without assigned pairs will derive colors from the old FNV-1a hash as a fallback. New registrations get server-assigned perceptual pairs. Over time, all users migrate to assigned pairs.

Accessibility

  • Color is never the ONLY indicator — always pair with text labels
  • Minimum contrast ratio 4.5:1 for text on colored backgrounds (WCAG AA)
  • Colorblind consideration: the gradient pattern itself helps distinguish users even if hues are confused
  • Future: add patterns (stripes, dots) as additional differentiation

Ref: #35 (collaborative editing), #18 (compound documents)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions