Skip to content

feat(web): rover ui - #17

Merged
thomasyuill-livekit merged 8 commits into
mainfrom
ty/rover-web-ui
May 12, 2026
Merged

feat(web): rover ui #17
thomasyuill-livekit merged 8 commits into
mainfrom
ty/rover-web-ui

Conversation

@thomasyuill-livekit

@thomasyuill-livekit thomasyuill-livekit commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a second teleop page for the rover alongside the existing pan/tilt arm app, and refactors shared UI/connection plumbing.

Routing

  • / is now a landing page that shows a "Connect to Robot" and/or "Connect to Rover" button based on which env vars are set, or an empty state if neither is configured.
  • The previous components/app.tsx moved to app/robot/page-client.tsx, and a new app/rover/page-client.tsx mirror was added. Each wraps the SessionProvider in its own app/<robot>/page.tsx.

Rover protocol

  • lib/rover.ts — topic helpers (<rover_id>.imu, <rover_id>.control_cmd, <rover_id>.arducam), ImuPayload type, and controlCmdJson(throttle_rps, steering_rps) encoder clamped to ±1 rev/s.
  • use-imu subscribes to the rover IMU track (bufferSize: 256 to keep up with ~100 Hz frames).
  • use-rover-control-cmd-track publishes the joystick-driven throttle/steering data track and cleans up on mode change.
  • The rover's joystick maps (horizontal, vertical)(steering_rps, throttle_rps) with vertical-up as forward throttle.

Shared components & hooks

  • DebugPanel (components/debug-panel.tsx): table-based panel taking {label, value, unit, precision} rows, used by both robot and rover pages.
  • Dialog + VideoDialog (components/{dialog,video-dialog}.tsx): a video container that selects the right TrackReference (by participant + track name + source) with a Waiting for <label> placeholder. The rover page targets <rover_id>.arducam explicitly.
  • use-video-fit-screen (replaces use-video-fit-container): computes a width/height fit given an inset and the track's aspect ratio.
  • use-connection: extracted session.start()/end() lifecycle that surfaces failures via a sonner toast and redirects to /.
  • StatusBar accepts an actions prop so each page provides its own disconnect / fullscreen / debug buttons.

Errors & UX

  • session.start() failures show a sonner toast (shadcn add sonner) with a stable id to dedupe StrictMode double-mounts, then redirect to /.
  • Cleanup-order fix in page-client.tsxs: the connection lifecycle effect is declared first so its cleanup runs last. Subscription hooks (useImu, useGyro, control-cmd track) tear down while the PC manager is still alive — eliminates the "Cannot read properties of undefined (reading 'client')" and "PC manager is closed" crashes during navigation.

Env vars

Split into NEXT_PUBLIC_ROBOT_* and NEXT_PUBLIC_ROVER_* (identity / LiveKit URL / token). .env.example and README updated.

Test plan

  • With no env vars set, / shows the "No robots configured" empty state
  • With only NEXT_PUBLIC_ROBOT_* set, only the Robot button appears (and vice versa for rover)
  • With all six env vars set, both buttons appear
  • Connect to robot, acquire control, drive pan/tilt, toggle debug panel, disconnect cleanly (no console errors)
  • Connect to rover, acquire control, drive joystick (vertical = throttle, horizontal = steering), verify IMU values update in debug panel, disconnect cleanly
  • Set an invalid LIVEKIT_TOKEN and verify an error toast appears and the page redirects back to /
  • Verify no "Track name already taken", "readable stream is full", or "PC manager is closed" warnings in the console

🤖 Generated with Claude Code

@thomasyuill-livekit
thomasyuill-livekit force-pushed the ty/rover-web-ui branch 4 times, most recently from 1cbc394 to aa87955 Compare April 27, 2026 21:10
@thomasyuill-livekit
thomasyuill-livekit force-pushed the ty/rover-web-ui branch 2 times, most recently from 3093961 to 2866c02 Compare April 29, 2026 20:37
@thomasyuill-livekit thomasyuill-livekit self-assigned this May 1, 2026
@thomasyuill-livekit
thomasyuill-livekit marked this pull request as ready for review May 1, 2026 20:12
Comment thread web/src/app/robot/page-client.tsx

@stephen-derosa stephen-derosa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

skimmed through and tested locally, works as expected!

Passive effect cleanups fire in registration order. Calling useConnection()
first meant session.end() ran before useAcquireControl's release RPC,
leaving the controller seat held when navigating away from /robot or /rover
while in operate mode.

Move useConnection() to be the last hook in both page-clients so cleanups
fire as: releaseOperator → data-track teardown → session.end. Added a
doc-comment to useConnection capturing the ordering requirement.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@thomasyuill-livekit
thomasyuill-livekit merged commit 543ad4d into main May 12, 2026
14 of 15 checks passed
@thomasyuill-livekit
thomasyuill-livekit deleted the ty/rover-web-ui branch May 12, 2026 21:05
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