--- name: nuke-shot-setup description: Batch-creates Nuke visdev or comp v001 files, per-shot folders and a tracker CSV from a ShotGrid CSV and plates data, with ACES Reads and per-show config. Use for "set up shots" or "create comps from csv"; the team job ritual is shot-setup. allowed-tools: Read,Write,Edit,Bash,Glob,Grep,mcp__nuke__runPythonScript,mcp__nuke__loadScript,mcp__nuke__listNodes,mcp__nuke__getNode --- # Nuke Shot Setup **Version:** 1.1.2 Batch setup of Nuke comp/visdev files, folder structures, and shot tracking CSV. ## Script Location `scripts/batch_shot_setup.py` (paths in this skill are relative to the skill directory) ## Show Configs `configs/.json` -- per-show overrides for OCIO, LUTs, viewer, format, etc. Only values that differ from the script's built-in defaults need to be in the JSON. `--show-config` may be repeated and is applied in order, so the standard call is `--show-config configs/studio_defaults.json --show-config configs/.json` (team defaults first, show overrides second; later files win). Start a show file from `configs/show_template.json`. **Built-in defaults:** Nuke 17.0 v2, ACEScg in/out, DWAA compression, 4608x3164, 23.976fps, and **no OCIO config**. The script prints the effective Nuke version and OCIO path at the top of every run and warns when OCIO is unset - point it at your team's config via `studio_defaults.json` (`ocio_config` key). A path baked into the script is always somebody's personal path on somebody else's machine. **An empty `ocio_config` is not neutral by itself.** The warning only covers the `ocio_config` key - the other colour keys (`ACES - ACEScg` read/write colorspace, the `Output - K1S1-like - Rec.709` viewer process, monitor LUTs) still default to ACES-specific names even when no OCIO config is set to resolve them. A run with `ocio_config` empty therefore still writes those ACES names, and the generated comp opens with "Bad value for viewerProcess" and every Read in error ("Invalid LUT selected : ACES - ACEScg") under plain `nuke-default`. Interim rule until this is fixed in the script: EITHER always pass a real `ocio_config` (never run with it empty), OR set `colorManagement` to `Nuke` and the Read/Write colorspaces to a linear default by hand in your show config when no studio config exists yet. **Read-back step, every run:** open one generated `.nk` with `nuke -t --safe ` and assert `Read1.error()` is False before calling the run done - a correct node count and correct plate paths do not prove the comp opens without a colour error. Open follow-up: make `batch_shot_setup.py` fall back to a coherent nuke-default colour set (no ACES names) when `ocio_config` is empty, instead of leaving the other keys ACES-specific. ## Network-Drive Policy (adapt to your studio) Many studios block agent shells from network drives. If yours does, run this script against a local mirror of the show tree and sync results back through your studio's approved channel. All paths passed to the script (`--shared`, `--csv`, `--plates-csv`, `--out`) must be readable from the agent shell - if plates are missing under the local mirror, the sync has not happened yet; ask the pipeline owner rather than reaching for the network path directly. **Show configs:** one JSON per show under `configs/`, e.g. `configs/example_show.json` -- override only what differs from the defaults (a common case: `viewer_process` set to a client-specific Rec.709 output transform). ## Quick Start Ask the user for: 1. **ShotGrid CSV path** 2. **Project shared path** (root of `05_asset/` and `06_seq/`) 3. **Plates CSV path** (or plates directory for file scanning) 4. **Output directory** for CSV tracker + thumbnails 5. **Show config** (if project-specific OCIO/viewer settings exist) 6. **Shots to skip** (ones that already have files) ### Full run (all sequences, visdev context): ```bash python scripts/batch_shot_setup.py \ --csv "path/to/ShotGrid.csv" \ --shared "PROJECT_ROOT/shared" \ --plates-csv "path/to/plates_metadata.csv" \ --show-config "configs/.json" \ --out "path/to/output/docs" ``` ### Single sequence, comp context (legacy): ```bash python scripts/batch_shot_setup.py \ --csv "path/to/ShotGrid.csv" \ --shared "PROJECT_ROOT/shared" \ --seq ac030 \ --context comp \ --plate-prefix source_plate \ --out "path/to/output/docs" ``` ### CLI arguments: | Arg | Default | Description | |-----|---------|-------------| | `--csv` | required | ShotGrid CSV export path | | `--shared` | required | Project shared root (containing `06_seq/`) | | `--out` | required | Output directory for CSV tracker | | `--context` | `visdev` | Work context (`visdev`, `comp`, etc.) | | `--plates-csv` | none | Plates metadata CSV (avoids file scanning) | | `--plates-dir` | auto | Plates root dir (defaults to dirname of `--plates-csv`) | | `--plate-prefix` | `processed_plate` | Subdir/filename prefix for file scanning | | `--show-config` | none | Config JSON; repeatable, applied in order (studio defaults, then show) | | `--seq` | all | Filter to one sequence | | `--skip` | none | Shot codes to skip | | `--csv-only` | false | Only generate CSV tracker | | `--format-w/h` | from config | Resolution override | | `--fps` | from config | Frame rate override | | `--ocio-config` | from config | OCIO config path override | ### Thumbnails (headless, no MCP needed): `scripts/make_shot_thumbnails.py` runs inside `nuke -t --safe`, takes the same plates CSV and plates dir, writes `{shot}_{plate}_thumb.png` (the name the tracker's Thumbnail column expects), reads every PNG back, and exits 1 if any failed: ``` "C:\Program Files\Nuke17.0v2\Nuke17.0.exe" -t --safe scripts/make_shot_thumbnails.py --plates-csv --plates-dir --out /thumbnails [--ocio-config ] ``` ### Thumbnails (alternative, via Nuke MCP): If you prefer to drive a GUI Nuke over MCP, run this Python inside Nuke: ```python # Use mcp__nuke__runPythonScript with this script: import nuke, os, glob PLATES_DIR = "path/to/plates/root" OUT_DIR = "path/to/output/docs/thumbnails" THUMB_W, THUMB_H = 960, 660 PLATE_PREFIX = "processed_plate" shots = [...] # list of shot codes for shot in shots: pattern = os.path.join(PLATES_DIR, shot, PLATE_PREFIX, "{}_{}_{}_raw_v*.*.exr".format(PLATE_PREFIX, shot, "bg01")) files = sorted(glob.glob(pattern)) if not files: continue first_frame = int(files[0].split(".")[-2]) # Use the first file to derive the sequence pattern sample = os.path.basename(files[0]) import re seq_path = os.path.join(PLATES_DIR, shot, PLATE_PREFIX, re.sub(r'\.\d+\.exr$', '.%04d.exr', sample)).replace("\\", "/") out_path = os.path.join(OUT_DIR, "{}_bg01_thumb.png".format(shot)).replace("\\", "/") nuke.scriptClear() read = nuke.createNode("Read", inpanel=False) read["file"].setValue(seq_path) read["first"].setValue(first_frame) read["last"].setValue(first_frame) read["origfirst"].setValue(first_frame) read["origlast"].setValue(first_frame) reformat = nuke.createNode("Reformat", inpanel=False) reformat["type"].setValue("to box") reformat["box_width"].setValue(THUMB_W) reformat["box_height"].setValue(THUMB_H) reformat["box_fixed"].setValue(True) reformat["filter"].setValue("Lanczos6") write = nuke.createNode("Write", inpanel=False) write["file"].setValue(out_path) write["file_type"].setValue("png") write["datatype"].setValue("8 bit") nuke.execute(write, first_frame, first_frame) ``` ### Verify: 1. Spot-check folder structures: `ls` a few `06_seq/{seq}/{shot}/work/{context}/nuke/` 2. Load 1-2 .nk files via `mcp__nuke__loadScript`, check `mcp__nuke__listNodes` and `mcp__nuke__getNode` on Read nodes 3. Confirm the Write node TCL expression resolves correctly 4. Check Read node colorspace is set to "ACES - ACEScg" ## What the Script Does ### Config Layering `DEFAULTS` (built-in) <- `--show-config` JSON <- CLI args. Only override what differs. ### CSV Parsing - Finds the "Shot Code" header row (handles ShotGrid's department grouping header) - Deduplicates by shot code (ShotGrid exports multiple task rows per shot) - Extracts: Shot Code, Head In, Cut In, Cut Out, Tail Out, Working Duration, Status, Retime, Description - Shots without frame data are included in the CSV tracker but skipped for Nuke setup ### Plate Loading Two modes: 1. **Plates CSV** (`--plates-csv`): reads metadata CSV with columns `Filename, Context, First Frame, Last Frame, Duration`, plus an optional `Directory` column (the folder holding the sequence, absolute or relative to `--plates-dir`) for deliveries that are not laid out as `{plates-dir}/{shot}/{prefix}/`. Derives plate name and subdir from the filename pattern; raw-delivery names that START with the shot code (`_bg01_raw_primary_v001_main`) are recognised too. Plates dir defaults to the CSV's parent directory. ShotGrid exports repeat column names per task (Status, Id...); the parser keeps the FIRST occurrence so the shot-level Status is read, not a task's (1.1.1). 2. **File scanning** (fallback): scans `{plates-dir}/{shot}/{plate-prefix}/`, groups by plate name via regex, picks highest version per plate group. ### Sequence Derivation Sequence code is derived from each shot code: `ac030_0110` -> `ac030`. No `--seq` required for multi-sequence shows. If `--seq` is provided, it filters. ### Nuke File Generation Each .nk file has: - **Root**: OCIO/ACES, frame range from bg01 plate, custom OCIO config path - **Per plate**: BackdropNode + Read (with colorspace) + Anchor (Stamps v1.2) + PostageStamp - **Processing chain**: PostageStamp (bg01) -> Dot -> Crop -> Write (TCL path) -> Viewer - **Write node**: 16-bit half EXR, DWAA compression, ACEScg colorspace, TCL expression derives render path from script name (seq + shot + context) - File saved at: `{shared}/06_seq/{seq}/{shot}/work/{context}/nuke/{shot}_{context}_main_v001.nk` ### CSV Output Columns match Google Sheets layout: ``` Shot Code | Thumbnail | Sequence | Status | Artist | Notes | Description | Head In | Cut In | Cut Out | Tail Out | Working Duration | Plates | Plate First | Plate Last | Retime ``` ## Adapting for Other Projects **Per-show (create a JSON show config):** - `viewer_process` -- what artists see in the viewport - `ocio_config` -- OCIO config path (if different from team default) - `write_view` -- Write node display view - `format_w`, `format_h` -- resolution - Any other value from DEFAULTS **Per-run (CLI args):** - `--context` -- visdev vs comp - `--plates-csv` / `--plates-dir` / `--plate-prefix` -- plate source - `--seq` -- sequence filter - `--skip` -- shots to skip **Baked into the template (edit `batch_shot_setup.py`):** - Node graph layout / positioning - Stamps v1.2 knob structure - Write node TCL expression pattern