Images & Media
StoryFlow dialogue nodes can include images for character portraits, inline illustrations, and full-screen backgrounds. This guide covers how image assets are imported, resolved, and displayed in the Unity plugin.
How Images Work
Images in StoryFlow are referenced by dialogue nodes via asset keys. When a project is imported into Unity, the importer converts image files into Texture2D assets with proper sprite import settings, then stores references in ResolvedAssets dictionaries. At runtime, the execution context resolves these keys to Sprite objects that you can display in your UI.
There are two levels of asset storage:
- Character assets - Character portraits are stored directly on each
StoryFlowCharacterAsset.ResolvedImage. They are defined incharacters.jsonand shared across all scripts. - Script-level assets - Defined per script file. Images used in a specific script's dialogue nodes (illustrations, background images, etc.) are stored on
StoryFlowScriptAsset.ResolvedAssets.
Image persistence
Images can persist across dialogue nodes without being explicitly re-assigned. The persistence logic follows three rules:
- Dialogue has an image assigned - That image is used and becomes the new persistent image for subsequent nodes.
- Dialogue has no image and image reset is false - The persistent image from the previous dialogue carries over.
- Dialogue has no image and image reset is true - The image is cleared. No image is shown.
Dialogue Images
The current dialogue image is available on StoryFlowDialogueState.Image as a Sprite. This field may be null if no image is assigned and the image was reset. Read it each time OnDialogueUpdated fires and apply it to a Unity UI Image component.
void OnDialogueUpdated(StoryFlowDialogueState state)
{
if (state.Image != null)
{
dialogueImage.sprite = state.Image;
dialogueImage.gameObject.SetActive(true);
}
else
{
dialogueImage.gameObject.SetActive(false);
}
}
Character portrait images are separate from the dialogue Image field. They are accessed through StoryFlowDialogueState.Character.Image, which is also a Sprite. Character images are resolved from each StoryFlowCharacterAsset.ResolvedImage since characters are defined in characters.json and shared across all scripts.
void OnDialogueUpdated(StoryFlowDialogueState state)
{
// Dialogue illustration
if (state.Image != null)
{
sceneImage.sprite = state.Image;
sceneImage.gameObject.SetActive(true);
}
else
{
sceneImage.gameObject.SetActive(false);
}
// Character portrait (separate from dialogue image)
if (!string.IsNullOrEmpty(state.Character.Name) && state.Character.Image != null)
{
characterPortrait.sprite = state.Character.Image;
characterPortrait.gameObject.SetActive(true);
}
else
{
characterPortrait.gameObject.SetActive(false);
}
} Handling null images gracefully
Always check for null before assigning a sprite. When state.Image is null, hide or disable the image GameObject rather than leaving a blank space. This keeps your dialogue UI clean when transitioning between nodes that have images and nodes that do not.
Background Images
Background images are set via dedicated SetBackgroundImage nodes rather than being attached to dialogue nodes. They are intended for full-screen visuals, scene transitions, or environment art that exist outside the dialogue box.
Background images are set via the SetBackgroundImage node in the StoryFlow Editor. When the runtime processes this node, it broadcasts the OnBackgroundImageChanged event with the resolved Sprite:
component.OnBackgroundImageChanged += (sprite) => {
backgroundImage.sprite = sprite;
};
The background image persists until explicitly changed by another SetBackgroundImage node or cleared by passing an empty value. It is stored internally on the execution context as PersistentBackgroundImage and survives across dialogue node transitions.
Dialogue image vs. background image
Internally, both dialogue node images and SetBackgroundImage nodes write to the same PersistentBackgroundImage field on the execution context. This means a SetBackgroundImage node will affect state.Image on subsequent dialogue nodes that have no image assigned. In your UI, you may want to use state.Image for inline illustrations and OnBackgroundImageChanged for full-screen backgrounds, but be aware they share the same underlying persistence.
Asset Resolution
The asset resolution system is the bridge between StoryFlow's string-based asset references and Unity's loaded asset objects. It operates at two levels:
-
StoryFlowScriptAsset.ResolvedAssets- Per-script assets. Images used only within a specific script's nodes are resolved from this dictionary. -
StoryFlowProjectAsset.ResolvedAssets- Project-wide assets shared across all scripts. Note: character portrait images are stored on individualStoryFlowCharacterAssetobjects, not in this dictionary.
The StoryFlowComponent provides a generic ResolveAsset<T> method that checks both levels automatically, prioritizing script-level assets:
// Resolves an asset by key, checking script assets first, then project assets
T asset = component.ResolveAsset<Sprite>("assetKey");
// Example: resolve a specific image
Sprite illustration = component.ResolveAsset<Sprite>("asset_image_forest");
if (illustration != null)
{
myImage.sprite = illustration;
} This two-level lookup means script-specific assets can override project-level assets with the same key, giving you fine-grained control over which asset is used in a given context.
Import Process
When you import a StoryFlow project via the editor importer, the following happens for image assets:
- The importer reads asset references from each script's JSON data and from
characters.json, then imports the referenced image files from the exportedbuild/directory. - Each image is imported as a
Texture2Dasset with sprite import settings applied (texture type set to Sprite, appropriate filter mode, etc.). - Script-specific image references are stored as
ResolvedAssetEntryentries on the correspondingStoryFlowScriptAsset. Character portrait images are stored directly on eachStoryFlowCharacterAsset.ResolvedImage. - At runtime, the
ResolvedAssetEntriesserialized list is lazily rebuilt into aDictionary<string, Object>for fast lookup.
Character images from characters.json are stored on individual StoryFlowCharacterAsset ScriptableObjects. Script-specific images (dialogue illustrations, background images referenced only in that script) go into the corresponding script asset's ResolvedAssets.
Re-importing updates assets
When you re-import a project, existing image assets are updated in place. Unity maintains the same asset references, so any prefabs or scenes referencing those Sprites will pick up the new images automatically without needing to be re-linked.