Skip to content

fix: improve collaborator cursor color generation - #177

Open
prathik-05 wants to merge 5 commits into
piyushdotcomm:developfrom
prathik-05:fix/collab-cursor-colors
Open

fix: improve collaborator cursor color generation#177
prathik-05 wants to merge 5 commits into
piyushdotcomm:developfrom
prathik-05:fix/collab-cursor-colors

Conversation

@prathik-05

@prathik-05 prathik-05 commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • replaced first-character based collaborator cursor color generation with deterministic string hashing
  • improved color uniqueness for collaborators with similar email initials
  • switched to HSL-based color generation for more readable and visually distinct collaborator cursors

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Test or CI improvement
  • Starter template change

Related issue

Closes #144

Validation

  • npm run lint
  • npm test
  • npm run build

List any additional manual verification you performed:

  • verified deterministic color generation across different email inputs
  • confirmed users with the same first email character now receive different cursor colors

Checklist

  • I kept this PR focused on one primary change
  • I updated documentation if behavior changed
  • I did not commit secrets, local logs, or scratch files
  • I am requesting review on the correct scope

Note: I had already started and completed the implementation while the assignment workflow was still in progress.

Summary by CodeRabbit

  • Bug Fixes
    • User colors are now deterministically derived from email for stable, consistent identification across sessions.
    • Improved fallback color for users without emails to reduce collisions and better distinguish anonymous participants.
    • Remote selection highlights and labels render with correct, lower-opacity backgrounds for consistent visual clarity.

Review Change Stack

@prathik-05
prathik-05 requested a review from piyushdotcomm as a code owner May 18, 2026 08:26
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions

Copy link
Copy Markdown

👋 Thanks for opening a PR, @prathik-05!

Your PR has entered the 🚦 PR Review Pipeline.

Standard PR detected — your PR will follow the standard review pipeline.


What happens next

Stage Reviewer Checks
Stage 1 — Automated Validation 🤖 Bot DCO · Format · AI/Slop · Duplicate
Stage 2 — Human Review 👥 Maintainer Code + Quality Review
Stage 3 — PA / Maintainer Review 🔑 Project Admin Final Merge Decision

A pipeline status comment will appear below and update automatically as your PR progresses.


While you wait

  • Sign all commits (git commit -s)
  • Link your issue (Closes #123)
  • Use a feature branch (not main)
  • Avoid unrelated changes

This comment is posted only once.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 402fb5f7-d1e7-48e2-8bbb-c0aeee5ae5ad

📥 Commits

Reviewing files that changed from the base of the PR and between 60162a0 and 2be9d1f.

📒 Files selected for processing (1)
  • modules/playground/components/playground-editor.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/playground/components/playground-editor.tsx

Walkthrough

Replaces single-character trig/hex email hashing with a full-string deterministic hashStringToColor(str, alpha?) returning hsl(...)/hsla(...), uses it for the Yjs local user's color (with a hashed fallback), and adds withOpacity(color, alpha) to produce lower-alpha remote selection backgrounds.

Changes

Collaboration Cursor Color Fix

Layer / File(s) Summary
hashStringToColor helper
modules/playground/components/playground-editor.tsx
Adds hashStringToColor(str, alpha?) that hashes the full string to a hue and returns hsl(...)/hsla(...).
Awareness local user color integration
modules/playground/components/playground-editor.tsx
Uses hashStringToColor(session.user.email) (with a hashed fallback when email absent) for the Yjs local user's color assignment.
withOpacity helper and remote selection CSS
modules/playground/components/playground-editor.tsx
Adds withOpacity(color, alpha) supporting hsl(...)/hsla(...) and hex inputs and applies it when generating .yRemoteSelection-{clientId} backgrounds, replacing prior hex-alpha string concatenation.

Sequence Diagram(s)

sequenceDiagram
  participant PlaygroundEditor
  participant hashStringToColor
  participant withOpacity
  participant YjsAwareness
  PlaygroundEditor->>hashStringToColor: provide session.user.email or fallback seed
  hashStringToColor-->>PlaygroundEditor: return hsl(...) / hsla(...)
  PlaygroundEditor->>YjsAwareness: set local user.color (hsl/hsla)
  PlaygroundEditor->>withOpacity: provide user.color and alpha
  withOpacity-->>PlaygroundEditor: return reduced-opacity color
  PlaygroundEditor->>YjsAwareness: set remote selection background color
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nibble strings to spin a shade,

From whole email each hue is made,
No twins from first-letter fate,
Soft alpha paints the selection state,
Hopping, I color every mate.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: improve collaborator cursor color generation' clearly and concisely summarizes the main change—improving cursor color generation through deterministic hashing instead of first-character based approach.
Description check ✅ Passed The PR description covers all essential template sections: summary of changes, type of change (bug fix selected), related issue (#144), validation steps performed, and checklist items completed.
Linked Issues check ✅ Passed The code changes fully satisfy issue #144 requirements: replaced first-character algorithm with deterministic string hashing, implemented HSL-based color generation for better contrast, and ensured color uniqueness for similar email initials.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #144: added hashStringToColor and withOpacity helpers, updated Yjs awareness color generation, and improved remote selection styling—all aligned with cursor color improvement objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added bug Something isn't working good first issue Good for newcomers gssoc26 level:intermediate labels May 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/playground/components/playground-editor.tsx`:
- Around line 309-310: The computed user color from hashStringToColor (assigned
to userColor) may be hex or HSL, but the selection highlight code currently
naively appends "40" to form translucency, which breaks for HSL; update the
playground-editor.tsx logic that builds the collaborator selection color (where
`${color}40` is used) to handle both formats: detect if userColor is hex and
append the hex alpha, otherwise convert HSL to an alpha form (produce an HSLA
string or use the modern hsl(... / alpha) syntax) or normalize hashStringToColor
to always return hex; adjust either hashStringToColor or the selection color
helper so collaborator highlights are generated with a valid alpha-aware color
string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: dc8d140f-bb3c-407b-b5f9-68dfe0457284

📥 Commits

Reviewing files that changed from the base of the PR and between 80da20e and 9745e64.

📒 Files selected for processing (1)
  • modules/playground/components/playground-editor.tsx

Comment thread modules/playground/components/playground-editor.tsx Outdated

@piyushdotcomm piyushdotcomm left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HSL conversion is a good idea, but the opacity handling is broken. Please address the inline comments.

css += `
.yRemoteSelection-${clientId} {
background-color: ${color}40; /* 40 hex is 25% opacity */
background-color: ${color}; /* 40 hex is 25% opacity */

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since color is now an HSL string with alpha 1, this makes the selection background completely opaque and it will obscure the text. You can't append 40 to HSL either. The safest cross-format way to handle this (since some remote clients might still send Hex) is to apply opacity: 0.25; to this class and keep background-color: ${color};.

left: -2px;
font-size: 11px;
background-color: ${color};
background-color: ${hashStringToColor(name, 0.25)};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sets the name label's background to 25% opacity, making the text unreadable. It also ignores the collaborator's actual assigned color and generates a new one from their name. You should just use background-color: ${color}; here so it matches the cursor exactly and remains opaque.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
modules/playground/components/playground-editor.tsx (1)

342-342: 💤 Low value

Update the outdated comment.

The comment /* 40 hex is 25% opacity */ references the previous hex-based approach and is no longer accurate. Consider updating it to reflect the current HSL alpha replacement approach or remove it entirely.

📝 Suggested comment update
-background-color: ${color.replace("/ 1)", "/ 0.25)")}; /* 40 hex is 25% opacity */
+background-color: ${color.replace("/ 1)", "/ 0.25)")}; /* 25% opacity for selection background */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/playground/components/playground-editor.tsx` at line 342, The inline
comment next to the background-color assignment in playground-editor.tsx is
outdated (it reads "/* 40 hex is 25% opacity */") while the code now uses
color.replace("/ 1)", "/ 0.25)") to set an HSL alpha; update or remove that
comment to reflect the HSL alpha approach (e.g., "/* set 25% alpha via HSL alpha
replacement */") or simply delete it next to the background-color line inside
the PlaygroundEditor component so the comment matches the current color.replace
usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/playground/components/playground-editor.tsx`:
- Line 316: The current userColor assignment uses a constant fallback ("hsl(210
100% 56% / 1)") for anonymous users, causing identical cursor colors; change the
fallback to generate a unique color by hashing a stable anonymous identifier
(e.g., session.id, session.clientId, or session.connectionTimestamp) or a
per-session random seed so each anonymous session gets a distinct color. Update
the expression that sets userColor (currently referencing session?.user?.email
and hashStringToColor) to prefer hashing session.user.email when present,
otherwise hash a stable anonymous key (session.id || session.clientId ||
session.connectionTimestamp) and only fall back to a truly random color if no
stable identifier exists. Ensure you keep using hashStringToColor for generation
so colors remain in the same palette and reference the userColor variable and
hashStringToColor function when making the change.
- Line 342: The current string .replace("/ 1)", "/ 0.25)") breaks when
state.user.color falls back to the named color "orange"; add a small helper
function addAlpha(colorStr: string, alpha: number) and call it where color is
used so you always produce a color with the desired alpha. Implement addAlpha
to: detect and replace an existing alpha token (e.g. match /\/\s*[\d.]+\)/ and
replace with `/ ${alpha})`), and for non-HSL/named colors resolve them to an
RGB(A) form (e.g. compute the computed style or parse rgb(...) and append the
alpha) so the background-color assignment always receives a valid
semitransparent color; replace the direct .replace call with addAlpha(color,
0.25).

---

Nitpick comments:
In `@modules/playground/components/playground-editor.tsx`:
- Line 342: The inline comment next to the background-color assignment in
playground-editor.tsx is outdated (it reads "/* 40 hex is 25% opacity */") while
the code now uses color.replace("/ 1)", "/ 0.25)") to set an HSL alpha; update
or remove that comment to reflect the HSL alpha approach (e.g., "/* set 25%
alpha via HSL alpha replacement */") or simply delete it next to the
background-color line inside the PlaygroundEditor component so the comment
matches the current color.replace usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0dc59bcb-d23b-438a-b8d0-2ca037b89609

📥 Commits

Reviewing files that changed from the base of the PR and between 2cdc9cb and 60162a0.

📒 Files selected for processing (1)
  • modules/playground/components/playground-editor.tsx

Comment thread modules/playground/components/playground-editor.tsx Outdated
Comment thread modules/playground/components/playground-editor.tsx Outdated

@piyushdotcomm piyushdotcomm left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the screenshot of the change and address all the suggestion by code rabbit

@piyushdotcomm
piyushdotcomm changed the base branch from main to develop June 1, 2026 15:36

@piyushdotcomm piyushdotcomm left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: collaboration cursor color generation uses only first email character — users with same first letter get identical colors

2 participants