This job bundle renders an animated turntable in Blender, encodes it into a
review-ready movie, extracts a poster-frame thumbnail, and publishes the
result to Autodesk Flow Production Tracking
(formerly ShotGrid) as a new Version on an Asset's review Task.
It is a deliberately end-to-end, representative example of a render-and-publish pipeline on AWS Deadline Cloud, and it demonstrates two core patterns:
- Post-render work modeled as job steps. Tasks like uploading to Flow, registering versions, and generating thumbnails are expressed as discrete steps in the job, not as side effects hidden inside the render.
- Chained, dependent, non-render tasks (movie encode, thumbnail, publish) that run after a render and fan out in parallel.
The canonical way to do post-render work on Deadline Cloud — uploading to Flow, registering versions, generating thumbnails — is a discrete OpenJD step with a step dependency. Each unit of post-render work is a first-class farm task, which means it is:
- Observable — it shows up in the monitor with its own logs and status.
- Independently retryable — a failed Flow publish can be retried without re-rendering a single frame.
- Independently schedulable — the publish step can run on a cheap CPU fleet instead of the GPU render fleet (this sample keeps them on one fleet for simplicity, but the steps are separable).
- Parallelizable —
GenerateMovieandGenerateThumbnailrun at the same time because neither depends on the other.
Modeling each piece of post-render work as its own step is what gives you all of the above, and it's the pattern to reach for when wiring a Flow publish into a render job.
RenderTurntable (Blender; one task per frame, parameter-space over the frame range)
├─ GenerateMovie (depends: RenderTurntable) ffmpeg frames → H.264 mp4
├─ GenerateThumbnail (depends: RenderTurntable) mid frame → jpg
└─ PublishToFlow (depends: GenerateMovie, GenerateThumbnail)
create Version, upload movie + thumbnail, advance Task
GenerateMovie and GenerateThumbnail both depend only on RenderTurntable, so
they run in parallel — a clear visual demonstration of step fan-out in the
monitor. PublishToFlow depends on both because it uploads both artifacts.
The sample follows idiomatic Flow conventions:
- The
Versionis the hero entity — the reviewable media record. The movie is uploaded tosg_uploaded_movie(what plays in the review player);sg_path_to_movie/sg_path_to_frameshold the filesystem paths. - The thumbnail belongs on the
Version(uploaded viaupload_thumbnail), which populates the Version'simagefield — that's what shows in the review grid. It is not attached to the Asset. - Status is advanced on the
Task, not the Asset. In Flow, an Asset isn't marked "rendered"; instead the review Task (for example a "Model" or "Turntable" task) is advanced. Many studios use arev("pending review") status for this, butrevis not a stock status code — it varies per site. TheFlowTaskStatusparameter defaults tofinbecause the demo site only defines the stock codeswtg/ip/fin; set it to whatever your site uses (revis the conventional choice where it exists). - The work hangs off an Asset rather than a Shot. An "Asset turntable" — build an asset, render a turntable to review the model or look — is self-contained, with no sequence/shot hierarchy required, and maps directly to "render an object and review it."
The job needs Blender, FFmpeg, and Python. On Deadline Cloud service-managed fleets, use a conda queue environment with:
CondaPackages:blender ffmpeg python>=3.10 pipCondaChannels:deadline-cloud conda-forge
Blender is on the deadline-cloud channel; FFmpeg is on the conda-forge
community channel.
Note on
shotgun_api3: the Flow Python client is published on PyPI only (it is not on conda-forge). ThePublishToFlowstep thereforepip installsshotgun_api3(andboto3) at runtime into the conda environment. This mixed conda + pip approach is normal for Python client libraries that have no conda package. A team that wants fully reproducible, offline-capable environments can instead build an internal conda package or bake the dependency into a custom worker image.
Flow script credentials are stored in AWS Secrets Manager. The PublishToFlow
step reads them at runtime using the worker's queue role, so the credentials
stay out of the job bundle and out of the job's parameters.
The secret value is JSON with three keys — your Flow site URL, the script name (from Flow → Admin → Scripts), and its API key:
aws secretsmanager create-secret \
--region us-west-2 \
--name "deadline-cloud-samples/flow-production-tracking" \
--description "Flow Production Tracking script credentials for the turntable demo job." \
--secret-string '{
"site_url": "https://your-site.shotgrid.autodesk.com",
"script_name": "your-script-name",
"api_key": "your-api-key"
}'Note the returned ARN — you'll pass it as the FlowSecretArn job parameter.
To update the credentials later:
aws secretsmanager put-secret-value \
--region us-west-2 \
--secret-id "deadline-cloud-samples/flow-production-tracking" \
--secret-string '{ "site_url": "...", "script_name": "...", "api_key": "..." }'The job runs under your queue role (the roleArn on your queue). That role
must be allowed secretsmanager:GetSecretValue on the secret ARN. Find the role
name:
aws deadline get-queue \
--region us-west-2 \
--farm-id farm-XXXX --queue-id queue-XXXX \
--query roleArn --output text
# e.g. arn:aws:iam::<account>:role/service-role/AWSDeadlineCloudQueueRole-XXXXXXXXAttach an inline policy granting read access to just this secret (replace the role name and ARN):
aws iam put-role-policy \
--role-name AWSDeadlineCloudQueueRole-XXXXXXXX \
--policy-name FlowProductionTrackingSecretRead \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadFlowProductionTrackingSecret",
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-west-2:<account>:secret:deadline-cloud-samples/flow-production-tracking-XXXXXX"
}
]
}'Scope the
Resourceto the exact secret ARN (including the random suffix Secrets Manager appends). Do not grantsecretsmanager:GetSecretValueon*.
blender_turntable_to_flow/
├── template.yaml the OpenJD job template
├── hooks.yaml submission hook configuration (preSubmission)
└── scripts/
├── build_turntable.py builds the turntable scene in Blender and renders a frame
├── publish_to_flow.py creates the Version and uploads the movie + thumbnail
└── flow_params_from_env.py preSubmission hook: fills the Flow parameters from the environment
The two render/publish scripts are referenced by the template as dataFlow: IN
PATH parameters (BuildTurntableScript, PublishScript). Deadline Cloud
uploads them with the job's attachments and path-maps them onto the worker, so
the steps run them as ordinary files rather than embedding the source inline.
Studios usually already have environment or project-tracking tooling that sets environment variables when an artist opens a shell or launches an application (via Rez, a launcher, a "set project" script, and so on). This bundle uses a Deadline Cloud submission hook to read those variables and fill in the job's Flow parameters, so the submitting artist doesn't re-enter the project id, asset name, secret ARN, etc. by hand.
The Flow parameters in the template are HIDDEN and carry only placeholder
defaults. hooks.yaml registers a preSubmission hook
(scripts/flow_params_from_env.py) that runs as part of every submission — CLI
or GUI — and rewrites those parameter defaults from the environment before the
job is created.
| Environment variable | Job parameter | Required |
|---|---|---|
FLOW_PROJECT_ID |
FlowProjectId |
yes |
FLOW_ASSET_NAME |
FlowAssetName |
yes |
FLOW_SECRET_ARN |
FlowSecretArn |
yes |
FLOW_ASSET_TYPE |
FlowAssetType |
no |
FLOW_STEP_SHORT_NAME |
FlowStepShortName |
no |
FLOW_TASK_NAME |
FlowTaskName |
no |
FLOW_TASK_STATUS |
FlowTaskStatus |
no |
FLOW_PUBLISH |
EnableFlowPublish |
no |
If a required variable is missing, the hook exits non-zero and the submission is
aborted with a message telling you which variables to set. To submit without
publishing (render → movie → thumbnail only), set FLOW_PUBLISH=FALSE; the
required-variable check is then skipped.
Bundle hooks are disabled by default. Enable them once:
deadline config set settings.allow_bundle_hooks trueWith the hook in place, a submission only needs the render parameters — the Flow parameters come from the environment:
# A studio "set project" step would normally export these for you:
export FLOW_PROJECT_ID=1234
export FLOW_ASSET_NAME="Hero Vehicle"
export FLOW_SECRET_ARN=arn:aws:secretsmanager:us-west-2:<account>:secret:deadline-cloud-samples/flow-production-tracking-XXXXXX
deadline bundle submit blender_turntable_to_flow/ -p ObjectShape=monkey -p FrameRange=1-48The hook reads and writes the template with PyYAML, so the Python that runs it
(the Deadline Cloud CLI's Python) needs pyyaml available.
These assume the FLOW_* environment variables are set (see the previous
section) and bundle hooks are enabled.
deadline bundle gui-submit blender_turntable_to_flow/deadline bundle submit blender_turntable_to_flow/ \
-p ObjectShape=monkey \
-p FrameRange=1-48To exercise just the render → movie → thumbnail pipeline without Flow
credentials, set FLOW_PUBLISH=FALSE so the hook skips the required-variable
check and the publish step is skipped:
FLOW_PUBLISH=FALSE deadline bundle submit blender_turntable_to_flow/ \
-p ObjectShape=torus| Parameter | Default | Description |
|---|---|---|
| ObjectShape | monkey |
Procedural subject: monkey, cube, torus, ico_sphere, cylinder, cone |
| FrameRange | 1-48 |
Frame range; a full 360° rotation is spread across it |
| ResolutionX / ResolutionY | 960 / 540 |
Render resolution |
| Samples | 48 |
Cycles render samples |
| OutputDir | output |
Working/output dir; frames in OutputDir/frames, movie+thumbnail in OutputDir |
| FrameRate | 24 |
Output movie fps |
The Flow parameters below are HIDDEN and supplied by the preSubmission hook |
||
from the FLOW_* environment variables; the "default" column is only the |
||
| template placeholder. |
| Parameter | Default | Description |
|---|---|---|
| EnableFlowPublish | TRUE |
FALSE (via FLOW_PUBLISH) skips the Flow publish step |
| FlowSecretArn | (empty) | Secrets Manager ARN holding {site_url, script_name, api_key} |
| FlowProjectId | 0 |
Numeric Flow Project id to publish into |
| FlowAssetName | (empty) | Asset code (found-or-created) |
| FlowAssetType | Prop |
sg_asset_type used if the Asset is created |
| FlowStepShortName | MDL |
Pipeline Step short name for the review Task (if created) |
| FlowTaskName | Turntable |
Task content/name on the Asset (found-or-created) |
| FlowTaskStatus | fin |
Status set on the Task after publishing (rev where defined) |
| BuildTurntableScript | scripts/build_turntable.py |
Blender scene/render script shipped in the bundle (hidden) |
| PublishScript | scripts/publish_to_flow.py |
Flow publish script shipped in the bundle (hidden) |
