VFX On-set Data Wrangling Workflow
This page describes a folder-driven workflow for VFX on-set data acquisition. The goal is to make every file self-describing at ingest by extracting tags and categories from the source path automatically. End of shooting day you only have to copy the captured data in the folders and ingest the entire shooting day folder into Das Element.
Purpose
Use a consistent folder structure on set so that the ingest process can automatically tag incoming material. During ingest, the pre_ingest_load hook reads the file path, splits it into folders, applies each folder as a tag and uses the last folder as the category. Each ingested file receives consistent, searchable metadata without manual entry. The folder structure becomes the source of truth for tags, while the final folder defines the category used for browsing and filtering.
Workflow
-
Capture on set: save captured data into the agreed folder structure
-
Preserve folder names: avoid renaming folders during copy. The folder names are used as metadata
-
Start ingest: the ingest system calls
pre_ingest_loadbefore each file is loaded -
Parse the path: the hook splits the file path into folder components
-
Assign tags: every folder component becomes a tag on the file
-
Assign category: the final folder component becomes the file category
-
Continue ingest: the file is loaded with the generated category and tags attached
Hook files on GitHub: resources > scripts/hooks/examples/on-set
ready-to-use pre_ingest_load.py and pre_hierarchy_load_folder.py for this workflow
Core rule
Path-to-metadata rule: split the source folder path into folder names. Use all folder names as tags. Use the final folder name as the category.
Example folder structures
{YYYYMMDD}_day-{shooting day}}/{type}/{asset name or scene}/{data type}
Example:
20261005_day-001/assets/chrAlienMother/photo/IMG_0123.cr3
20261005_day-001/slates/sc12_5/reference/video.mov
Get categories and tags
|
Source folder |
Generated tags |
Category |
|---|---|---|
|
|
|
|
|
|
|
|
Category hierarchy
The category hierarchy is based directly on the folder hierarchy. Each folder level narrows the context for the material.
-
20261005_day-001-
assets-
chrAlienMother-
hdri -
photo -
photogrammetry -
reference -
scan -
texture
-
-
-
slates-
sc12_5-
hdri -
photo -
photogrammetry -
reference -
scan -
screen_capture -
set_reference -
texture -
video -
witnesscam
-
-
-
pre_ingest_load hook behavior
The hook pre_ingest_load.py (project hooks folder: .config/hooks/) runs when files are added to the ingest window, before anything is ingested. It receives one dict per file with at least path and optionally tags, category, mapping, colorspace, media_type, and metadata, and returns the modified list.
This implementation only looks at folders below the hierarchy root folder (ROOT_FOLDER). Each folder name below it becomes a tag, and the final folder becomes the category. Files outside ROOT_FOLDER are left unchanged.
The ready-to-use hook files are available on GitHub in the resources > on-set examples folder (pre_ingest_load.py and pre_hierarchy_load_folder.py).
Category ID: when the hierarchy uses a folder source (Settings > Hierarchy > "define source"), a category's ID is the md5 hash of the folder path relative to the source folder, using "/" as separator and keeping the case: md5("day-001/assets/photo"). A plain folder name such as item["category"] = "photo" does not match these categories, so the hook builds the same hash. Renaming or moving a folder changes its category ID.
import hashlib
import re
# name of the hierarchy source folder
ROOT_FOLDER = "/path/to/on-set-folder"
# folder names matching this pattern also add a short scene tag: "sc010 hallway" -> "sc010"
SCENE_PATTERN = r"^sc\d"
def get_category_id(folders: list) -> str:
"""Return the category ID das element generates for a folder source.
folders: folder names from below ROOT_FOLDER down to the category,
e.g. ["day-001", "assets", "photo"]
"""
return hashlib.md5("/".join(folders).encode("utf-8")).hexdigest()
def get_folders(path: str) -> list:
"""Return the folder names between ROOT_FOLDER and the file.
"/path/to/on-set-folder/day-001/assets/photo/img_0038.png"
-> ["day-001", "assets", "photo"]
"""
parts = path.replace("\\", "/").split("/")[:-1]
if ROOT_FOLDER not in parts:
return []
return parts[parts.index(ROOT_FOLDER) + 1 :]
def get_tags(folders: list) -> list:
"""Turn folder names into tags: "_sc010_hallway" -> ["sc010 hallway", "sc010"]"""
tags = []
for folder in folders:
tag = folder.lstrip("_").replace("_", " ")
tags.append(tag)
if re.match(SCENE_PATTERN, tag):
tags.append(tag.split(" ")[0])
return tags
def main(*args, logger=None) -> list:
items = args[0]
for item in items:
folders = get_folders(item.get("path", ""))
if not folders:
continue
tags = item.get("tags") or []
for tag in get_tags(folders):
if tag not in tags:
tags.append(tag)
item["tags"] = tags
item["category"] = get_category_id(folders)
return items
Naming recommendations
-
Use stable shoot-day folders, for example
20261005_day-001. -
Use broad department or data-type folders, for example
assets,slates,plates,hdris, orwitness_cam. -
Use asset, scene, slate, or setup folders where useful, for example
chrAlienMotherorsc12_5. -
Use the final folder as the intended category, for example
photo,reference,scan, orsurvey. -
Avoid spaces and ambiguous names. Prefer lowercase, camelCase, snake_case, or production-approved naming conventions.