Skip to content

Instantly share code, notes, and snippets.

@shricodev
Created March 4, 2025 12:23
Show Gist options
  • Select an option

  • Save shricodev/d0083c72d80f66056cf6f9a9cc042614 to your computer and use it in GitHub Desktop.

Select an option

Save shricodev/d0083c72d80f66056cf6f9a9cc042614 to your computer and use it in GitHub Desktop.
Collaborative whiteboard application (generated by GPT-4.5 AI Model). This gist is for one of my blog post comparison of AI Models.
"use client";
import React, { useRef, useEffect, useState } from "react";
export default function Whiteboard() {
const canvasRef = useRef<HTMLCanvasElement>(null);
const ws = useRef<WebSocket | null>(null);
const [drawing, setDrawing] = useState(false);
const [lastPos, setLastPos] = useState<{ x: number; y: number } | null>(null);
useEffect(() => {
ws.current = new WebSocket("ws://localhost:3001");
ws.current.onopen = () => {
console.log("Connected to WebSocket server");
};
ws.current.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === "draw") {
const { from, to } = message;
const canvas = canvasRef.current;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.beginPath();
ctx.moveTo(from.x, from.y);
ctx.lineTo(to.x, to.y);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
}
} else if (message.type === "clear") {
const canvas = canvasRef.current;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
}
};
return () => {
if (ws.current) ws.current.close();
};
}, []);
// Mouse event handlers for drawing
const handleMouseDown = (e: React.MouseEvent<HTMLCanvasElement>) => {
setDrawing(true);
setLastPos({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY });
};
const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => {
if (!drawing) return;
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (!ctx || !lastPos) return;
const newPos = { x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY };
// Draw line locally on the canvas
ctx.beginPath();
ctx.moveTo(lastPos.x, lastPos.y);
ctx.lineTo(newPos.x, newPos.y);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
// Broadcast the drawing data to other clients via WebSocket
const message = {
type: "draw",
from: lastPos,
to: newPos,
};
ws.current?.send(JSON.stringify(message));
setLastPos(newPos);
};
const handleMouseUp = () => {
setDrawing(false);
setLastPos(null);
};
// Clear the canvas (both locally and for all connected clients)
const clearCanvas = () => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (ctx && canvas) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const message = {
type: "clear",
};
ws.current?.send(JSON.stringify(message));
}
};
return (
<div className="text-black flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
<h1 className="text-3xl font-bold mb-6">
Real-Time Collaborative Whiteboard
</h1>
<canvas
ref={canvasRef}
width={800}
height={600}
className="border border-gray-400 bg-white"
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseUp}
/>
<button
onClick={clearCanvas}
className="mt-4 px-6 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors"
>
Clear Canvas
</button>
</div>
);
}
const WebSocket = require("ws");
const PORT = 3001;
const wss = new WebSocket.Server({ port: PORT });
wss.on("connection", (ws) => {
console.log("New client connected");
ws.on("message", (data) => {
// Broadcast the incoming message to all clients except the sender.
wss.clients.forEach((client) => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
ws.on("close", () => {
console.log("Client disconnected");
});
});
console.log(`WebSocket server is running on ws://localhost:${PORT}`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment