4 min readCase study

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:

RepoFocus
react-native-camera-exampleOfficial-style expo-camera sample — capture and display
react-native-sandboxExpo Router starter + early components/messages/ UI experiments
react-native-threejsexpo-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:

JSON
"@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 skillUsed later in
Camera permissionsProfile / story media flows (archived app)
Router structureExpo Router in the main social codebase
Performance cautionDeciding 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:

TypeScript
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-gl lifecycle, 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
SandboxProvesCopy into production, not the repo
react-native-camera-examplePer-platform permission + captureProfile/story media flows
react-native-sandboxExpo Router + memoized list rowsInbox layout patterns (platform post)
react-native-threejsR3F + expo-gl memory on backgroundUsually 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.


#On this site

PostWhy
Lessons from building a mobile events social platformProduction-shaped architecture these sandboxes fed into
Shipping an Expo app through TestFlightWhat happens after spikes graduate to signed builds
Securing Firebase for a social mobile appRules 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.

ReferenceNotes
Expo CameraPermissions and preview lifecycle on device, not simulator-only.
Expo RouterFile routes before you nest custom navigators.
React Three Fiberexpo-gl + R3F spikes—watch GPU memory on older iPhones.
Expo SDK referenceVersion skew across sandboxes is the usual breakage mode.