viewer: fix visibility=highlight — show all elements, highlight selection

Previously applySelector always called hider.isolate() which hid all
non-selected elements regardless of visibility mode. For highlight mode,
set up the Highlighter before applying the selector and use
highlightByID("select") instead so all elements remain visible with the
selection highlighted in orange.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bruno Postle 2026-04-26 00:20:51 +01:00
parent 837a9d10c8
commit 7aa4ef85ab
2 changed files with 26 additions and 14 deletions

View file

@ -43,9 +43,9 @@
{"id":"ifcurl-ei8","title":"Fix syncCameraUrl: convert WebGL coords to IFC world space","description":"syncCameraUrl in viewer.py currently records camera.position/direction/up directly from Three.js, which are in WebGL/Three.js coordinate space (Y-up, different scale/orientation than IFC). The ifc:// URL spec expects IFC world coordinates (Z-up, matching BCF viewpoint conventions). Need to find the IFC→Three.js transform that @thatopen/components applies when loading a model, then apply its inverse in syncCameraUrl before serialising the camera params. Repos cloned for reference: ~/src/engine_components and ~/src/engine_fragment.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-23T05:53:06Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:36Z","closed_at":"2026-04-23T06:14:36Z","close_reason":"Split into atomic tasks: ifcurl-ldk, ifcurl-j2s, ifcurl-cmd","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-ei8","title":"Fix syncCameraUrl: convert WebGL coords to IFC world space","description":"syncCameraUrl in viewer.py currently records camera.position/direction/up directly from Three.js, which are in WebGL/Three.js coordinate space (Y-up, different scale/orientation than IFC). The ifc:// URL spec expects IFC world coordinates (Z-up, matching BCF viewpoint conventions). Need to find the IFC→Three.js transform that @thatopen/components applies when loading a model, then apply its inverse in syncCameraUrl before serialising the camera params. Repos cloned for reference: ~/src/engine_components and ~/src/engine_fragment.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-23T05:53:06Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:36Z","closed_at":"2026-04-23T06:14:36Z","close_reason":"Split into atomic tasks: ifcurl-ldk, ifcurl-j2s, ifcurl-cmd","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-i1s","title":"Test Phase 3b web viewer end-to-end","description":"After deploying the footer template (ifcurl-ach), test the full flow: open an .ifc file in Forgejo at localhost:3000, click 'View in 3D', verify the viewer loads the model. CDN versions (@thatopen/components 2.4.0, three 0.160.0, web-ifc 0.0.66) may need adjustment if the API has changed.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:01Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:05:04Z","started_at":"2026-04-23T19:54:56Z","closed_at":"2026-04-23T20:05:04Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-49o","type":"blocks","created_at":"2026-04-23T07:14:12Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-4yu","type":"blocks","created_at":"2026-04-23T07:14:11Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ach","type":"blocks","created_at":"2026-04-23T06:48:10Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:54Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":4,"dependent_count":1,"comment_count":0} {"id":"ifcurl-i1s","title":"Test Phase 3b web viewer end-to-end","description":"After deploying the footer template (ifcurl-ach), test the full flow: open an .ifc file in Forgejo at localhost:3000, click 'View in 3D', verify the viewer loads the model. CDN versions (@thatopen/components 2.4.0, three 0.160.0, web-ifc 0.0.66) may need adjustment if the API has changed.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:01Z","created_by":"Bruno Postle","updated_at":"2026-04-23T20:05:04Z","started_at":"2026-04-23T19:54:56Z","closed_at":"2026-04-23T20:05:04Z","close_reason":"Closed","dependencies":[{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-49o","type":"blocks","created_at":"2026-04-23T07:14:12Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-4yu","type":"blocks","created_at":"2026-04-23T07:14:11Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ach","type":"blocks","created_at":"2026-04-23T06:48:10Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"ifcurl-i1s","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:54Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":4,"dependent_count":1,"comment_count":0}
{"id":"ifcurl-ach","title":"Deploy Phase 3b footer template to Forgejo","description":"The footer.tmpl file that injects a 'View in 3D' button on .ifc file pages has been written but not yet deployed. Deploy it to /etc/forgejo/templates/custom/footer.tmpl and verify the button appears when viewing an .ifc file on localhost:3000.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T05:47:53Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:35Z","closed_at":"2026-04-23T06:14:35Z","close_reason":"Split into atomic tasks: ifcurl-ohq, ifcurl-49o","dependencies":[{"issue_id":"ifcurl-ach","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:40Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"id":"ifcurl-ach","title":"Deploy Phase 3b footer template to Forgejo","description":"The footer.tmpl file that injects a 'View in 3D' button on .ifc file pages has been written but not yet deployed. Deploy it to /etc/forgejo/templates/custom/footer.tmpl and verify the button appears when viewing an .ifc file on localhost:3000.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T05:47:53Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:14:35Z","closed_at":"2026-04-23T06:14:35Z","close_reason":"Split into atomic tasks: ifcurl-ohq, ifcurl-49o","dependencies":[{"issue_id":"ifcurl-ach","depends_on_id":"ifcurl-ahd","type":"blocks","created_at":"2026-04-23T07:02:40Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"ifcurl-irp","title":"viewer: no render_diff preview shown on Forgejo commit pages","description":"When viewing a commit in Forgejo that contains .ifc file changes (e.g. /bruno/simple-ifc/commit/61e64e05d783e621d77869feadfc218a0858c499), no 3D diff preview image is injected. The footer.tmpl is supposed to detect .ifc diffs on commit pages and inject an img tag pointing to /render_diff. Either the detection is not firing or the render_diff request is failing.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:17:59Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:17:59Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-irp","title":"viewer: no render_diff preview shown on Forgejo commit pages","description":"When viewing a commit in Forgejo that contains .ifc file changes (e.g. /bruno/simple-ifc/commit/61e64e05d783e621d77869feadfc218a0858c499), no 3D diff preview image is injected. The footer.tmpl is supposed to detect .ifc diffs on commit pages and inject an img tag pointing to /render_diff. Either the detection is not firing or the render_diff request is failing.","status":"closed","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:17:59Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:57:57Z","closed_at":"2026-04-25T22:57:57Z","close_reason":"Fixed by render_diff fixes in commit 837a9d1","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-3sz","title":"preview: visibility=highlight renders non-selected elements as opaque grey instead of transparent grey","description":"In the rendered PNG, visibility=highlight shows selected elements normally but non-selected elements appear as opaque grey rather than transparent grey (semi-transparent). The highlight mode should make non-selected elements translucent so the selected elements are visually emphasised against a faded context.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:42Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:42Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-3sz","title":"preview: visibility=highlight renders non-selected elements as opaque grey instead of transparent grey","description":"In the rendered PNG, visibility=highlight shows selected elements normally but non-selected elements appear as opaque grey rather than transparent grey (semi-transparent). The highlight mode should make non-selected elements translucent so the selected elements are visually emphasised against a faded context.","status":"closed","priority":3,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:42Z","created_by":"Bruno Postle","updated_at":"2026-04-25T23:03:49Z","started_at":"2026-04-25T22:59:19Z","closed_at":"2026-04-25T23:03:49Z","close_reason":"Not a bug — opaque grey is the model's actual IFC material colors displayed normally in highlight mode, which is correct per spec","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-d7m","title":"viewer: visibility=highlight renders as isolate (non-selected elements should be transparent grey)","description":"In the viewer, visibility=highlight and visibility=isolate produce identical results — only selected elements are shown. The correct behaviour for highlight is to show selected elements normally and render all other elements as transparent grey. Isolate should hide non-selected elements entirely. The preview service already handles both modes correctly.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:41Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:41Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-d7m","title":"viewer: visibility=highlight renders as isolate (non-selected elements should be transparent grey)","description":"In the viewer, visibility=highlight and visibility=isolate produce identical results — only selected elements are shown. The correct behaviour for highlight is to show selected elements normally and render all other elements as transparent grey. Isolate should hide non-selected elements entirely. The preview service already handles both modes correctly.","status":"in_progress","priority":3,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:41Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:59:21Z","started_at":"2026-04-25T22:59:21Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-xy9","title":"viewer: orthographic projection not implemented (works in preview)","description":"The viewer ignores the 'scale' parameter that selects orthographic projection. The preview service renders orthographic views correctly, but the 3D viewer in the browser always shows perspective. The viewer needs to switch to an orthographic camera when the IFC URL contains 'scale=' instead of 'fov='.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:38Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:38Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-xy9","title":"viewer: orthographic projection not implemented (works in preview)","description":"The viewer ignores the 'scale' parameter that selects orthographic projection. The preview service renders orthographic views correctly, but the 3D viewer in the browser always shows perspective. The viewer needs to switch to an orthographic camera when the IFC URL contains 'scale=' instead of 'fov='.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T22:15:38Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:15:38Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-a9x","title":"viewer: typing in selector box does not filter or apply selector","description":"Typing an IfcOpenShell selector expression (e.g. 'IfcWall') into the selector input box has no effect. The selector should be applied to the model, updating the view to show only matching elements.","status":"closed","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:17Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:36:10Z","closed_at":"2026-04-25T22:36:10Z","close_reason":"selector box now working in viewer","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-a9x","title":"viewer: typing in selector box does not filter or apply selector","description":"Typing an IfcOpenShell selector expression (e.g. 'IfcWall') into the selector input box has no effect. The selector should be applied to the model, updating the view to show only matching elements.","status":"closed","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:17Z","created_by":"Bruno Postle","updated_at":"2026-04-25T22:36:10Z","closed_at":"2026-04-25T22:36:10Z","close_reason":"selector box now working in viewer","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-66h","title":"viewer: browse branches/tags button does not navigate to selected ref","description":"The browse branches and tags button does not appear to do anything when clicked. The ref input box has a datalist populated with heads/main but selecting a branch/tag and clicking browse does not navigate to that ref.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:16Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:16Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-66h","title":"viewer: browse branches/tags button does not navigate to selected ref","description":"The browse branches and tags button does not appear to do anything when clicked. The ref input box has a datalist populated with heads/main but selecting a branch/tag and clicking browse does not navigate to that ref.","status":"open","priority":3,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-25T21:37:16Z","created_by":"Bruno Postle","updated_at":"2026-04-25T21:37:16Z","dependency_count":0,"dependent_count":0,"comment_count":0}
@ -83,6 +83,7 @@
{"id":"ifcurl-0oj","title":"Phase 4: Bonsai ifc:// OS protocol handler","description":"Register ifc:// as an OS protocol handler in Bonsai on installation (Windows, macOS, Linux). On receiving a URL, resolve the git source, load the model, and apply the view state from the URL parameters (camera, selector, clipping planes, visibility mode). This is the foundation for all other Phase 4 work.","status":"deferred","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:45Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:15:09Z","defer_until":"2026-12-01T00:00:00Z","dependency_count":0,"dependent_count":3,"comment_count":0} {"id":"ifcurl-0oj","title":"Phase 4: Bonsai ifc:// OS protocol handler","description":"Register ifc:// as an OS protocol handler in Bonsai on installation (Windows, macOS, Linux). On receiving a URL, resolve the git source, load the model, and apply the view state from the URL parameters (camera, selector, clipping planes, visibility mode). This is the foundation for all other Phase 4 work.","status":"deferred","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:45Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:15:09Z","defer_until":"2026-12-01T00:00:00Z","dependency_count":0,"dependent_count":3,"comment_count":0}
{"id":"ifcurl-cyw","title":"Phase 3c: Verify Forgejo merge-ability check works with ifcmerge","description":"Investigate whether Forgejo's merge-ability check (the 'branches can be merged automatically' indicator) correctly reflects ifcmerge's ability to handle .ifc files. Determine if Forgejo runs a trial git merge or uses a heuristic. If needed, patch Forgejo to run a trial git merge --no-commit to get an accurate result.","status":"closed","priority":3,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:22Z","created_by":"Bruno Postle","updated_at":"2026-04-24T08:27:25Z","started_at":"2026-04-24T08:19:58Z","closed_at":"2026-04-24T08:27:25Z","close_reason":"Verified: git merge-tree --write-tree (Forgejo's code path for git ≥2.38) does invoke merge drivers. Bare repos require core.attributesFile in /etc/gitconfig — committed .gitattributes not read. Added gitattributes server-config file and updated deployment docs.","dependencies":[{"issue_id":"ifcurl-cyw","depends_on_id":"ifcurl-c69","type":"blocks","created_at":"2026-04-23T06:48:29Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"id":"ifcurl-cyw","title":"Phase 3c: Verify Forgejo merge-ability check works with ifcmerge","description":"Investigate whether Forgejo's merge-ability check (the 'branches can be merged automatically' indicator) correctly reflects ifcmerge's ability to handle .ifc files. Determine if Forgejo runs a trial git merge or uses a heuristic. If needed, patch Forgejo to run a trial git merge --no-commit to get an accurate result.","status":"closed","priority":3,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:22Z","created_by":"Bruno Postle","updated_at":"2026-04-24T08:27:25Z","started_at":"2026-04-24T08:19:58Z","closed_at":"2026-04-24T08:27:25Z","close_reason":"Verified: git merge-tree --write-tree (Forgejo's code path for git ≥2.38) does invoke merge drivers. Bare repos require core.attributesFile in /etc/gitconfig — committed .gitattributes not read. Added gitattributes server-config file and updated deployment docs.","dependencies":[{"issue_id":"ifcurl-cyw","depends_on_id":"ifcurl-c69","type":"blocks","created_at":"2026-04-23T06:48:29Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-c69","title":"Phase 3c: Register ifcmerge as git merge driver on Forgejo server","description":"Configure ifcmerge as the git merge driver for .ifc files on the Forgejo server. Add to /etc/gitconfig or ~forgejo/.gitconfig: [merge \"ifcmerge\"] name = IFC merge driver / driver = ifcmerge %O %A %B %L. Add *.ifc merge=ifcmerge to server-side gitattributes. This allows Forgejo's 'merge automatically' path to invoke ifcmerge via git when merging .ifc files.","status":"closed","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:21Z","created_by":"Bruno Postle","updated_at":"2026-04-24T08:15:20Z","closed_at":"2026-04-24T08:15:20Z","close_reason":"Documented ifcmerge driver registration (gitconfig-ifcmerge), gitattributes setup, merge direction constraint, and merge-commit strategy requirement","comments":[{"id":"019dbc54-bf0a-76e2-b64d-7d1681f0c730","issue_id":"ifcurl-c69","author":"Bruno Postle","text":"ifcmerge needs to be installed as a pair of merge tools because the merge process is asymmetrical and we need to be able to prefer one branch over another (because step-ids from one branch get rewritten in the merged file). In practice we prefer origin and/or main/master branches. there is code in the ifcopenshell bonsai ifcgit module for reference.","created_at":"2026-04-23T21:52:44Z"}],"dependency_count":0,"dependent_count":1,"comment_count":1} {"id":"ifcurl-c69","title":"Phase 3c: Register ifcmerge as git merge driver on Forgejo server","description":"Configure ifcmerge as the git merge driver for .ifc files on the Forgejo server. Add to /etc/gitconfig or ~forgejo/.gitconfig: [merge \"ifcmerge\"] name = IFC merge driver / driver = ifcmerge %O %A %B %L. Add *.ifc merge=ifcmerge to server-side gitattributes. This allows Forgejo's 'merge automatically' path to invoke ifcmerge via git when merging .ifc files.","status":"closed","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:21Z","created_by":"Bruno Postle","updated_at":"2026-04-24T08:15:20Z","closed_at":"2026-04-24T08:15:20Z","close_reason":"Documented ifcmerge driver registration (gitconfig-ifcmerge), gitattributes setup, merge direction constraint, and merge-commit strategy requirement","comments":[{"id":"019dbc54-bf0a-76e2-b64d-7d1681f0c730","issue_id":"ifcurl-c69","author":"Bruno Postle","text":"ifcmerge needs to be installed as a pair of merge tools because the merge process is asymmetrical and we need to be able to prefer one branch over another (because step-ids from one branch get rewritten in the merged file). In practice we prefer origin and/or main/master branches. there is code in the ifcopenshell bonsai ifcgit module for reference.","created_at":"2026-04-23T21:52:44Z"}],"dependency_count":0,"dependent_count":1,"comment_count":1}
{"id":"ifcurl-s1o","title":"viewer: extract inline JS from viewer.html into viewer.js","description":"viewer.html is ~1250 lines, almost entirely JavaScript. This makes it hard to edit with proper tooling (no syntax highlighting, linting, or go-to-definition). Extract the main viewer logic into a separate viewer.js file alongside viewer-url.js. The build.js step would need to copy it to the assets directory.","status":"open","priority":4,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-25T23:16:36Z","created_by":"Bruno Postle","updated_at":"2026-04-25T23:16:36Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-nd1","title":"Submit provisional IANA registration for ifc:// scheme","description":"Once the Phase 1 URL spec is stable, submit a provisional IANA URI scheme registration for ifc://.\\n\\nProcess: email iana@iana.org with scheme name, syntax description, security considerations, and a link to the spec (GitHub URL suffices). First Come First Served — no committee review, typically processed within days to weeks. See RFC 7595 for requirements.\\n\\nThis secures the namespace, establishes priority, and is a prerequisite if the scheme is ever proposed to buildingSMART as an open standard.","status":"open","priority":4,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-25T11:17:45Z","created_by":"Bruno Postle","updated_at":"2026-04-25T11:17:45Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-nd1","title":"Submit provisional IANA registration for ifc:// scheme","description":"Once the Phase 1 URL spec is stable, submit a provisional IANA URI scheme registration for ifc://.\\n\\nProcess: email iana@iana.org with scheme name, syntax description, security considerations, and a link to the spec (GitHub URL suffices). First Come First Served — no committee review, typically processed within days to weeks. See RFC 7595 for requirements.\\n\\nThis secures the namespace, establishes priority, and is a prerequisite if the scheme is ever proposed to buildingSMART as an open standard.","status":"open","priority":4,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-04-25T11:17:45Z","created_by":"Bruno Postle","updated_at":"2026-04-25T11:17:45Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-u6r","title":"Forgejo commit page: no IFC thumbnail — git log gives no visual indication of model state","description":"In the Forgejo repository commit list, each commit shows only the commit message. When a commit modifies an IFC file, there is no thumbnail showing what the model looks like. Reviewers browsing commits have no visual cues about which commits changed significant geometry versus metadata-only changes. A Forgejo webhook or CI integration could post a rendered PNG thumbnail as a commit status/check comment when .ifc files change, using the preview service. This would make the git log visually meaningful for BIM projects.","status":"closed","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T11:04:41Z","created_by":"Bruno Postle","updated_at":"2026-04-25T20:07:21Z","closed_at":"2026-04-25T20:07:21Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-u6r","title":"Forgejo commit page: no IFC thumbnail — git log gives no visual indication of model state","description":"In the Forgejo repository commit list, each commit shows only the commit message. When a commit modifies an IFC file, there is no thumbnail showing what the model looks like. Reviewers browsing commits have no visual cues about which commits changed significant geometry versus metadata-only changes. A Forgejo webhook or CI integration could post a rendered PNG thumbnail as a commit status/check comment when .ifc files change, using the preview service. This would make the git log visually meaningful for BIM projects.","status":"closed","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T11:04:41Z","created_by":"Bruno Postle","updated_at":"2026-04-25T20:07:21Z","closed_at":"2026-04-25T20:07:21Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-l50","title":"SPECIFICATION.md section 6: BCF-to-IFC-URL direction not implemented","description":"SPECIFICATION.md §6 defines both directions of BCF ↔ IFC URL conversion. The IFC URL → BCF direction is fully implemented (build_bcf(), /bcf endpoint, viewer BCF button). The BCF → IFC URL direction (extract GUIDs from Components/Selection, construct GUID selector, convert camera and clips to URL params) has no implementation. This would be useful for round-tripping: import a BCF viewpoint and get back a shareable ifc:// URL.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T10:41:01Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:41:01Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-l50","title":"SPECIFICATION.md section 6: BCF-to-IFC-URL direction not implemented","description":"SPECIFICATION.md §6 defines both directions of BCF ↔ IFC URL conversion. The IFC URL → BCF direction is fully implemented (build_bcf(), /bcf endpoint, viewer BCF button). The BCF → IFC URL direction (extract GUIDs from Components/Selection, construct GUID selector, convert camera and clips to URL params) has no implementation. This would be useful for round-tripping: import a BCF viewpoint and get back a shareable ifc:// URL.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T10:41:01Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:41:01Z","dependency_count":0,"dependent_count":0,"comment_count":0}

View file

@ -614,7 +614,7 @@
return selectorStr.split("+").every(part => /^[Ii]fc[A-Za-z0-9]+$/.test(part.trim())); return selectorStr.split("+").every(part => /^[Ii]fc[A-Za-z0-9]+$/.test(part.trim()));
} }
async function applySelector(components, model, selectorStr, srcUrl) { async function applySelector(components, model, selectorStr, srcUrl, visibility = "isolate", highlighter = null) {
if (!selectorStr) return; if (!selectorStr) return;
const hider = components.get(OBC.Hider); const hider = components.get(OBC.Hider);
@ -633,7 +633,11 @@
if (!matchingCategories.length) return; if (!matchingCategories.length) return;
const matching = await classifier.find({ Categories: matchingCategories }); const matching = await classifier.find({ Categories: matchingCategories });
if (!matching || Object.keys(matching).length === 0) return; if (!matching || Object.keys(matching).length === 0) return;
await hider.isolate(matching); if (visibility === "highlight" && highlighter) {
await highlighter.highlightByID("select", matching, true, false);
} else {
await hider.isolate(matching);
}
return; return;
} }
@ -658,7 +662,11 @@
const localIds = (await model.getLocalIdsByGuids(guids)).filter(id => id !== null); const localIds = (await model.getLocalIdsByGuids(guids)).filter(id => id !== null);
if (!localIds.length) return; if (!localIds.length) return;
await hider.isolate({ [model.modelId]: localIds }); if (visibility === "highlight" && highlighter) {
await highlighter.highlightByID("select", { [model.modelId]: localIds }, true, false);
} else {
await hider.isolate({ [model.modelId]: localIds });
}
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -1179,17 +1187,13 @@
.filter(v => v.length === 6 && !v.some(isNaN)); .filter(v => v.length === 6 && !v.some(isNaN));
setupClipper(components, world, clips); setupClipper(components, world, clips);
const visibility = qsPost.get("visibility") ?? "highlight";
const selectorStr = qsPost.get("selector") ?? ""; const selectorStr = qsPost.get("selector") ?? "";
if (selectorStr) {
statusEl.textContent = "Applying selector…";
await applySelector(components, model, selectorStr, ifcUrl);
}
await fragments.core.update(true); // Set up Highlighter before selector so visibility=highlight can use it.
let highlighter = null;
// Click-to-identify: highlight element and show its properties.
try { try {
const highlighter = components.get(OBC.Highlighter); highlighter = components.get(OBC.Highlighter);
highlighter.setup({ world }); highlighter.setup({ world });
highlighter.events.select.onHighlight.add(async (fragmentIdMap) => { highlighter.events.select.onHighlight.add(async (fragmentIdMap) => {
for (const expressIds of Object.values(fragmentIdMap)) { for (const expressIds of Object.values(fragmentIdMap)) {
@ -1207,6 +1211,13 @@
console.warn("Highlighter unavailable:", err.message); console.warn("Highlighter unavailable:", err.message);
} }
if (selectorStr) {
statusEl.textContent = "Applying selector…";
await applySelector(components, model, selectorStr, ifcUrl, visibility, highlighter);
}
await fragments.core.update(true);
syncCameraUrl(threeCamera); syncCameraUrl(threeCamera);
cameraControls.addEventListener("rest", () => syncCameraUrl(threeCamera)); cameraControls.addEventListener("rest", () => syncCameraUrl(threeCamera));