ykcheungab 92da51217c add session browsing, calibration diagnostics and the 2D layout preset
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.
2026-09-13 13:34:26 +08:00
2026-09-12 14:03:00 +08:00
2026-09-12 14:03:00 +08:00

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, logging
  • apps/studio/config/ — locales, default prefs, editable sensors/ copies
  • apps/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 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%