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)
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 collisionsDesign Principles
Color Pair Structure
Example Pairs (5 users)
Each pair has maximum internal contrast (opposite hues) and maximum external distance (evenly spaced around the wheel).
UI Usage Guidelines
Awareness Pills (top bar)
Top portion shows primary, bottom shows secondary, smooth blend on sides.
Attribution Spans (canvas overlay)
Remote Cursors
Timeline (Attribution Panel)
Transclusion Source Badges
Implementation Plan
Phase 1: Color Pair Engine (backend + frontend)
Backend:
color_pair: Option<(u32, u32)>to Club struct (stores HSL hue pair)Frontend:
ColorPairRegistry— fetches all users's color pairs, caches locallyauthorColor(name)withauthorColorPair(name): ColorPairPhase 2: UI Updates
AwarenessIndicatorsCollaborativeEditorcanvasRemoteCursorsAttributionPanelCompoundPanelVirtualizedEditorPhase 3: Color System Documentation
docs/color-system.html— visual guide showing all UI elements with color pairsMigration
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
Ref: #35 (collaborative editing), #18 (compound documents)