> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Phone-Frame Preview

> 11 device presets, landscape mode, and color variants for QA'ing your mobile app inside the editor

The phone-frame preview is what you see in the editor when you create a Native Mobile project. It's a real React Native Web build of your app — the same `app/_layout.tsx`, `app/(auth)/sign-in.tsx`, NativeWind classes — rendered inside a CSS chrome that mimics an iPhone or Android device. No simulator install. No real phone required for layout work.

## What it is — and what it isn't

**It is:** a fast, accurate way to check layouts, navigation flows, Tailwind/NativeWind styling, Supabase queries, form behavior, and route transitions. The bundle is built by Metro the same way EAS would build it for production.

**It isn't:** a full native runtime. APIs that touch native code — push notifications, biometric auth, camera, file system, haptics, Bluetooth — won't fire in the iframe. For those you publish to a Preview OTA channel and open the link on a real device with Expo Go.

## Devices

Eleven device presets cover the realistic spread of modern hardware. Pick from the dropdown in the preview toolbar:

| Group   | Devices                                           |
| ------- | ------------------------------------------------- |
| iPhone  | SE (3rd gen), 13 mini, 14, 15, 15 Pro, 15 Pro Max |
| iPad    | mini, Pro 11"                                     |
| Android | Pixel 8, Galaxy S24, Galaxy Fold (folded)         |

Each preset uses the **logical pixel** dimensions Apple and Google publish, not the raw screen resolution. So a Pixel 8 frame is 412×915 (logical), not 1080×2400 (physical) — which matches what your `<View>`s actually render against.

The Galaxy Fold preset renders the **folded** outer screen (374×882). For unfolded testing, use the iPad mini preset as a stand-in — same aspect ratio family.

<Tip>
  Test layout extremes by toggling between **iPhone SE** (smallest modern iPhone, 375×667) and **iPad Pro 11"** (largest tablet, 834×1194). If your screen survives both, it survives 95% of devices in the wild.
</Tip>

## Landscape mode

Click the rotate icon in the toolbar to flip orientation. The chrome rotates with the content — notch ends up on the right, home indicator on the bottom — so screenshots look correct for App Store landscape submissions.

Some screens are intentionally portrait-only (auth flows, simple forms). React Native respects the `app.json` `orientation` setting at runtime, but the preview lets you override it visually so you can audit what *would* happen if a user rotated mid-flow.

## Color variants

Below the device dropdown is a color picker for the chrome itself. Six accent colors per device:

* **iPhone**: Natural Titanium, Blue Titanium, White Titanium, Black Titanium, Gold, Pacific Blue
* **Android**: Obsidian, Porcelain, Bay, Mint, Wintergreen, Rose

This is purely cosmetic — affects only the bezel color in the screenshot, not the rendered app. Useful when generating App Store hero images or marketing screenshots and you want a Pixel 8 in Mint instead of the default Obsidian.

The selection persists in localStorage keyed by project ID, so each project remembers its own chrome.

## Boot lifecycle

When you open the preview pane:

<Steps>
  <Step title="Fly machine spin-up (cold boot ~10–20s)">
    A per-project Fly machine boots from `ghcr.io/locus2012/hiveku-previews:expo`. First boot pulls the Docker image (\~400 MB) and starts Metro. You see a "Starting your project..." splash with a moving progress bar.
  </Step>

  <Step title="Metro bundle (~5–8s after spin-up)">
    `npx expo start --web --port 3000` compiles your `app/`, `components/`, `lib/` directories into a single JS bundle. Source maps are inline so errors point at the file you wrote, not the bundle line.
  </Step>

  <Step title="Iframe handshake">
    Once Metro responds with `200 OK`, the LivePreview iframe loads `https://hvk-{hash}.preview.hiveku.com`. You see your sign-in screen rendered inside the phone frame.
  </Step>

  <Step title="Hot reload">
    Subsequent edits trigger Metro HMR. JS-only changes apply in \~1.5 seconds without a full reload. Adding a native dependency (e.g. `expo-camera`) requires a full rebuild — Metro detects the dependency change and shows a "rebuilding native bundle" toast.
  </Step>
</Steps>

If the boot stalls past 60 seconds, the preview shows a **"Restart preview"** button. Click it to recreate the Fly machine from scratch — usually fixes a stuck Metro process.

## Errors in the preview

Metro errors don't return HTTP 500 — they return HTTP 200 with the error embedded in the bundle response. We detect 8 distinct Metro patterns and surface them as a clear banner above the iframe:

| Pattern                                              | What it means                                                  |
| ---------------------------------------------------- | -------------------------------------------------------------- |
| `Unable to resolve module`                           | Import path is wrong or the package isn't installed            |
| `SyntaxError` (Babel)                                | TypeScript or JSX syntax error — file path + line number shown |
| `Identifier '...' has already been declared`         | Duplicate import or variable name clash                        |
| `Cannot find name 'X'`                               | Missing import or reference to undefined symbol                |
| `Failed to apply 'expo-router' babel plugin`         | `app/` directory layout violates Expo Router conventions       |
| `nativewind: Could not parse class`                  | Invalid NativeWind/Tailwind class name                         |
| `react-native-reanimated/plugin must be listed last` | Babel plugin order issue in `babel.config.js`                  |
| `Module not found: Can't resolve 'react-native'`     | RN-Web alias broken — usually fixed by restarting the preview  |

Each banner has a **Fix with AI** button that drops the error into the chat as the next user message — the AI reads the relevant files and proposes a patch.

## Bundle size warnings

If your Metro bundle exceeds 75 MB compressed, the preview toolbar shows a yellow **"Bundle size: 81.2 MB"** chip. Tap it for a breakdown by package:

* Native modules contributing the most bytes (e.g. `react-native-skia`: 14.2 MB)
* Asset sizes (PNG/SVG you've added under `assets/`)
* Whether tree-shaking is fully eliminating dev-only code

Apps over 100 MB will be **rejected by App Store Connect**, so this catches a problem early in dev rather than after a 30-minute EAS build fails at submit.

## Auth & data flow in the preview

The preview is a **real** environment, not a mock:

* Supabase queries hit your actual project database (provisioned at project creation)
* The sign-up button creates a real `auth.users` row
* Items you create persist across reloads, across other devices, and into the EAS-built binary later
* RLS policies enforce the same `auth.uid() = user_id` rules in preview as in production

This means the preview doubles as your QA environment for backend behavior. You don't need a separate Supabase staging project — the same database backs preview, OTA, and EAS-built apps.

<Warning>
  Because the preview shares the same database as builds, **don't run destructive SQL** (TRUNCATE, DROP TABLE) in the preview if you've already shared TestFlight builds with testers. Their data lives in the same place.
</Warning>

## Web-only quirks to know

The preview runs React Native **Web**, which means a few things behave slightly differently than on a real device:

| Thing                           | Preview (RN Web)        | Real device (iOS/Android) |
| ------------------------------- | ----------------------- | ------------------------- |
| `Pressable` ripple              | None on web             | Native ripple on Android  |
| `Alert.alert()`                 | Browser `alert()` modal | Native alert sheet        |
| Keyboard behavior               | Keyboard event differs  | Native software keyboard  |
| `Linking.openURL('mailto:...')` | Opens new browser tab   | Opens native Mail app     |
| Status bar                      | Hidden (no top inset)   | Real status bar height    |

These are cosmetic — your code doesn't change. Just don't be surprised when a screenshot from the preview looks 20px taller than a real-device screenshot (no status bar inset).

## Editor integration

The preview pane sits beside the file tree and Monaco editor. Three syncing flavors:

* **Save → reload (\~1.5s)**: Edit a file in the editor, save (Cmd+S), and the preview hot-reloads.
* **AI edit → reload (\~3s)**: AI chat applies a patch via `manage_file` tool, file-sync pushes to the Fly machine, Metro HMR triggers.
* **Branch switch (\~10s)**: If you switch git branches via the GitHub panel, the preview re-pulls and rebuilds.

The preview survives editor refreshes (we keep the Fly machine warm for 30 minutes idle). You don't lose state when reloading the dashboard.

## What's next

<CardGroup cols={2}>
  <Card title="Builds & Submissions" icon="rocket" href="/mobile/builds">
    OTA channel deep-dive, the full Build & Ship lifecycle, and Fix-with-AI workflows.
  </Card>

  <Card title="Native Modules" icon="puzzle-piece" href="/mobile/native-modules">
    Which packages work in the web preview vs need a real device or full rebuild.
  </Card>

  <Card title="App Store Assets" icon="sparkles" href="/mobile/app-store-assets">
    Use the preview's screenshots feature when generating App Store hero images.
  </Card>

  <Card title="Mobile Credentials" icon="key" href="/mobile/credentials">
    Connect your Apple + Google accounts to start shipping past the preview.
  </Card>
</CardGroup>
