Vibe Coding with Lovable: Build a Real-Time Collaborative Image Gallery in Minutes 📸❤️🔥
Modern web development isn't just about code; it's about connection. Imagine a site where multiple users can scroll, comment, and interact side-by-side — all live in real-time. Fancy, right? Thanks to AI-powered tools like Lovable and collaboration SDKs like Velt, this is no longer a pipe dream but a quick, achievable project.
In this guide, we'll vibe code a collaborative Pinterest-esque Masonry grid that lets users:
- See each other's cursors move live
- Add and view comments on specific images
- Toggle between light and dark themes seamlessly
- Enjoy a responsive, infinite-scroll gallery filled with beautiful Unsplash images
Ready? Let's dive in! 🚀
🛠️ What is Vibe Coding Anyway?
Fun fact: "Vibe Coding" is the new buzzword for blending AI power with rapid development. Developers are buzzing on Twitter about using AI to handle heavy-lifting — from writing actual code to complex app logic — cutting down dev time from days to hours.
With Lovable, an AI UI component generator, and Velt, a real-time collaboration toolkit, we’re going to vibe code our masterpiece.
📐 Masonry Layout: The Pinterest Wall You Know and Love
Masonry grids arrange items based on height and width, creating that flowing Pinterest-style look. It’s visually clean, easy to scan, and perfect for showcasing image galleries.
Here’s a quick snapshot of what it looks like:
Kinda makes you want to start building right away, huh?
⚠️ The Real-World Challenges of Crafting a Pinterest-Style Grid
You might think, “How hard can it be?” But stacking images nicely while juggling responsiveness, smooth infinite scrolling, and performance is a real puzzle. Consider:
- Dynamic sizing: Images have wildly different heights — your layout must gracefully accommodate without nasty gaps.
- Infinite scroll: Users expect bottomless content. But loading it without hiccups? That’s tricky.
- Responsiveness: Works beautifully on desktop, tablet, and mobile — no exceptions.
- Performance: Too many images at once? Your browser tanks. 🥴
Here’s the essence of Masonry layout logic in React-ish pseudocode:
// Calculate Masonry items position
const calculateLayout = (items, containerWidth, columnWidth, gap) => {
const columnCount = Math.floor((containerWidth + gap) / (columnWidth + gap));
const columnHeights = Array(columnCount).fill(0);
return items.map(item => {
const shortestColumnIndex = columnHeights.indexOf(Math.min(...columnHeights));
const x = shortestColumnIndex * (columnWidth + gap);
const y = columnHeights[shortestColumnIndex];
columnHeights[shortestColumnIndex] += item.height + gap;
return { ...item, x, y };
});
};
And infinite scrolling can be managed with a scroll listener watching for the user hitting near the bottom:
useEffect(() => {
const handleScroll = () => {
const scrollHeight = document.documentElement.scrollHeight;
const scrollTop = document.documentElement.scrollTop;
const clientHeight = document.documentElement.clientHeight;
if (scrollHeight - scrollTop <= clientHeight + 200 && !isLoading) {
setIsLoading(true);
loadMoreItems();
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [isLoading]);
Nothing too scary — but putting the pieces together AND adding real-time collaboration? That’s where the magic (and complexity) starts.
🖼️ Leveraging Unsplash API for Beautiful Images
Why handle image uploads when you can tap into the world’s best free photo database? Unsplash’s API lets you fetch stunning, royalty-free images on demand — no backend hassle needed.
Our Masonry grid will pull 10 new images at a time, keeping the gallery fresh without the pain of image storage.
⚙️ Backend Complexities? No Sweat. Enter Velt.
Managing real-time state, presence, comments, and updates traditionally requires a soup of WebSockets, databases, and backend logic.
Check out this simplified WebSocket handler snippet (yikes!):
const socket = new WebSocket("wss://your-server.com/ws");
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === "cursor_move") {
updateUserCursor(data.userId, data.position);
} else if (data.type === "new_comment") {
addNewComment(data.imageId, data.comment);
}
};
socket.onclose = () => {
setTimeout(() => {
// Your reconnection logic here
}, 1000);
};
Building all that from scratch? A nightmare.
But good news! Velt does this heavy lifting for you, offering:
- Ready-made collaboration components (cursors, comments, presence taps)
- Real-time syncing out of the box
- Simple integration with just a few lines of code
- Handling of all the nasty backend and WebSocket stuff
Think of Velt as the Firebase for collaboration features — without the boilerplate headache.
💡 Step 1: Generate Your UI with Lovable
Lovable is an AI wizard that turns descriptions or reference images into UI components.
Pro tip for best Lovable results:
- Attach a reference image (Pinterest shots work like charm)
- Mention exact libraries/components you want used
- Spell out your styling and behavior needs
- Note down any no-go libraries or approaches
Here's a sample prompt to whip up our Masonry grid:
I've attached a screenshot of my Pinterest wall. This layout is a Masonry Grid.
I want a responsive, infinite-scroll grid filled with random Unsplash images fetched via their API.
The control panel at the bottom should have:
- User presence
- Comment button
- Comments stack
- Dark/Light mode toggle
Make the control panel minimalist with a dark option and use libraries similar to the blog reference provided.
Lovable generates your starter UI code — clone your GitHub repo synced with Lovable, plug in your Unsplash API key (VITE_UNSPLASH_CLIENT_ID
) into your .env
file, and watch the magic begin.
🛠️ Step 2: Add Real-Time Collaboration with Velt
Install the Velt SDK:
npm install @veltdev/react
npm install --save-dev @veltdev/types
Set up velt.tsx
to manage user context & Velt providers:
import {
VeltProvider as BaseVeltProvider,
useVeltClient
} from "@veltdev/react";
const USERS = [
{ id: "user1", name: "John Doe", profileUrl: "https://randomuser.me/api/portraits/men/62.jpg" },
{ id: "user2", name: "Jane Smith", profileUrl: "https://randomuser.me/api/portraits/women/2.jpg" },
];
export function VeltProvider({ children }) {
const [user, setUser] = useState(null);
useEffect(() => {
const savedUserId = localStorage.getItem("currentUserId");
const savedUser = savedUserId ? USERS.find(u => u.id === savedUserId) : USERS[0];
setUser(savedUser || USERS[0]);
}, []);
const switchUser = () => {
const currentIndex = USERS.findIndex(u => u.id === user?.id);
const nextUser = USERS[(currentIndex + 1) % USERS.length];
localStorage.setItem("currentUserId", nextUser.id);
setUser(nextUser);
};
return (
<UserContext.Provider value={{ user, switchUser }}>
<BaseVeltProvider apiKey={import.meta.env.VITE_VELT_API_KEY}>
<VeltUserProvider user={user}>{children}</VeltUserProvider>
</BaseVeltProvider>
</UserContext.Provider>
);
}
Wrap your main <App />
component with Velt providers and add <VeltCursor />
to display live cursors:
import { VeltProvider, VeltDocumentProvider } from '@/lib/velt';
import { VeltCursor } from '@veltdev/react';
const App = () => (
<QueryClientProvider client={queryClient}>
<VeltProvider>
<VeltDocumentProvider>
<VeltCursor />
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
</VeltDocumentProvider>
</VeltProvider>
</QueryClientProvider>
);
Key components:
VeltProvider
: Bootstraps collaboration logic and user contextVeltDocumentProvider
: Creates a shared "room" for real-time syncVeltCursor
: Shows live user pointer positions
🗨️ Step 3: Add Real-Time Comments and Sidebar
Attach the powerful <VeltComments />
component inside your Masonry grid to enable image-specific threaded comments:
import { VeltComments } from '@veltdev/react';
const MasonryGrid = () => {
const [isDarkMode, setIsDarkMode] = useState(false);
useEffect(() => {
const checkDarkMode = () => {
const dark = document.documentElement.classList.contains('dark');
setIsDarkMode(dark);
};
checkDarkMode();
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.attributeName === 'class') checkDarkMode();
});
});
observer.observe(document.documentElement, { attributes: true });
return () => observer.disconnect();
}, []);
return (
<>
<VeltComments darkMode={isDarkMode} popoverMode={true} popoverTriangleComponent={false} />
{/* Your Masonry items here */}
</>
);
};
Bonus: Unique IDs for images!
Generate unique IDs to link comments specifically to each image:
const imageId = `image-${index}`; // can be Unsplash ID or any unique string
Use data-velt-target-comment-element-id
attribute on your image container:
<div data-velt-target-comment-element-id={imageId}>
<img src={image.url} alt={image.alt} />
</div>
Add a floating comment bubble that shows comment count and last commenter:
<VeltCommentBubble targetElementId={imageId} commentCountType="total" />
Finally, create a minimalist comments sidebar with toggle button:
import { VeltCommentsSidebar, VeltSidebarButton } from '@veltdev/react';
const Toolbar = () => {
return (
<div className="flex justify-between items-center p-4">
<VeltCommentsSidebar darkMode={isDarkMode} />
<VeltSidebarButton>
<Button variant="ghost" size="icon" className="rounded-full text-gray-400 hover:text-white hover:bg-white/10 h-8 w-8 p-0">
<Inbox className="h-5 w-5" strokeWidth={1.5} />
</Button>
</VeltSidebarButton>
</div>
);
};
🎉 The Result: Collaborate Like a Pro
In under 15 minutes, you've built an app where users can:
- See who's online and where their cursor points
- Add meaningful comments tied to specific images
- Enjoy a beautiful, responsive Pinterest-like layout
- Toggle light and dark themes like a boss
🍒 On Top: Testing and Demos
Check out the working live demo here: Endless Unsplash Grid Demo
Peek the full source on GitHub: Studio1HQ/endless-unsplash-grid
Also, here’s a quick demo video to see it in action:
🚀 Taking It Further: More Velt Goodies to Explore
Feeling adventurous? Push your app’s collaboration game up a notch with:
- Live Reactions: Emoji your friends’ favorite images in real-time🫶
- Follow Mode: Jump in on someone else’s actions for demos or tutorials🎥
- Huddles: Instant audio/video meetups inside your own app🎙️
🤖 Why This Matters: The Future of Modern Dev
Gone are the days of building every feature from scratch.
With Lovable and Velt, you combine AI-powered UI generation with plug-and-play collaboration components — drastically slashing your dev time and complexity.
This is how developers build faster, smarter, and better user experiences. So if you’re making anything that’s collaborative, it’s time to vibe code and level up.
Thanks for vibing with me today! If this lit your dev spirit on fire, share with your friends and community.
Stay curious, keep building, and hit me up on Twitter @Astrodevil_
Pro Tip: Peek at the SaaS tools I love here 👉🏼 My Tech Bento and if you want to collab on writing, find me here 📅 Contact Me
Happy coding! ✨