Skip to content
Builds
Native Lab experiment, designed and built solo

Split the bill by dragging

Drag each item off the receipt onto whoever had it, and their share rolls up, service included.

Expo · Reanimated · Gesture Handler · Expo UI (SwiftUI) · React Native Skia · Expo Haptics

1Demo

  • Dragging a bottle of Chianti off the receipt onto Everyone

Scripted simulator take with a drawn finger. Sample bill and people; no payments are sent. Not yet tested on a phone.

2Flow

  1. 1Receipt printsAppout of a slot in line-sized feeds, a haptic tick each
  2. 2Long-press a lineYoua ghost of the row lifts and follows your finger
  3. 3Drop it on a faceYouor on Everyone to split it evenly between all three
  4. 4The total rollsAppthe ghost flies in, the face bumps, a firm tap, then the digits roll
  5. 5Tap SettleYouthe receipt tears off with a heavy tap and everyone gets a stub with their share
From a printed receipt to everyone's stub.

3How it fits

System
tab-experience.tsxscheduleOnRNsame callsfollow,then flyinlift · landassignedlands,facebumpscentsYour fingerGesture.Pan, long-press120 msScripted fingerdemo-script.tsDrag handlerspickUp · moveTo · dropHapticsfeedback.tsGhost rowReanimated shared valuesMoneybill.ts · totals() incentsFaces and totalsnumeric-text.tsx(SwiftUI)
A real finger and the scripted one call the same three handlers.

4Code

  const drop = useCallback(
    (x: number, y: number) => {
      const index = dragging;
      if (index < 0) return;
      const hit = layout.targets.findIndex((t) => Math.hypot(t.x - x, t.y - y) < 58);
      if (hit < 0) {
        gx.value = withSpring(layout.rowX, { damping: 16 });
        gy.value = withSpring(layout.rowY(index), { damping: 16 }, () => {
          go.value = 0;
        });
        gs.value = withSpring(1);
        setTimeout(() => setDragging(-1), 320);
        return;
      }
      const t = layout.targets[hit];
      const ease = { duration: 360, easing: Easing.in(Easing.cubic) };
      gx.value = withTiming(t.x - layout.rowW / 2, ease);
      gy.value = withTiming(t.y - ROW / 2, ease);
      gs.value = withTiming(0.12, ease);
      go.value = withTiming(0, { duration: 380 });
      setTimeout(() => {
        feedback.land();
        bumps[hit].value = withSequence(withTiming(1.16, { duration: 120 }), withSpring(1, { damping: 9 }));
        if (hit === 3) for (let i = 0; i < 3; i += 1) bumps[i].value = withSequence(withTiming(1.1, { duration: 140 }), withSpring(1, { damping: 10 }));
        setAssigned((a) => ({ ...a, [ITEMS[index].id]: hit === 3 ? EVERYONE : PEOPLE[hit].id }));
        setDragging(-1);
      }, 340);
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [dragging, go, gs, gx, gy, layout],
  );

The ghost flies into the face first; the item is only assigned 340 ms later, so the total rolls as it lands.

5Decisions

  • Assign the item 340 ms after the drop over assigning it the moment you let go

    the ghost reaches the face first, so the total rolls as it arrives, not before

  • Reveal the receipt in line-sized feeds, a tick each over one smooth slide out of the slot

    it judders out like thermal paper

  • SwiftUI's numeric text, through Expo UI over rolling digits rebuilt in Reanimated

    it is the system's own digit roll, not an imitation of it

  • Whole cents, service pro rata over dollars with service split evenly

    whoever ordered more pays more of the service, and every share is whole cents

More builds

  • Buddy cheering the last task with confetti

    A mascot rigged in code, not animated

    A to-do list mascot who watches your finger, giggles when poked, flies when flung, leans when you tilt the phone and cheers your last task.

    Native Lab experiment, designed and built soloDemo · Flow · System · Code

    23 Oct 2026

  • 12:41 PM in London, and everyone is awake

    A globe that shows who's awake

    Your people on a globe lit by the real Sun: scrub the next day to see who is awake, or tap once for a time that suits everyone.

    Native Lab experiment, designed and built soloDemo · Flow · System · Code

    23 Oct 2026

Meer's mascot, waving a peace sign

Have an app in mind?

Tell me what you're building. Replies within 24h. It's in Chittagong.

Booking new projects for Q4

Free 30-minute call

Talk through your app with me. You leave with a plan and a fixed price.

Video callShown in your time zone in Chittagong