Inspiration

Dandan Run began as a Unity prototype: a vertical runner about three chaos-prone office mascots escaping the consequences of their own lunch break. We loved how quickly it could hook someone with a single thumb, but the prototype was trapped behind an install and a desktop build. We wanted to turn it into a link you can send to a friend. No app store, no controller, no gaming PC. Just a phone browser and one tap.

We also wanted the game to look like something you could pick up and unfold. Our references were manga ink, screen-printed gig posters, sticker-covered notebooks, and the graphic-novel confidence of Persona 5's menus. The office setting gave us the comedy; the print aesthetic gave us the rules: fat outlines, limited colors, halftone dots, paper grain, and typography that is allowed to be as loud as the characters.

What it does

Dandan Run is a portrait-mode endless runner set in a surreal glass office tower. You choose one of three color-coded coworkers: Dandan, the mouthy blue speedster; Lulu, the red one with goggles and terrible aim; and Tete, the green innocent who always has a gadget and an excuse. Then you sprint down a corridor of white tile, glass and cargo while a literal red cube of executive fury chases you.

Swipe left or right to change lanes, swipe up to jump and jump again in the air, swipe down to roll under low obstacles. Collect coins, dodge cargo stacks, coffee machines, industrial racks and collapsing crates, and push your score as the speed ramps up. Your score combines distance and coins, and your best run is saved locally.

It is a complete loop rather than a single scene: boot screen, animated attract title, a 3D lobby where the trio goof off and lob ice, fire and a sentinel hive across the room, a character select with turntable props, a cinematic panic-and-escape opening, the run, pause with a three-beat countdown resume, results, and one-tap retry. It works with touch or keyboard and auto-pauses when the tab loses focus.

How we built it

Dandan Run is a hand-written TypeScript game on top of Three.js r186 and Vite. There is no Unity runtime and no off-the-shelf game engine. We froze the original Unity tuning into a JSON rules file: speeds, lane geometry, obstacle unlocks, coin spacing and camera beats. Then we rebuilt the simulation around a deterministic seeded spawner and a sampled route. A custom vertex-shader curved world makes a finite set of 28.5 m corridor modules feel endless; the city outside each module is merged into a single draw call, and the original 730k-triangle lobby streams in from GLB.

The asset pipeline is our own. Meshes, skeletons, animation clips, facial-expression atlases and materials are exported from Unity, retargeted and packed for the browser, with animation data shared across characters and a mobile tier that rebuilds heavy textures at a lower resolution. The screen-printed look is a post-process pass: limited palette, halftone dots, ink edges, paper grain and slight registration drift. Menus and HUD are real DOM above the canvas, never baked into the 3D scene, so text stays sharp on high-DPR phones and remains accessible. We also built a pure-UI entry point that loads no Three.js or GLBs, which let us iterate on menus and HUD at full speed. Eight browser-based regression harnesses cover lane alignment, coin distribution, pause/resume, HUD fit and the whole menu-to-run flow.

Challenges we ran into

The first challenge was parity. Porting a runner is not a code translation: the feel lives in acceleration curves, camera lag, collision forgiveness and the exact spacing of coins. One bug made every coin and obstacle drift after an S-bend because placement used the corridor module's tangent instead of each object's own route distance. We fixed the math and locked it with a lane-alignment test that samples the route before, inside and after the hall.

The second challenge was the phone itself. A high-fidelity build downloaded completely on an iPhone, and then Safari reloaded in a loop. The network logs showed every asset had arrived; the crash was memory pressure from decoded 4K character atlases, five 4K VRM textures and 2K architecture maps. We built a mobile asset tier that keeps geometry and animation intact, rebuilds the same GLBs with smaller textures, and recomputes the model's SHA-256 integrity record, cutting the texture footprint dramatically. The lesson was blunt: on mobile, memory is the frame budget.

The third was making the art direction survive the real world: 320–430 px widths, notches, 56 px backdrop blur, halftone post-processing, reduced-motion preferences, and a 3D lobby behind it all. The HUD and menus became a responsive, keyboard-accessible DOM layer with safe-area math and quality tiers, so the look does not depend on one device's GPU.

Accomplishments that we're proud of

We built a complete, install-free game loop that feels like one continuous performance. The title's graffiti layers peel away into the lobby; the three characters goof off and throw props; the chosen runner freezes in a shocked close-up and bolts; the camera hands off into the chase without a loading screen. Every screen, from the first loading bar to the results poster, shares one visual language.

We kept the original game's feel while rebuilding it for the web: deterministic spawn patterns, convex collision for collapsing crates, one-draw-call skyline modules, a 730k-triangle lobby, and eight automated browser tests that keep the invisible rules honest. We also diagnosed a real-device memory failure and built a mobile asset pipeline that preserves the same game, geometry and integrity checks at a fraction of the texture cost. Most importantly, the result does not feel like a tech demo with a menu bolted on. It feels like a small, complete arcade game.

What we learned

Porting is re-authoring. The code can be translated; the feel cannot. The parts players never name, like the camera's late follow, the extra frames of collision grace, or the pause that freezes generation and input, are the game.

On the web, constraints are the design. One thumb, a 390 px screen, an unknown GPU and a browser tab forced every element to compete for attention. That pressure produced a clearer game than the version with more room.

Automated probes are not a substitute for taste, but they are a guardrail for it. Being able to change a shader or a HUD size and immediately verify that the lane math, pause state and menu flow still work let us spend our human attention on look and feel.

Real devices tell the truth. A build that boots perfectly in headless Chrome can still die on a phone. Profiling memory on the target device is part of game design, not cleanup.

What's next for Dandan Run

The next milestone is a public, properly licensed release. We are replacing the remaining placeholder props, confirming the rights for every legacy asset, finishing the audio and haptic layer, and completing the facial-expression pass for all three characters.

After that: adaptive streaming that chooses texture and geometry tiers from the device's memory and network, an installable PWA with offline play, daily and weekly runs with shareable ghost replays and leaderboards, unlockable outfits and props, and more corridor modules and set pieces.

We also want to bring first play under a few seconds, add full English localization and a short interactive tutorial, and test on low-end Android phones, not just iPhones, so the link works for everyone who receives it. The long-term goal is simple: a game you can send as a link, and a world people want to return to for one more run.

Built With

Share this project:

Updates

Submission history