Project · Lakshay Mehandru · Aug 2026

Marketplace

A shop page where the other visitors show up as cursors. Press / to say something, e to throw an emoji.

Another weekend build with Aswin Nair. More of his work is at aswinnair.com.

Next.jsCloudflareRealtimeWeekend project
Marketplace
3 online
  • Studio Lamp$129
  • Ceramic Mug$24
  • Headphones$249
  • Field Watch$420
A web version of the idea. The cursors and chat lines are scripted and nothing here talks to the real app. Press the / button to send a line.

A shop with other people in it

Why is shopping online so lonely?

You can be looking at a lamp while other people look at the same lamp, and nobody can tell. Aswin and I wanted to see what changes if they can. So we made a small shop page, twelve things for sale, and everyone who has it open shows up as a cursor.

Press / and a chat bubble opens under your cursor. Press e and an emoji bursts out of it. Open a product and its card shows who else has it open. When someone adds something to their bag, you get a small toast.

Making phones and laptops agree

The part I liked: a laptop and a phone lay the same grid out completely differently, so a pixel position means nothing across them. Each cursor goes out as a fraction of the content column's width and a distance down the page, and each screen puts it back in its own layout. Reactions are tied to a card instead of a coordinate, so a heart on the lamp comes out of the lamp wherever the lamp is on your screen.

A server that forgets

Every browser keeps a WebSocket open to one Cloudflare Durable Object. We built it with PartyServer, Cloudflare's library for real-time rooms, and partysocket on the client. The server relays where everyone is and keeps nothing. Pointer updates go out about fifty times a second, and the receiving side smooths them so the cursors glide. Every page pings every fifteen seconds, and one that goes quiet for three pings gets dropped. That's what stops a closed laptop from leaving a ghost cursor behind.

A side trip into 3D

Along the way we modeled the products in 3D. A Blender script builds all twelve as GLB files, and a small viewer lets you orbit them. The shop itself ended up using flat renders, so the 3D folder is still a side experiment.

What it is

It's a weekend toy: one page, twelve products, and a checkout button that just says thank you.

How it's built

The cursors

Each page sends its pointer to one shared room about every 20 ms, and every other cursor is smoothed on arrival, so it glides instead of stepping. A position goes out as a fraction of the content column's width and a distance down the page, which keeps a phone and a laptop roughly in line even though their grids differ.

The chat bubble

Press / and a bubble opens under your cursor. Text goes out as you type, up to 200 characters, and the bubble fades five seconds after the last keystroke. Everyone else sees it live, caret and all.

On a phone

A touch screen has no pointer to share, so a fingertip shows only while a finger is down. A long press opens a reaction picker, and double-tapping a photo sends a heart that erupts from that card on everyone's screen.

The room server

One Cloudflare Durable Object, through PartyServer, relays presence and keeps no history. Clients ping every 15 seconds and a connection that stays quiet for three pings is dropped, so a closed laptop doesn't leave a ghost cursor. The server only forwards six whitelisted emoji.

The shop

Next.js 16 and Tailwind 4. Twelve products, a sheet that slides up for each one with an Add to bag button that morphs when you press it, a bag saved in your browser, and a checkout button that only says thank you. Light and dark, with a reveal that spreads from the theme toggle.

The 3D side trip

A Blender script builds all twelve products as GLB models, and a small viewer page lets you orbit them with model-viewer. The shop itself uses flat renders, so this stayed a side experiment.