DEV Community

PatilRB
PatilRB

Posted on

The reward moment is the product

Free-to-play UI is not decoration. It is the reward loop made visible, and the moment a player taps "claim" is closer to being the product than anything in your feature list.

That sounds like marketing copy until you look at what actually differs between a game people keep opening and one they don't. It is rarely the systems. It is whether collecting something feels like collecting something.

The reward moment, decomposed

A reward tap that reads well is doing four things in about 400 milliseconds:

  1. Acknowledging the input — something happens on press, not on release, so the tap never feels ignored.
  2. Showing the value — the thing you earned is visibly a thing, moving from where you claimed it to where it lives.
  3. Marking significance — scale, timing and particle density say "this was a big one" or "this was routine".
  4. Getting out of the way — it resolves fast enough that a player tapping through twenty of them is not fighting your animation.

Point 4 is the one that gets missed. Juice is easy to add and hard to bound, and a reward sequence that delights on first sight becomes the thing players complain about on day thirty.

Where the effort actually goes

Not into the particle system. Into the timing relationships between the layers:

onClaim() {
  spark(button.position);              // t=0    input acknowledged
  setTimeout(() => fountain(tray), 80); // t=80  value appears, after the spark reads
  setTimeout(() => countUp(amount), 140); // t=140 number climbs into place
}
Enter fullscreen mode Exit fullscreen mode

Those offsets are the design. Fire everything at t=0 and it reads as one undifferentiated flash; space them too far and it reads as lag. The 60–150 ms band is where "responsive but legible" lives, and finding it is iteration, not calculation.

Which is why the authoring loop matters more than the feature set. If changing an 80 to a 110 requires an engineer, a rebuild and a redeploy, nobody will tune it, and the reward moment will ship at whatever numbers the first implementation happened to use.

Making it tunable by the person with the taste

Two properties get you there:

Effects as data, not code. A named effect loaded from a bundle can be re-authored by whoever has the eye for it. A drawCoinBurst() function can only be changed by whoever writes functions.

Timing in one place. The offsets above belong in the presentation layer next to each other, not scattered across the handlers that trigger them. You want a person to be able to read the whole sequence at once.

This walkthrough builds the concrete version for PixiJS v8 — a claim button that sparks on press and a coin fountain for the reward popup, both authored in an editor and played from the ticker. What I'd take from it is less the particles than the shape: the game says a reward happened, and a separate layer owns how that reads.

The test

Ask whoever has the best instinct for game feel on your team to change how a reward reads — not to describe it, to change it.

If they can do it alone in a few minutes, your pipeline is right. If they have to file a ticket, then the most commercially important 400 milliseconds in your game are being tuned by whoever has build access, which is not the same person and never was.

Top comments (0)