Files
PozzettiAndrea-ComfyUI-Geom…/javascript/viewer.html
T
PozzettiAndrea 414f759791 Vendor frontend JS into javascript/; drop the prestartup copy dance
The viewer JS/HTML/bundles are now committed in javascript/ (declared via
pyproject [tool.comfy] web = "javascript") instead of being copied from the
shared comfy-3d-viewers pip package at prestartup. Consequences:

- requirements.txt is now just comfy-env (host env installs nothing else,
  per the never-touch-the-host-env principle)
- prestartup_script.py no longer copies viewers or web_src; it keeps only
  setup_env() and the input-asset copies
- WEB_DIRECTORY attribute removed; the pyproject declaration is the single
  source (served at /extensions/comfyui-geometrypack/, keyed by project name)
- web_src/ deleted; its 6 widgets now live in javascript/js/ as the tracked
  source, edited directly
- viewer_pbr.html hardcoded-fallback URL updated to the new mount name

Iframe URLs auto-detect the mount from import.meta.url, so the folder rename
and mount-name change are transparent at runtime.
2026-08-12 17:37:09 +02:00

219 lines
8.2 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GeomPack 3D Viewer</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #2a2a2a;
font-family: monospace;
}
#canvas {
width: 100%;
height: 100%;
display: block;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 14px;
text-align: center;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="loading">Ready to load mesh</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
console.log('[GeomPack Viewer] Initializing...');
const canvas = document.getElementById('canvas');
const loading = document.getElementById('loading');
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x2a2a2a);
// Camera
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(2, 2, 2);
// Renderer
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
// Controls
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.zoomSpeed = 3.0; // 3x faster zoom
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const dirLight1 = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight1.position.set(5, 10, 7);
scene.add(dirLight1);
const dirLight2 = new THREE.DirectionalLight(0xffffff, 0.4);
dirLight2.position.set(-5, -5, -7);
scene.add(dirLight2);
// Grid
const grid = new THREE.GridHelper(10, 10, 0x444444, 0x222222);
scene.add(grid);
// Axes
const axes = new THREE.AxesHelper(1);
scene.add(axes);
// Current mesh
let currentMesh = null;
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Load mesh function
function loadMesh(filepath) {
console.log('[GeomPack Viewer] Loading:', filepath);
console.log('[GeomPack Viewer DEBUG] Full filepath URL:', filepath);
loading.textContent = 'Loading mesh...';
loading.style.display = 'block';
// Remove old mesh
if (currentMesh) {
scene.remove(currentMesh);
currentMesh = null;
}
// Check if filepath contains .glb or .gltf (even with query params)
const isGLB = filepath.includes('.glb') || filepath.includes('.gltf');
const loader = isGLB ? new GLTFLoader() : new OBJLoader();
console.log('[GeomPack Viewer] File type detected:', isGLB ? 'GLB/GLTF' : 'OBJ');
console.log('[GeomPack Viewer DEBUG] Using loader:', loader.constructor.name);
console.log('[GeomPack Viewer DEBUG] About to call loader.load()...');
loader.load(
filepath,
(result) => {
console.log('[GeomPack Viewer DEBUG] Loader success callback called');
console.log('[GeomPack Viewer DEBUG] Result:', result);
currentMesh = isGLB ? result.scene : result;
console.log('[GeomPack Viewer DEBUG] currentMesh:', currentMesh);
// Center mesh
const box = new THREE.Box3().setFromObject(currentMesh);
const center = box.getCenter(new THREE.Vector3());
currentMesh.position.sub(center);
console.log('[GeomPack Viewer DEBUG] Mesh bounds:', box);
console.log('[GeomPack Viewer DEBUG] Mesh center:', center);
// Add material if needed
let meshCount = 0;
currentMesh.traverse((child) => {
if (child.isMesh) {
meshCount++;
if (!child.material) {
child.material = new THREE.MeshStandardMaterial({
color: 0x88aacc,
metalness: 0.3,
roughness: 0.7
});
}
}
});
console.log('[GeomPack Viewer DEBUG] Mesh count in scene:', meshCount);
// Add to scene
scene.add(currentMesh);
console.log('[GeomPack Viewer DEBUG] Mesh added to scene');
// Adjust camera
const size = box.getSize(new THREE.Vector3());
const maxDim = Math.max(size.x, size.y, size.z);
const distance = maxDim * 2.5;
camera.position.set(distance, distance, distance);
camera.lookAt(0, 0, 0);
controls.target.set(0, 0, 0);
controls.update();
console.log('[GeomPack Viewer DEBUG] Camera adjusted to distance:', distance);
loading.style.display = 'none';
console.log('[GeomPack Viewer] Mesh Loaded successfully');
},
(progress) => {
if (progress.lengthComputable) {
const percent = (progress.loaded / progress.total * 100).toFixed(0);
loading.textContent = `Loading mesh... ${percent}%`;
}
},
(error) => {
console.error('[GeomPack Viewer] Error loading mesh:', error);
console.error('[GeomPack Viewer DEBUG] Error type:', error?.constructor?.name);
console.error('[GeomPack Viewer DEBUG] Error message:', error?.message);
console.error('[GeomPack Viewer DEBUG] Error stack:', error?.stack);
loading.textContent = 'Error loading mesh - check console';
loading.style.color = '#ff6666';
}
);
}
// Listen for messages from parent window
window.addEventListener('message', (event) => {
console.log('[GeomPack Viewer DEBUG] Received postMessage:', event.data);
console.log('[GeomPack Viewer DEBUG] Message type:', event.data?.type);
console.log('[GeomPack Viewer DEBUG] Message filepath:', event.data?.filepath);
if (event.data.type === 'LOAD_MESH') {
console.log('[GeomPack Viewer] Received LOAD_MESH message:', event.data.filepath);
loadMesh(event.data.filepath);
} else {
console.warn('[GeomPack Viewer DEBUG] Unknown message type or missing type');
}
});
console.log('[GeomPack Viewer] Ready');
console.log('[GeomPack Viewer DEBUG] Waiting for LOAD_MESH postMessage...');
</script>
</body>
</html>