npm install socket.io # server
npm install socket.io-client # client
const { Server } = require('socket.io');
const io = new Server(httpServer, {
cors: { origin: '*' }
});
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
// Join an image editing room
socket.on('join-image', (imageId) => {
socket.join(`image:${imageId}`);
const users = io.sockets.adapter
.rooms.get(`image:${imageId}`);
io.to(`image:${imageId}`)
.emit('users-updated', {
count: users?.size || 0
});
});
// Broadcast filter changes to other editors
socket.on('filter-change',
({ imageId, filterName, value }) => {
socket.to(`image:${imageId}`)
.emit('filter-change', {
filterName, value, userId: socket.id
});
});
// Broadcast cursor position
socket.on('cursor-move',
({ imageId, x, y }) => {
socket.to(`image:${imageId}`)
.emit('cursor-move', {
x, y, userId: socket.id
});
});
socket.on('disconnect', () => {
console.log('User disconnected:',
socket.id);
});
});
function useCollaboration(imageId) {
const [socket, setSocket] = useState(null);
const [collaborators, setCollaborators]
= useState([]);
useEffect(() => {
const s = io(API_URL);
setSocket(s);
s.emit('join-image', imageId);
s.on('filter-change',
({ filterName, value, userId }) => {
// Apply the remote user's filter change
dispatch({
type: 'SET_FILTER',
payload: { name: filterName, value }
});
});
s.on('cursor-move',
({ x, y, userId }) => {
setCollaborators(prev => ({
...prev,
[userId]: {
x, y, lastSeen: Date.now()
},
}));
});
s.on('users-updated', ({ count }) => {
// Show "2 people editing"
});
return () => s.disconnect();
}, [imageId]);
const emitFilterChange =
(filterName, value) => {
socket?.emit('filter-change',
{ imageId, filterName, value });
};
const emitCursorMove = (x, y) => {
socket?.emit('cursor-move',
{ imageId, x, y });
};
return {
collaborators,
emitFilterChange,
emitCursorMove
};
}
Open two browser windows, same image. Move a slider in one → the other updates instantly. Show collaborator cursors on the canvas with colored indicators.
git switch -c feature/PIXELCRAFT-057-realtime-collab
git add server/ src/
git commit -m "Add WebSocket real-time collaboration (PIXELCRAFT-057)"
git push origin feature/PIXELCRAFT-057-realtime-collab
# PR → Review → Merge → Close ticket ✅
The client-server model has evolved.
HTTP is request-response (half-duplex). WebSockets are full-duplex — both sides send at any time over a persistent connection.