Expo sandboxes: camera, Expo Router, and React Three Fiber
Before the archived social mobile codebase: camera capture, file-based routing sandboxes, and a Three.js scene through expo-gl — practice reps on the path to production Expo work.
- React Native
- Expo
- Three.js
- Mobile
Expo sandboxes: camera, Expo Router, and React Three Fiber
#TL;DR
Before the archived mobile events platform, I kept three small Expo repos as deliberate practice:
| Repo | Focus |
|---|---|
react-native-camera-example | Official-style expo-camera sample — capture and display |
react-native-sandbox | Expo Router starter + early components/messages/ UI experiments |
react-native-threejs | expo-gl + @react-three/fiber + three on device |
None of these shipped to the App Store. Together they de-risked the bigger Firebase codebase.
#Camera example
Forked from the Expo examples pattern: install, optional pod-install, yarn start, open on iOS simulator or Android emulator or web.
Lesson: permissions and secure context rules differ per platform — camera on web is not camera on device. I treated this repo as the capability spike before building profile photo flows in a real app.
#Sandbox with Expo Router
Created with create-expo-app, using file-based routes under app/. Includes a components/messages/ area — early UI slicing for chat-like layouts without backend wiring.
Lesson: Expo Router’s file tree is the same mental model as Next.js App Router — good for portfolio engineers crossing web and mobile.
#React Three Fiber on mobile
react-native-threejs pins Expo SDK 54, React 19, expo-router 6, and:
"@react-three/fiber": "^9.3.0",
"expo-gl": "^16.0.7",
"three": "^0.180.0"Lesson: 3D on mobile means GL surface lifecycle — mounting, unmounting, and memory when users background the app. I never merged this into the social product (2D feed was enough complexity), but the spike informed how I think about heavy views in RN.
#How this ties to production-shaped work
| Sandbox skill | Used later in |
|---|---|
| Camera permissions | Profile / story media flows (archived app) |
| Router structure | Expo Router in the main social codebase |
| Performance caution | Deciding not to ship Three.js in a social feed |
#Message list row patterns (react-native-sandbox)
The sandbox’s MessageItem is React.memo’d with haptic feedback on press, relative “Active 5m ago” copy, and unread badge styling — patterns copied into the production inbox without dragging the whole spike repo:
export const MessageItem: React.FC<MessageItemProps> = React.memo(({ conversation, onPress }) => {
const formatLastSeen = (date: Date): string => {
const diffInMinutes = Math.floor((Date.now() - date.getTime()) / (1000 * 60));
if (diffInMinutes < 1) return 'Active now';
if (diffInMinutes < 60) return `Active ${diffInMinutes}m ago`;
// ...
};
});Keeping list rows pure and memoized mattered once Firestore snapshot listeners started firing on every typing indicator update in the main app.
#Three.js spike stack (Expo SDK 54)
react-native-threejs pins @react-three/fiber 9.x with expo-gl and three@0.180 — useful as a compatibility matrix when upgrading Expo major versions, even though 3D never shipped in the social product.
#Closing thought
Spikes belong in repos you can delete—camera APIs, GL surfaces, and router experiments should not land in the same branch as your Firestore schema. Once a spike works, copy the pattern, not the folder structure.
#Reader field guide
Use separate sandboxes when the production app already carries Firebase schema, messaging rules, and TestFlight paperwork.
When to spin a spike repo
- Capability unknown (camera permissions,
expo-gllifecycle, Router nested layouts)—prove on a throwaway app first - No backend yet—UI rows and navigation structure without Firestore listeners
- Heavy native dep—confirm prebuild + device build before merging into the main
app.config
| Sandbox | Proves | Copy into production, not the repo |
|---|---|---|
react-native-camera-example | Per-platform permission + capture | Profile/story media flows |
react-native-sandbox | Expo Router + memoized list rows | Inbox layout patterns (platform post) |
react-native-threejs | R3F + expo-gl memory on background | Usually skip for a 2D social feed |
Stop spike work when: you can archive a device build with the native module, or you have a one-page note on what failed—then delete or freeze the sandbox so it does not become a second product.
#Related reading
#On this site
| Post | Why |
|---|---|
| Lessons from building a mobile events social platform | Production-shaped architecture these sandboxes fed into |
| Shipping an Expo app through TestFlight | What happens after spikes graduate to signed builds |
| Securing Firebase for a social mobile app | Rules and App Check before any spike touches prod data |
#References (curated)
I treat these repos as throwaway—official Expo and R3F docs are where I copy API names, not blog summaries.
| Reference | Notes |
|---|---|
| Expo Camera | Permissions and preview lifecycle on device, not simulator-only. |
| Expo Router | File routes before you nest custom navigators. |
| React Three Fiber | expo-gl + R3F spikes—watch GPU memory on older iPhones. |
| Expo SDK reference | Version skew across sandboxes is the usual breakage mode. |