Phase 2 of the review: browse the whole session instead of only the rolling window, diagnose a calibration from the recorded points, and provide the reviewed two-panel layout. What - SessionStore gains extent(), visible(t0, t1, max_points) and statistics(t0, t1, unit). visible() walks only the blocks that overlap the window and decimates by taking each bucket's minimum and maximum, so a spike survives decimation and browsing a long session does not copy all of it. - ForcePlotsPanel gains follow/browse modes, a whole-session overview strip with the current window, pan and wheel zoom, a rubber-band zoom toggle, a shared time cursor across all three channels, and a selection readout (duration, valid samples, per-axis peak/mean/std). - CalibrationPoint records a bounded per-axis trace, an excluded flag, a validation flag and its fit residual. CalibrationRecorder gains set_excluded/set_validation/fit; the fit is a least-squares line over the non-excluded, non-validation points with per-point residuals and an independent validation error. - The calibration table becomes the reviewed diagnostic view (reference load | FN | FX | FY | stability | state) with the residual shown next to the loaded axis, plus exclude/restore and mark-validation actions and a fit summary line. Double clicking a row opens the point's three-axis trace. - Add a layout preset: free layout or 2D mode (depth map on the left, force charts on the right, calibration folded away), persisted in preferences. Why - Browsing is a display pause, not a capture pause: the record channel keeps running while the charts show an older window. - Excluding a point removes it from the fit and from the exported calibration but keeps it on record, so the evidence for the decision is not destroyed. - The non-loaded axes are recorded but never given a reference load: their true load is unknown during a single-axis calibration, so it stays empty. Verification - shared/tests/test_record_channel.py grows to 18 cases, covering extent, peak-preserving decimation, windowed reads, inverted/empty windows, unit-aware statistics and the time origin. - tools/ui_check.py gains "session browsing" and "layout preset" sections (223 checks, 0 failures overall). - apps/studio/tests/test_ui_smoke.py covers the same invariants. Not in this change: synchronised playback of video, depth and curves. It needs a decision on how depth is stored for replay (per-frame PNG, reduced-rate PNG, or offline recomputation); the cursor plumbing (cursor_moved / set_cursor) is already in place for it.
orisys-app
Desktop applications that consume the Orisys SDK.
| App | Status |
|---|---|
apps/studio |
Scaffold shell (theme / locale / prefs / logging) |
apps/internal |
Stub for future calibration & automated testing |
Layout
shared/— common paths, prefs, theme, i18n, loggingapps/studio/config/— locales, default prefs, editablesensors/copiesapps/studio/outputs/— generated logs and calibration exports (gitignored)build/— Windows PyInstaller packaging (build/studio/build.ps1)
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.
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 declaresREQUIRES_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.