Reward Claim — Coin Shower & Balance Delivery
- Skia
- Reanimated
- Haptics
A chest bursts, rains coins that bounce and settle, then pours the pile up into a glass balance pill. Every coin's position is a closed-form function of time and a seed, so no frame depends on the one before it and a recorded claim replays exactly.
Purchases are not open yet.
Bounces without a physics step
Nothing integrates the shower forward. The coin's first meeting with the floor is the positive root of a quadratic, and the arcs after it are a geometric series: each lasts 2v / gravity, and the rebound speed is multiplied by 0.55. The walk stops when an arc falls under 20 ms or the speed under 12 px/s, and the coin is placed at rest.
const vImpact = coin.vy + gravity * tf; // > 0 (downward)let tRemain = local - tf;let v = vImpact * e; // upward rebound speed after the first bouncefor (let bounceN = 0; bounceN < 24; bounceN++) { const arc = (2 * v) / gravity; // … if (tRemain < arc) { const yArc = floorY - (v * tRemain - 0.5 * gravity * tRemain * tRemain); return { x, y: yArc, rot, flipScale, flip, alpha: 1, landed: false }; } tRemain -= arc; v *= e;}Coins that stop sliding
Horizontal travel used to be velocity times elapsed time in every branch, the resting one included, so settled coins kept drifting and most of the pile had left the frame before it was collected. Friction now begins at first floor contact and decays exponentially, converging on a finite offset. Flight before contact is untouched, so the eruption looks the same.
const qa0 = 0.5 * gravity;const disc0 = coin.vy * coin.vy + 4 * qa0 * floorY;const tf0 = disc0 <= 0 ? 0 : (-coin.vy + Math.sqrt(disc0)) / (2 * qa0);let x: number;if (!bounce || local < tf0) { x = coin.vx * local;} else { const kd = 3.0; x = coin.vx * tf0 + ((coin.vx * 0.55) / kd) * (1 - Math.exp(-kd * (local - tf0)));}The pill takes the impact
The arriving stream drives one pressure value rather than striking the pill coin by coin. It opens over a 90 ms attack, so the first arrival cannot pop it, then decays as the pour thins. Under load the pill widens by 3%, flattens by 5% and carries a fine tremor; when the stream stops it springs back through a damped cosine held between 0.97 and 1.07.
const attack = Math.min(1, Math.max(0, (s - countA) / 0.09));return Math.max(0, Math.min(1, rate * attack));// …scale = 1 + 0.045 * q + 0.006 * Math.sin(s * 46) * q;// …const v = 1 + 0.06 * Math.exp(-9 * e) * Math.cos(13 * e);scale = v < 0.97 ? 0.97 : v > 1.07 ? 1.07 : v;<RewardClaimCoinShower params={{ coinCount: 120, rewardAmount: 2500, coinColor: "#FFC93C", floorBounce: true }} fireSignal={0} />