# Images

<!-- ::platform-badge platform="both" -->

Inspect captured React Native Image and expo-image loads, including timing, dimensions, errors, and cache information. Use the registry to find oversized sources and retry failed loads.

Buoy's icons, backgrounds and tool previews are excluded from the registry. App images remain visible, including app views that use the same source as a tool preview.

The demo uses a mock storefront. Cache verdicts and byte data depend on the image component and platform; the coverage notes below explain the differences.

<!-- ::tool-film id="images" -->

<!-- ::images-live-demo -->

## Installation

<!-- ::PM npm="npm install @buoy-gg/images" yarn="yarn add @buoy-gg/images" pnpm="pnpm add @buoy-gg/images" bun="bun add @buoy-gg/images" -->

Add the register import as the **first line** of your app entry file (`index.js` / `index.ts`):

```ts
import "@buoy-gg/images/register";
```

With core account setup complete, the installed tool appears in the floating menu. Keep your existing account initialization and providers; this example shows the menu placement:

```tsx
import { FloatingDevTools } from "@buoy-gg/core";

export default function App() {
  return (
    <>
      <YourApp />
      <FloatingDevTools />
    </>
  );
}
```

> **Why first?** RN core's `<Image>` instrumentation uses React Native's official component-decorator hook, which must be installed before the Image module first evaluates. expo-image capture has no timing constraint — it works whenever the tool loads. If the import is missing or too late, the tool tells you exactly what to fix instead of sitting silently empty.

---

## What You Can Do

- **Inspect captured image loads** — thumbnail, source URL, load time, decoded dimensions, format, status. Tap for the full detail view.
- **Get cache verdicts per load** — memory, disk, or network. expo-image reports it directly on every load; RN core images are classified via `Image.queryCache` right after loading.
- **Catch oversized sources** — the tool compares decoded pixels against the laid-out size × device pixel ratio, Lighthouse-style: green within 10%, red beyond 50% — with the estimated wasted decoded memory and the exact dimensions you should serve instead.
- **Catch upscaled (blurry) sources too** — a 50px thumbnail stretched into a 300pt hero gets flagged the other way.
- **Track decoded memory** — estimated decoded-bitmap bytes per image and totaled across mounted images, so you catch ballooning before the OOM crash.
- **Diagnose failures** — instrumented `onError` events are captured with the error message; on iOS, RN core also gives you the HTTP status code and response headers.
- **Act on any image** — hard reload (bypass caches + refetch), retry, or flash a red border on the on-screen image to locate it visually.
- **Simulate the bad day** — force an error, an endless loading state, or a blank on any mounted image; swap its source URL in place; or flip app-wide modes: **Offline** (network images fail, bundled assets still load), **Cold** (every load bypasses caches like first launch), and Chrome-style **blank images**. Mass actions apply any of these to everything on screen at once.
- **Prove the savings** — re-encode an oversized source at its displayed size as WebP *on the device*, get the real byte savings, and preview the optimized file in place before you touch your CDN.
- **Clear caches** — expo-image memory and disk caches, one tap from the detail view.

## How it works

React Native ships an official (if `unstable_`-prefixed) hook that lets a devtool wrap every `<Image>` in the app — the Images tool uses it to observe sources and attach load/progress/error handlers app-wide, with zero native code. expo-image's component is instrumented the same way through a render-level patch that's immune to import order. Both paths force-attach the load events the libraries already emit natively, so capture works identically in Expo Go, dev clients, and release builds.

Buoy's own UI (like the thumbnails inside the tool) is excluded from capture — the tool never appears in its own registry.

## Coverage notes

- Byte counts (`loaded/total`) come from image `onProgress` events: reliable on iOS RN core and expo-image; RN core on Android (Fresco) doesn't report real byte counts.
- Cache classification for RN core images uses `Image.queryCache`, which reflects the cache *after* the load — combined with whether network progress events fired, the verdict distinguishes a fresh download from a cache hit.
- Decoded-memory numbers are estimates (`width × height × 4` bytes) — the same math the platforms use for RGBA bitmaps.

## Desktop & AI

The same live registry streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) — the full tool (list, detail, simulations, mass actions) on a big screen — and to your editor's AI agent via the MCP server: `get_images` audits a screen's images in one call, `image_action` drives per-image reloads/overrides (including the on-device savings re-encode), and `set_image_simulation` flips the app-wide modes.

## What's Next

Cache explorer (browse the actual disk cache directories with sizes and ages), per-screen waste reports, and an X-ray overlay mode (badges on every on-screen image).

---

## FAQ

### Why can’t my network inspector see image requests in React Native?

Image fetches happen in native code (NSURLSession / Fresco), never in the JS network stack — so JS-level network devtools can’t observe them. Buoy Images hooks the image components themselves instead, capturing every load with its cache verdict and timing.

### Does it work in Expo Go and release builds?

Yes — capture is pure JavaScript (RN’s official component-decorator hook plus an expo-image render patch), so there’s no native module to install and it works in Expo Go, dev clients, and release builds.

### How do I find images that waste memory?

The registry compares each image’s decoded pixels against its rendered size × device pixel ratio and totals the estimated wasted decoded bytes — sort by the red verdicts, then use the on-device re-encode to prove what a right-sized source would save.

## Web support

Browser capture observes DOM images and supports shared overrides and size analysis. Savings previews use Canvas; cross-origin reads require permission from the image server. Import it from the package's `/web` entry (7.0.41 or later). See [Web installation](../web/installation#tool-setup) for registration, dependencies, and browser boundaries.

## Native iOS (Swift)

Images is also part of [Buoy for Swift](../swift/overview) for SwiftUI and UIKit apps. Setup and what the Swift version covers are in the [Swift tools guide](../swift/tools#images).

Buoy keeps its own images and tool previews out of this view.
