Added the Scene Manager (Libreflow casting, load, update, assetize)

New Scene Manager panel (WTD tab) talking to a running Libreflow through
its IPC server and the wtdcmds commands: pick the shot context, read the
casting, link the latest available publishes (overrides for chars and
props, collection instances otherwise), flag out-of-date versions in red,
update / roll back / remove loaded assets, and publish local collections
as assets. Requests run in the background. Settings in config.py
(SCENE_MANAGER_*, LIBREFLOW_*).

The Shot Viewer groups rigs loaded by the Scene Manager by asset type.
The manifest declares the network permission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nero Frame 13andClaude Opus 5.5 committed 2026-10-27 11:15:02 +01:00
1 parent 10fe71e79e
commit c238f4db7c
10 files changed
+1630 -11

No files matched your search

+18 -8
View File
@@ -150,20 +150,35 @@ def _new_camera_rig(context, shot, is_3d):
# --------------------------------------------------------------------------- #
# Rigs
# --------------------------------------------------------------------------- #
def _rig_library(ob):
reference = ob.override_library.reference if ob.override_library else None
return ob.library or (reference.library if reference else None)
def _rig_names(ob):
"""Names a rig is classified by: object, its collections and its library file."""
names = [ob.name, *(collection.name for collection in ob.users_collection)]
reference = ob.override_library.reference if ob.override_library else None
library = ob.library or (reference.library if reference else None)
library = _rig_library(ob)
if library is not None:
names.append(os.path.basename(library.filepath))
return names
def _rig_group(ob, patterns):
library = _rig_library(ob)
# Loaded by the Scene Manager: its Libreflow asset type decides.
asset_type = library.get("wtd_asset_type") if library is not None else None
if asset_type in config.SHOT_VIEWER_ASSET_TYPE_GROUPS:
return config.SHOT_VIEWER_ASSET_TYPE_GROUPS[asset_type]
names = _rig_names(ob)
return next((label for label, pattern in patterns if any(pattern.search(name) for name in names)), OTHER_GROUP)
def rig_groups(view_layer):
"""{group label: [armature objects]} for the armatures of the view layer, empty groups left out."""
patterns = [(label, re.compile(pattern)) for label, pattern in config.SHOT_VIEWER_RIG_GROUPS.items()]
groups = {label: [] for label, _pattern in patterns}
groups.update({label: [] for label in config.SHOT_VIEWER_ASSET_TYPE_GROUPS.values() if label not in groups})
groups[OTHER_GROUP] = []
# Camera rigs (armatures carrying a camera) are left out: one per shot.
rigs = sorted(
@@ -175,12 +190,7 @@ def rig_groups(view_layer):
key=lambda ob: ob.name.lower(),
)
for ob in rigs:
names = _rig_names(ob)
label = next(
(label for label, pattern in patterns if any(pattern.search(name) for name in names)),
OTHER_GROUP,
)
groups[label].append(ob)
groups[_rig_group(ob, patterns)].append(ob)
return {label: rigs for label, rigs in groups.items() if rigs}