Skip to content

fix(viewer): route grid lines to their own overlay channel on #3368's single-owner base - #3387

Closed
BIMvoice wants to merge 3 commits into
mainfrom
fix-3359-on-3368
Closed

fix(viewer): route grid lines to their own overlay channel on #3368's single-owner base#3387
BIMvoice wants to merge 3 commits into
mainfrom
fix-3359-on-3368

Conversation

@BIMvoice

@BIMvoice BIMvoice commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

References #3368 and #3359. Supersedes #3381 by rebuilding it on top of #3376's single-owner grid pipeline instead of alongside it — #3376 and the original #3381 are mutually exclusive as written (#3376 deletes useGridLines3D; #3381 keeps it and merges its output with the symbolic path via a new mergeGridLineChannels).

Why the split still matters with one source

CHANNEL_EXPANDS_MODEL_BOUNDS.annotation is true (an annotation-only model must still be frameable) but .grid is false (grid axes routinely extend past the model envelope, issue #967). With annotations off and the grid on, the single shared buffer carried only grid content but still reached the bounds-expanding annotation channel — inflating the scene bounds that the empty-space orbit-pivot fallback (camera.getSceneBounds() centroid, see useMouseControls.ts/useTouchControls.ts) falls back to, so orbiting swung the camera toward the grid instead of the model. This is independent of how many hooks feed the buffer, so it survives #3376's consolidation.

Test plan

  • apps/viewer: targeted node:test run of useSymbolicAnnotations.test.ts, the new useSymbolicAnnotations.gridChannelSplit.test.ts, useSymbolicAnnotations.cacheKeyFrame.test.ts, useSymbolicAnnotations.frameRace.test.ts, useSymbolicAnnotations.retryStorm.test.ts, useSymbolicAnnotationsForDrawing.classGate.test.tsx, and Two extractors both own IfcGridAxis lines, so grid section-clipping is inert and the copies can disagree in Y #3368's grid-overlay-single-owner.test.ts — 34/34 pass, 0 failures.
  • packages/renderer: renderer-overlays-grid-channel-reframe.test.ts (new, ported from fix(viewer): route grid-only annotation content to its own line-overlay channel #3381) + renderer-overlays-line-channels.test.ts — 15/15 pass, confirming CHANNEL_EXPANDS_MODEL_BOUNDS is annotation: true / grid: false and that a grid-only upload to 'grid' leaves the orbit-pivot fallback untouched while the same content on 'annotation' (today's pre-fix wiring) drags it.
  • tsc --noEmit clean for apps/viewer and packages/renderer.
  • node scripts/check-module-size.mjs exits 0 (Viewport.tsx trimmed to 1839 lines, budget 1840).
  • node scripts/check-source-text-assertions.mjs exits 0 (no new source-text assertions).
  • git status --porcelain clean before push.
  • Confirmed apps/viewer/src/hooks/useGridLines3D.ts and apps/viewer/src/components/viewer/merge-grid-line-channels.ts do not exist on this branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436

Summary by CodeRabbit

  • Bug Fixes
    • Removed duplicate 3D grid lines in the viewport.
    • Grid lines now respect section clipping and model alignment consistently.
    • Disabling IFC annotations no longer causes the camera to reframe around grid geometry.
    • Separated annotation and grid overlays to prevent grid lines from affecting model bounds and camera positioning.
  • Tests
    • Added regression coverage for duplicate grids, alignment offsets, overlay separation, and camera reframing.

…lic path (#3368)

Two independent sources fed the ifcGrid-visibility toggle: useSymbolicAnnotations
(section-clipped, origin-shift-rebased grid buckets) and useGridLines3D (raw
parseGridLines wasm output, unclipped, rebased only by RTC). Both uploaded to
their own renderer line-overlay channel, so every axis drew twice, #862's grid
section-clipping was inert, and a federated/re-aligned model with nonzero
originShift could show the two copies at different elevations.

Grid lines now draw only from useSymbolicAnnotations; useGridLines3D is
removed. parseGridLines/parseGridAxes stay as published @ifc-lite/geometry
SDK surface, unrelated to this viewer-internal wiring.

Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
`grid-overlay-single-owner.test.ts` read `Viewport.tsx` and regex-matched it
to assert the redundant hook was no longer imported and no second 'grid'
line-overlay channel was uploaded. `check-source-text-assertions.mjs` refuses
new assertions of that shape -- its `@source-text-assertion-ok` hatch is for
anchor guards, which these are not -- so the Node tests lane failed on the
step named 'Check for new source-text assertions'.

The import assertion was redundant anyway: `useGridLines3D.ts` is deleted in
this branch, so an import of it does not compile and typecheck already
enforces it. The file-absence check stays -- `existsSync` is not a text
predicate, and it is what stops the hook being restored and re-wired.

What is genuinely lost is a guard against a NEW second channel wired from
somewhere else. That is left to review rather than kept as an assertion the
house rule bans.
…gle-owner base (#3359, #3368)

Rebuilds #3381 on top of #3376's single-owner grid pipeline instead of
alongside it. #3376 collapsed grid-line ownership onto
`useSymbolicAnnotations` and deleted the redundant `useGridLines3D`
extractor; #3381 (mutually exclusive with #3376 as originally written)
kept `useGridLines3D` and merged its output with the symbolic path via a
new `mergeGridLineChannels`. Two grid-line sources that must stay in
agreement is exactly the failure mode #3376 exists to retire, so this
keeps #3376's single owner and ports only #3381's channel split onto it.

`useSymbolicAnnotations` previously lifted IfcAnnotation curves AND
IfcGridAxis lines into one buffer uploaded to the renderer's
`annotation` line-overlay channel. With annotations off and the grid
on, that buffer carried only grid content, but
`CHANNEL_EXPANDS_MODEL_BOUNDS.annotation` is `true` (so an
annotation-only model can still be framed) while `.grid` is `false`
(grid axes routinely extend past the model envelope, issue #967) — the
grid-only upload grew the scene bounds the `grid` channel exists to
protect. Every camera fit and empty-space orbit gesture (whose pivot
falls back to the scene-bounds centroid) then reframed onto the grid.

`useSymbolicAnnotations` now returns `{ annotation, grid }` separately
(`buildSymbolicLineChannels` in the new `symbolic-line-channels.ts`,
split out for unit testing with no React/store/WASM dependency and to
keep the hook file under the module-size budget), and `Viewport.tsx`
uploads each buffer to its like-named channel. There is no
`useGridLines3D` and no merge step — one source, one channel.

Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
@BIMvoice
BIMvoice requested a review from louistrue as a code owner August 28, 2026 08:39
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad1726e7-e10a-437a-aa6d-f058940ae3d1

📥 Commits

Reviewing files that changed from the base of the PR and between 5a431e5 and c46cedd.

📒 Files selected for processing (12)
  • .changeset/grid-line-single-owner.md
  • .changeset/grid-only-annotation-channel-camera-reframe.md
  • apps/viewer/src/components/viewer/Viewport.tsx
  • apps/viewer/src/components/viewer/grid-overlay-single-owner.test.ts
  • apps/viewer/src/hooks/symbolic-line-channels.ts
  • apps/viewer/src/hooks/symbolic-parse-cache.ts
  • apps/viewer/src/hooks/useDxfUnderlay.ts
  • apps/viewer/src/hooks/useGridLines3D.ts
  • apps/viewer/src/hooks/useSymbolicAnnotations.gridChannelSplit.test.ts
  • apps/viewer/src/hooks/useSymbolicAnnotations.retryStorm.test.ts
  • apps/viewer/src/hooks/useSymbolicAnnotations.ts
  • packages/renderer/src/renderer-overlays-grid-channel-reframe.test.ts
💤 Files with no reviewable changes (1)
  • apps/viewer/src/hooks/useGridLines3D.ts

Included review availability: Your plan provides up to 2 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Grid overlay pipeline

Layer / File(s) Summary
Symbolic channel construction
apps/viewer/src/hooks/symbolic-line-channels.ts, apps/viewer/src/hooks/useSymbolicAnnotations.ts, apps/viewer/src/hooks/useSymbolicAnnotations.gridChannelSplit.test.ts
The symbolic pipeline now returns separate annotation and grid buffers. Grid lines retain visibility and section-clipping behavior.
Viewport overlay ownership
apps/viewer/src/components/viewer/Viewport.tsx, apps/viewer/src/hooks/useGridLines3D.ts, apps/viewer/src/hooks/symbolic-parse-cache.ts, apps/viewer/src/hooks/useDxfUnderlay.ts, apps/viewer/src/hooks/useSymbolicAnnotations.retryStorm.test.ts, apps/viewer/src/components/viewer/grid-overlay-single-owner.test.ts
The viewport uploads grid lines to the dedicated grid channel and removes the separate useGridLines3D owner. Regression tests cover duplicate rendering and origin-shift divergence.
Overlay bounds regression coverage
packages/renderer/src/renderer-overlays-grid-channel-reframe.test.ts, .changeset/grid-line-single-owner.md, .changeset/grid-only-annotation-channel-camera-reframe.md
Renderer tests verify that grid-channel uploads do not expand model bounds. Changesets record the two viewer patch fixes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to c46ce

The PR separates grid overlays from model-bound annotations and reports targeted tests and validation checks passing; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Viewport
  participant useSymbolicAnnotations
  participant RendererOverlays
  participant Camera
  Viewport->>useSymbolicAnnotations: obtain separate annotation and grid buffers
  useSymbolicAnnotations-->>Viewport: return lifted and clipped line buffers
  Viewport->>RendererOverlays: upload annotation buffer to annotation channel
  Viewport->>RendererOverlays: upload grid buffer to grid channel
  RendererOverlays->>Camera: synchronize bounds only for expanding channels
Loading

Suggested reviewers: louistrue

Poem

A rabbit sees grids in a single bright stream

Annotations travel beside them, serene
No doubled-up axes cross paths in the air
The camera keeps bounds with its model-world care
I twitch my nose: clean channels are here!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 9 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: routing grid lines to a dedicated overlay channel while retaining the single-owner pipeline.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 9 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Viewer benchmark

✅ No threshold regressions detected.

01_Snowdon_Towers_Sample_Structural(1).ifc

Baseline recorded 2026-07-01T20:31:05.538Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.

Metric Current Baseline Delta Threshold Status
firstBatchWaitMs 1999ms 2905ms -31.2% +50%
firstVisibleGeometryMs 2692ms 3652ms -26.3% +50%
streamCompleteMs 3129ms 3598ms -13.0% +50%
spatialReadyMs 1355ms 1032ms +31.3% +50%
metadataCompleteMs 2093ms 3063ms -31.7% +50%
totalWallClockMs 3200ms 3700ms -13.5% +50%

AC20-FZK-Haus.ifc

Baseline recorded 2026-07-01T20:30:59.972Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.

Metric Current Baseline Delta Threshold Status
firstBatchWaitMs 281ms 1075ms -73.9% +50%
firstVisibleGeometryMs 1583ms 1572ms +0.7% +50%
streamCompleteMs 1075ms 1980ms -45.7% +50%
spatialReadyMs 1119ms 915ms +22.3% +50%
metadataCompleteMs 1279ms 1392ms -8.1% +50%
totalWallClockMs 1700ms 3300ms -48.5% +50%

Refresh the baseline from a CI run: dispatch the Benchmark workflow with record_baseline, download the benchmark-baseline artifact, and commit baseline.json (see tests/benchmark/README.md).

@BIMvoice

Copy link
Copy Markdown
Collaborator Author

Superseded by #3394.

main moved under this PR: #3381 merged first and its design won — main keeps apps/viewer/src/hooks/useGridLines3D.ts and merges it with the symbolic grid buffer via merge-grid-line-channels.ts. This PR was built on deleting that hook, so it now reads CONFLICTING against main.

#3394 (branch fix-3368-grid-dedupe) rebuilds the same single-owner fix directly on post-#3381 main, removing both useGridLines3D and the now-empty mergeGridLineChannels.

For the record, #3368 is still not fixed on main: merge-grid-line-channels.ts's own doc comment says "Pending #3368's dedupe, which collapses this to a single owner." Until that lands, every grid axis still draws twice, and the unclipped copy still draws regardless of the active cut plane, so #862's grid section-clipping stays inert.

Not closing this — leaving it to the maintainer's judgment.

@louistrue

Copy link
Copy Markdown
Collaborator

Closing as superseded by #3394.

This carries two changesets, and grid-only-annotation-channel-camera-reframe.md is already on main: #3381 merged an hour ago as cb2ef0f. So half of this PR is a duplicate of something landed, which is why it now reads CONFLICTING.

The remaining half, the #3368 single-owner dedupe, is what #3394 does on the correct post-#3381 base. I am reviewing #3394 now.

No work lost. Closing #3376 for the same reason.

@louistrue louistrue closed this Aug 28, 2026
louistrue pushed a commit that referenced this pull request Aug 28, 2026
…#3394)

The viewport fed the 'grid' line-overlay channel from two independent
sources: useSymbolicAnnotations's grid buckets (section-clipped and
origin-shift-rebased) and useGridLines3D (the wasm parseGridLines API,
unclipped and rebased only by RTC), merged with mergeGridLineChannels.
Every IfcGridAxis drew twice, #862's grid section-clipping was inert
(the unclipped copy always drew the full grid), and a federated or
re-aligned model with a nonzero originShift could show the two copies
at different elevations.

Grid lines now draw only from useSymbolicAnnotations's 'grid' channel.
useGridLines3D and mergeGridLineChannels are removed as dead code.
parseGridLines/parseGridAxes stay as published @ifc-lite/geometry SDK
surface.

Supersedes #3376 and #3387, both stale against main after #3381
(#3359) changed which grid extractor main keeps and added the
annotation/grid channel split this rebuilds on top of.

Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants