feat(preview): burn the production name into the slate and the overlay
Deploy / deploy (push) Successful in 5m57s

The preview manifest now carries the show name, taken from the project's
name rather than its code — a slate is read by a human, so "Ungovernable"
beats "UNG_S1".

Both the worker's headless build and the panel's own preview set it, so a
farm-generated preview and an artist-built one still match. The panel
writes it whenever it touches an overlay, not only when building a
preview, so existing comps pick it up on the next Add Overlay.

The slate's other properties are title case ("Date", "Scene") while the
overlay's are upper ("DATE", "SHOT NAME"), so both spellings of SHOW are
attempted; a template exposing neither reports its actual property names
as a build warning rather than failing silently, matching how the VFX
Scope and Submission Note fields already behave.

Panel 2.2.0, worker 1.2.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
twotalesanimation
2026-08-14 01:42:37 +02:00
parent 37f73a2bd7
commit 1163bd6455
5 changed files with 65 additions and 2 deletions
+2
View File
@@ -134,6 +134,8 @@ public sealed class SlateInfo
public string? Description { get; set; }
public string? Notes { get; set; }
public string ShotCode { get; set; } = "";
/// <summary>Production name, burned into the slate and the overlay.</summary>
public string? Show { get; set; }
public string? Episode { get; set; }
public string? Scene { get; set; }
public string? VfxScope { get; set; }
@@ -15,7 +15,7 @@
every change that gets published. publish.ps1 appends the git SHA via
SourceRevisionId, giving "1.1.0+feb1c7b".
-->
<Version>1.1.0</Version>
<Version>1.2.0</Version>
</PropertyGroup>
<ItemGroup>
@@ -266,6 +266,27 @@
}
}
// The production name, burned into both the slate and the overlay. The
// slate's other fields are title case ("Date", "Scene") while the overlay's
// are upper ("DATE", "SHOT NAME"), so both spellings are attempted rather
// than assuming which template uses which — and a template that exposes
// neither reports its actual property names instead of failing silently.
function setShowField(layer, value, label) {
var candidates = ["SHOW", "Show"];
var i;
if (value === null || value === undefined || value === "") {
return;
}
for (i = 0; i < candidates.length; i += 1) {
if (setEssentialProperty(layer, candidates[i], value)) {
return;
}
}
warn(label + ": no Essential Property named " + candidates.join(" or ") +
". Available: " + listEssentialPropertyNames(layer).join(", "));
}
function setCompStartFrame(comp, frameNumber) {
try {
comp.displayStartFrame = frameNumber;
@@ -437,6 +458,7 @@
overlayLayer.enabled = true;
setEssentialProperty(overlayLayer, "DATE", ctx.slate.date);
setEssentialProperty(overlayLayer, "SHOT NAME", ctx.slate.versionName);
setShowField(overlayLayer, ctx.slate.show, "Overlay SHOW");
} else {
warn("Overlay comp \"" + ctx.overlayComp + "\" not found — rendering without burn-ins");
}
@@ -471,6 +493,7 @@
setEssentialProperty(slateLayer, "Episode", ctx.slate.episode);
setEssentialProperty(slateLayer, "Scene", ctx.slate.scene);
setEssentialProperty(slateLayer, "Frames", result.frameCount);
setShowField(slateLayer, ctx.slate.show, "Slate SHOW");
setSlateField(slateLayer, ctx.slateScopeProp, ctx.slate.vfxScope, "VFX Scope");
// The slate's Notes field carries this submission's note; when the
+34 -1
View File
@@ -32,7 +32,7 @@ var SETTINGS_KEY = "cfg";
// Bump on every change deployed to a workstation. The panel reports this to
// the server on load, so Pipeline → Machines shows which version each machine
// is actually running and flags the ones left behind.
var PANEL_VERSION = "2.1.2";
var PANEL_VERSION = "2.2.0";
(function VFXReviewConnector(thisObj) {
var uiState = {
@@ -1331,6 +1331,36 @@ var PANEL_VERSION = "2.1.2";
return null;
}
// The production name, burned into both the slate and the overlay. The
// slate's fields are title case ("Date", "Scene") and the overlay's are
// upper ("DATE", "SHOT NAME"), so both spellings are attempted rather than
// assuming which template uses which. Mirrors setShowField in the worker's
// vfxr_build_preview.jsx so panel- and farm-built previews match.
function setShowProperty(layer, label) {
var value = getShowName();
var candidates = ["SHOW", "Show"];
var i;
if (!value) {
return false;
}
for (i = 0; i < candidates.length; i += 1) {
if (setEssentialProperty(layer, candidates[i], value)) {
return true;
}
}
diagLog(label + ": no Essential Property named SHOW or Show on this layer");
return false;
}
// The production's own name, not its code: this is read off a slate.
function getShowName() {
if (!CURRENT_PROJECT) {
return "";
}
return trimText(CURRENT_PROJECT.name || CURRENT_PROJECT.code || "");
}
function setEssentialProperty(layer, propName, value) {
try {
layer.property("Essential Properties").property(propName).setValue(String(value));
@@ -1480,6 +1510,7 @@ var PANEL_VERSION = "2.1.2";
essentialProperties = overlayLayer.property("Essential Properties");
essentialProperties.property("DATE").setValue(getDateString());
essentialProperties.property("SHOT NAME").setValue(overlayShotCode + "_cmp_TT_" + (apiData.shot.shotVersion || "v001"));
setShowProperty(overlayLayer, "Overlay SHOW");
return true;
} catch (overlayError) {
return false;
@@ -1620,6 +1651,7 @@ var PANEL_VERSION = "2.1.2";
essentialProperties = overlayLayer.property("Essential Properties");
essentialProperties.property("DATE").setValue(dateString);
essentialProperties.property("SHOT NAME").setValue(shotCode + "_cmp_TT_" + (data.shot.shotVersion || "v001"));
setShowProperty(overlayLayer, "Overlay SHOW");
updated += 1;
} catch (overlayError) {
skipped += 1;
@@ -1670,6 +1702,7 @@ var PANEL_VERSION = "2.1.2";
setEssentialProperty(slateLayer, "Episode", shot.episode);
setEssentialProperty(slateLayer, "Scene", shot.scene);
setEssentialProperty(slateLayer, "Frames", frameCount);
setShowProperty(slateLayer, "Slate SHOW");
shotLayer = previewComp.layer("SHOT");
var targetOutPoint = shotLayer.inPoint + shotComp.duration;
+5
View File
@@ -37,6 +37,8 @@ export interface PreviewManifest {
description: string | null;
notes: string | null;
shotCode: string;
/** Production name, burned into the slate and the overlay. */
show: string | null;
episode: string | null;
scene: string | null;
vfxScope: string | null;
@@ -75,6 +77,7 @@ export async function buildPreviewManifest(exportRow: ExportForPreview): Promise
description: true,
notes: true,
slateDescription: true,
project: { select: { name: true, code: true } },
},
});
if (!shot) throw new PipelineError(404, "Shot not found for export");
@@ -111,6 +114,8 @@ export async function buildPreviewManifest(exportRow: ExportForPreview): Promise
description: shot.slateDescription ?? shot.description,
notes: shot.notes,
shotCode: shot.shotCode,
// The production's own name, not its code: this is read off a slate.
show: shot.project?.name ?? shot.project?.code ?? null,
episode: shot.episode,
scene: shot.scene,
vfxScope: exportRow.vfxScope,