- What: 新增 `apps/studio/src/orisys_studio/session_metadata.py`(273 行,纯函数 + 一个 `SessionFacts` 数据类,无 Qt、无状态),把 `StudioMainWindow` 里"记录必须自述"的那部分逻辑搬过去: `config_sha256` / `sdk_version` / `device_serial` / `capture_metadata` / `filter_metadata` / `filter_settings_from_prefs` / `video_fps` / `device_sample_rate` / `build_session_metadata`。 `app_window` 侧只留一行转发(保留 `_config_hash`/`_sdk_version`/`_device_serial`/`_capture_metadata`/ `_filter_metadata`/`_filter_settings`/`_video_fps`/`_device_sample_rate` 这些名字,因为测试与 `ui_check` 会直接调它们),`_build_session_metadata` 缩减为"把只有窗口能看见的事实装进 `SessionFacts`,然后交给模块"。`app_window.py` 3045 → 2901 行(-196/+51)。 - Why: 用户已同意分拆 `app_window.py`(当前 155 个方法、fan-out 36、唯一 fan-in=1 的中心),并选定四个 新模块的命名。A 步(会话/采集/记录)本身约 1100 行、40 处调用点,一次搬完风险高,所以按"两种变化原因 分开命名"的原则切成两步:**A1(本提交)= 无状态的事实与规则**,A2 = 带状态的 `SessionController` (worker 生命周期、phase、定时器、packet 扇出),后者将调用本模块组装记录块。 顺带把这几条规则从"只在记录流程里被间接覆盖"变成可单测:录制视频的 fps 对相机取**配置值**、对文件取 **实测值**、且永不写 0 fps;滤波器从**真正运行它们的 worker** 读回(旧 SDK 可能少应用),并把 `unsupported_by_sdk` 明确记下;任何元数据读取失败都只是空块,绝不让一次记录失败。 - Verification: 新增 `apps/studio/tests/test_session_metadata.py` **15 项**:配置内容哈希(含缺失/空路径)、 SDK 版本恒为字符串、设备序列号三种字段与嵌套 `info.SN`、capture 状态缺失/抛异常都返回空块、 滤波器回读与 `unsupported_by_sdk`、空/损坏 preferences 等于"什么都不滤"、 相机 vs 文件的 fps 规则与 0 fps 兜底、Nyquist 用的采样率来源与垃圾输入、完整 session 块(设备/版本/采集/ 标定/深度/约定/滤波/录像模式/video_config/3D 块逐项断言)、worker 消失且从未收到包时仍产出完整块、 3D 描述原样透传、三种录像模式如实记录。全量:shared+apps 同一次运行 **603 项 0 失败 15 跳过** (较上一提交 +15)、`ui_check` 587 项 0 失败、`locale_check` 0 缺失。 - Not in this change: 行为零改动(同一批函数、同一批默认值),也没有搬任何**状态**——`_latest_fps`/ `_latest_process_ms`/`_latest_capture_*`/`_record_error_count`/`_capture_checked`/`_dropped_reported` 仍在窗口里,A2 连同 worker 生命周期、phase、定时器与 packet 扇出一起搬; 回放(B)与视图/显示(C)两个控制器未开始。四个模块的名字已定: `SessionController` / `ReplayController`(引擎已改名 `ReplayEngine`)/ `ViewLayoutController` / `DisplayPrefsController`。
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.