Please sign in to access this page
MeshInk is a real-time, collaborative whiteboard application featuring an infinite canvas. It allows multiple users to draw together seamlessly, with features designed for a smooth and intuitive experience.
No followers yet
Once you ship this you can't edit the description of the project, but you'll be able to add more devlogs and re-ship it as you add new features!
With the collaborative canvas operational, my focus shifted to refining the user experience, particularly around navigation and visual clarity. The pan and zoom functionality, while functional, felt abrupt. To address this, I implemented a much smoother, animated zoom using requestAnimationFrame. Instead of jarring jumps, the canvas now glides to the target scale, creating a more fluid and professional feel. To complement this, I added a zoom indicator to the toolbar, displaying the current zoom percentage and ratio, giving users a clear sense of their viewport. The grid system also received a major overhaul. The previous static grid was replaced with a dynamic, shape-based grid that intelligently adjusts its density based on the zoom level. As you zoom in, more subdivisions appear, providing greater precision, and as you zoom out, they fade away to keep the view uncluttered. This ensures the grid is always useful, never overwhelming.
To further enhance usability, I introduced a Reset View button that smoothly animates the canvas back to its default position and zoom level. I also made the pen color theme-aware, automatically switching between black and white for optimal visibility in light and dark modes.
With the core features in place, the next major step was to enable private, shareable sessions. I transformed the landing page into a hub for creating or joining rooms, using nanoid to generate unique 7-character room IDs. To keep the UI responsive, I implemented React's useTransition hook for non-blocking loading states. I then replaced the static canvas with a dynamic [roomId] route. The key to isolating sessions was making the Ably channel subscription dynamic, creating a unique channel for each room based on its ID.
To prevent the blank canvas issue for new joiners, I implemented a state synchronization handshake. A new client requests the current state, and an existing client responds by publishing the entire canvas history, instantly syncing the new user.
Finally, to improve the sharing experience, I built a CollapsibleShareNotification for room creators, which automatically appears and provides easy copy-to-clipboard functionality for the room link and code. A crucial fix to the Ably auth URL ensures reliable connections from the new nested routes.
I started by building the foundation for a real-time collaborative whiteboard using Next.js and Konva.js. The initial goal was to get the core drawing mechanic working, so I used Ably to sync pen strokes between users. It worked, but the experience was limited; everyone was drawing inside the same fixed-size box.
The challenge was to make the canvas infinite. My solution was to scrap the static background entirely and make a dynamic grid. It hooks into the canvas's pan and zoom events to calculate and render only the grid lines visible in the current viewport. This created a seamless illusion of a boundless space.
With the core logic in place, I shifted to the user-facing side of the project. I built the main toolbar with essential tools like a pen, an eraser, and a pan control. To give users more creative freedom, I added a proper color picker and a stroke width slider. The final touches were a toggle to hide the grid and a theme switcher