Indie Game Lab

How I Built “Super Miserable Adventurer” — A Cocos Creator WeChat Mini-Game Case Study

By Haitao Pan · Game Developer & Studio Owner · 12 min read

TL;DR: I shipped a 750×1334 portrait survival/crafting mini-game on Cocos Creator 3.8 for the WeChat platform. This is the post-mortem — the architecture that held up, the performance traps I walked into, and the overseas-i18n work that turned a Chinese-only build into something portable.

Disclaimer: this is a personal engineering write-up. Any tool or engine mentioned is based on my own usage; some links on this site may be affiliate links, but they never affect what I recommend.

1. Why this game, why this engine

I wanted a game with a real progression loop — gather, craft, fight, dive dungeons — that still loads fast on a phone. WeChat's mini-game runtime is unforgiving about package size, so the engine choice was less "what's most powerful" and more "what fits the constraint." Cocos Creator 3.8 LTS won on three points: small runtime, real TypeScript support, and a build pipeline that targets WeChat directly.

I'm the one making the design calls, so the loop was built around a simple promise to the player: every session should move a number that matters. That single rule drove most of the UI decisions below.

Every session moves a number that matters Gather Craft Fight Dungeon
The loop everything serves. Each station feeds the center promise — if a feature doesn't move a number, it didn't ship.

2. The UI layer: a code-only widget library

The biggest architectural win was throwing out prefab-driven UI in favor of a small code-only widget library — think UINode, UILabel, UIButton, UIVStack/UIHStack, UIGrid. Reasons:

The grid is a streaming layout: content height is computed from the row flow, the scroll view's viewport is fixed (not driven by a Widget, which fought scrollToTop), and each cell positions itself relative to contentHeight/2. That one detail killed a week of "scroll lands in the wrong place" bugs.

Game panels — Home · Map · Bag · Battle · Trade declare data + intent, never touch nodes directly Layout components — UIGrid · UIVStack · UIHStack one positioning algorithm, three surfaces Primitives — UINode · UILabel · UIButton · UIShape code-built, pooled, no prefabs Cocos Creator 3.8 nodes & components
The code-only UI stack. Panels talk down one layer at a time — swapping the grid algorithm never touches a panel.

3. Performance budget I had to respect

Mini-game runtimes punish sloppiness. Three fixes moved the needle most:

Rule I now live by: profile before you optimize, but optimize the package size before you profile the frame rate. Size blocks the install; frame rate only blocks the retention.

4. The overseas problem: i18n without a rewrite

The original build was Chinese-only, hardcoded strings everywhere. To make it portable I treated text as data:

This is the part most post-mortems skip: localization is an architecture decision, not a find-and-replace pass. If you didn't build the seam in week one, you pay for it in a rewrite.

5. What I'd do differently

  1. Design the save/cloud layer earlier. Retention lives or dies on "I can pick this up tomorrow," and that needs a sync story, not a localStorage gamble.
  2. Ship one deep loop, not five shallow ones. The dungeon, the trade system, and the crafting tree each wanted to be the star. Picking one to go deep first would have shipped sooner.
  3. Measure fun, not just frames. I had a perf dashboard before I had a retention dashboard. Inverted priority.

6. Takeaways for other small teams

If you're building a mini-game or web game on a tight runtime: choose the engine by package-size ceiling first, build UI as code not prefabs, and treat i18n as a foundation pour, not a coat of paint. The game below the surface is the same game everywhere — only the words and the width of the text box change.

← Back to all field notes