@ericrisco/rsc 3.3.1 β 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/manifest.json +43 -22
- package/package.json +1 -1
- package/scripts/lib/default-skill-floor.js +5 -1
- package/scripts/lib/domains.js +2 -2
- package/scripts/lib/retired-skills.js +4 -0
- package/scripts/rsc.js +1 -1
- package/skills/design/SKILL.md +4 -3
- package/skills/design/evals/cases.yaml +2 -2
- package/skills/ftd/SKILL.md +1 -1
- package/skills/react/SKILL.md +2 -1
- package/skills/ux/SKILL.md +149 -0
- package/skills/ux/THIRD_PARTY.md +32 -0
- package/skills/ux/evals/cases.yaml +40 -0
- package/skills/ux/references/flows.md +124 -0
- package/skills/ux/upstream/UPSTREAM.json +59 -0
- package/skills/ux/upstream/ux-designer/GUIDE.md +180 -0
- package/skills/ux/upstream/ux-designer/LICENSE +21 -0
- package/skills/ux/upstream/ux-designer/references/01-core-principles.md +251 -0
- package/skills/ux/upstream/ux-designer/references/02-laws-of-ux.md +330 -0
- package/skills/ux/upstream/ux-designer/references/03-accessibility.md +411 -0
- package/skills/ux/upstream/ux-designer/references/04-visual-design.md +433 -0
- package/skills/ux/upstream/ux-designer/references/05-information-architecture.md +432 -0
- package/skills/ux/upstream/ux-designer/references/06-interaction-design.md +495 -0
- package/skills/ux/upstream/ux-designer/references/07-forms-and-inputs.md +491 -0
- package/skills/ux/upstream/ux-designer/references/08-mobile-ux.md +539 -0
- package/skills/ux/upstream/ux-designer/references/09-ux-writing.md +493 -0
- package/skills/ux/upstream/ux-designer/references/10-user-research.md +533 -0
- package/skills/ux/upstream/ux-designer/references/11-design-systems.md +618 -0
- package/skills/ux/upstream/ux-designer/references/12a-presence-awareness.md +395 -0
- package/skills/ux/upstream/ux-designer/references/12b-conflict-resolution-sync.md +420 -0
- package/skills/ux/upstream/ux-designer/references/13a-canvas-navigation.md +388 -0
- package/skills/ux/upstream/ux-designer/references/13b-canvas-objects-performance.md +559 -0
- package/skills/ux/upstream/ux-designer/references/14-ai-ux-patterns.md +511 -0
- package/skills/ux/upstream/ux-designer/references/15-ethical-design.md +419 -0
- package/skills/ux/upstream/ux-designer/references/16-onboarding.md +430 -0
- package/skills/ux/upstream/ux-designer/references/17-notifications.md +461 -0
- package/skills/ux/upstream/ux-designer/references/18-data-visualization.md +453 -0
- package/skills/ux/upstream/ux-designer/references/19-search-ux.md +479 -0
- package/skills/ux/upstream/ux-designer/references/20-emotional-design.md +382 -0
- package/skills/ux/upstream/ux-designer/references/21-data-tables.md +629 -0
- package/skills/ux/upstream/ux-designer/references/22-performance-ux.md +626 -0
- package/skills/ux/upstream/ux-designer/references/23-internationalization.md +347 -0
- package/skills/ux/upstream/ux-designer/references/24-voice-and-multimodal.md +308 -0
- package/skills/ux/upstream/ux-designer/references/25a-barcode-camera-scanning.md +342 -0
- package/skills/ux/upstream/ux-designer/references/25b-barcode-scanner-workflows.md +412 -0
- package/skills/ux/upstream/ux-designer/references/25c-barcode-display.md +277 -0
- package/skills/ux/upstream/ux-usability-foundations/GUIDE.md +285 -0
- package/skills/ux/upstream/ux-usability-foundations/LICENSE +21 -0
- package/skills/ux/upstream/ux-usability-foundations/references/anti-patterns.md +267 -0
- package/skills/ux/upstream/ux-usability-foundations/references/checklists.md +130 -0
- package/skills/ux/upstream/ux-usability-foundations/references/decision-prompts.md +340 -0
- package/skills/ux/upstream/ux-usability-foundations/references/principle-cards.md +449 -0
- package/skills/worktrees/SKILL.md +19 -5
- package/targets/branch-guard.mjs +59 -4
- package/targets/clone-bootstrap.mjs +1 -1
- package/targets/session-memory-adapter.mjs +2 -2
- package/targets/team-safe-start.mjs +1 -0
- package/targets/worktree-reaper.mjs +14 -1
- package/skills/ui-engineering/SKILL.md +0 -113
- package/skills/ui-engineering/evals/cases.yaml +0 -38
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# Collaborative UX: Presence & Awareness
|
|
2
|
+
|
|
3
|
+
Real-time collaboration UX focuses on enabling multiple users to work together seamlessly in shared digital spaces. Good collaborative UX creates "social translucence"βthe ability to see and feel others' activities within digital environments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- Presence & Awareness
|
|
10
|
+
- Communication Features
|
|
11
|
+
- Viewport Coordination
|
|
12
|
+
- Key Metrics
|
|
13
|
+
- Anti-Patterns
|
|
14
|
+
- Sources
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Presence & Awareness
|
|
19
|
+
|
|
20
|
+
Awareness is "an understanding of the activities of others, which provides a context for your own activity" (Dourish & Bellotti, 1992).
|
|
21
|
+
|
|
22
|
+
### Live Cursors
|
|
23
|
+
|
|
24
|
+
Live cursors show the real-time pointer position of collaborators, creating a sense of shared presence.
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
/* Live cursor component */
|
|
28
|
+
.live-cursor {
|
|
29
|
+
position: absolute;
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
z-index: 1000;
|
|
32
|
+
transition: transform 50ms linear; /* Smooth interpolation */
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.live-cursor__pointer {
|
|
36
|
+
width: 20px;
|
|
37
|
+
height: 20px;
|
|
38
|
+
/* Each user gets unique color */
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.live-cursor__label {
|
|
42
|
+
position: absolute;
|
|
43
|
+
left: 16px;
|
|
44
|
+
top: 16px;
|
|
45
|
+
padding: 2px 8px;
|
|
46
|
+
border-radius: 4px;
|
|
47
|
+
font-size: 12px;
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
max-width: 100px;
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
text-overflow: ellipsis;
|
|
53
|
+
color: white;
|
|
54
|
+
/* Background matches cursor color */
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Best Practices
|
|
59
|
+
|
|
60
|
+
| Aspect | Recommendation |
|
|
61
|
+
|--------|---------------|
|
|
62
|
+
| Label length | Max 12 characters, truncate with ellipsis |
|
|
63
|
+
| Color assignment | Unique per user, consistent across session |
|
|
64
|
+
| Update frequency | 50-100ms for smooth movement |
|
|
65
|
+
| Visibility | Hide after 30-60s of inactivity |
|
|
66
|
+
| Scaling | Consider hiding cursors at extreme zoom levels |
|
|
67
|
+
|
|
68
|
+
#### When Cursors Become Too Many
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
1-5 users β Show all cursors with labels
|
|
72
|
+
6-10 users β Show cursors, abbreviated labels
|
|
73
|
+
11-20 users β Show cursors without labels
|
|
74
|
+
20+ users β Consider hiding distant cursors or showing only nearby
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Avatar Stacks
|
|
78
|
+
|
|
79
|
+
Show who's currently viewing or editing a document.
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<div class="avatar-stack">
|
|
83
|
+
<div class="avatar" style="background: #e63946;" title="Alice">A</div>
|
|
84
|
+
<div class="avatar" style="background: #2a9d8f;" title="Bob">B</div>
|
|
85
|
+
<div class="avatar" style="background: #e9c46a;" title="Carol">C</div>
|
|
86
|
+
<div class="avatar-overflow">+3</div>
|
|
87
|
+
</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
.avatar-stack {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: row-reverse; /* Newest on left */
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.avatar {
|
|
97
|
+
width: 32px;
|
|
98
|
+
height: 32px;
|
|
99
|
+
border-radius: 50%;
|
|
100
|
+
border: 2px solid white;
|
|
101
|
+
margin-left: -8px; /* Overlap */
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
font-size: 14px;
|
|
106
|
+
font-weight: 600;
|
|
107
|
+
color: white;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.avatar-overflow {
|
|
111
|
+
background: #6b7280;
|
|
112
|
+
/* Same styling as .avatar */
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Guidelines
|
|
117
|
+
|
|
118
|
+
- Show 3-5 avatars maximum before overflow
|
|
119
|
+
- Use "+N" pattern for additional users
|
|
120
|
+
- Clicking should reveal full list
|
|
121
|
+
- Consider adding online/away status indicators
|
|
122
|
+
|
|
123
|
+
### Typing Indicators
|
|
124
|
+
|
|
125
|
+
Show when collaborators are actively editing.
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
// Typing indicator with debounce
|
|
129
|
+
let typingTimeout;
|
|
130
|
+
|
|
131
|
+
function handleInput() {
|
|
132
|
+
broadcastTyping(true);
|
|
133
|
+
clearTimeout(typingTimeout);
|
|
134
|
+
typingTimeout = setTimeout(() => {
|
|
135
|
+
broadcastTyping(false);
|
|
136
|
+
}, 2000); // Stop after 2s of inactivity
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```css
|
|
141
|
+
/* Typing indicator animation */
|
|
142
|
+
.typing-indicator {
|
|
143
|
+
display: flex;
|
|
144
|
+
gap: 4px;
|
|
145
|
+
padding: 8px 12px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.typing-indicator__dot {
|
|
149
|
+
width: 8px;
|
|
150
|
+
height: 8px;
|
|
151
|
+
border-radius: 50%;
|
|
152
|
+
background: #6b7280;
|
|
153
|
+
animation: typing-bounce 1.4s infinite ease-in-out both;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.typing-indicator__dot:nth-child(1) { animation-delay: 0s; }
|
|
157
|
+
.typing-indicator__dot:nth-child(2) { animation-delay: 0.16s; }
|
|
158
|
+
.typing-indicator__dot:nth-child(3) { animation-delay: 0.32s; }
|
|
159
|
+
|
|
160
|
+
@keyframes typing-bounce {
|
|
161
|
+
0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
|
|
162
|
+
40% { transform: scale(1); opacity: 1; }
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Activity Feeds
|
|
167
|
+
|
|
168
|
+
Show recent changes and who made them.
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
172
|
+
β Activity β
|
|
173
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
|
|
174
|
+
β π’ Alice edited "Header component" 2m ago β
|
|
175
|
+
β π΅ Bob added comment on "Login flow" 5m ago β
|
|
176
|
+
β π‘ Carol joined the document 12m ago β
|
|
177
|
+
β π’ Alice created "Footer component" 15m ago β
|
|
178
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Communication Features
|
|
184
|
+
|
|
185
|
+
### Threaded Comments
|
|
186
|
+
|
|
187
|
+
```css
|
|
188
|
+
/* Comment thread styling */
|
|
189
|
+
.comment-thread {
|
|
190
|
+
border-left: 3px solid #3b82f6;
|
|
191
|
+
padding-left: 12px;
|
|
192
|
+
margin: 8px 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.comment {
|
|
196
|
+
padding: 8px;
|
|
197
|
+
margin-bottom: 4px;
|
|
198
|
+
background: #f3f4f6;
|
|
199
|
+
border-radius: 8px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.comment__header {
|
|
203
|
+
display: flex;
|
|
204
|
+
justify-content: space-between;
|
|
205
|
+
font-size: 12px;
|
|
206
|
+
color: #6b7280;
|
|
207
|
+
margin-bottom: 4px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.comment__reply-form {
|
|
211
|
+
margin-top: 8px;
|
|
212
|
+
padding-top: 8px;
|
|
213
|
+
border-top: 1px solid #e5e7eb;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Contextual Comments (Annotations)
|
|
218
|
+
|
|
219
|
+
Pin comments to specific elements or canvas positions.
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
// Attach comment to element
|
|
223
|
+
const annotation = {
|
|
224
|
+
id: "comment-123",
|
|
225
|
+
targetElement: "component-456",
|
|
226
|
+
position: { x: 100, y: 50 }, // Relative to target
|
|
227
|
+
thread: [
|
|
228
|
+
{ author: "alice", text: "Should this be blue?", timestamp: "..." },
|
|
229
|
+
{ author: "bob", text: "Good idea, updating now", timestamp: "..." }
|
|
230
|
+
],
|
|
231
|
+
resolved: false
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Emoji Reactions
|
|
236
|
+
|
|
237
|
+
Quick feedback without requiring a full comment.
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<div class="reaction-bar">
|
|
241
|
+
<button class="reaction" data-emoji="π">π <span>3</span></button>
|
|
242
|
+
<button class="reaction" data-emoji="β€οΈ">β€οΈ <span>1</span></button>
|
|
243
|
+
<button class="reaction" data-emoji="π">π <span>2</span></button>
|
|
244
|
+
<button class="reaction reaction--add">+</button>
|
|
245
|
+
</div>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### @Mentions
|
|
249
|
+
|
|
250
|
+
Notify specific collaborators.
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
// Mention autocomplete
|
|
254
|
+
function handleMentionTrigger(text) {
|
|
255
|
+
if (text.includes('@')) {
|
|
256
|
+
const query = text.split('@').pop();
|
|
257
|
+
const matches = collaborators.filter(c =>
|
|
258
|
+
c.name.toLowerCase().includes(query.toLowerCase())
|
|
259
|
+
);
|
|
260
|
+
showMentionSuggestions(matches);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Anonymous Voting
|
|
266
|
+
|
|
267
|
+
Prevent groupthink by hiding voter identity.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
βββββββββββββββββββββββββββββββββββββββββββββ
|
|
271
|
+
β Vote: Which design direction? β
|
|
272
|
+
βββββββββββββββββββββββββββββββββββββββββββββ€
|
|
273
|
+
β Option A: Bold colors ββββββββββ 4 β
|
|
274
|
+
β Option B: Minimal ββββββββββ 5 β
|
|
275
|
+
β Option C: Playful ββββββββββ 2 β
|
|
276
|
+
βββββββββββββββββββββββββββββββββββββββββββββ€
|
|
277
|
+
β 11 votes total β’ Voting ends in 5:00 β
|
|
278
|
+
β Your vote: Option B β
|
|
279
|
+
βββββββββββββββββββββββββββββββββββββββββββββ
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Viewport Coordination
|
|
285
|
+
|
|
286
|
+
### Follow Mode
|
|
287
|
+
|
|
288
|
+
Lock your viewport to follow another user's view.
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
// Follow mode implementation
|
|
292
|
+
class ViewportFollower {
|
|
293
|
+
constructor() {
|
|
294
|
+
this.following = null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
follow(userId) {
|
|
298
|
+
this.following = userId;
|
|
299
|
+
this.showFollowingIndicator(userId);
|
|
300
|
+
|
|
301
|
+
// Subscribe to their viewport changes
|
|
302
|
+
subscribeToViewport(userId, (viewport) => {
|
|
303
|
+
animateToViewport(viewport, { duration: 300 });
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
stopFollowing() {
|
|
308
|
+
this.following = null;
|
|
309
|
+
this.hideFollowingIndicator();
|
|
310
|
+
unsubscribeFromViewport();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
```css
|
|
316
|
+
/* Following indicator */
|
|
317
|
+
.viewport--following {
|
|
318
|
+
border: 3px solid var(--user-color);
|
|
319
|
+
border-radius: 8px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.following-banner {
|
|
323
|
+
position: fixed;
|
|
324
|
+
top: 60px;
|
|
325
|
+
left: 50%;
|
|
326
|
+
transform: translateX(-50%);
|
|
327
|
+
padding: 8px 16px;
|
|
328
|
+
background: var(--user-color);
|
|
329
|
+
color: white;
|
|
330
|
+
border-radius: 20px;
|
|
331
|
+
font-size: 14px;
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Spotlight / Presenter Mode
|
|
336
|
+
|
|
337
|
+
Present to collaborators by controlling their view.
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
341
|
+
β π― Alice is presenting β
|
|
342
|
+
β Following her view β’ Click anywhere to stop [Stop] β
|
|
343
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Implementation:**
|
|
347
|
+
1. Presenter clicks "Spotlight me"
|
|
348
|
+
2. All viewers receive notification
|
|
349
|
+
3. Viewers have 3-5 seconds to opt out
|
|
350
|
+
4. Non-opted-out viewers' viewports lock to presenter
|
|
351
|
+
5. Presenter's cursor becomes more prominent
|
|
352
|
+
|
|
353
|
+
### Jump to User
|
|
354
|
+
|
|
355
|
+
Navigate to where a collaborator is working.
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
function jumpToUser(userId) {
|
|
359
|
+
const userViewport = getUserViewport(userId);
|
|
360
|
+
animateToViewport(userViewport, {
|
|
361
|
+
duration: 500,
|
|
362
|
+
easing: 'ease-out'
|
|
363
|
+
});
|
|
364
|
+
highlightUserCursor(userId, { duration: 2000 });
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## Key Metrics
|
|
371
|
+
|
|
372
|
+
| Metric | Value | Context |
|
|
373
|
+
|--------|-------|---------|
|
|
374
|
+
| Cursor update rate | 50-100ms | Smooth movement perception |
|
|
375
|
+
| Typing indicator timeout | 2-3s | After last keystroke |
|
|
376
|
+
| Avatar stack max | 3-5 visible | Before "+N" overflow |
|
|
377
|
+
| Cursor label max | 12 chars | Truncate longer names |
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Anti-Patterns
|
|
382
|
+
|
|
383
|
+
1. **No presence indicators** - Users feel alone, cause conflicts
|
|
384
|
+
2. **Cursor overload** - Too many cursors create visual noise
|
|
385
|
+
3. **Forced following** - Lock users to presenter without consent
|
|
386
|
+
4. **Comment spam** - No way to resolve or archive discussions
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Sources
|
|
391
|
+
|
|
392
|
+
- [Liveblocks - Presence Documentation](https://liveblocks.io/presence)
|
|
393
|
+
- [Ably - Collaborative UX Best Practices](https://ably.com/blog/collaborative-ux-best-practices)
|
|
394
|
+
- [Figma - How Multiplayer Technology Works](https://www.figma.com/blog/how-figmas-multiplayer-technology-works/)
|
|
395
|
+
- Dourish, P. & Bellotti, V. (1992). "Awareness and Coordination in Shared Workspaces"
|