Exporting Data
An image pipeline rarely ends at the images. A game engine wants to know where every sprite sits on its sheet, a website wants a manifest of files and sizes, a reviewer wants a spreadsheet of what was exported, and a training set wants a metadata.csv of file names and labels. The Export Data node writes that file from the same graph that makes the pictures, so the list never drifts out of step with the images.
The quick answer
Section titled “The quick answer”- Add Export Data (Export category; search “csv”, “json”, “atlas”, or “manifest”) and wire an image, a batch, a texture set, or an atlas into its Input pin.
- Pick a Preset, or edit the Columns: each column is a header plus a value made of tokens such as
{name}or{width}. - Set Folder and File Name under Output, then press Export. Copy puts the same text on the clipboard instead.
- Wire the same images into the export node that writes them too. Export Data finds it by itself, and
{data:file}becomes the file each image was written to.
Like every export node, Export Data writes only when you export; its Preview updates as you work.
Why a data file from the graph
Section titled “Why a data file from the graph”A hand-kept list drifts: rename a sprite, repack a sheet, or add a frame, and the JSON in your game project no longer matches the PNG beside it. Export Data reads the facts from the graph at export time:
- Names and sizes come from the images themselves, including names set with Tag or batch templates.
- File names come from the export nodes that write the images, after any collision suffix, so the list names the files that are really on disk.
- Placements, including trim offsets and UVs, come from the node that packed the sheet: Arrange, Sprite Sheet, Trim Sheet, or an Export Batch set to Generate Sprite Sheet.
- Texture maps come from the set and the files Export Texture writes for it.
Export All writes data files last, after every image export in the run, so one click writes the images and the file that describes them.
How it finds what it lists
Section titled “How it finds what it lists”Rows come from what you wire, in pin order. An image is one row, a batch one row per frame, a texture set one row per set or per map (Texture Sets), and an atlas one row per sprite or per sheet (Atlases).
Exports are found, never wired. Any Export Image, Export Batch, or Export Texture writing an image in the rows is listed under Found Exports with its status (Saved, Not saved yet, Updating…, or Failed), and while Export Data is selected, dashed lines on the canvas run from each one to it. {data:file} gives the exported file where there is one and the source file where there is not, row by row.
If a found export has not written its images yet, Export asks Save the Images First?:
- Save Them First writes the images and then the file with their real names.
- This File Only writes the file with the planned names.
See the node reference for statuses, several exports of one image, and every token.
Presets, one recipe each
Section titled “Presets, one recipe each”A preset sets the whole look (format, columns, and options) and never touches Folder or File Name. Change anything and the menu reads Custom; Save as Preset… lists your look under Yours in every project.
The samples below are real output. The list presets ran on three icons (icon_heart and icon_star at 64 x 64, icon_gem at 48 x 48) collected into an Export Batch named Sprites that writes to export/sprites, with the data file in export. The atlas and code presets ran on the same icons packed by a Sprite Sheet named Icons Atlas (MaxRects, Trim Transparency on; icon_heart has a transparent border), written by an Export Image to export/atlas/icons_atlas.png, with the data file beside it.
Image List
Section titled “Image List”A plain CSV of every image’s name, file, size, and position; the default on a new node. Wire any images or batches.
name,file,width,height,positionicon_heart,icon_heart.png,64,64,1icon_star,icon_star.png,64,64,2icon_gem,icon_gem.png,48,48,3Review Spreadsheet
Section titled “Review Spreadsheet”A CSV for Excel with each image’s source file, SHA-256, size, channels, bit depth, the export node that writes it, and whether it is saved: the sheet you hand to a reviewer or keep as a record of a delivery.
- Wire the images into Export Data, and into the export node that writes them.
- Pick Review Spreadsheet. The format is CSV for Excel: Windows line endings, a UTF-8 byte order mark so Excel reads non-English letters, and formulas protected.
- Press Export and choose Save Them First if asked, so the
savedcolumn reads Saved.
name,file,source file,SHA-256,size,channels,bit depth,exported by,savedicon_heart,icon_heart.png,art/icons/icon_heart.png,6919be800f9a8e0e2e8112a46cb418e6ee8795e1f72d1ce7e66c670491c26bef,64x64,4,8,Sprites,Savedicon_star,icon_star.png,art/icons/icon_star.png,cce34cb19d42b045e786cb0b0d5f3bb847d373cf72a7d1ba62e29105d191f57c,64x64,4,8,Sprites,Savedicon_gem,icon_gem.png,art/icons/icon_gem.png,42938bd858ed533d891f607b0fe4f8610c5dfe2c99c54349d029ccb6b9aa5364,48x48,4,8,Sprites,SavedFormula protection puts an apostrophe before a value that starts with =, +, -, or @, so opening the file never runs a formula; a plain number such as -12 is left alone.
XML Image List
Section titled “XML Image List”One self-closing image element per row, values XML escaped. Wire any images or batches.
<?xml version="1.0" encoding="UTF-8"?><images count="3"> <image name="icon_heart" file="icon_heart.png" width="64" height="64"/> <image name="icon_star" file="icon_star.png" width="64" height="64"/> <image name="icon_gem" file="icon_gem.png" width="48" height="48"/></images>Markdown Table
Section titled “Markdown Table”A table with a preview of each image, for a README or a wiki. The image link is the exported file’s path (else the source file’s) relative to the data file, in angle brackets so a space keeps the link whole.
| Preview | Name | Size || --- | --- | --- ||  | icon_heart | 64x64 ||  | icon_star | 64x64 ||  | icon_gem | 48x48 |A | in a name still splits its cell, since Markdown tables have no escape.
Atlas Coordinates
Section titled “Atlas Coordinates”A CSV of each sprite’s atlas, rectangle, untrimmed size, trim offset, UVs, and sheet size: the generic form any engine or script can read. Wire an Arrange, Sprite Sheet, or Trim Sheet.
atlas,name,x,y,w,h,source_width,source_height,offset_x,offset_y,trimmed,u0,v0,u1,v1,sheet_width,sheet_heightIcons Atlas,icon_star,1,1,64,64,64,64,0,0,false,0.008547,0.009174,0.555556,0.59633,117,109Icons Atlas,icon_heart,67,1,48,56,64,64,8,4,true,0.57265,0.009174,0.982906,0.522936,117,109Icons Atlas,icon_gem,67,59,48,48,48,48,0,0,false,0.57265,0.541284,0.982906,0.981651,117,109Sprite Sheet’s MaxRects packing reorders sprites to pack them tightly, and the rows follow; Arrange keeps its input order.
Atlas JSON (Hash)
Section titled “Atlas JSON (Hash)”The frames and meta JSON that Phaser and PixiJS load, frames keyed by name.
- Wire the sprites into a Sprite Sheet (an Image Folder straight in, or images through a Collect). Leave Pack Mode on MaxRects and Trim Transparency on.
- Wire Sprite Sheet into an Export Image writing
export/atlas/icons_atlas.png. - Wire the same Sprite Sheet output into Export Data, pick Atlas JSON (Hash), and set Folder to
export/atlas, so theimagepath is just the file name. - Press Export, and Save Them First if the sheet is not saved yet.
{ "frames": { "icon_star": { "frame": {"x": 1, "y": 1, "w": 64, "h": 64}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x": 0, "y": 0, "w": 64, "h": 64}, "sourceSize": {"w": 64, "h": 64} }, "icon_heart": { "frame": {"x": 67, "y": 1, "w": 48, "h": 56}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x": 8, "y": 4, "w": 48, "h": 56}, "sourceSize": {"w": 64, "h": 64} }, "icon_gem": { "frame": {"x": 67, "y": 59, "w": 48, "h": 48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x": 0, "y": 0, "w": 48, "h": 48}, "sourceSize": {"w": 48, "h": 48} } }, "meta": { "app": "ArcBrush", "image": "icons_atlas.png", "size": {"w": 117, "h": 109}, "scale": "1" }}Load the picture and this file together as an atlas, and each frame is available by name. Arrange works the same way, without trimming.
Atlas XML
Section titled “Atlas XML”A Starling TextureAtlas with one SubTexture per sprite. Same steps as Atlas JSON; one atlas per file.
<?xml version="1.0" encoding="UTF-8"?><TextureAtlas imagePath="icons_atlas.png"> <SubTexture name="icon_star" x="1" y="1" width="64" height="64" frameX="-0" frameY="-0" frameWidth="64" frameHeight="64"/> <SubTexture name="icon_heart" x="67" y="1" width="48" height="56" frameX="-8" frameY="-4" frameWidth="64" frameHeight="64"/> <SubTexture name="icon_gem" x="67" y="59" width="48" height="48" frameX="-0" frameY="-0" frameWidth="48" frameHeight="48"/></TextureAtlas>CSS Sprites
Section titled “CSS Sprites”A .sprite class naming the sheet, then one class per sprite with its position and size, for icons served from one image. Pack the icons as for Atlas JSON, pick CSS Sprites, and set Folder to the stylesheet’s folder: the url(...) is the sheet’s path relative to it.
.sprite { background-image: url("icons_atlas.png"); background-repeat: no-repeat; display: inline-block;}
.sprite-icon-star { background-position: -1px -1px; width: 64px; height: 64px; }.sprite-icon-heart { background-position: -67px -1px; width: 48px; height: 56px; }.sprite-icon-gem { background-position: -67px -59px; width: 48px; height: 48px; }Use it as <span class="sprite sprite-icon-heart"></span>. Each class is the sprite’s name in kebab-case, and a sprite at 0 reads -0px, which CSS reads as 0.
ZenUV Trim Sheet
Section titled “ZenUV Trim Sheet”For Blender’s ZenUV add-on, pasted straight from the clipboard: a trimsheet object with one entry per trim, keyed by the trim’s name, each holding its rect and its color. rect is [left, top, right, bottom] with v measured from the bottom edge, as Blender’s UVs are, and color is the trim’s color as sRGB 0 to 1 values, the display values ZenUV stores. One atlas per file.
- Add a Trim Sheet node and shape the trims: set the sheet’s size, drag the lines between trims in the Preview, split, and name each trim.
- Wire its Sheet output into Export Data, pick ZenUV Trim Sheet, and press Copy.
- In Blender, open ZenUV’s Trim List panel, click the dropdown arrow on the list’s right toolbar, and choose Paste Trims from Clipboard. Pick Clear for a fresh sheet (it clears every trim first), Replace to update the trims with the same names after you change the sheet, or Add to append them.
- For the texture, wire the same Sheet output into an Export Image writing
export/trims/trimsheet.png.
To keep the layout as a .json file instead, set Folder and press Export.
This sample is a 16 x 16 Trim Sheet with a 6 px row named Trim, a 3 px row split into Edge (8 px wide) and Edge.001, and a last row named Rest, all on auto colors:
{"trimsheet": {"Trim": {"rect": [0, 1, 1, 0.625], "color": [0.8, 0.239216, 0.239216]},"Edge": {"rect": [0, 0.625, 0.5, 0.4375], "color": [0.521569, 0.8, 0.239216]},"Edge.001": {"rect": [0.5, 0.625, 1, 0.4375], "color": [0.239216, 0.8, 0.8]},"Rest": {"rect": [0, 0.4375, 1, 0], "color": [0.521569, 0.239216, 0.8]}}}The file is keyed by name, so every trim needs its own: two rows sharing a name earn the note 2 rows share the key "Trim"; only the last one is kept.
Each material edited on its own. Wire the Trim Sheet’s Trims output (one image per trim, named and colored) into the nodes that make each material, splitting it with Split Batch where each trim needs its own branch. Bring the trims back together with Collect, wire them into an Arrange set to Original Positions, and wire Arrange into the Export Data (then Copy and paste as above) and the Export Image. Every trim goes back to its place on the sheet, keeping its name and color, so ZenUV’s trims match the sheet.
C# Sprite Table
Section titled “C# Sprite Table”A static class any C# engine can compile, with an enum naming every sprite and an array of their rectangles in the same order. Wire an Arrange, Sprite Sheet, or Trim Sheet as for Atlas JSON and export a .cs file.
public static class Sprites{ public readonly struct Rect { public readonly int X, Y, W, H;
public Rect(int x, int y, int w, int h) { X = x; Y = y; W = w; H = h; } }
public const int Count = 3;
public enum Sprite { IconStar, IconHeart, IconGem, }
// Indexed by (int)Sprite, in the same order. public static readonly Rect[] Rects = { new Rect(1, 1, 64, 64), // IconStar new Rect(67, 1, 48, 56), // IconHeart new Rect(67, 59, 48, 48), // IconGem };}Read a sprite’s rectangle as Sprites.Rects[(int)Sprites.Sprite.IconHeart], or loop over Sprites.Rects. Enum names go through {name|pascal|identifier}, so any name becomes a valid identifier (9 lives becomes _9Lives). The enum is Each Row and the array is the Custom Text Second Pass, which writes the same rows again in the same order.
GDScript Regions
Section titled “GDScript Regions”For Godot: a REGIONS dictionary of Rect2 by name, each ready for an AtlasTexture, and the atlas path, relative to the .gd file, in ATLAS. One atlas per file.
const REGIONS := { &"icon_star": Rect2(1, 1, 64, 64), &"icon_heart": Rect2(67, 1, 48, 56), &"icon_gem": Rect2(67, 59, 48, 48),}
const ATLAS := "icons_atlas.png"TypeScript Image Module
Section titled “TypeScript Image Module”A typed module a web build imports: an images object keyed by camelCase name with each file and size, and an ImageName type. Wire images and the Export Batch that writes them where your site serves them.
export const images = { iconHeart: { src: "icon_heart.png", width: 64, height: 64 }, iconStar: { src: "icon_star.png", width: 64, height: 64 }, iconGem: { src: "icon_gem.png", width: 48, height: 48 },} as const;
export type ImageName = keyof typeof images;Web Image Manifest
Section titled “Web Image Manifest”JSON your code reads at run time, keyed by name, with each image’s file, size, and format. Wire images and their export nodes.
{ "icon_heart": { "src": "icon_heart.png", "width": 64, "height": 64, "format": "PNG" }, ...}src is the file’s name. For a path relative to the data file, change its value to {data:export_path|relative}; for a path from the project folder, {data:export_relative_path}.
Dataset Metadata
Section titled “Dataset Metadata”Many dataset tools read a folder of images plus a metadata.csv naming each file and its label.
- Wire the images into an Export Batch writing
export/sprites. - To label them, put a Tag node before Export Data with a tag named
label, valueicon. Without it, the label is the name of whatever is wired in. - Wire the Tag into Export Data, pick Dataset Metadata, set Folder to
exportand File Name tometadata. - Press Export.
file_name,label,width,heightsprites/icon_heart.png,icon,64,64sprites/icon_star.png,icon,64,64sprites/icon_gem.png,icon,48,48file_name is each exported file relative to the data file, which is what these tools expect. For several classes, wire one tagged batch per class into the pins of the same node; rows follow pin order.
Material Maps
Section titled “Material Maps”A JSON list of a material’s files, one entry per map with its set, role, file, and size.
- Build a texture set with a Texture node (or read one with Texture Folder) and wire it into an Export Texture with a folder, such as
export/materials. - Wire the same set into Export Data and pick Material Maps. It sets Texture Sets to Each Map.
- Press Export. For a set named Brick with a base color and a roughness map:
[ { "set": "Brick", "map": "base_color", "file": "Brick_base_color.png", "width": 32, "height": 32 }, { "set": "Brick", "map": "roughness", "file": "Brick_roughness.png", "width": 32, "height": 32 }]file is the name Export Texture writes for that map under its destination. For a library, wire a batch of sets and every set adds its maps; switch Texture Sets to Each Set for one row per set, with {data:set} for its name.
Sharing your setup
Section titled “Sharing your setup”Once a format works, you rarely want to build it again, and in a team everyone should write the same file:
| To share | Use | What travels |
|---|---|---|
| The whole format with a teammate or the studio | Preset menu, Save as Preset…, then Manage Presets… and Export to a .json file. The other artist uses Import. | Format, columns, Advanced options, Atlases and Texture Sets choices, Custom Text. Never Folder or File Name, so it works in anyone’s project. |
| Everything on this node, quickly, in chat | The gear menu beside the node’s name: Copy All Parameters, then Paste All Parameters on the other node. The copy is plain text you can paste into a message. | Every setting, including Folder and File Name. |
| Just the columns | Copy Keys and Values under the column list, then Paste Keys and Values and Replace Columns on the other node. | Two lines of text, headers then values, easy to edit in a spreadsheet or text editor. |
| The node and its wiring | Copy the Export Data node itself and paste it into the other document. | Everything. |
Copy Keys and Values quotes a header or value that holds a comma, a quote, or a leading space, so it pastes back exactly. A value with a line break cannot be copied this way; the status line names the column. Opening Paste Keys and Values with those two lines on the clipboard fills in both fields.
Custom Text from scratch
Section titled “Custom Text from scratch”When no preset fits, Custom Text writes any text format around your columns. Say a tool wants this XML:
<?xml version="1.0" encoding="UTF-8"?><sprites count="3"> <sprite name="icon_heart" file="icon_heart.png"> <size w="64" h="64"/> </sprite> ...</sprites>-
Set Format to Custom Text, Extension to
.xml, and Escape Values to As XML, so a name with&or<still makes valid XML. -
Make four columns:
name={name},file={data:file},w={width},h={height}. The quickest way is Paste Keys and Values withname,file,w,hand{name},{data:file},{width},{height}, then Replace Columns. -
Before Rows, ending with a line break:
<?xml version="1.0" encoding="UTF-8"?><sprites count="{data:row_count}"> -
Each Row, using the column chips above the box to insert
{name},{file},{w}, and{h}:<sprite name="{name}" file="{file}"><size w="{w}" h="{h}"/></sprite> -
Between Rows holds
\n; After Rows holds a line break,</sprites>, and another line break. -
Check the Raw tab of the preview, then press Export, or save the look as your own preset.
The rules that make this work:
- Each Row reads your columns by header; any other name is read as a token, so
{data:x}works directly. Before Rows and After Rows read tokens from the first row, for one-per-file facts such as{data:row_count},{data:sheet_width}, or{date}. - Escape Values changes only substituted values, never what you type, and it does not add quotes: type
"name": "{name}"with As JSON or C# Strings, and leave numbers unquoted. - Braces in code need no escaping. A brace starts a token only when a letter or
_follows it and a}closes it on the same line, so{ get; set; }and{"a": 1}are written as typed. To write literal token-like text, double the braces:{{name}}writes{name}. - A second pass. Add Second Pass writes the rows again after the first pass, with its own Middle, Each Row, and Between Rows, so one file can list every name and then every rectangle in the same order, as C# Sprite Table does.
- No arithmetic. A token cannot be negated or added to, which is why Starling offsets are written as
-plus the offset.
The same recipe makes YAML, INI, Lua, or any other text: change the extension, the escaping, and the four boxes.
Good to know
Section titled “Good to know”- One row per written file. Set Rows to Each Written File for a line per file an export writes: a PNG and a WebP of each image give two rows, each reading its own export.
- One file per input or atlas. Split writes One File, One per Input, or One per Atlas;
{name}in the File Name names each file. - Types in JSON. A column’s Write as (right-click its grip) writes it as Text, a Number, or True or False instead of Auto, so an id like
007stays a string. - Empty cells are explained. An amber note under the preview names the column, the token, the reason, and the rows affected, such as
needs an atlasorno export writes this image. The file itself just has an empty cell. - Duplicates. JSON Keyed by First Column refuses repeated or empty keys, marking the rows in red. CSV and TSV note repeated values in the first column but still write them, and Custom Text whose rows each open with a key, such as ZenUV Trim Sheet, notes a repeated key, since a JSON reader keeps only the last one.
- Limits. At most 1,000,000 rows and 64 MiB per file; the preview shows the first 200 rows.
- Reproducible. The same graph and settings write the same bytes on any computer; numbers never use a comma for the decimal point.
- Tokens in file names. File Name and Folder take the same tokens as other export paths, including
{this.label},{this.id},{graph},{date}, your variables, and the transforms and fallbacks such as{this.label|snake|or:this.id}. A new node’s File Name is{this.label|or:this.id}: its custom label, else its Node ID; Naming with Tokens walks through it. Every token is in the Token Reference.
Related
Section titled “Related”- Export Data: every parameter, token, format, and status.
- Arrange, Sprite Sheet, and Trim Sheet: the nodes whose placements the atlas presets read.
- Export Batch, Export Image, and Export Texture: the exports Export Data finds.
- Batch Processing and Texture Sets: what the rows are made of.