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

# Reference Images

> Best practices for character and style reference images in realtime models

Reference images guide how realtime models transform your video. Lucy 2.1 uses them for character transformation — your face maps onto the reference identity. Lucy Restyle Live uses them for style guidance — the visual aesthetic of the reference carries into the output.

This guide covers image requirements, best practices for character portraits, style references, and troubleshooting.

## How reference images work

<Tabs>
  <Tab title="Lucy 2.1 — Character Reference">
    Upload a face photo and Lucy 2.1 maps your movements, expressions, and gestures onto that character in realtime. The reference image provides the **visual identity** — your camera provides the **motion**.

    ```typescript theme={null}
    import { createDecartClient, models } from "@decartai/sdk";

    const client = createDecartClient({ apiKey: "your-api-key-here" });
    const model = models.realtime("lucy-2.1");

    const stream = await navigator.mediaDevices.getUserMedia({
      video: { frameRate: model.fps, width: model.width, height: model.height },
    });

    const realtimeClient = await client.realtime.connect(stream, {
      model,
      onRemoteStream: (s) => { document.getElementById("output").srcObject = s; },
    });

    // Upload a character reference
    const photo = document.querySelector("input[type=file]").files[0];
    await realtimeClient.set({
      prompt: "Transform into this character",
      image: photo,
      enhance: true,
    });
    ```
  </Tab>

  <Tab title="Lucy Restyle Live — Style Reference">
    Upload a style image and Lucy Restyle Live uses its visual aesthetic — colors, textures, lighting — to guide the transformation of your live stream.

    ```typescript theme={null}
    import { createDecartClient, models } from "@decartai/sdk";

    const client = createDecartClient({ apiKey: "your-api-key-here" });
    const model = models.realtime("lucy-restyle-2");

    const stream = await navigator.mediaDevices.getUserMedia({
      video: { frameRate: model.fps, width: model.width, height: model.height },
    });

    const realtimeClient = await client.realtime.connect(stream, {
      model,
      onRemoteStream: (s) => { document.getElementById("output").srcObject = s; },
      initialState: {
        prompt: { text: "Apply this artistic style", enhance: true },
      },
    });

    // Set a style reference image
    const styleImage = await fetch("/style-reference.jpg").then((r) => r.blob());
    await realtimeClient.setImage(styleImage);
    ```
  </Tab>
</Tabs>

## Image requirements

| Property                 | Requirement                                        |
| ------------------------ | -------------------------------------------------- |
| **Formats**              | JPEG, PNG, WebP                                    |
| **Minimum resolution**   | 512×512 pixels recommended                         |
| **Maximum size**         | No hard limit, but keep under 5MB for fast uploads |
| **Accepted input types** | `File`, `Blob`, URL string                         |

```typescript theme={null}
// From a file input
const file = document.querySelector("input[type=file]").files[0];
await realtimeClient.set({ image: file });

// From a URL
await realtimeClient.set({ image: "https://example.com/character.jpg" });

// From a fetch
const blob = await fetch("/character.jpg").then((r) => r.blob());
await realtimeClient.set({ image: blob });
```

## Character reference best practices (Lucy 2.1)

The quality of the character transformation depends heavily on the reference image. Follow these guidelines for the best results:

### What works well

<CardGroup cols={2}>
  <Card title="Clear, well-lit portraits" icon="sun">
    Front-facing photos with even lighting and a neutral background produce the most consistent transformations.
  </Card>

  <Card title="Head-and-shoulders framing" icon="crop">
    Cropped portraits with the face centered and clearly visible. Full-body shots reduce face detail.
  </Card>

  <Card title="Neutral expressions" icon="face-smile">
    Neutral or mildly expressive faces transfer better. Extreme expressions can conflict with your live movements.
  </Card>

  <Card title="High resolution" icon="expand">
    At least 512×512 pixels. Higher resolution captures more identity detail.
  </Card>
</CardGroup>

### What to avoid

* **Heavy occlusion** — Images where the face is partially hidden by hands, hair, or objects reduce transformation quality
* **Extreme angles** — Profile shots or heavily tilted faces don't transfer well to front-facing camera input
* **Low resolution** — Blurry or pixelated images lose identity details
* **Multiple faces** — The model picks one face, but results are unpredictable. Crop to a single face.
* **Non-face images** — Character reference expects a face. For non-face references, use Lucy Restyle Live's style reference instead.

### Switching characters

You can change the reference image at any time without reconnecting. The transition is near-instant:

```typescript theme={null}
// Switch to a new character
const newCharacter = document.querySelector("input[type=file]").files[0];
await realtimeClient.set({
  prompt: "Transform into this character",
  image: newCharacter,
  enhance: true,
});

// Or clear the reference entirely to fall back to text-only editing
await realtimeClient.set({ image: null });
```

<Tip>
  `set()` replaces the entire state — always include every field you want to keep. When changing the prompt, include the image again to preserve it.
</Tip>

### Combining with text prompts

Character reference and text prompts work together. The reference sets the identity; the prompt adds modifications:

```typescript theme={null}
// Character reference + text modification
await realtimeClient.set({
  prompt: "Transform into this character, wearing a red cape",
  image: characterPhoto,
  enhance: true,
});

// Change the prompt while keeping the character — include the image to preserve it
await realtimeClient.set({
  prompt: "Same character but in a dark room with dramatic lighting",
  image: characterPhoto,
});
```

## Style reference best practices (Lucy Restyle Live)

When using Lucy Restyle Live for style transfer, the reference image sets the overall visual aesthetic — colors, textures, artistic style, lighting.

### What works well

* **Artworks and illustrations** — Paintings, digital art, and stylized illustrations transfer their visual language effectively
* **Strong visual identity** — Images with distinct color palettes, textures, or lighting produce recognizable style transfers
* **Clean compositions** — Simple, focused images with a clear style are more effective than busy scenes

### What to avoid

* **Photos of real scenes** — These often lack a distinctive "style" for the model to extract
* **Very dark or very bright images** — Extreme exposure can produce washed-out or muddy results
* **Text-heavy images** — The model may try to reproduce text elements, which usually looks wrong in video

### Using style references

```typescript theme={null}
// Set initial style with a reference image
const styleRef = await fetch("/monet-painting.jpg").then((r) => r.blob());
await realtimeClient.setImage(styleRef);

// Combine with a text prompt for more control
realtimeClient.setPrompt("Apply this painting style with warm golden lighting");
```

## Managing reference images in your app

### Image upload UI

Build a simple image picker that sends the file to the realtime client:

```typescript theme={null}
const fileInput = document.getElementById("character-upload") as HTMLInputElement;

fileInput.addEventListener("change", async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file) return;

  // Validate before uploading
  if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) {
    showError("Please upload a JPEG, PNG, or WebP image.");
    return;
  }

  // Show preview
  const preview = document.getElementById("preview") as HTMLImageElement;
  preview.src = URL.createObjectURL(file);

  // Send to Lucy 2.1
  await realtimeClient.set({
    prompt: "Transform into this character",
    image: file,
    enhance: true,
  });
});
```

### Preset characters

Pre-load a gallery of character options that users can tap to transform:

```typescript theme={null}
const characters = [
  { name: "Anime Hero", url: "/characters/anime-hero.jpg", prompt: "Transform into this anime character" },
  { name: "Viking Warrior", url: "/characters/viking.jpg", prompt: "Transform into this fierce viking warrior" },
  { name: "Robot", url: "/characters/robot.jpg", prompt: "Transform into this metallic robot" },
];

async function selectCharacter(character: typeof characters[0]) {
  const imageBlob = await fetch(character.url).then((r) => r.blob());
  await realtimeClient.set({
    prompt: character.prompt,
    image: imageBlob,
    enhance: true,
  });
}
```

### Clearing the reference

Remove the reference image to return to text-only editing:

```typescript theme={null}
// Clear the character reference
await realtimeClient.set({ image: null });

// Now text prompts apply directly to your camera feed
await realtimeClient.set({ prompt: "Add sunglasses" });
```

## Troubleshooting

| Issue                                       | Cause                                | Solution                                                |
| ------------------------------------------- | ------------------------------------ | ------------------------------------------------------- |
| Character doesn't resemble reference        | Low-resolution or occluded face      | Use a clear, high-res portrait (512×512+)               |
| Transformation looks generic                | Reference image too small or blurry  | Crop to head-and-shoulders, ensure sharp focus          |
| Flickering between original and transformed | Prompt and image updated separately  | Use `set()` to update both atomically                   |
| Style reference not taking effect           | Using Lucy Restyle Live with `set()` | Use `setImage()` for Lucy Restyle Live style references |
| Image upload fails                          | Unsupported format                   | Use JPEG, PNG, or WebP only                             |
| Slow image upload                           | Large file size                      | Resize to under 2048px on longest side before uploading |

## Next steps

<CardGroup cols={2}>
  <Card title="Lucy 2.1 Guide" icon="sparkles" href="/models/realtime/lucy-2.1">
    Full Lucy 2.1 integration guide
  </Card>

  <Card title="Streaming Best Practices" icon="bolt" href="/models/realtime/streaming-best-practices">
    Optimize your realtime integration
  </Card>

  <Card title="Use Cases" icon="lightbulb" href="/examples/use-cases">
    Explore what you can build with realtime models
  </Card>

  <Card title="JavaScript SDK" icon="js" href="/sdks/javascript-realtime">
    Full SDK reference for `set()`, `setImage()`, and more
  </Card>
</CardGroup>
