SHARP Memories
(iOS, Next.js) Converting 2D photos into immersive 3D Gaussian Splats using a serverless, event-driven architecture.
SHARP Memories turns a single 2D photo into an immersive 3D Gaussian Splat you can view and share on iOS, the web, and Apple Vision Pro.
Most 3D capture tools require LiDAR or 50+ images. Using Apple's open-source SHARP model, I built a pipeline that needs only one input image, so anyone with a smartphone can do it.
Built for Sharing
I could have generated and stored the splats locally on-device, but the whole point is the moment you "revive" a photo and immediately want to show somebody. So I designed around distribution and retention from the start.
1. Virality via App Clips
The truth is people don't want to download another random app. To solve the "cold start" problem, I built an iOS App Clip. When a user shares a memory via iMessage, the recipient doesn't need to download the full app. They tap the link, and the 3D model renders instantly in a lightweight viewer (< 15MB).
2. The "Snapchat" Mechanics
To release this publicly without paying for storage, I implemented a "Snapchat-style" lifecycle:
- 0-24 Hours: Memories are fully visible in 3D.
- 24 Hours - 7 Days: Memories "fade" (turn gray). Users must tap to "resurrect" them, triggering a re-generation.
- 7+ Days: Hard deletion to respect user privacy and storage limits.
Gaussian splats are large files (~60MB), and my Cloudflare R2 bucket is on the free tier. Deleting the heavy splat after 24 hours while keeping the small preview image for 7 days keeps storage flat, and the "faded" state gives users a reason to come back.
Architecture: The "Free Tier" Stack
My main constraint was cost. Storing gigabytes of PLY (point cloud) files is expensive, so I stitched together a hybrid storage setup from the best free tiers of different providers.
The Event-Driven Pipeline
The backend is fully serverless and asynchronous, so the UI never blocks while the GPU crunches data.
- Ingestion: The client uploads the raw 2D image to Supabase Storage (1GB Free Tier).
- Trigger: An Edge Function inserts a row into the
splatstable. - Inference: A Supabase Database Webhook detects the
INSERTand calls thetrigger-inferenceEdge Function. - GPU Processing: The function calls Modal AI, where I host the Python ML inference code on serverless NVIDIA T4 GPUs. Modal returns a
200 OKimmediately so the connection doesn't hang. - Storage Optimization: Once generated, the heavy PLY file (~60MB+) is uploaded to Cloudflare R2 (10GB Free Tier), which offers zero egress fees.
- Realtime Feedback: The clients subscribe to Supabase Realtime updates. As soon as the status flips to
completed, the UI updates automatically.
// Example: Supabase Edge Function snippet for triggering inference
Deno.serve(async (req) => {
const payload = await req.json();
const { record } = payload;
// Offload to Modal AI (Python)
const response = await fetch("https://modal-api-url/generate", {
method: "POST",
body: JSON.stringify({ image_url: record.input_image_url }),
});
return new Response("Inference Started", { status: 200 });
});
Try it out!
Visit sharpmemories.app, upload a photo (you'll need an account), and play around with the 3D memory. I'm sure it will bring you a curious sense of nostalgia.
You can also download the iOS version here
This project was a lot of fun to make, especially because I could view it on my phone, my laptop, and even the Vision Pro. Plus, I could share it with people!