All projects

Tellytubbies

Holographic trading cards of your friends, opened from a sealed 3D pack

2026 Personal
Tellytubbies
React NativeExpoThree.jsexpo-glSkiaGyroscopeSupabase

You make a card out of a photo of someone, seal it into a pack, and send it. They open the pack on their phone — it tears, the cards fan out — and the card they pull has a real holographic foil that shifts as they tilt the device.

It’s a toy. The engineering question underneath it is a good one: how do you make a digital object feel like a physical one you own?

Foil that responds to the phone, not to a loop

The holographic effect isn’t a looping animation. It’s driven by the gyroscope: a useGyro hook feeds device orientation into a Three.js scene rendered through expo-gl, and the foil’s highlight moves against the tilt.

That’s the entire trick, and it’s why it reads as material rather than as an effect. A looping shimmer says this is a graphic. A highlight that tracks your wrist says this is a surface catching light. Same shader budget, completely different object.

Cards render through a small family of components — HoloCard for the full 3D treatment, CSSHoloCard as the cheap gyroscope-driven fallback, PhotoCard and MemberCard for the static faces — so a screen full of cards in a grid doesn’t run a WebGL context each.

The pack is the whole ritual

SealedPack → Pack3D → OpenedPack is deliberately three components and three beats. Pack opening is the entire emotional payload of trading cards, and it’s carried by delay: sealed and heavy, then a tear, then the reveal. Haptics fire on the tear, a whoosh plays on the pull.

Skipping straight to the card would save a second and lose the point.

Performance work that the effect required

Holo textures are preloaded and cached at module level, keyed remote URI → local resized JPEG, with in-flight promises deduped so ten cards mounting at once trigger one download each rather than ten. Without the preload, the foil appears a beat after the card does — and a card whose material loads late reads as broken rather than precious.

Supabase holds profiles, pack photos and push tokens; a pack arriving is a notification, because a gift nobody knows about isn’t a gift.