When the ifc:// URL is edited and Enter pressed, capture toRawUrl() of
the loaded model at load time. On any subsequent loadUrl() call, compare
against that snapshot: if the raw file URL is unchanged, call the new
applyViewChanges() function in-place instead of navigating to a new page.
applyViewChanges() diffs old vs new URL query params and applies only what
changed: camera position (with cameraControls.update(0) flush before
render), FOV/scale, clipping planes, selector/visibility, and query. A
full page reload now only happens when host, repo, ref, or path changes.
Fixes ifcurl-ntm.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /query proxy rule to nginx config (was missing, caused 404)
- Fix populateMetaPanel: call groupData.get() instead of reading empty
groupData.map, and use ids.size (Set) not ids.length
- Update CLAUDE.md check #17 to reflect type counts now working
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
web-ifc's COORDINATE_TO_ORIGIN=true shifts all model geometry so the first
element lands at origin (≈12m shift for simple-ifc). GetCoordinationMatrix
returns identity despite the shift, so engine_fragment can't compensate.
Camera URLs are in IFC world coords (per spec §5), but the model was in
shifted coords, causing the JS viewer and Python renderer to disagree.
Set COORDINATE_TO_ORIGIN: false in ifcLoader.setup() so model geometry
stays in IFC world coords, matching what IfcOpenShell outputs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
viewer-url.js: parseIfcUrl returns query field; buildIfcUrl gains optional
fifth query param, included in the QS when non-empty.
viewer.html: add 'query' text field (label + input) in toolbar row 2
after the visibility selector. Add #query-panel (fixed bottom-centre)
with a scrollable table showing GlobalId | value rows, a header
displaying the query path, and a close button.
viewer.js: populate queryInput from parsed URL on load; include query
in buildIfcUrl() wrapper; wire queryInput into Enter-key and focus/blur
listeners. Add applyQuery(srcUrl, queryPath) which calls GET /query,
populates the table, and shows the panel. Called from main() after
applySelector when both selector and query params are present.
viewer-url.test.js: add tests for parseIfcUrl query field, buildIfcUrl
with query, and buildIfcUrl omitting empty query.
https://claude.ai/code/session_01NBsytCd6L7UQPiKbcLn4kn
viewer.html: add 'clash' option to the visibility <select> dropdown.
viewer.js: add clash branch in applySelector for both the simple
type-selector path and the complex server-side GUID path. Selected
elements are coloured 0xdc3232 (red, matching render.py's _CLASH_COLOR);
non-selected elements remain at their normal material colours, consistent
with highlight mode behaviour.
https://claude.ai/code/session_01NBsytCd6L7UQPiKbcLn4kn
Displays "Double-click model surface to place clip plane" in the status
bar when clip mode is toggled on, clears it when toggled off.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bundle OBCF (components-front) alongside OBC so Highlighter is sourced from the
correct package. Update click handler to use item.getGuid() — GlobalId is no
longer in the attributes map in fragments 3.4.x. Fix populateMetaPanel crash
(ClassificationGroupData now wraps ids in a .map property, not a plain object).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract parseCommitHref, isSimpleTypeSelector, subtractIdMap, and
isCommitHash into a new viewer-util.js ES module so they can be tested
without a browser. Convert ifcurl.js from an IIFE to an ES module
importing from viewer-util.js; update footer.tmpl to type="module".
Add node:test suites for viewer-url.js (32 tests) and viewer-util.js
(28 tests). Add npm test script and document it in the build section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ifcurl.js: scan a[href^="ifc://"] at page load and replace with preview
figures — works with [title](ifc://...) syntax without any Go extension
- viewer.js: Issue button now emits [title](ifc://...) markdown link syntax
instead of a bare URL, so shared views render as previews without the patch
- README: document no-rebuild quick setup path; Go patch section is now optional
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
viewer.html was ~1250 lines of almost entirely JavaScript. The script
block is now a single <script type="module" src="./viewer.js"> tag,
leaving viewer.html as pure HTML/CSS (~238 lines).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>