RFC — Viewer-side Advanced Options host contract
Summary
I would like to propose a viewer-side Advanced Options / Authoring Host contract before moving larger viewer tools such as Rig Editor or PoseClip into Modly upstream.
The goal is to avoid adding too much feature-specific orchestration directly into Viewer3D.tsx, while also avoiding a premature jump into external UI/plugin extensions before Modly has a safe renderer panel contract.
This is an architecture proposal / RFC, not a request to implement external UI extensions immediately.
Context
The current extension system is mostly model/process-node oriented:
- model extensions;
- process extensions;
- workflow nodes derived from those extension nodes.
Today, extension manifests support execution nodes, but they do not yet define renderer-side UI contributions such as:
- viewer panels;
- right-side authoring tools;
- docked advanced options windows;
- detached viewer windows;
- React/TSX panel bundles;
- capability-scoped viewer APIs.
At the same time, some advanced viewer features, such as Rig Editor and PoseClip, naturally need UI panels and access to viewer/runtime context.
Why not external UI extensions immediately?
Jumping directly to external GitHub/local UI panel extensions would require solving several hard problems first:
- renderer TSX/React packaging;
- React/runtime compatibility;
- CSS/style isolation;
- renderer security and sandboxing;
- permission/capability model;
- versioned host contract;
- safe Electron bridge exposure;
- install/reload lifecycle for UI panels;
- compatibility with existing model/process extension contracts.
The current local extension/link workflow is useful for extension development, but it does not by itself solve safe renderer UI contribution loading.
So I think external UI panels should be a later phase, not the first step.
Current local/private reference
In my local/private work, Rig Editor and PoseClip already have their own UI components:
src/areas/generate/components/RigEditorPanel.tsx
src/areas/generate/components/PoseClipPanel.tsx
src/areas/generate/components/RigTargetBrowser.tsx
src/areas/generate/components/RigOverlay.tsx
Some domain logic is also already separated:
src/areas/generate/rigSkeleton.ts
src/areas/generate/rigRenamePlan.ts
src/areas/generate/rigMetaNaming.ts
src/areas/generate/rigEffectiveNaming.ts
src/areas/generate/rigDisplayNames.ts
src/areas/generate/poseClipPlan.ts
src/areas/generate/poseClipPreview.ts
However, the orchestration still lives in Viewer3D.tsx, including:
- selected bone / rig target state;
- sidecar hydration;
- save/load calls through Electron;
- live Three.js bone references;
- pose preview snapshots;
- model-change reset behavior;
- shared selection between Rig Editor, PoseClip, and rig overlay;
- layout/placement of panels;
- semantic source rules for generated/derived rig metadata.
So moving these features is not just moving one or two .tsx files. The host needs to own and expose the right runtime context safely.
Proposed direction
I suggest a phased approach:
Phase 1 — Internal host contract only
Create an internal renderer-side host abstraction, for example:
type ViewerAuthoringSlot =
| right-rail
| top-right-panel
| bottom-rail
| detached-window
interface ViewerAuthoringToolDescriptor {
id: string
label: string
slot: ViewerAuthoringSlot
isAvailable(context: ViewerAuthoringContext): boolean
renderPanel(context: ViewerAuthoringPanelContext): React.ReactNode
}
This would initially be built-in only.
No external renderer-loaded extensions yet.
Phase 2 — Built-in adapters
Register first-party tools through this host contract, for example:
RigEditorTool
PoseClipTool
The panels can remain in the core app, but their visibility, placement, and toolbar entries would go through the host contract.
This gives Modly a cleaner architecture without requiring an external plugin system on day one.
Phase 3 — Declarative metadata
Once the host contract is stable, add optional metadata for built-in or known adapters.
Example concept:
{
"contributes": {
"viewerPanels": [
{
"adapter": "modly.rig-editor",
"slot": "top-right-panel"
}
]
}
}
At this stage, the adapter could still resolve to a built-in implementation.
Phase 4 — External UI panels later
Only after the host API, permissions, packaging, and compatibility model are stable, consider experimental external UI panel loading.
This should probably be feature-flagged and local/dev-first before GitHub-distributed UI panels are supported.
Host API requirements
A future viewer authoring host would likely need to expose controlled context and actions, not raw window.electron or raw Three.js refs.
Possible read-only context:
- current mesh/model identity;
- rig skeleton summary;
- selected bone id;
- skeleton context id;
- effective/display names;
- hydration warnings;
- capability flags such as
canSaveAliases, canSavePoseClip, etc.
Possible host-controlled actions:
- select bone;
- open/close panel;
- set/revert/save aliases;
- capture/update/delete pose keyframes;
- scrub/play/pause/reset pose preview;
- load/save sidecar data through host-controlled APIs.
Possible runtime services:
- apply local bone rotation;
- reset pose preview;
- read current selected bone transform;
- request workspace artifact reads/writes through explicit typed callbacks.
Important: external or semi-external panels should not get unrestricted filesystem or Electron access.
What this would help with
This could make it easier to add advanced viewer tools without continuously expanding Viewer3D.tsx with feature-specific logic.
Potential future tools:
- Rig joints viewer mode;
- Rig Editor;
- PoseClip;
- other developer-provided viewer authoring panels later.
But each of those should still be introduced as small separate issues/PRs.
Suggested scope for this RFC
In scope:
- define the viewer-side host boundary;
- define possible slots;
- define built-in adapter registration shape;
- define what context/actions the host owns;
- preserve current core behavior;
- keep external UI loading out of scope for now.
Out of scope for the first implementation:
- loading arbitrary React/TSX panels from external repos;
- exposing raw
window.electron to extension UI;
- moving Rig Editor or PoseClip to separate GitHub repos immediately;
- replacing model/process extension contracts;
- changing FastAPI model/backend readiness ownership.
Main question
Would you prefer this kind of host-first approach?
My instinct is:
- build the internal Advanced Options / Viewer Authoring Host first;
- adapt built-in Rig Editor / PoseClip to it later;
- only then consider external developer-provided UI panels once the contract is stable.
That would preserve existing working behavior while still opening the door to a cleaner extension model for advanced viewer tools.
RFC — Viewer-side Advanced Options host contract
Summary
I would like to propose a viewer-side Advanced Options / Authoring Host contract before moving larger viewer tools such as Rig Editor or PoseClip into Modly upstream.
The goal is to avoid adding too much feature-specific orchestration directly into
Viewer3D.tsx, while also avoiding a premature jump into external UI/plugin extensions before Modly has a safe renderer panel contract.This is an architecture proposal / RFC, not a request to implement external UI extensions immediately.
Context
The current extension system is mostly model/process-node oriented:
Today, extension manifests support execution nodes, but they do not yet define renderer-side UI contributions such as:
At the same time, some advanced viewer features, such as Rig Editor and PoseClip, naturally need UI panels and access to viewer/runtime context.
Why not external UI extensions immediately?
Jumping directly to external GitHub/local UI panel extensions would require solving several hard problems first:
The current local extension/link workflow is useful for extension development, but it does not by itself solve safe renderer UI contribution loading.
So I think external UI panels should be a later phase, not the first step.
Current local/private reference
In my local/private work, Rig Editor and PoseClip already have their own UI components:
Some domain logic is also already separated:
However, the orchestration still lives in
Viewer3D.tsx, including:So moving these features is not just moving one or two
.tsxfiles. The host needs to own and expose the right runtime context safely.Proposed direction
I suggest a phased approach:
Phase 1 — Internal host contract only
Create an internal renderer-side host abstraction, for example:
This would initially be built-in only.
No external renderer-loaded extensions yet.
Phase 2 — Built-in adapters
Register first-party tools through this host contract, for example:
The panels can remain in the core app, but their visibility, placement, and toolbar entries would go through the host contract.
This gives Modly a cleaner architecture without requiring an external plugin system on day one.
Phase 3 — Declarative metadata
Once the host contract is stable, add optional metadata for built-in or known adapters.
Example concept:
{ "contributes": { "viewerPanels": [ { "adapter": "modly.rig-editor", "slot": "top-right-panel" } ] } }At this stage, the adapter could still resolve to a built-in implementation.
Phase 4 — External UI panels later
Only after the host API, permissions, packaging, and compatibility model are stable, consider experimental external UI panel loading.
This should probably be feature-flagged and local/dev-first before GitHub-distributed UI panels are supported.
Host API requirements
A future viewer authoring host would likely need to expose controlled context and actions, not raw
window.electronor raw Three.js refs.Possible read-only context:
canSaveAliases,canSavePoseClip, etc.Possible host-controlled actions:
Possible runtime services:
Important: external or semi-external panels should not get unrestricted filesystem or Electron access.
What this would help with
This could make it easier to add advanced viewer tools without continuously expanding
Viewer3D.tsxwith feature-specific logic.Potential future tools:
But each of those should still be introduced as small separate issues/PRs.
Suggested scope for this RFC
In scope:
Out of scope for the first implementation:
window.electronto extension UI;Main question
Would you prefer this kind of host-first approach?
My instinct is:
That would preserve existing working behavior while still opening the door to a cleaner extension model for advanced viewer tools.