- Delete 7 dead-squat widgets (registered UI only for other packs' nodes: UniRig/SAM3D/Mocap/FBXPreview/BVH/pointcloud) + their 6 orphaned viewer HTMLs + the entire unused js/viewer tree (21 files, imported by nothing; only ui/styles.css survives) + unused utils barrel. - Rename namespace geompack -> geometrypack (= DisplayName, lowercased); all 17 surviving extensions now geometrypack.*. - Add event.source provenance guards to every message listener (2 inline, 2 factory handlers via new iframe param). - Stop touching document.body: upload file input stays detached (click() works detached in modern browsers); folder autocomplete dropdown becomes a manual popover inside the widget's own DOM (top layer escapes canvas transforms without shared-DOM appends). Passes comfy-test's javascript isolation lint with 0 errors.
120 lines
5.4 KiB
JavaScript
120 lines
5.4 KiB
JavaScript
/**
|
|
* ComfyUI GeomPack - UV Mesh Preview Widget
|
|
* Synchronized 3D mesh and 2D UV layout viewer with interactive picking
|
|
*/
|
|
|
|
import { app } from "../../../scripts/app.js";
|
|
|
|
// Auto-detect extension folder name (handles ComfyUI-GeometryPack or comfyui-geometrypack)
|
|
const EXTENSION_FOLDER = (() => {
|
|
const url = import.meta.url;
|
|
const match = url.match(/\/extensions\/([^/]+)\//);
|
|
return match ? match[1] : "ComfyUI-GeometryPack";
|
|
})();
|
|
|
|
console.log("[GeomPack] Loading UV mesh preview extension...");
|
|
|
|
app.registerExtension({
|
|
name: "geometrypack.meshpreviewuv",
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if (nodeData.name === "GeomPackPreviewMeshUV") {
|
|
console.log("[GeomPack] Registering Preview Mesh UV node");
|
|
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function() {
|
|
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
|
|
|
|
console.log("[GeomPack UV] Node created, adding widget");
|
|
|
|
// Create iframe for UV viewer
|
|
const iframe = document.createElement("iframe");
|
|
iframe.style.width = "100%";
|
|
iframe.style.height = "100%";
|
|
iframe.style.border = "none";
|
|
iframe.style.backgroundColor = "#2a2a2a";
|
|
iframe.style.aspectRatio = "2"; // Wide aspect for split view
|
|
|
|
// Point to our UV viewer HTML
|
|
iframe.src = `/extensions/${EXTENSION_FOLDER}/viewer_uv.html?v=` + Date.now();
|
|
|
|
// Add widget
|
|
const widget = this.addDOMWidget("uv_preview", "MESH_UV_PREVIEW", iframe, {
|
|
getValue() { return ""; },
|
|
setValue(v) { }
|
|
});
|
|
|
|
// Set widget size - wider for split view
|
|
widget.computeSize = function(width) {
|
|
const w = width || 600;
|
|
const h = w / 2; // 2:1 aspect ratio
|
|
return [w, h];
|
|
};
|
|
|
|
widget.element = iframe;
|
|
|
|
// Store iframe reference
|
|
this.uvViewerIframe = iframe;
|
|
|
|
// Set initial node size (wide for split view)
|
|
this.setSize([600, 350]);
|
|
|
|
// Handle execution
|
|
const onExecuted = this.onExecuted;
|
|
this.onExecuted = function(message) {
|
|
console.log("[GeomPack UV] onExecuted called with message:", message);
|
|
onExecuted?.apply(this, arguments);
|
|
|
|
if (message?.mesh_file && message.mesh_file[0]) {
|
|
const meshFilename = message.mesh_file[0];
|
|
const uvDataFilename = message.uv_data_file ? message.uv_data_file[0] : null;
|
|
const showChecker = message.show_checker ? message.show_checker[0] : false;
|
|
const showWireframe = message.show_wireframe ? message.show_wireframe[0] : true;
|
|
|
|
console.log(`[GeomPack UV] Loading mesh: ${meshFilename}`);
|
|
console.log(`[GeomPack UV] UV data: ${uvDataFilename}`);
|
|
console.log(`[GeomPack UV] Checker: ${showChecker}, Wireframe: ${showWireframe}`);
|
|
|
|
// Build file URLs
|
|
const meshPath = `/view?filename=${encodeURIComponent(meshFilename)}&type=output&subfolder=`;
|
|
const uvDataPath = uvDataFilename ?
|
|
`/view?filename=${encodeURIComponent(uvDataFilename)}&type=output&subfolder=` : null;
|
|
|
|
// Send message to iframe
|
|
setTimeout(() => {
|
|
if (iframe.contentWindow) {
|
|
console.log(`[GeomPack UV] Sending postMessage to iframe`);
|
|
iframe.contentWindow.postMessage({
|
|
type: "LOAD_MESH_UV",
|
|
meshPath: meshPath,
|
|
uvDataPath: uvDataPath,
|
|
checker: showChecker,
|
|
wireframe: showWireframe,
|
|
timestamp: Date.now()
|
|
}, "*");
|
|
} else {
|
|
console.error("[GeomPack UV] Iframe contentWindow not available");
|
|
}
|
|
}, 100);
|
|
|
|
// Update node title with UV info
|
|
if (message.has_uvs && message.has_uvs[0]) {
|
|
const coverage = message.uv_coverage ? message.uv_coverage[0].toFixed(3) : "?";
|
|
const inUnit = message.uv_in_unit_square ? message.uv_in_unit_square[0] : false;
|
|
console.log(`[GeomPack UV] UV Coverage: ${coverage}, In Unit Square: ${inUnit}`);
|
|
} else {
|
|
console.warn("[GeomPack UV] No UV data found on mesh");
|
|
}
|
|
} else {
|
|
console.log("[GeomPack UV] No mesh_file in message data. Keys:", Object.keys(message || {}));
|
|
}
|
|
};
|
|
|
|
return r;
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log("[GeomPack] UV mesh preview extension registered");
|