diff --git a/shared/components/rstack-collab-overlay.ts b/shared/components/rstack-collab-overlay.ts
index 56344859..97e4f0bd 100644
--- a/shared/components/rstack-collab-overlay.ts
+++ b/shared/components/rstack-collab-overlay.ts
@@ -400,6 +400,11 @@ export class RStackCollabOverlay extends HTMLElement {
// ── Local broadcasting ──
+ /** Effective view identifier — viewId if set, else moduleId. Used to scope cursor visibility. */
+ get #effectiveViewId(): string | null {
+ return this.#viewId || this.#moduleId || null;
+ }
+
#broadcastPresence(cursor?: { x: number; y: number }, selection?: string) {
if (this.#soloMode) return; // suppress outgoing awareness in solo mode
@@ -411,7 +416,7 @@ export class RStackCollabOverlay extends HTMLElement {
selection,
username: this.#localUsername,
color: this.#localColor,
- viewId: this.#viewId,
+ viewId: this.#effectiveViewId,
});
}
@@ -619,7 +624,8 @@ export class RStackCollabOverlay extends HTMLElement {
if (peer.module) ctxParts.push(peer.module);
if (peer.context) ctxParts.push(peer.context);
const ctxStr = ctxParts.join(' · ');
- const differentView = !!(this.#viewId && peer.viewId && this.#viewId !== peer.viewId);
+ const localView = this.#effectiveViewId;
+ const differentView = !!((localView || peer.viewId) && localView !== peer.viewId);
fragments.push(`
@@ -778,10 +784,12 @@ export class RStackCollabOverlay extends HTMLElement {
const now = Date.now();
const fragments: string[] = [];
- for (const peer of this.#peers.values()) {
+ // Deduplicate by username — only show the most recent cursor per user
+ const localView = this.#effectiveViewId;
+ for (const peer of this.#uniquePeers()) {
if (!peer.cursor) continue;
- // Skip peers viewing a different sub-document (e.g. different note in rDocs)
- if (this.#viewId && peer.viewId && this.#viewId !== peer.viewId) continue;
+ // Only show cursors for peers on the same page/view
+ if ((localView || peer.viewId) && localView !== peer.viewId) continue;
const age = now - peer.lastSeen;
const opacity = age > 5000 ? 0.3 : 1;
@@ -819,10 +827,11 @@ export class RStackCollabOverlay extends HTMLElement {
// Remove all existing focus rings from the document
document.querySelectorAll('.rstack-collab-focus-ring').forEach(el => el.remove());
- for (const peer of this.#peers.values()) {
+ const localView = this.#effectiveViewId;
+ for (const peer of this.#uniquePeers()) {
if (!peer.selection) continue;
- // Skip peers viewing a different sub-document
- if (this.#viewId && peer.viewId && this.#viewId !== peer.viewId) continue;
+ // Only show focus rings for peers on the same page/view
+ if ((localView || peer.viewId) && localView !== peer.viewId) continue;
const target = this.#findCollabEl(peer.selection);
if (!target) continue;