Skip to content

Repository files navigation

Mira — a true mirror

Mira

Meet your true face.

Mira is a front-camera app that shows a live, horizontally un-reversed feed — so you see the face the world actually sees, not the left-right-flipped image an ordinary mirror (or a normal selfie camera) gives you.

A normal mirror, and every selfie camera, flips you left-to-right. You're so used to that reflection that the real, un-flipped you can look subtly "off." Mira shows the un-flipped view by default, and lets you flick back to the familiar mirror to see the difference.


Features

  • True / Mirror toggle — flip the live preview between the un-reversed true view (how others see you) and the familiar mirror view.
  • Clean-mirror mode — controls auto-hide after a few seconds; tap anywhere to bring them back. At rest it's just an unobstructed, full-screen mirror.
  • Freeze & compare — capture one frame and view True | Flipped side-by-side, then save both versions to your photos.
  • Capture — save a still to your library, with shutter flash, haptics, and a thumbnail of your last shot.
  • Front-camera only, portrait, fully offline (no network, no accounts, no tracking).

Screenshots

Mira See the face the world sees True or Mirror, in one tap Freeze and compare

How it works

The interesting part is the live flip. On Android, expo-camera's mirror prop only flips the captured photo, never the live preview, and a React Native transform: scaleX(-1) is ignored by the camera's underlying SurfaceView. Mira flips the preview at the native layer instead — it mirrors the CameraX PreviewView directly (previewView.scaleX = -1), applied via a small patch-package patch to expo-camera (patches/expo-camera+*.patch). On iOS the preview is flipped with a normal RN transform.

Note: Expo SDK 54 ships expo-camera as a precompiled binary, so the patch only takes effect when the module is built from source. That's enabled via expo.autolinking.buildFromSource in package.json. Because of this, Mira runs as a native build, not in Expo Go.

Tech stack

  • Expo SDK 54 · React Native 0.81 · TypeScript
  • expo-camera (preview + capture), expo-image-manipulator (mirror the saved frame), expo-media-library (save), expo-haptics, expo-sharing, expo-system-ui
  • react-native-safe-area-context
  • Fonts via @expo-google-fonts: Instrument Serif, Hanken Grotesk, Spline Sans Mono

Getting started

npm install            # also applies the expo-camera patch via postinstall

Prerequisites: Node (LTS recommended), the Android SDK / Android Studio, and a JDK (17).

Run on a connected device or emulator (builds a dev client — this is not Expo Go):

npm run android

Building

Standalone, installable artifacts (JS bundled in, no Metro needed):

cd android
./gradlew assembleRelease   # -> app/build/outputs/apk/release/app-release.apk   (sideload)
./gradlew bundleRelease     # -> app/build/outputs/bundle/release/app-release.aab (Play upload)

Signing

Release builds are signed from a gitignored keystore.properties at the repo root:

storeFile=your-upload-key.jks
storePassword=…
keyAlias=…
keyPassword=…

Generate an upload key with keytool -genkeypair -v -keystore your-upload-key.jks -alias … -keyalg RSA -keysize 2048 -validity 10000. Keep the keystore and password backed up — losing them means you can't publish updates. If keystore.properties is absent, the release falls back to debug signing so the build still succeeds.

android/ is generated by expo prebuild and is gitignored. Re-running prebuild regenerates android/app/build.gradle, which drops the signing block — re-apply it, or move to EAS Build for managed signing.

Project structure

App.tsx                     # single screen: permission gate, camera, compare, capture
theme.ts                    # Mira design tokens (color, radii, fonts)
components/
  MiraMark.tsx              # the lens + seam + off-center-dot logo
  SegmentedToggle.tsx       # True | Mirror switch
  Toast.tsx                 # save confirmation
app.json                    # Expo config (name, icons, permissions, plugins)
patches/                    # expo-camera native preview-flip patch
assets/                     # icon, adaptive icon, splash, favicon

Permissions

  • Camera — required, the whole point of the app.
  • Save to photos / vibrate — to save captures and provide haptic feedback.

Microphone, system-overlay, and audio/video read permissions are explicitly removed (android.blockedPermissions in app.json). Nothing is collected or sent anywhere.

Brand

The identity ("Mira") is defined in design_handoff_mira_brand/ — a warm Ink/Clay/Bone palette, a serif wordmark, mono labels, and the lens-with-an-off-center-dot symbol (a face that refuses to be symmetrical). Tokens live in theme.ts.

License

Application code is released under the MIT License. Fonts are licensed under the SIL Open Font License via @expo-google-fonts. "Mira", its wordmark, and the logo are brand assets — you're welcome to fork the code, but please ship your own branding.

About

Mira shows you the face the world actually sees. A front-camera app that un-reverses your reflection — mirrors and selfie cameras flip you left-to-right; this doesn't. Fully offline, no accounts, no tracking.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages