Skip to content

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:

[[pipeline.my_publisher_pipeline.collect]]
action = "CollectPublisherPaths"
slot   = "source_files"

[[pipeline.my_publisher_pipeline.collect]]
action = "CollectImageFiles"
slot_in_paths = "source_files"
slot          = "images"