Samohit Studio
A cassette deck, hand painted weather, and one playlist shared across two cities
A browser music player that treats listening as a mood rather than a playlist. Songs play on a retro cassette deck set against hand painted scenes, with rain, wind, fireflies and lightning you can switch on, and a mode that lets two people in different cities share one deck.
Context
A hobby project, built with Rohit. It started as a small gift between two people in a long distance relationship: somewhere to put on a song and feel like you were in the same room. It turned into a full player, and it is the only thing on this site I built for an audience of two.
I am including it because the engineering problem underneath it is real, and because it is the clearest example of me building something end to end with no team, no deadline and nobody to delegate the artwork to.
Problem
Listening together across cities is badly served. The tools that exist are built for watch parties, or they need both people to hold a paid account, or they want an install and a sign up before you can hear anything. None of that survives being sent as a link on WhatsApp at eleven at night.
The second problem was softer and mattered more to us. Every music app presents listening as a list of tracks. We wanted it to feel like a place you were in together.
Insight
You do not need to stream audio between two people to make them feel like they are listening together. You only need both screens to agree on what should be playing.
That single reframing is what let the whole thing run on a static site and three small functions. Share intent, not sound: which song, whether it is playing, the position, and the server time that position was recorded. Each browser gets the audio itself, straight from YouTube, and works out locally whether it has drifted.
What I built
A cassette deck with reels that spin while a song plays, set against twelve mood scenes drawn from our own artwork. Chandni, Pahadi, Sunehri, Gulabi, Shehar, Hari, Gali, Neela, Cafe, Chhat, Jugnu, Safar. Every scene has a portrait cut for phones and a landscape cut for laptops, because one image cropped two ways always looks wrong in one of them.
On top of any scene you can layer Baarish, Hawa, Jugnu and Bijli. Rain, wind, fireflies and lightning. In the indoor scenes the rain falls only inside the window areas of the artwork, so the room stays dry.
Then Saath Saath, the listen together mode, which is the heart of it. One person starts a room and sends the link, the other opens it and types a name. Both see one playlist and both control one deck, with a chat and six quick reactions beside it. No accounts. A room is a long random id that cannot be listed or guessed, and it expires thirty days after it was last used.
Keeping two screens in step
The room stores what should be playing, not a stream of events. Each screen computes the expected position as the stored position plus the time elapsed since it was stored, and if its own player has drifted more than two seconds it quietly seeks to catch up. No jarring jumps, no fight between the two players.
Clock skew was the first thing to bite. A phone with a wrong clock lands on the wrong second, so each screen measures the gap between its own clock and the server's from the round trip of every request, and corrects for it.
Polling rather than sockets. Every two seconds, dropping to eight when the tab is in the background, with a version number on the room so a screen only downloads the playlist and chat when something has actually changed. On a free serverless plan this was enough, and it meant no socket server to run or pay for.
The bug I liked solving most: when a song ends, both screens ask for the next one at almost the same instant, and the playlist jumps two songs ahead. The fix is a once only key per song version on the server, so only the first request counts. Similarly, a screen ignores the update caused by its own button press, otherwise a pause bounces back as a second pause.
Calls I made
No framework and no build step. Plain HTML, CSS and JavaScript. For a project this size a framework would have been weight without leverage, and I wanted to be able to open the file and change one thing a year from now.
Never host or proxy the audio. Songs play through the official YouTube player from uploads on YouTube, which keeps views, ads and credit with the rights holders and keeps us out of a problem we had no business being in. This was a constraint I set before writing any code, not a thing I retrofitted.
Polling over a real time server. Less elegant on paper, and the right call here: two people, a two second tolerance, and a free tier to stay inside.
Test the thing that actually breaks. The automated tests drive two browser windows at once in Playwright and check that play, pause, skip, seek and chat stay in step between them. Single browser tests would have passed on a product that was broken in the only way that mattered.
What I learned
Most of the hard work was not in the sync logic, it was in the hundred small decisions that make something feel handmade rather than assembled. Short Hindi names for the moods instead of English labels. A palette that shifts with each scene. Rain that respects the windows. None of that is technically interesting and all of it is why the thing feels like a place.
I also learned how much restraint a free tier buys you. Not being able to reach for a socket server forced a simpler design, and the simpler design is the one I would choose again with a budget.
What I would do differently: the About section grew long before I thought about how it would read on a phone, and I ended up rebuilding the layout to cut roughly a third of its height. Designing it narrow first would have been faster than fixing it later.
Credits and music
Concept, artwork and build by Samiksha Das and Rohit, together #Samohit. The mood scenes and photos are our own. The code and artwork are not open source, and the repository is private, though I am happy to walk anyone through it.
Samohit Studio does not host, download or stream any audio. Songs play through the official YouTube player, from videos uploaded on YouTube, under YouTube's Terms of Service. All songs belong to their respective labels and artists, and rights holders can ask for a song to be removed.
A personal hobby project. No ads, no paid features, and no tracking beyond a simple visitor count.