Skip to main content
Reference images guide how realtime models transform your video. Lucy 2 uses them for character transformation — your face maps onto the reference identity. Mirage 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

Upload a face photo and Lucy 2 maps your movements, expressions, and gestures onto that character in realtime. The reference image provides the visual identity — your camera provides the motion.
import { createDecartClient, models } from "@decartai/sdk";

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

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,
});

Image requirements

PropertyRequirement
FormatsJPEG, PNG, WebP
Minimum resolution512×512 pixels recommended
Maximum sizeNo hard limit, but keep under 5MB for fast uploads
Accepted input typesFile, Blob, URL string
// 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)

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

What works well

Clear, well-lit portraits

Front-facing photos with even lighting and a neutral background produce the most consistent transformations.

Head-and-shoulders framing

Cropped portraits with the face centered and clearly visible. Full-body shots reduce face detail.

Neutral expressions

Neutral or mildly expressive faces transfer better. Extreme expressions can conflict with your live movements.

High resolution

At least 512×512 pixels. Higher resolution captures more identity detail.

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 Mirage’s style reference instead.

Switching characters

You can change the reference image at any time without reconnecting. The transition is near-instant:
// 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 });
Use set() when updating both the prompt and image together. This applies both changes atomically, avoiding intermediate states.

Combining with text prompts

Character reference and text prompts work together. The reference sets the identity; the prompt adds modifications:
// Character reference + text modification
await realtimeClient.set({
  prompt: "Transform into this character, wearing a red cape",
  image: characterPhoto,
  enhance: true,
});

// Update just the prompt (keep the same character)
await realtimeClient.set({ prompt: "Same character but in a dark room with dramatic lighting" });

Style reference best practices (Mirage)

When using Mirage 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

// 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:
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
  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:
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:
// 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

IssueCauseSolution
Character doesn’t resemble referenceLow-resolution or occluded faceUse a clear, high-res portrait (512×512+)
Transformation looks genericReference image too small or blurryCrop to head-and-shoulders, ensure sharp focus
Flickering between original and transformedPrompt and image updated separatelyUse set() to update both atomically
Style reference not taking effectUsing Mirage with set()Use setImage() for Mirage style references
Image upload failsUnsupported formatUse JPEG, PNG, or WebP only
Slow image uploadLarge file sizeResize to under 2048px on longest side before uploading

Next steps