Action Reference¶
This page catalogues all built-in actions available in K-Pipe pipelines. Actions are referenced by class name in kpipe-publish.toml or kpipe-load.toml.
For how to declare and configure actions in a pipeline, see Pipeline Configuration. For the execute()/cleanup() action lifecycle, see Publishing Pipeline.
Universal actions¶
These actions have no DCC dependency and can be used in any pipeline.
CollectImageFiles¶
Phase: collect
Scans a list of file paths or directories for image files and stores them as a LayeredSequencePipelineData in the output slot. Directories are scanned non-recursively. Unrecognised file types are skipped with a warning.
Supported extensions: .exr, .png, .jpg, .jpeg, .tif, .tiff, .hdr, .tga, .bmp
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes LayeredSequencePipelineData) |
slot_in_paths |
"main" |
Input slot containing a list[str \| Path] of files or directories |
CollectPBRTextureSet¶
Phase: collect
Classifies images from a LayeredSequencePipelineData slot into a TextureSetPipelineData by inferring PBR map type and colorspace from filenames. Common naming conventions are recognised automatically (e.g. _BaseColor, _roughness, _nrm, _AmbientOcclusion). Typically chained after CollectImageFiles.
If multiple files resolve to the same map type, the first one is kept and a warning is logged. Files with unrecognised names are skipped.
The publish layer name is read from ctx.layer — set by the layer selector in the publish UI — and falls back to the main layer when empty.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes TextureSetPipelineData) |
slot_in_images |
"main" |
Input slot (reads LayeredSequencePipelineData) |
ExtractBurnIn¶
Phase: extract
Composites text burn-ins onto an image sequence using OpenImageIO Python bindings. Reads a SequencePipelineData or LayeredSequencePipelineData from the slot, writes burned-in frames to a sibling temp directory (original directory name + _burnin), and updates the sequence path so downstream integrate actions pick up the new frames automatically.
Requires the oiio-python package (import OpenImageIO), which bundles freetype for text rendering. Raises PublishError if the bindings are not available.
Text fields accept Python format strings. Available variables:
| Variable | Value |
|---|---|
{project} |
Entity project name |
{entity} |
String representation of the entity |
{task} |
Pipeline task name |
{version} |
Sequence version number (int) |
{artist} |
Artist's full name |
{artist_short} |
Artist's first name |
{frame} |
Current frame number (int) |
{frame_start} |
First frame of the scene (int) — from entity.get_frame_range() where available, else 0 |
{frame_end} |
Last frame of the scene (int) — same source as {frame_start} |
{handle_start} |
Frame handle at the start of the scene (int) — from the handles attribute config |
{handle_end} |
Frame handle at the end of the scene (int) — same source as {handle_start} |
{fps} |
Frames per second of the scene (float) — from entity.get_fps() where available, else the project's fps attribute config |
{date} |
Today's date as YYYY-MM-DD |
Standard Python format specifiers work: {version:03d}, {frame:04d}, etc.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Input/output slot — accepts SequencePipelineData or LayeredSequencePipelineData |
top_left |
"" |
Text rendered top-left. Empty = skip |
top_center |
"" |
Text rendered top-center |
top_right |
"" |
Text rendered top-right |
bottom_left |
"" |
Text rendered bottom-left |
bottom_center |
"" |
Text rendered bottom-center |
bottom_right |
"" |
Text rendered bottom-right |
font_size |
30 |
Font size in pixels |
font_path |
"" |
Path to a font file. Empty uses the OIIO default font |
color |
(0.8, 0.8, 0.8) |
Text colour as an RGB tuple |
shadow |
2 |
Drop-shadow size in pixels. 0 = no shadow |
padding_x |
30 |
Horizontal padding from the image edge in pixels |
padding_y |
10 |
Vertical padding from the image edge in pixels |
Example:
[[pipeline.render_blender_cycles.config]]
action = "ConfigBlenderRenderSettings"
[[pipeline.render_blender_cycles.extract]]
action = "ExtractBlenderFrames"
slot = "main"
[[pipeline.render_blender_cycles.extract]]
action = "ExtractBurnIn"
slot = "main"
top_left = "{project} | {entity} | {task}"
top_right = "{date}"
bottom_left = "v{version:03d}"
bottom_right = "{frame:04d}"
[[pipeline.render_blender_cycles.integrate]]
action = "IntegrateMedia"
slot = "main"
ExtractFfmpegSequenceToVideo¶
Phase: extract
Muxes an image sequence into a video file using ffmpeg (provided by the kpipe-imgtools package, which bundles its own ffmpeg binary). Reads a SequencePipelineData from the slot, encodes it to the configured container/codec, and replaces the slot with a VideoPipelineData pointing at the resulting file. Raises PublishError for LayeredSequencePipelineData — select a single layer upstream first.
Input frame files are matched by file_format and their numeric naming convention (prefix, separator, zero-padding) is parsed directly rather than relying on ffmpeg's glob demuxer, so this works on builds without libglob (e.g. Windows).
Supported containers and the codecs valid for each:
| Container | Codecs |
|---|---|
mp4 |
h264, av1 |
mov |
h264, av1, prores |
webm |
av1 |
Quality is a preset name resolved per codec: low, medium, high (h264/av1 map to a CRF value, prores to a profile — proxy/standard/hq). None of the three has a reliably-built true-lossless mode, so lossless is not offered here.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Input/output slot — reads SequencePipelineData, writes VideoPipelineData |
container |
"mp4" |
Output container: mp4, mov, webm |
codec |
"h264" |
Video codec: h264, av1, prores — must be valid for container (see table above) |
quality |
"high" |
Quality preset: low, medium, high |
fps |
null |
Output frame rate. Falls back to the sequence's frame_range.fps/original_frame_range.fps, then the project's fps attribute config |
extra_args |
{} |
Extra ffmpeg output kwargs merged over the quality preset, e.g. { "profile:v" = "3" } |
Example:
[[pipeline.blender_render_review_video.extract]]
action = "ExtractBlenderSequencerFrames"
[[pipeline.blender_render_review_video.extract]]
action = "ExtractBurnIn"
bottom_left = "v{version:03d} | {task}"
[[pipeline.blender_render_review_video.extract]]
action = "ExtractFfmpegSequenceToVideo"
container = "mp4"
codec = "h264"
quality = "high"
[[pipeline.blender_render_review_video.integrate]]
action = "IntegrateMedia"
[[pipeline.blender_render_review_video.integrate]]
action = "CleanMedia"
ExtractFfmpegVideoToSequence¶
Phase: extract
Decodes a video file into an image sequence using ffmpeg. Reads a VideoPipelineData from the slot, writes one frame file per frame in the configured format, and replaces the slot with a SequencePipelineData (frame_range and original_frame_range both set to 1–frame count). If fps isn't given, it's probed from the source video, falling back to the project's fps attribute config.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Input/output slot — reads VideoPipelineData, writes SequencePipelineData |
file_format |
"png" |
Output image format: png, exr, webp, avif |
quality |
"high" |
Quality preset: low, medium, high, lossless — valid presets depend on file_format (see below) |
fps |
null |
Output frame rate. If unset, probed from the source video, then falls back to the project's fps attribute config |
extra_args |
{} |
Extra ffmpeg output kwargs merged over the quality preset |
Quality presets per format:
| Format | Encoder | Presets |
|---|---|---|
png |
png |
(quality has no effect — always lossless) |
exr |
exr |
low/medium/high use DWAA compression (lossy, VFX-standard); lossless uses ZIP compression |
webp |
libwebp |
low/medium/high set a numeric quality; lossless enables WebP's lossless mode |
avif |
libaom-av1 |
low/medium/high only — AV1's lossless mode isn't reliably built across ffmpeg distributions, so lossless isn't offered |
Example:
[[pipeline.plate_conform.extract]]
action = "ExtractFfmpegVideoToSequence"
file_format = "exr"
quality = "high"
[[pipeline.plate_conform.integrate]]
action = "IntegrateMedia"
IntegrateMedia¶
Phase: integrate
Moves or copies extracted media from temp render directories into the versioned publish tree and writes product metadata. Handles image sequences, videos, layered sequences, and texture sets. For SequencePipelineData, VideoPipelineData, and TextureSetPipelineData (not LayeredSequencePipelineData, which has no single path), writes the same object back into slot_out — the default input slot for OpenFolder and IntegrateKitsuVideo — with path updated: the published file for VideoPipelineData (a single file), the published folder for SequencePipelineData/TextureSetPipelineData (inherently multi-file).
| Field | Default | Description |
|---|---|---|
slot_in |
"main" |
Input slot — accepts SequencePipelineData, VideoPipelineData, LayeredSequencePipelineData, or TextureSetPipelineData |
slot_out |
"publish" |
Output slot — the same pipeline data with path updated to the published file (VideoPipelineData) or folder (SequencePipelineData/TextureSetPipelineData) |
remap_frames |
false |
Remap frame numbers from original_frame_range to frame_range (1-based) on copy |
keep_files |
true |
Copy files instead of moving them, leaving the source intact |
source_name |
null |
Optional string recorded in the publish metadata as the source identifier |
CleanMedia¶
Phase: integrate
Deletes the temp render folder(s) left behind by extract actions. Typically placed as the last integrate step. Safe to run even if the folder is already gone.
| Field | Default | Description |
|---|---|---|
slot_in |
"main" |
Slot containing pipeline data whose temp path to delete |
ignore_missing |
true |
If false, raises an error when the temp folder does not exist |
OpenFolder¶
Phase: integrate
Opens the OS file browser at the folder containing a MediaPipelineData's path — the file's containing folder if path is a file, or path itself if it's already a folder. Typically chained right after IntegrateMedia, reading the slot it wrote.
| Field | Default | Description |
|---|---|---|
slot_in |
"publish" |
Slot containing a MediaPipelineData (e.g. written by IntegrateMedia's slot_out) |
IncrementWorkfileVersion¶
Phase: integrate
Saves the current DCC workfile as a new incremented version after a successful publish, via Session.increment() — resolves the next workfile version, records it in kpipe-metadata.toml, and invokes the DCC's registered save handler. Typically the last integrate step, so it only runs once everything else has published successfully. Requires a live K-Pipe session (Session.is_valid(), i.e. an entity and task already set by the running DCC); raises PublishError otherwise.
| Field | Default | Description |
|---|---|---|
file_extension |
"" |
Workfile extension to save as, e.g. "blend", "nk". Empty = infer from the currently open workfile's own suffix |
Blender actions¶
CollectBlenderObjects¶
Phase: collect
Collects objects from one or more named Blender collections, or the current selection, into a slot as an ObjectsPipelineData (packages/blender/.../kpipe_blender/pipeline_data.py) — a flat, deduplicated list[bpy.types.Object] on its objects field.
If use_selection is set, uses the members of the collection currently active in the Outliner, unless that's just the scene's root collection (nothing specific selected), in which case it falls back to the currently selected objects instead. Otherwise, resolves each name in collection_names and flattens their members (all_objects, recursively including nested collections, deduplicated across multiple collections) — raises ValidationError if any named collection isn't found.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes ObjectsPipelineData) |
use_selection |
false |
If true, collects the active Outliner collection's members, falling back to selected objects. Takes priority over collection_names |
collection_names |
[] |
Name(s) of the collection(s) to collect (a single string is also accepted) |
One of collection_names or use_selection must be set; neither raises a ValidationError.
CollectBlenderSingleFrame¶
Phase: collect
Collects a single frame number from the active Blender scene as SequencePipelineData. The output frame_range is always 1–1; original_frame_range holds the actual scene frame number, which IntegrateMedia uses when remap_frames = true.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes SequencePipelineData) |
use_current_frame |
false |
false uses scene.frame_start; true uses scene.frame_current |
CollectBlenderCamera¶
Phase: collect
Collects a camera object from the active Blender scene into a slot for use by ConfigBlenderRenderSettings.
| Field | Default | Description |
|---|---|---|
slot |
"camera" |
Output slot (writes bpy.types.Object) |
camera_name |
"" |
Name of a specific camera object. If empty, uses the scene's active camera |
CollectBlenderStoryboardFrames¶
Phase: collect
Collects per-shot frame ranges from VSE storyboard strips into a LayeredSequencePipelineData. Each shot marker becomes one SequencePipelineData entry, with the layer set to {sequence}_{shot}.
Reads use_selection from ctx.settings — if true, only selected strips are processed.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes LayeredSequencePipelineData) |
ConfigBlenderRenderSettings¶
Phase: config
Configures the scene's camera, output path, and file format for a render. Reads sequence data from slot_in and camera from slot_in_camera, resolves the render output path from the entity/task/product type, and writes it (with file_format) into the sequence data — so a following ExtractBlenderFrames step only has to render. cleanup() restores the original camera, filepath, and file format once the pipeline finishes.
| Field | Default | Description |
|---|---|---|
slot_in |
"main" |
Input/output slot (reads SequencePipelineData, writes it back with path/file_format filled in) |
slot_in_camera |
"camera" |
Input slot (reads bpy.types.Object camera) |
file_format |
"PNG" |
Blender file format identifier. See table below |
Supported file_format values:
| Value | Extension |
|---|---|
PNG |
.png |
JPEG |
.jpg |
OPEN_EXR |
.exr |
OPEN_EXR_MULTILAYER |
.exr |
TIFF |
.tif |
BMP |
.bmp |
CINEON |
.cin |
DPX |
.dpx |
ConfigBlenderTurntable¶
Phase: config
Rigs a two-empty Z-axis turntable and keyframes its rotation over frames frames, then sets scene.frame_start/frame_end to that range and writes a SequencePipelineData covering it to slot_out. In the first half, both empties rotate 0°→360° together — the subject keeps the same relative pose to the camera while the (unparented) environment/lighting sweeps past a fixed framing. In the second half, the camera empty holds and the object empty keeps rotating 0°→360° alone — the classic all-sides object turntable. Rotation is linear (constant speed).
Reads the objects to turn from slot_in_objects (an ObjectsPipelineData, from CollectBlenderObjects) and the camera from slot_in_camera (from CollectBlenderCamera) — both must be collected earlier in the pipeline. Only root objects of the collected set (those not parented to another object in the set) are reparented, so existing internal hierarchies (e.g. meshes parented to an armature) are preserved.
Each empty's rotation keyframes are set to LINEAR interpolation directly on their F-curves after insertion (so the turntable spins at constant speed), navigating Blender's layered-action structure (action.layers[].strips[].channelbag(slot).fcurves) rather than the pre-4.4 action.fcurves shortcut, which no longer exists.
cleanup() restores original parenting, deletes both empties, and restores the original frame range once the pipeline finishes.
| Field | Default | Description |
|---|---|---|
slot_in_objects |
"objects" |
Input slot (reads ObjectsPipelineData) |
slot_in_camera |
"camera" |
Input slot (reads bpy.types.Object camera) |
slot_out |
"main" |
Output slot (writes a SequencePipelineData covering the turntable's frame range) |
frames |
96 |
Total turntable length in frames (minimum 8), split into two equal halves |
Example:
[[pipeline.render_turntable.collect]]
action = "CollectBlenderObjects"
slot = "objects"
collection_names = ["Render_Beauty"]
[[pipeline.render_turntable.collect]]
action = "CollectBlenderCamera"
[[pipeline.render_turntable.config]]
action = "ConfigBlenderTurntable"
frames = 120
[[pipeline.render_turntable.config]]
action = "ConfigBlenderRenderSettings"
[[pipeline.render_turntable.extract]]
action = "ExtractBlenderFrames"
ExtractBlenderFrames¶
Phase: extract
Renders each frame of a collected SequencePipelineData's original_frame_range (from slot_in). Expects the scene's camera, output path, and file format to already be configured — e.g. by a preceding ConfigBlenderRenderSettings step, which also fills in the sequence data's path/file_format. This action only steps through frames and calls Blender's renderer; it saves and restores scene.frame_start/frame_end around the loop.
| Field | Default | Description |
|---|---|---|
slot_in |
"main" |
Input slot (reads SequencePipelineData) |
slot_out |
"render" |
Output slot (writes the same SequencePipelineData, already carrying path/file_format from ConfigBlenderRenderSettings) |
ExtractBlenderSequencerFrames¶
Phase: extract
Renders frame ranges from the Blender VSE (OpenGL render) to temp render paths. Handles both a single SequencePipelineData and a LayeredSequencePipelineData (renders each layer separately). Saves and restores scene render settings after rendering.
| Field | Default | Description |
|---|---|---|
slot_in_sequence |
"main" |
Input slot (reads SequencePipelineData or LayeredSequencePipelineData) |
slot |
"main" |
Output slot (writes the same data with path/format filled in) |
file_format |
"PNG" |
Blender file format identifier (same values as ConfigBlenderRenderSettings) |
shading_type |
"MATERIAL" |
VSE viewport shading. One of WIREFRAME, SOLID, MATERIAL, RENDERED |
Blender load actions¶
Load actions are used in kpipe-load.toml and run as ordered [[pipeline.<key>.load]] steps.
The version and layer to load, and the reference id, are not step fields — they are provided on the pipeline context (ctx.version, ctx.layer, ctx.ref_id) by Session.load_product().
LoadBlenderMedia¶
Loads a published image, image sequence, or video as a Blender image datablock. The datablock is tagged with a kpipe_ref_id custom property linking it back to the reference entry in the sidecar file; if a datablock tagged with the same reference already exists it is reloaded in place rather than duplicated. Datablock names are purely cosmetic ("{entity} {product_type} [{layer}]") — identity always lives in the custom property, so the 63-character name limit and Blender's .001 dedup suffixes are harmless.
| Field | Default | Description |
|---|---|---|
source |
"AUTO" |
AUTO detects from metadata; or set explicitly to SEQUENCE, MOVIE, or FILE |
AUTO detection rules: if frame-end > frame-start in the publish metadata → SEQUENCE; if the file extension is a known video format → MOVIE; otherwise → FILE.
LoadBlenderTextureSet¶
Loads all maps in a published texture set (layer = material name, ctx.layer) as individual Blender image datablocks, applying the colorspace stored in publish metadata. Colorspaces can be overridden per map via colorspace_override. Every created datablock is tagged with kpipe_ref_id (so the full set can be found and removed as a unit) and kpipe_map (the map name, e.g. base_color) custom properties; datablock names are cosmetic ("{entity} {product_type} [{layer}] {map}").
| Field | Default | Description |
|---|---|---|
colorspace_override |
{} |
Dict mapping map name to a Blender colorspace string, overriding stored metadata |
SetupBlenderPBRMaterial¶
Wires texture-set datablocks into a Principled BSDF material node tree. Runs as a second [[load]] step after LoadBlenderTextureSet: it finds all image datablocks tagged with the current ctx.ref_id, identifies each map via the kpipe_map custom property, and connects it to the matching BSDF socket (normal maps get a Normal Map node in between).
The material is named after ctx.layer (the published texture-set layer name). If that is empty, the active material on the selected object is used; when neither yields a name the step is skipped (or raises if skip_no_mat = false).
| Field | Default | Description |
|---|---|---|
normal_strength |
1.0 |
Strength value on the Normal Map node |
skip_no_mat |
true |
Skip silently when no material name can be resolved instead of raising |
Kitsu actions¶
IntegrateKitsuImage¶
Phase: integrate
Uploads a rendered still image as a preview revision on the current Kitsu task. Picks the first image file found in the render directory of the SequencePipelineData slot. Reads note from ctx.settings and attaches it as the revision comment.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Input slot (reads SequencePipelineData) |
task_status |
"" |
Short name of the Kitsu task status to set on upload (e.g. "wfa"). Empty = no change |
set_as_main |
true |
Whether to set the uploaded preview as the entity's main thumbnail |
IntegrateKitsuVideo¶
Phase: integrate
Uploads a rendered video as a preview revision on the current Kitsu task. Reads note from ctx.settings and attaches it as the revision comment.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Input slot (reads VideoPipelineData) |
task_status |
"" |
Short name of the Kitsu task status to set on upload (e.g. "wfa"). Empty = no change |
set_as_main |
true |
Whether to set the uploaded preview as the entity's main thumbnail |
normalize_movie |
true |
Let Kitsu re-encode the video for streaming. Set to false for pre-encoded files |
K-Pipe GUI¶
Actions provided by the kpipe_gui package. They are registered automatically when kpipe_gui is imported.
CollectPublisherPaths¶
Phase: collect
Reads the file paths added in the K-Pipe Publisher tool and writes them to a slot as a list[PurePosixPath]. The publisher injects the dropped paths into ctx.settings["source_files"] before calling run_publish(). Raises PublishError if no files were provided.
Typically the first collect step in a publisher pipeline, feeding its output slot into a downstream action such as CollectImageFiles.
| Field | Default | Description |
|---|---|---|
slot |
"main" |
Output slot (writes list[PurePosixPath]) |
Example: