ykcheungab 33a3d8c9c2 add the Studio UI layout contract
Studio had a colour contract with a mechanical audit but no layout equivalent,
which is where the recurring visual defects live: window flashing, the label
under the 3D view, the platform-not-moving report, and the 2D/3D sync work all
passed a 3,408-assertion tool suite because that suite asserts widget state, not
the visible result.
apps/studio/docs/ui-layout.md states the contract: ViewLayoutController owns the
top-level arrangement and each panel owns its internal layout; every path that
changes the view must go through apply_preset(); each view's pane priority and
degradation order; and which numeric geometry arguments are legitimate (a 1px
separator is not the same defect as a magic width on a flexible panel).
It also records the one transition that is broken today.
on_cal_panel_toggled(False) sets view_preset = "live" directly instead of
calling apply_preset("live"), so the replay -> calibration -> calibration-off
sequence leaves the rail on the replay source, the run button in playback role,
and the previous view's splitter sizes. The live branch does call apply_preset,
which is what makes the asymmetry easy to miss.
Three claimed enforcement gaps are stated so the contract is not mistaken for
something already enforced: audit_palette reads theme JSON and never scans
source for the hex literals ui-palette.md forbids; the containment test compares
width and height without x/y, so a shifted or overlapping child passes; and the
GL pixel suite skips invisibly without a real context.
Verified: doc_lint default and --all both exit 0; the new document is registered
in the workspace inventory (63 collected, 63 inventoried, 0 missing) and linked
from README.md beside the palette reference. No source file changed.
2026-10-01 11:59:00 +08:00
2026-10-01 11:59:00 +08:00
2026-09-25 17:46:37 +08:00
2026-09-30 21:22:41 +08:00
2026-09-20 21:15:39 +08:00
2026-10-01 11:59:00 +08:00
2026-09-27 19:20:43 +08:00

orisys-app

Desktop applications that consume the Orisys SDK.

App Status Qt binding
apps/studio The customer-facing shell (theme / locale / prefs / logging, acquisition, 3D) PySide6
apps/autocal Internal 5-axis calibration platform control PySide6
apps/internal Stub, superseded by apps/autocal —

Both shipped apps are PySide6 — Qt's LGPLv3 binding. PyQt5's free option is GPLv3-or-commercial, which is why the studio was migrated off it: a closed-source product would otherwise need a licence purchase. The rule is enforced, not just documented: neither app may import PyQt5/PyQt6/PySide2, and shared/ (used by both) may import PySide6 and nothing else. See apps/studio/tests/test_binding_purity.py and apps/autocal/tests/test_binding_purity.py.

One practical consequence: pyqtgraph binds to whichever toolkit it imports first, so a development environment that still has PyQt5 installed can build plots from the wrong binding. orisys_studio.main sets PYQTGRAPH_QT_LIB=PySide6 before anything imports it, and the purity test asserts that importing the app pulls in no other binding.

Layout

  • shared/ — common paths, prefs, theme, i18n, logging, and the ZMotion client
  • shared/resources/zmotion/ — vendored ZMotion runtime DLLs (internal use only)
  • apps/studio/config/ — locales, default prefs, editable sensors/ copies
  • apps/studio/outputs/ — generated logs and calibration exports (gitignored)
  • apps/autocal/ — internal platform control; see apps/autocal/README.md
  • build/ — Windows PyInstaller packaging (build/studio/build.ps1)

Selecting which app's paths resolve

orisys_app_shared.paths reads ORISYS_APP_ID (an apps/ directory name) to decide which product's config/, preference.json and outputs/ a process owns. Each app's launcher sets it before importing the shared package; when it is unset the studio is assumed, which keeps existing callers working unchanged. A named app whose config/ is missing raises rather than silently resolving another product's tree.

Run (studio shell)

cd D:\repo\orisys-app
python -m pip install -e .\shared -e .\apps\studio
python .\apps\studio\run.py

Or without install:

$env:PYTHONPATH = "D:\repo\orisys-app\shared\src;D:\repo\orisys-app\apps\studio\src"
python D:\repo\orisys-app\apps\studio\run.py

Local orisys SDK

orisys_app_shared.force imports orisys.calibration at module scope, so the studio app cannot start against an SDK build that predates that module (the published 0.5.2 wheel does not include it). When working from a repo checkout, install the SDK from source instead of from an index:

python -m pip install .\..\orisys-sdk          # same checkout that built this app

If a pip build is blocked by the environment, the equivalent manual install is to copy orisys-sdk/src/orisys/**/*.py over site-packages/orisys/ and delete the stale __init__.cp310-win_amd64.pyd (an extension module shadows the package __init__.py, which hides sibling modules such as calibration.py).

Verifying UI changes

Both tools render the real main window with the offscreen Qt platform — no display, camera or sensor hardware required:

python .\apps\studio\tools\ui_check.py                      # layout/theme assertions
python .\apps\studio\tools\ui_snapshot.py --theme light --demo `
    --sensor finger --panels cal,3d --size 1600x900 --out shot.png

ui_check.py needs only the runtime dependencies. The pytest suite in shared/tests and apps/studio/tests covers the same ground plus locale and preference-schema parity:

pip install pytest
python -m pytest

On Windows the offscreen platform finds no fonts unless QT_QPA_FONTDIR points at C:\Windows\Fonts; both tools set it automatically.

ui_check.py also runs the palette rules (WCAG contrast, colour separation, ramp monotonicity) that guard the brand tokens; see apps/studio/docs/ui-palette.md for the colour system, its relationship to the UI design spec, and every deliberate deviation from it.

Layout follows apps/studio/docs/ui-layout.md: which controller owns the arrangement, the fixed effect set every view change must apply, each view's pane priority and degradation order, when a numeric geometry argument is legitimate, and which of these rules are not yet mechanically enforced.

ui_check.py includes a record channel section as well; see apps/studio/docs/record-channel.md for why recording and calibration sampling no longer hang off the UI refresh timer, and for the data-reliability fixes that came with it.

Branding

Window / EXE icon: shared/resources/branding/logo.png
Top bar / About: shared/resources/branding/logo_topbar.png

Dark mode is the default. Logos currently sit on a black tile; a transparent (or light) variant may be needed for polished light mode later.

Versioning

  • Studio app version (orisys_studio.__version__) — shown in Help → About and used for releases.
  • Shared package version (orisys_app_shared.__version__) — internal library version.
  • Shared API (orisys_app_shared.API_VERSION) — compatibility tag. Studio declares REQUIRES_SHARED_API; startup logs a warning on mismatch.

Deferred

Run/Stop pipeline, arrow/force plots, units, calibration capture, Open3D finger mesh, sync-from-wheel for config/sensors, PyInstaller packaging, and the internal app.

S
Description
No description provided
Readme 68 MiB
Languages
Python 84.8%
HTML 11.7%
C 2.6%
PowerShell 0.8%
FreeBASIC 0.1%