Studio recipe reference
A recipe is one YAML file describing an entire dataset run: the scene, the
camera, the environment, the population rules and the label taxonomy. It is the file Studio's
Save recipe button writes, and the file studio-compile consumes.
The lifecycle of a recipe#
# check it without touching Unreal
nameframe studio-validate my_recipe.yml
# see the randomisation it will actually produce
nameframe studio-dry-run my_recipe.yml _local/plans/my_recipe --samples 20
# compile to the low-level plugin job
nameframe studio-compile my_recipe.yml _local/jobs/my_recipe.json
# run it against an open editor
nameframe capture-unreal _local/jobs/my_recipe.json --verify --dataset-out _local/datasets/my_recipe
The smallest valid recipe#
Three things are mandatory: an output folder, a positive frame count, and at least one class with a selector.
capture:
out_dir: D:/NameFrame/_local/dumps/first
frames: 100
seed: 42
classes:
- label: crate
select:
prefix: SM_Crate_
Top-level sections#
| Section | Required | Controls |
|---|---|---|
capture | yes | Output folder, frame count, seed, depth |
classes | yes | Labels, actor selectors, keypoint policy |
scene | no | The Unreal map this recipe expects |
camera | no | Resolution, FOV, motion, zones, rigs, calibration |
viewpoint_validation | no | Rejecting and resampling unusable views |
environment | no | Weather driver, sun, fog, clouds, settle time |
render | no | RGB quality, exposure, bloom, ray tracing, QA thresholds |
performance | no | Throughput profile and per-stage waits |
population | no | Spawn zones, scatter, spacing, clusters, groups |
sensor | no | Offline lens and sensor simulation applied after capture |
visibility | no | Hiding non-target actors for clean subsets |
name, preset | no | Human name and stable id, carried into the job |
capture#
capture:
out_dir: D:/NameFrame/_local/dumps/beach
frames: 500
seed: 42
write_depth: true
out_dir and a positive frames are required. seed
makes the run reproducible: same seed, same frames. write_depth writes
depth.npy per frame. Scene depth is still rendered for occlusion labels either
way, so turning it off saves disk rather than render time.
classes#
Each class needs a label and exactly one positive selector.
| Selector | Matches |
|---|---|
prefix | Actors whose name starts with the string |
actor_tag | Actors carrying that Unreal tag |
class_name | Actors of that class, for example BP_FoodPlate_C |
class_path | Actors of that full class path |
exclude_prefix | Negative filter on name prefix |
exclude_actor_tag | Negative filter on tag |
classes:
- label: person
select:
prefix: BP_RB_
keypoints: coco
- label: car
actor_tag: DatasetTargetCar
keypoints: none
- label: food
class_name: BP_FoodPlate_C
keypoints: none
Selectors can be nested under select: or written flat. Both work, but do not
set the same selector twice.
keypoints: coco emits the 13-joint human pose profile. Everything that is not
a human (vehicles, props, food, tools, most animals) should use keypoints: none,
which is also the default.
camera#
camera:
width: 1280
height: 960
hfov_deg: 57.3
altitude_m: [16, 34]
radius_m: [8, 42]
lookat_jitter_m: [0, 8]
min_fill_ratio: 0.12
near_clip_cm: 10
far_clip_cm: 200000
export_intrinsics: true
camera_zones:
- name: beach_drone_lane
center_m: [5, -16, 0]
radius_m: [8, 42]
altitude_m: [16, 34]
Any numeric field accepting a range takes [min, max] and gets sampled per
frame. Field of view can be given as hfov_deg, fov_deg, or as
focal_length_mm plus sensor_width_mm. The compiler derives the
horizontal FOV either way.
Other camera keys: fixed_camera_actor to use a named CameraActor,
flight_path to follow a named spline, camera_poses for an explicit
pose list, and a multi-camera rig with multi_camera set to sample,
all or all_per_frame.
viewpoint_validation#
Rejects unusable camera samples and draws again, before the frame is written.
viewpoint_validation:
enabled: true
min_targets: 1
max_targets: 0
min_visible_percent: 20
min_bbox_width_px: 16
min_bbox_height_px: 16
require_fully_visible: false
max_retries: 12
reject_empty_segmentation: true
reject_invalid_depth: true
reject_blur: false
reject_exposure: false
min_depth_valid_percent: 95
min_focus_score: 2.5
min_mean_luma: 35
max_mean_luma: 220
fallback: stop_job
fallback takes stop_job, skip_frame,
continue or relax_constraints. Also available:
min_camera_distance_m, max_camera_distance_m,
reject_camera_collision and reject_under_landscape.
environment#
Choose one driver. Omit weather_driver and NameFrame's built-in weather is used
unless UDS/UDW keys are present. The nine built-in profiles, their exact sun/fog/cloud ranges,
and the complete Ultra Dynamic Sky surface are in
Weather, sky and UDS.
Built-in weather
environment:
weather_driver: builtin
weather: random
weather_profiles:
- {name: clear_sun, weight: 40}
- {name: fog, weight: 20}
- {name: rain, weight: 20}
- {name: storm, weight: 10}
- {name: snow, weight: 10}
sun_elevation_deg: [30, 60]
sun_azimuth_deg: [0, 360]
fog_density: [0.0, 0.4]
weather_settle_seconds: 0.75
Ultra Dynamic Sky / Weather
environment:
weather_driver: ultra_dynamic
ultra_dynamic_sky:
Time of Day: [900, 1700]
Cloud Coverage: [0, 10]
ultra_dynamic_weather:
Weather: [clear_skies, rain_light, snow]
weather_settle_seconds: 1.5
UDS spans many times of day. If you do not set render.fixed_exposure
explicitly, the compiler switches to adaptive exposure for the dynamic driver, because a
fixed negative bias inherited from a sunny-only render profile turns valid daytime frames
nearly black.
render#
render:
profile: beach_sunny_drone
quality: cinematic
fixed_exposure: true
exposure_bias: -1.8
motion_blur_amount: 0.0
bloom_intensity: 0.65
ambient_occlusion_intensity: 1.6
use_ray_tracing_if_enabled: true
rgb_underexposed_luma: 30.0
rgb_overexposed_luma: 238.0
rgb_low_contrast_std: 14.0
Two named profiles ship with the compiler, beach_sunny_drone and
concrete_daylight, and they preset both environment and render values. Anything
you set explicitly wins over the profile. quality takes standard or
cinematic. The three rgb_* values are QA thresholds used to flag
frames as under-exposed, over-exposed or low-contrast.
performance#
performance:
profile: safe
render_quality: standard
streaming_timeout_seconds: 5
weather_batch_frames: 1
progress_interval_frames: 1
profile takes safe, balanced, fast or
custom. Boolean fields control the individual wait and warmup steps: finish asset
compilation, warm target shaders, stream level resources, pin target textures, reset temporal
history after camera moves, batch weather, record stage timings.
population#
population:
ground_actor_prefix: Landscape
max_ground_clearance_m: 2.0
use_level_spawn_zones: true
scatter_existing_targets: true
shuffle_per_frame: true
scatter_radius_m: [0.5, 4.0]
scatter_yaw_deg: [0, 360]
scatter_min_spacing_m: 0.5
scatter_max_slope_deg: 30
scatter_max_attempts: 120
spawn_zones:
- name: beach_people_area
center_m: [5, -16, 0]
radius_m: [0, 45]
labels: [person]
Clusters, relatives, groups and distances
population:
cluster_spawn:
- label: person
cluster_count: [2, 5]
actors_per_cluster: [2, 6]
cluster_radius_m: [3, 12]
zone: main_spawn
relative_spawn:
- label: person
relative_to: vehicle
count: [2, 8]
distance_m: [3, 20]
inter_class_distances:
- between: [person, vehicle]
min_m: 1.5
Group definitions and nested group spawning are also supported, as are named spatial
distribution profiles and exact anchor constraints. The example recipes under
examples/ whose names end in _testing.yml each demonstrate one of
these features end to end.
Declarative distributions#
Any numeric field sampled by the planner can take a distribution object instead of a range.
camera:
hfov_deg:
distribution: uniform
min: 45
max: 75
radius_m:
distribution: normal
mean: 14
std: 3
min: 6
max: 28
altitude_m:
distribution: triangular
min: 10
mode: 18
max: 32
Preview one as JSON plus an SVG histogram before committing to it:
nameframe distribution-preview "{\"distribution\":\"normal\",\"mean\":14,\"std\":3,\"min\":6,\"max\":28}" _local/reports/dist_radius
sensor#
Applied offline, after capture, by the report and dataset exporters. Change it and re-export without re-rendering.
sensor:
enabled: true
profile: random
strength: 1.0
profile_weights: "realistic_drone:40,dashcam:25,rainy_lens:20,cctv:15"
save_clean_images: true
save_segmentation: false
Twenty-seven distinct looks ship under forty names, plus the four random aliases. The full
catalogue, the default random weights, and the individual parameters you can override through
sensor.effects are in Camera lens profiles. With
save_clean_images: true you keep the un-degraded frames alongside the processed
ones.
visibility#
Hides actors that resemble targets but must not be labelled, producing a clean subset dataset.
visibility:
hide_non_target_prefixes: [BP_RB_]
hide_non_target_actor_tags: [Crowd]
hide_non_target_class_names: [BP_Extra_C]
Studio warnings#
The compiler emits studio_warnings for risky-but-allowed jobs: no map guard, no
custom camera zone, automatic exposure, default RGB QA thresholds, or a target subset with no
visibility policy. They never block a capture, they just make the job reviewable. Read them
after every studio-compile.
Promoting a recipe to a managed scenario#
For repeatable project work, put recipes under the Scenario Manager. It adds stable ids, immutable versions, config hashes, change notes, archive and duplicate operations, and field-level comparison between versions.
nameframe scenario-init _local/scenarios
nameframe scenario-create _local/scenarios examples/studio_generic_object_detection.yml --id generic-object
nameframe scenario-version _local/scenarios generic-object examples/studio_generic_object_detection.yml --note "wider altitude range"
nameframe scenario-compare _local/scenarios generic-object --from v001 --to v002
Preset gallery#
Turn a folder of recipes into a browsable HTML gallery:
nameframe presets examples _local/reports/presets
Or start a new one from a template:
nameframe preset-new _local/recipes/my_preset.yml