65 lines
2.3 KiB
JavaScript
65 lines
2.3 KiB
JavaScript
// Shared registry of live 3D Poser (PromptChain_PoseStudio) nodes.
|
|
//
|
|
// pose-studio.js populates this as Poser nodes mount/unmount; main.js reads it
|
|
// so each PromptChain node's menubar can gate the "pop the Poser into a panel"
|
|
// button (enabled only when a Poser exists) and so the panel knows which Poser
|
|
// to dock. A single shared module instead of a window global keeps it
|
|
// deterministic regardless of which extension file the loader runs first.
|
|
//
|
|
// Event-driven: subscribers are notified on add/remove (never polled).
|
|
|
|
const nodes = new Set();
|
|
const listeners = new Set();
|
|
let lastActive = null;
|
|
|
|
function notify() {
|
|
for (const cb of listeners) {
|
|
try { cb(); } catch (e) { console.error("[PromptChain] pose-registry listener error", e); }
|
|
}
|
|
}
|
|
|
|
export const poseRegistry = {
|
|
// Called by pose-studio.js on mount.
|
|
add(node) {
|
|
nodes.add(node);
|
|
lastActive = node;
|
|
notify();
|
|
},
|
|
// Called by pose-studio.js on teardown.
|
|
remove(node) {
|
|
const had = nodes.delete(node);
|
|
if (lastActive === node) lastActive = null;
|
|
if (had) notify();
|
|
},
|
|
// Called when a Poser viewport is interacted with, so "which Poser does the
|
|
// panel dock" follows the one you last touched. Quiet by design — switching
|
|
// focus shouldn't yank an already-open panel onto a different node.
|
|
touch(node) {
|
|
if (nodes.has(node)) lastActive = node;
|
|
},
|
|
// The viewport finished its async mount (Three.js loaded, _pcrPose with
|
|
// enterDock now exists). add() fired its notify far earlier, before docking
|
|
// was possible — so re-notify here, letting an already-open panel dock now.
|
|
signalReady(node) {
|
|
if (nodes.has(node)) notify();
|
|
},
|
|
// Every live Poser node — e.g. so a latent-size edit can offer itself to
|
|
// each one (they individually re-trace whether that latent feeds them).
|
|
all() {
|
|
return [...nodes];
|
|
},
|
|
// The Poser a freshly-opened panel should host: last-interacted if still
|
|
// alive, else any live one.
|
|
getActive() {
|
|
if (lastActive && lastActive._pcrAlive && nodes.has(lastActive)) return lastActive;
|
|
for (const n of nodes) if (n._pcrAlive) return n;
|
|
return null;
|
|
},
|
|
get count() { return nodes.size; },
|
|
// Returns an unsubscribe fn. Fires on add/remove (gating + open-panel refresh).
|
|
subscribe(cb) {
|
|
listeners.add(cb);
|
|
return () => listeners.delete(cb);
|
|
},
|
|
};
|