Redesigned steering interface and session controls

#2
by imstevenpmwork HF Staff - opened

Redesigns the Space's interface in the LeRobot brand and fixes session-control bugs. Robot physics, policy inference, the browser renderer, and the exported scene assets are unchanged.

Screenshots

Local preview: static scene, simulated session states.

Interface

  • New layout, moved from app.py into ui.py and shared with the local preview.
  • LeRobot look: the official logo (README banner, scaled, tracked with Git LFS), the logo's orange #FF9D00 and yellow #FFD21E, black outlines with hard shadows, and Hugging Face's typefaces (Source Sans 3, IBM Plex Mono). The hero gets the full treatment; the workspace stays calm, with yellow marking what is active. Light mode is forced.
  • Phone layout uses the full width. Gradio prefixes custom selectors, which had silently disabled the phone padding rule and left 236 px of content on a 390 px screen.
  • A slim status bar above the simulated view shows the state, the current instruction, the goal or note, the timer, and an inline Stop button. It keeps a fixed height, so the view never shifts.
  • The skill library highlights the active trained instruction.
  • Task reasoning and Scene Q&A are separate conversations.
  • Example goals fill the goal box; Steer sends them.
  • The top and bottom LeRobot links share one button style. Gradio's own footer link uses the class .built-with too, so it had been restyled as the prominent button.
  • Gradio's per-output progress lines are hidden for the streaming session event; the status bar already shows progress.

Behavior fixes

  • Questions never start a session. LeRobot's RolloutController.ask() only answers during a run segment, so a question used to start the robot on the scene's default instruction (task 8, "put the bowl on the plate"). The Ask box is now disabled between sessions, and send() refuses a question that arrives without one.
  • No more blanked controls. For a command that doesn't start a session, run() now yields one gr.skip(). A generator that yields nothing makes Gradio set every output to None, which blanked the status bar and the skill-button labels after an empty submit, and briefly after every follow-up command during a session.
  • If a session fails, the controls reset to an error state.

API changes

  • The example_0โ€“example_3 endpoints are removed; examples now run in the browser only. steer, ask, stop, and task_* are unchanged.
  • The session event has one more output (the question box).

Development

  • scripts/preview.py runs the production UI on a laptop, with mock sessions and no models or GPU.
  • make setup, make check, make preview. make check runs compilation, Ruff (Pyflakes rules), a JS syntax check, the GLB/camera asset contract, 16 unit tests, and a dependency check.
  • DEVELOPMENT.md covers local setup, full-backend requirements, and a code walkthrough.

Testing

  • make check passes (16 tests).
  • Exercised in the local preview at desktop and phone widths: status bar states, Stop, example goals, Ask gating, typing while session updates stream, and empty submits.
  • Not yet run on the full backend (Linux, CUDA, planner). The app.py changes are small (the send() question guard, the run() skip, the extra output, and the light-theme hook), but this needs a GPU run before merging. After pushing, check that the fonts and logo load on the Space itself.

๐Ÿค– Generated with Claude Code

imstevenpmwork changed pull request status to open
imstevenpmwork changed pull request status to merged

Sign up or log in to comment