</yunmakai-room-as-store>
The Yunmakai motel room is the storefront
How I built a 3D commerce experience for an indie music project where every product is an object in a room, every navigation step preserves spatial continuity, and the cart never leaves the scene.
Yunmakai is an indie music project that needed a store. The brief was unusual. The client wanted a place, not a shop. Buying a record should feel like picking it up off a shelf in a strange motel room, not adding a SKU to a cart on a one-page generic theme. So the storefront for Yunmakai is one interactive 3D scene, and everything you can buy lives inside that scene as an object.
Spatial continuity is the entire UX
The decision that ran the whole project is this. Every navigation step preserves spatial continuity. There are no page transitions in the traditional sense. The TV in the motel room is the product grid, and tapping the TV does not load a new route. The camera auto-zooms into the TV screen, the product grid renders against the screen surface, and the room is still behind it. Tapping a product slides the camera into a product-detail position. Round-trip back to the room lands the camera exactly where it left.
The user never feels like they navigated. They feel like they walked.
That sounds simple. It is not. It means the cart drawer, the music player, the account view, and the checkout overlay all have to exist as scene-aware layers on top of the room rather than as full-page routes. State has to travel through Zustand stores keyed to spatial positions so that pressing back inside checkout returns you to the product detail you came from, with the camera at the same dolly distance.
GLB budget is part of the brief
The motel room is one Blender model loaded as a GLB through useGLTF with a Draco decoder. The room loads in under three seconds on a midrange phone over LTE. That is non-negotiable. The product is buying a record, and the customer never gets to do it if the room is still spinning up. The budget is under 5 MB compressed, between 50k and 100k triangles, PBR metallic-roughness for materials, and a 2K HDR for environment light.
Hotspot mesh names in the GLB are load-bearing in the code. Room, TV, TV_Screen, Poster, Lamp. The model is the API. If a future artist renames the TV mesh, half the interactions disappear silently. This is a constraint, not a bug. It keeps the modelling and the code in conversation.
Postprocessing as a brand layer
Bloom, vignette, a custom split-toning effect, and a very mild chromatic aberration sit on top of the scene as a postprocessing stack. This is doing brand work, not just look-and-feel work. Yunmakai's reference is Southern Gothic Noir motel photography. Ozark, Twin Peaks, neon-lit lobbies. The postprocessing stack is how a scene built in Blender with mostly neutral materials ends up feeling like it is in a Coen Brothers film.
The cost is real. On older Android the stack adds five to eight frames of latency per draw, so the pipeline is gated behind a device capability check. Below a threshold, the postprocessing falls back to a static color grade applied to the renderer output instead of a per-frame stack. The room still feels right. The phone still hits 60.
Commerce sits behind Shopify, the room stays in Next.js
The Yunmakai stack splits commerce between Shopify and Supabase. Product, inventory, and checkout are Shopify Storefront API. Audio metadata, user state, and Yunmakai-specific business rules are Supabase. The room and the renderer are Next.js with React Three Fiber. This is the right boundary for an indie music client. Shopify is the best at the transactional rails. Supabase is the best at the soft state. The 3D layer never has to know whether checkout is finished. It only knows where the camera is.
A sandboxed scene viewer is embedded on this site's Yunmakai project page so you can walk the room without leaving the portfolio.