Phaser Tweens: Making a 2048 Merge Feel Juicy
Phaser Tweens: Making a 2048 Merge Feel Juicy
Direct answer: Tweens are the cheapest way to make an HTML5 game feel good. We use them in three places — button press/hover feedback, fish merge/teleport animations, and screen transitions — roughly 30 tween call sites in one scene alone. Start there before touching particles or screen shake.
“Juice” is what makes a merge feel like a merge instead of a spreadsheet. Here is the tween toolkit from Merge Fish 2048.
1. Button feedback: the 2-tween press
All our buttons go through one factory, so every button in the game gets the same feel:
// on press
this.tweens.add({ targets: btn, scale: 0.92, duration: 80, ease: 'Quad.easeOut' });
// on release
this.tweens.add({ targets: btn, scale: 1, duration: 120, ease: 'Back.easeOut' });
Scale down on press, spring back on release. Back.easeOut overshoots slightly, which reads as “clickable” even on flat UI art. Because it lives in ButtonFactory, one change re-skins every screen.
2. Merge animation: move, pop, and breathe
The merge itself is three tweens layered on the same sprite:
- Move: the sliding fish tweens to the target cell (
duration ~150ms). - Pop: on arrival it scales to 1.15 and back — the “I became something” moment.
- Breathe: the new fish gets a gentle looping scale tween (1 → 1.03) so the board never feels static.
this.tweens.add({ targets: fish, x: toX, y: toY, duration: 150, ease: 'Cubic.easeInOut' });
this.tweens.add({ targets: fish, scale: 1.15, yoyo: true, duration: 90, ease: 'Sine.easeInOut' });
The numbers are not sacred — the pattern is: every state change announces itself with motion. A merge that just swaps a texture feels broken; a merge that pops feels satisfying.
3. Screen transitions: fade in, fade out, slide
Scene changes in Phaser are instant by default — jarring. We wrap them:
this.cameras.main.fadeOut(200, 0, 0, 0);
this.cameras.main.once('camerafadeoutcomplete', () => this.scene.start('LevelSelect'));
200ms fade out, start the next scene, fade in on arrival. It costs 3 lines per transition and removes the “hard cut” feeling between menu and gameplay. For overlay scenes (help, settings) we tween the panel container scale from 0.95 → 1 while fading in — cheap and effective.
4. When tweens are not enough
Tweens animate properties. For these jobs reach for something else:
| Job | Tool |
|---|---|
| Particle bursts (merge sparkles) | Phaser particle emitter |
| Fish swimming idle motion | Tween the sprite (works) |
| Camera shake | camera.shake() — dedicated API |
| Physics-driven movement | An arcade/matter body, not a tween |
A tween on a physics body fights the physics engine. Keep tweens for UI and presentation, physics for simulation.
Common mistakes
- Tweening the wrong target: tween a container’s position, not the child that physics moves.
- Forgetting to remove tweens: on scene stop, Phaser cleans up scene tweens automatically — but tweens created on global/game objects don’t. Kill them in
shutdownor you’ll get ghosts. - Every duration the same: identical timings feel mechanical. Vary press (80ms), merge (150ms), transitions (200ms) so the game has rhythm.
Related reading
- Phaser Scene Management: How We Structure 9 Scenes
- Phaser Particle Effects: A Practical Intro
- Phaser 3 Game Tutorial: Your First Playable in a Day
Written by ruofan, independent HTML5 game developer. Tween patterns come from Merge Fish 2048 (Phaser 3.90 + Vite), a game we’re building. API details: Phaser tweens docs.