Skip to content

capture: add open capture protocol and viewer runtime - #713

Merged
Aymericr merged 14 commits into
mainfrom
feat/capture-session-scan-node
Aug 24, 2026
Merged

capture: add open capture protocol and viewer runtime#713
Aymericr merged 14 commits into
mainfrom
feat/capture-session-scan-node

Conversation

@Aymericr

@Aymericr Aymericr commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds the public capture-session foundation used by Pascal Capture and Community:

  • introduces @pascal-app/capture-protocol for extensible capture manifests, artifacts, coordinate frames, and live streams
  • introduces @pascal-app/capture-viewer for room models, point clouds, surface meshes, and animated device motion
  • extends scan nodes with capture-session references, transforms, and per-layer visibility
  • exposes capture layers as host-provided scene-tree children and fully unmounts hidden layers
  • adds runtime recovery/error hooks plus architecture documentation and release-workflow coverage for the new packages

How to test

  1. Run bun run check.
  2. Run bun run check-types && bun run test.
  3. Run bun run build and confirm the editor and package builds complete.
  4. In a host with a capture source, expand a scan node and toggle model, points, mesh, and device layers; hidden layers should disappear from rendering and hit testing.

Screenshots / screen recording

Validated through the Community/Capture integration on the companion private branch.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Medium Risk
Touches published package APIs, ScanNode schema, and the npm release workflow. Additive and well-tested, but a bad schema or publish-order change can break consumers and uninstallable releases.

Overview
Adds @pascal-app/capture-protocol and @pascal-app/capture-viewer so capture sessions are a host-owned extension of the viewer, not a private renderer or extra scene graph.

Protocol owns versioned manifests (v1 RoomPlan-style normalized to v2 streams), locators, packet headers, and CaptureSource (createHttpCaptureSource, PushCaptureSource). No React, Three, auth, or prescribed transport. Viewer runtime mounts CaptureRuntime as a Viewer child, portals layers into the scan node, unmounts hidden sessions/layers, and ships reference model, device-motion, point-cloud, and surface-mesh renderers plus custom stream renderers.

ScanNode now stores an optional captureSession locator, nullable mesh url, and an extensible layers visibility map. Legacy GLB scans still parse. Scan nodes become movable/rotatable/scalable; the editor can host extra tree children under scans, move/hide captures, and copy a project ID.

Release workflow can bump/publish the new packages, sync dependencies as well as peers, refresh the lockfile, and refuse a single-package publish if a required @pascal-app/* dep is not on npm.

Reviewed by Cursor Bugbot for commit 8dda820. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8dda820. Configure here.

? EMPTY_STREAM_EPOCHS
: retainLiveCaptureStreamValues(current.streamEpochs, event.descriptor),
}
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale live stream subscriptions

High Severity

captureSubscriptionStreamIds runs only against the initial descriptor before subscribe(). When a later descriptor event adds streams or flips them from pending to live, the existing subscription keeps the old streamIds filter, so new live streams never receive packets until something remounts the source.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8dda820. Configure here.

return inline.success
? parseDeviceTrajectoryPayload(inline.data)
: parseDeviceTrajectoryPackets(packets.map((packet) => packet.payload))
}, [layerKey, packets, stream.inline])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline motion blocks live updates

High Severity

For deviceMotion, a successful parse of stream.inline always wins over live packets. Point-cloud layers correctly prefer live data first, so device-motion streams that seed an inline trajectory and then stream samples stay frozen on the snapshot.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8dda820. Configure here.

const sourceState = useCaptureSource(scan.captureSession, resolveSource, {
maxPacketsPerStream,
streamFilter,
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layer toggle remounts session

Medium Severity

streamFilter is recreated whenever scan.layers changes and is listed in the useCaptureSource effect deps, so toggling one layer tears down the whole source: re-resolve, re-describe, clear packets, and remount every other visible layer.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8dda820. Configure here.

@Aymericr
Aymericr merged commit b8c0568 into main Aug 24, 2026
4 checks passed
@Aymericr
Aymericr deleted the feat/capture-session-scan-node branch August 24, 2026 04:00
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.

1 participant