examples/gui/ is a full Qt + open3d application (30 modules, 4,815 lines) rather than an example, and its proper home is the orisys-studio application. The move is planned but not started, so this records the plan rather than performing any of it. What the plan establishes, so the work does not have to be re-derived: - src/orisys/ imports no gui/viz/examples module, verified by AST rather than grep. The dependency is one-way, so the GUI can leave without a library change. The single apparent hit is `from .pipeline import ...` in src/orisys/__init__.py, which is the SDK's own module. - examples/viz/ is shared and cannot follow the GUI wholesale: it mixes open3d renderers with toolkit-independent helpers that examples/pipeline/service.py and tests/test_contact_arrow_scale.py depend on. It has to be split. - The real coupling is inverted and lives in the tests: tests/test_qt_viewer_backend.py imports examples/gui, and tests/conftest.py deliberately puts examples/ ahead of build/ because both define a package named `gui`. Removing the GUI means re-deriving that guard, not deleting it blindly. - UVMeshViewer and friends are in src/orisys/finger/__init__.__all__, so removing them is a breaking change to a released API and needs a deprecation release first. It must not be folded into a code move. - The `examples/` directory must keep existing in the packaged layout even after gui/ leaves it: src/orisys/configs.py anchors its run-root detection on a sibling examples/ folder. Also updates examples/README.md to say "lives here for now" instead of "is moving out", so nothing reads as work in progress. The GUI itself is untouched, and the only guidance offered is that new SDK work should not build on it.
8.1 KiB
kind
| kind |
|---|
| reference |
Plan: move the GUI out of the SDK into orisys-studio
Status: planned, then postponed (2026-09-30). Nothing here is in progress. This document records what would move, what would stay, and the one coupling that makes the move non-trivial, so that the work can be picked up without re-deriving it. It is a plan, not a description of current behaviour — everything described below is still in the SDK exactly as listed.
Why
examples/gui/ is not an example. It is a full Qt + open3d + pyqtgraph application — 30 modules,
4,815 lines — that ships inside the SDK wheel. The GUI belongs to the orisys-studio application,
which already exists for that purpose. Leaving it in the SDK means the SDK ships, versions and
installs an application it is not responsible for.
Current state
| Path | Modules | Lines | What it is |
|---|---|---|---|
examples/gui/ |
30 | 4,815 | The application: viewer2d/, viewer3d/, widgets/, app.py, log_config.py |
examples/viz/ |
11 | 2,298 | Shared drawing/rendering helpers — see the coupling below |
examples/pipeline/ |
6 | 577 | Sensor service, CSV recorder, profiling. SDK support code, not GUI |
Good news: the SDK core does not depend on the GUI
Verified by AST, not by grep: no module under src/orisys/ imports gui, viz, pipeline or
examples. The only match is src/orisys/__init__.py importing orisys.pipeline, which is the
SDK's own module. The dependency runs one way, so the GUI can leave without touching the library.
Two apparent hits are prose, not code: src/orisys/configs.py mentions examples/ in a docstring
about run-root layout, and export_sensors.py has an Examples:: docstring section. The
configs.py anchor is a real behavioural dependency to preserve — the run-root heuristic keys off
a sibling examples/ directory, so that directory must keep existing in the packaged layout even
after gui/ leaves it.
The coupling: viz/ is shared, so it cannot simply follow the GUI
examples/gui/ ──uses──▶ examples/viz/ ──uses──▶ orisys (SDK)
examples/pipeline/service.py ──uses──▶ examples/viz/
tests/test_contact_arrow_scale.py ──uses──▶ examples/viz/
examples/pipeline/service.py and a test depend on viz, and viz is a mix: mesh_camera.py,
contact_arrow.py, flow_arrow.py and offscreen_mesh.py are open3d rendering helpers, while
render_2d.py, recording.py, signal_filters.py and force_charts.py are toolkit-independent.
Moving viz/ wholesale would break examples/pipeline/. It has to be split, not moved.
The real coupling is in the tests, and it is inverted
tests/test_qt_viewer_backend.py imports examples/gui directly, and tests/conftest.py inserts
EXAMPLES_ROOT into sys.path with a guard whose stated reason is that examples/gui must win
over build/gui, because both are packages named gui. So the SDK's test suite currently
depends on the GUI application being present and on a name-resolution guard existing for it.
This is the inversion to fix: the SDK must not depend on the GUI.
Two related facts:
examples/gui/contains committed__pycache__directories (adapter.cpython-310.pyc,cpython-313.pyc, …) — build artefacts tracked alongside source.tests/test_wheel_contents.pyandtests/test_pyproject.pyassert on what the wheel bundles, so they will need updating when thegui/**/*.pybundle pattern goes.
What moves, what stays
Moves to orisys-studio:
examples/gui/**— the whole application, as the single home for GUI code.examples/finger_pipeline_3dview.py— a 91-line launcher for the dashboard; its only purpose is to start the GUI, so it belongs with the GUI.- The open3d rendering half of
examples/viz/:contact_arrow.py,flow_arrow.py,mesh_camera.py,offscreen_mesh.py, plus the open3d-dependent__init__re-exports. tests/test_qt_viewer_backend.py— it tests the GUI, so it moves with the GUI.
Stays in the SDK:
examples/pipeline/— SDK support code (sensor service, CSV recording, profiling).examples/viz/toolkit-independent half:render_2d.py,recording.py,signal_filters.py,force_charts.py— needed byexamples/pipeline/service.py.examples/plot_data.py— uses pyqtgraph for force charts only; 96 lines. Decide separately whether it follows the GUI; it is the one remaining example with a Qt dependency after the move.src/orisys/finger/viewer.py(UVMeshViewer) — see the deprecation note below.
The public-API problem, handled separately
UVMeshViewer, init_uv_mesh_viewer and update_uv_mesh_viewer are exported in
src/orisys/finger/__init__.py's __all__. Removing them is a breaking change to a released
API, so it must not be bundled into a code move:
- Release with them present and documented
DeprecationWarnings emitted on construction. - Remove them at the next major version, with the release notes naming the replacement.
The audit (docs/api-audit.md) already lists UVMeshViewer among the surface that is used by
examples and absent from the reference.
Sequence, lowest risk first
| # | Step | Risk | Notes |
|---|---|---|---|
| 1 | Add docs/plan-gui-extraction.md (this file) |
none | Done |
| 2 | Delete the committed __pycache__ under examples/gui/ and add it to .gitignore |
none | Pure hygiene; ship independently |
| 3 | Tag the SDK at the commit whose examples/gui is known-good, so the studio move has a pinned source |
none | A tag, not a submodule or subtree |
| 4 | In orisys-studio: import examples/gui + the open3d half of viz as its own provenance-stated change, reconciling against its existing viewer code |
medium | The studio repo already has viewer code; this is a merge decision, not a copy |
| 5 | In the SDK: move tests/test_qt_viewer_backend.py out, and simplify the conftest.py guard |
medium | The guard exists for gui; with gui gone, EXAMPLES_ROOT may still be needed for viz/pipeline. Re-derive, do not guess |
| 6 | In the SDK: retire examples/gui/, finger_pipeline_3dview.py, and the moved viz modules |
low once 4 and 5 land | |
| 7 | Update the bundle patterns in pyproject.toml (drop gui/**/*.py, adjust viz/**) and the wheel tests |
low | test_wheel_contents.py, test_pyproject.py |
| 8 | Update examples/README.md and the SDK reference to stop pointing at the dashboard |
low | The README already says the GUI is moving |
| 9 | Deprecate UVMeshViewer in a release; remove at the next major |
low | Separate release cycle |
Steps 2 and 3 are safe to do immediately and independently. Steps 4–5 are the actual move and need both repositories. Nothing here requires a library behaviour change, which is what makes the move tractable.
Open questions for the studio side
- Merge or adopt?
orisys-studioalready has its own viewer. If its code is the descendant of this one, take the SDK copy only where it is ahead; otherwise choose one and delete the other. This must be decided before step 4, because the answer changes what gets imported. - Do the SDK's 2D and 3D viewers need to keep working headless for CI?
examples/vizcontains offscreen rendering used to produce evidence images. If any SDK or sensor-design workflow depends on that, the offscreen half may need to stay reachable from the SDK even after the app moves. - Does
plot_data.pyfollow the GUI? It is an example, not an application, and it is the last Qt-dependent file inexamples/.
Acceptance criteria
src/orisys/still imports nogui/viz/examplesmodule (re-run the AST check).- The SDK test suite passes with
examples/gui/absent. - No module named
guiships in the wheel;test_wheel_contents.pyasserts it. examples/pipeline/service.pyandtests/test_contact_arrow_scale.pystill import theirvizdependencies.UVMeshVieweris either deprecated-but-present or removed by an explicit major-version decision — never dropped silently in a move.- The
examples/sibling directory still exists in the packaged layout, becauseconfigs.py's run-root anchor depends on it.