diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 96aad18..56d55d1 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,7 +1,7 @@ -{"id":"ifcurl-1sh","title":"viewer.html: place camera from ifc:// URL camera= param on load","description":"When viewer.html loads with a camera= param in the ifc:// URL (9 comma-separated floats: position, direction, up in IFC world coordinates), apply the IFC→Three.js coordinate transform (Y/Z swap, one negated) and set the Three.js camera position, direction and up vector accordingly. Depends on the syncCameraUrl fix (ifcurl-j2s) so the forward and inverse transforms are consistent.","status":"in_progress","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T20:05:57Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:09:26Z","started_at":"2026-04-23T20:09:26Z","dependencies":[{"issue_id":"ifcurl-1sh","depends_on_id":"ifcurl-j2s","type":"blocks","created_at":"2026-04-23T21:06:08Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-940","title":"viewer.html: URL input box and drag-and-drop target","description":"Add a text entry box and a drag-and-drop target to viewer.html so any ifc:// URL can be loaded without navigating from a Forgejo page. The input should accept a pasted ifc:// URL and immediately load it into the viewer. Drag-and-drop should accept a dropped ifc:// URL or a .ifc file URL. This makes the viewer usable as a standalone tool.","status":"in_progress","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T20:05:43Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:09:23Z","started_at":"2026-04-23T20:09:23Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-cmd","title":"Apply forward IFC→Three.js transform when setting camera from URL params","description":"When the viewer page loads with a camera= param in the ifc:// URL, the 9 floats are in IFC world coordinates. Apply the IFC→Three.js transform to convert them before passing them to the Three.js camera / camera-controls. This is the forward direction of the same transform used in the inverse task.","status":"in_progress","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:38Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:09:25Z","started_at":"2026-04-23T20:09:25Z","dependencies":[{"issue_id":"ifcurl-cmd","depends_on_id":"ifcurl-ldk","type":"blocks","created_at":"2026-04-23T07:14:10Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-j2s","title":"Apply inverse IFC↔Three.js transform in syncCameraUrl","description":"Using the transform found in the research task, apply its inverse to camera.position, the direction vector, and camera.up before serialising them as the ifc:// camera param in syncCameraUrl. The result should be in IFC world coordinates (Z-up, matching BCF viewpoint conventions) not Three.js scene space.","status":"in_progress","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:37Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:09:25Z","started_at":"2026-04-23T20:09:25Z","dependencies":[{"issue_id":"ifcurl-j2s","depends_on_id":"ifcurl-ldk","type":"blocks","created_at":"2026-04-23T07:14:09Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} +{"id":"ifcurl-1sh","title":"viewer.html: place camera from ifc:// URL camera= param on load","description":"When viewer.html loads with a camera= param in the ifc:// URL (9 comma-separated floats: position, direction, up in IFC world coordinates), apply the IFC→Three.js coordinate transform (Y/Z swap, one negated) and set the Three.js camera position, direction and up vector accordingly. Depends on the syncCameraUrl fix (ifcurl-j2s) so the forward and inverse transforms are consistent.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T20:05:57Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:15:45Z","started_at":"2026-04-23T20:09:26Z","closed_at":"2026-04-23T20:15:45Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-1sh","depends_on_id":"ifcurl-j2s","type":"blocks","created_at":"2026-04-23T21:06:08Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-940","title":"viewer.html: URL input box and drag-and-drop target","description":"Add a text entry box and a drag-and-drop target to viewer.html so any ifc:// URL can be loaded without navigating from a Forgejo page. The input should accept a pasted ifc:// URL and immediately load it into the viewer. Drag-and-drop should accept a dropped ifc:// URL or a .ifc file URL. This makes the viewer usable as a standalone tool.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T20:05:43Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:15:43Z","started_at":"2026-04-23T20:09:23Z","closed_at":"2026-04-23T20:15:43Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-cmd","title":"Apply forward IFC→Three.js transform when setting camera from URL params","description":"When the viewer page loads with a camera= param in the ifc:// URL, the 9 floats are in IFC world coordinates. Apply the IFC→Three.js transform to convert them before passing them to the Three.js camera / camera-controls. This is the forward direction of the same transform used in the inverse task.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:38Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:15:44Z","started_at":"2026-04-23T20:09:25Z","closed_at":"2026-04-23T20:15:44Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-cmd","depends_on_id":"ifcurl-ldk","type":"blocks","created_at":"2026-04-23T07:14:10Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-j2s","title":"Apply inverse IFC↔Three.js transform in syncCameraUrl","description":"Using the transform found in the research task, apply its inverse to camera.position, the direction vector, and camera.up before serialising them as the ifc:// camera param in syncCameraUrl. The result should be in IFC world coordinates (Z-up, matching BCF viewpoint conventions) not Three.js scene space.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:37Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:15:44Z","started_at":"2026-04-23T20:09:25Z","closed_at":"2026-04-23T20:15:44Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-j2s","depends_on_id":"ifcurl-ldk","type":"blocks","created_at":"2026-04-23T07:14:09Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"id":"ifcurl-ldk","title":"Find IFC↔Three.js coordinate transform in @thatopen/components source","description":"Grep ~/src/engine_components and ~/src/engine_fragment for the matrix or transform applied when an IFC model is loaded into Three.js scene space. IFC uses Z-up; Three.js uses Y-up. @thatopen/components almost certainly applies a 90° X-axis rotation (and possibly a scale) when constructing the Three.Group from IFC geometry. Record the exact transform so the inverse can be applied in syncCameraUrl.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:36Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:05:29Z","started_at":"2026-04-23T06:19:35Z","closed_at":"2026-04-23T20:05:29Z","close_reason":"Transform identified: IFC→Three.js is a Y/Z swap with one axis negated (Z-up to Y-up). Unblocks j2s and cmd.","dependency_count":0,"dependent_count":2,"comment_count":0} {"id":"ifcurl-49o","title":"Deploy footer.tmpl to Forgejo custom templates directory","description":"Copy forgejo/templates/custom/footer.tmpl from the repo to /etc/forgejo/templates/custom/footer.tmpl on the Forgejo server. No Forgejo restart needed — custom templates are loaded dynamically. Verify the View in 3D button appears on an .ifc file page.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:22Z","created_by":"Bruno Postle","updated_at":"2026-04-23T19:47:16Z","closed_at":"2026-04-23T19:47:16Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-49o","depends_on_id":"ifcurl-ohq","type":"blocks","created_at":"2026-04-23T07:14:08Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"id":"ifcurl-ohq","title":"Update footer.tmpl: point viewer button to Forgejo static file URL","description":"Change the VIEWER_BASE URL in forgejo/templates/custom/footer.tmpl from http://localhost:8000/viewer to the Forgejo static file URL determined by the research task (ifcurl-5t3). The button href should become something like /assets/viewer.html?url=ifc://... rather than the ifcurl service URL.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T06:12:21Z","created_by":"Bruno Postle","updated_at":"2026-04-23T19:47:15Z","started_at":"2026-04-23T18:48:37Z","closed_at":"2026-04-23T19:47:15Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-ohq","depends_on_id":"ifcurl-5t3","type":"blocks","created_at":"2026-04-23T07:14:07Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} diff --git a/forgejo/custom/public/assets/viewer.html b/forgejo/custom/public/assets/viewer.html index a1e6508..a3d0052 100644 --- a/forgejo/custom/public/assets/viewer.html +++ b/forgejo/custom/public/assets/viewer.html @@ -8,7 +8,7 @@ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { background: #1c1c1e; color: #f0f0f0; font-family: system-ui, sans-serif; overflow: hidden; } - #viewer { position: fixed; inset: 0; } + #viewer { position: fixed; inset: 0; top: var(--toolbar-h, 40px); } #toolbar { position: fixed; top: 0; left: 0; right: 0; z-index: 10; display: flex; align-items: center; gap: 8px; padding: 8px 12px; @@ -67,9 +67,30 @@ const ifcUrl = params.get("url") ?? ""; const statusEl = document.getElementById("status"); const urlInput = document.getElementById("url-input"); + const toolbar = document.getElementById("toolbar"); + + // Keep viewer below the toolbar so the toolbar never overlaps the canvas. + const resizeObs = new ResizeObserver(() => { + document.documentElement.style.setProperty("--toolbar-h", toolbar.offsetHeight + "px"); + }); + resizeObs.observe(toolbar); + + // Module-level reference so event handlers can reach camera controls. + let cameraControls = null; urlInput.value = ifcUrl; + // Disable camera controls while the input has focus so keystrokes are not + // swallowed by the camera-controls library. + urlInput.addEventListener("focus", () => { + if (cameraControls) cameraControls.enabled = false; + }); + urlInput.addEventListener("blur", () => { + if (cameraControls) cameraControls.enabled = true; + }); + urlInput.addEventListener("pointerdown", e => e.stopPropagation()); + urlInput.addEventListener("mousedown", e => e.stopPropagation()); + // ----------------------------------------------------------------------- // Navigate to the viewer with a different ifc:// URL. // ----------------------------------------------------------------------- @@ -235,6 +256,7 @@ world.camera = new OBC.OrthoPerspectiveCamera(components); world.scene.setup(); components.init(); + cameraControls = world.camera.controls; // --- FragmentsManager --- // Firefox blocks cross-origin module workers; wrap in a blob URL so the