Party Without Video Fatigue
Shopify Party is an internal, browser-based tool for virtual socializing. It swaps grid-view video calls for 3D avatars exploring toy-like worlds together. The aim was straightforward: offer a space built for playful interaction, not another meeting room. Byron Delgado and I built the first version in three months, during Shopify’s broader shift to remote work.
Three design principles kept the project focused:
- No prescribed goals. Levels are sandboxes with vehicles, throwable objects, and hidden corners. You can race cars—or ignore them and organize a tire-pushing contest instead. Fewer rules also mean less game logic to build.
- Join anytime, leave anytime. Without win conditions or scripted rounds, a late arrival never disrupts anyone’s progress. Spaces stay open for drop-ins.
- Minimal controls. Arrow keys or WASD to move, space to jump, E to interact. Skipping a complex control scheme keeps the barrier to entry low for casual hangouts.
Stack: Unity and Normcore
Running in the browser was non-negotiable. That pointed to WebGL for rendering. While lower-level libraries like THREE.js, Babylon.js, and PlayCanvas are popular options, we chose Unity. It ships with a full editor, built-in physics for interactions, and a solid WebAssembly export path. We were already comfortable with Unity’s workflow, which helped compress the timeline. The project runs on Unity 2020 with the Universal Rendering Pipeline.
Networking runs on Normcore, which handles VoIP, physics synchronization, and game state. Rather than a traditional client/server model with authoritative hosts, Normcore behaves like a realtime database. Each client owns and updates the entities it controls, pushing changes to a server that fans them out to every other connected client.
In practice, each browser maintains a local copy of all players. When Daniel moves, his browser sends the position update to Normcore’s server, which relays it to Byron’s browser. Interpolation smooths the movement between updates. Normcore only transmits data when a value actually changes, which keeps bandwidth usage low.
Keeping Uncontrolled Objects in Sync
Objects that no player drives need another synchronization strategy. Consider a platform that moves up and down. If it runs on a Unity animation, each client’s playhead can drift apart—especially if someone joins mid-meeting.
Our solution was to derive the platform’s position from room time, Normcore’s synchronized server clock. All clients see effectively the same value after latency compensation. Setting the y position to Sin(roomTime) means every client computes the same oscillation at the same instant, deterministic and independent of when someone connected.
Shipping in Three Months
Building an entire virtual world that quickly meant leaning hard on existing content. Most of our props and environments came from the Unity Asset Store, combining low-poly packs into cohesive scenes. The characters were the main piece we created ourselves.
Characters From Texture Layers
Modeling thousands of custom outfits wasn’t realistic. Instead, all clothing exists as textures layered onto one base 3D model. Shirt, pants, shoes, gloves, and accessories each live in a separate texture file. At runtime, a single shader blends them all—overlaying clothing textures over the character’s skin color.
Consolidating all outfit logic into one shader program also helps performance; fewer shaders means less GPU work per frame. The blending process uses standard shader nodes: tiling and offset to position each garment, a texture sample, then a blend operation to composite it onto the stack.
This approach made creating new outfits trivial. Transparent regions of a texture simply reveal skin underneath, which designs long sleeves or shorts easily. It also means employees can design new outfits using a simple template, without touching 3D modeling software.
Hair, Hats, and Faces
Hair and hats couldn’t stay flat textures, so we modeled 40 hairstyles. Each style has a hat-on and hat-off variant to prevent wide hair from clipping through headwear. The game toggles between them based on the character’s accessories.
Eyes and mouths are separate meshes layered over the face rather than part of the skin shader. This made animation easy: we added a blink cycle and drive the mouth shape whenever a player speaks, which does a lot to make avatars feel lively.
Performance on Mixed Hardware
Because Party is internal, the hardware target is known in advance—but that range still spans M1 Pros to Pixelbooks. Keeping a smooth 60 frames per second required deliberate choices.
First, materials stay on Simple Lit rather than full physically based rendering. The stylized look doesn’t need PBR’s realistic light simulation, and a cheaper lighting model pays off. Each material uses at most one texture, capped at 1024×1024, skipping expensive normal, metallic, and occlusion maps.
Second, we used GPU instancing early on, before Unity’s Scriptable Render Pipeline Batcher supported WebGL. Instancing lets the CPU submit one model with a list of positions instead of issuing a separate draw call per object. That made a measurable difference on repeated props—trees, rocks, and wheels. Unity even handles the implementation details; enabling GPU instancing is a checkbox on the material settings.
Render Scale Tuning
The Universal Render Pipeline exposes a render scale setting that controls the resolution of the rendered image relative to the window size. At a render scale of 1, a 1920x1080 window renders at 1920x1080. Dropping the scale to 0.5 renders at 960x540, with the output stretched to fill the window.
Reducing the render scale cuts the pixel count and improves performance, which makes it a straightforward lever for weaker hardware like Pixelbooks. But a fixed scale factor is not enough when the display changes. A Pixelbook connected to a 4K monitor still renders at 1920x1080 even with a scale of 0.5. Instead of relying on a static scale, the render scale is computed from a target resolution and the current window size:
For Pixelbooks, targetWidth is set to 1536. That approach caps the maximum render width at 1536 pixels regardless of the window's resolution.
Looking Ahead
Shopify Party's launch was a success. Hundreds of games are played every week across one-on-ones, icebreakers, standups, and other team gatherings. Employees have shared that they feel more at ease joining this playful setting than attending a large video call.
The tool isn't meant to replace video conferencing; it's an alternative for connecting with colleagues and a space for both social play and creative contribution. A person can complete a Blender tutorial over a weekend and see their art in the game days later. Another can work through a Unity course and create an experience for thousands of employees. The project is designed as a sandbox for experimentation, inviting people to learn new skills and apply them.
The project is open for contributions, and feedback from weekly use will continue to shape its development. The goal is to grow Shopify Party alongside the people who engage with it, expanding both its social utility and the range of experiences it hosts.



