Using reference characters, props, and environments

Generated images have no memory. Ask for "Thales" in ten prompts and you get ten different old men. References fix that: you declare a character, a prop or a place once, the library makes or takes one image of it, and every prompt that mentions it is generated with that image in front of the model.

Declaring references

from imaginaryarts import CharacterReference, PropReference, EnvironmentReference, ReferencesBuilder

references = ReferencesBuilder(
    project=project,
    direction=ImageDirection(art_style=ImageDirectionStyle.EuroStorybook()),
    references=[
        CharacterReference("Thales", prompt="An old Greek philosopher, long white beard, deep blue himation with a gold border"),
        PropReference("Amphora", image=ROOT / "refs/amphora.png"),
        EnvironmentReference("Agora", prompt="A sunlit Ionian marketplace, marble columns, market stalls"),
    ],
).build()

Three kinds, because the reference picture of each is framed differently:

KindReference image
CharacterReferenceA character sheet: the character alone, full length, facing the viewer.
PropReferenceA product shot: the object alone, three-quarter view, no hands.
EnvironmentReferenceAn establishing shot of the place, empty of people.

Each takes a name, and a prompt and/or an image:

  • The name is the handle you mention in prompts, so it is one word: letters, digits, _ and -. "SodaCan", not "Soda Can". Names are matched ignoring case and must be unique.
  • A prompt describes the thing, and the reference image is generated from it in the builder's art style.
  • An image is a picture you already have, a photo of a real person or product, or a picture from an earlier project. When both are given the image is used and the prompt only tells the scene writer what it is.

build() makes every reference image that does not exist yet, several at a time, and returns References. The images are cached like everything else, and a take=2 on a reference re-rolls it.

Mentioning a reference

In any image prompt, @Name attaches that reference's image to the generation and tells the model to match it:

ImageAssetBuilder(prompt="@Thales fills the @Amphora at a well in the @Agora, morning light")

The @ is removed before the prompt reaches the model; the images are attached in the order they are first mentioned, and the prompt is extended with instructions to render each one as it looks in its picture, to draw each character exactly once, and to treat an environment as the setting rather than an object.

Mentions work in .edit() instructions too. In a clip's video_prompt they are stripped but attach nothing: the clip is animated from its keyframe, which the references already shaped.

Pass the built References wherever prompts are used:

scenes = ScenesBuilder(project=project, type="storyline", references=references, scenes=[...]).build()
assets = AssetsBuilder(project=project, references=references, direction=style,
                       assets=[ImageAssetBuilder.from_scene(s) for s in scenes]).build()

The scene writer is shown the roster with each reference's description, and writes @Thales into the prompts it authors instead of describing him each time. To bring a reference into an authored scene, mention it in that scene's direction: ImageSceneDirection(pointer="@Thales arguing with a merchant").

Two things produce a warning rather than an error: a mention that matches no declared reference (usually a typo), and attaching more than four reference images to one prompt, which the model handles poorly.

Real people and products

A reference with an image is how real things get into generated pictures. A photo of a person as a CharacterReference, a product shot as a PropReference, a photo of your shop as an EnvironmentReference:

CharacterReference("Elon", image=ROOT / "assets/references/elon.jpg")

For a single prompt that needs a picture and nothing else does, skip the declaration and attach the file directly:

ImageAssetBuilder(
    prompt="Return a photo of Elon Musk (see reference image) laughing on a heap of dollar bills",
    files=[ImageFile(ROOT / "assets/references/elon.jpg")],
)

files= is the quick way for a one-off. Declared references are the way to keep something consistent across many images, and the only way the scene writer can use it.

What changes what

  • Bumping a reference's take regenerates its image and, with it, every image that mentions it.
  • Adding a reference to the roster does not rewrite already-authored scenes. A scene starts using a new reference when you mention it in that scene's direction, or bump the scene's take.
  • Renaming a reference changes the handle, so old prompts that mention the old name will warn until you update them.