design: narrow per-sex depth range in .ppda; fix light hold buttons (Tim)
@@ -372,3 +372,8 @@ The 2D previewer gets a mode picker: **Resultaat** (default; the real relit comp
372
372
## Decision 2026-11-07 (Tim t961u): 2D playback loops on whole frames
373
373
374
374
Cause found: the 2D preview wrapped its clock on the source clip duration, while the export holds `ceil(duration × fps)` frames. As a result, the last frame of the loop was shown for only `duration − (frames−1)/fps` instead of a full `1/fps`. For example, at 4 fps a clip of 1.1 s showed its fifth frame for only 0.1 s. Fix: playback loops over exactly `frames / fps` seconds, so every frame, including the last, is shown for an equal `1/fps`. A regression test covers a non-whole duration.
375
376
## Decision 2026-11-07 (Tim t963u/t964u): narrow fixed depth range per body; light hold-button fix
377
378
- **Depth range:** the exported depth no longer uses the global near 0.05 / far 40, where a body filled only about 1.3% of the 16-bit range. Each sex gets a **fixed, narrow depth interval around the orbit pivot**, derived deterministically from its fixed framing: `near = camera_distance − R`, `far = camera_distance + R`, where R is a half-depth derived from the framing height (default R = framing height × 0.5, at least 0.5 m). For the default 2.6 m framing, that is roughly 8.7 m to 11.3 m. All clips, frames, views and the equipment of that sex share exactly the same interval, so depth compositing stays consistent. Geometry outside the interval is clamped and reported as a diagnostic, never silently rescaled per frame. The encoding stays `distance = near + (gray/65535)·(far−near)`. near/far per sex are stored in `render.json`, the export contract and the **`.ppda` metadata** (`depth_near`, `depth_far`, `depth_encoding`), so a renderer can convert depth back to distance. Exports that use the old global range are recognized as such through their contract and are not mixed with exports that use the new range.
379
- **Light hold buttons:** holding Azimut ± / Elevatie ± in the 2D previewer stops after about 1 second. The likely cause is egui's click-sense, which stops reporting a press as `is_pointer_button_down_on` once it lasts longer than a click. Fix: drive holds from the raw pointer state (primary button down, press started on the button, pointer still over the button), so a hold lasts as long as it is held. Release, losing focus or the pointer leaving the window still stop it. Add a test that a hold of several seconds keeps rotating.
@@ -372,3 +372,8 @@ The 2D previewer gets a mode picker: **Resultaat** (default; the real relit comp372
## Decision 2026-11-07 (Tim t961u): 2D playback loops on whole frames372
## Decision 2026-11-07 (Tim t961u): 2D playback loops on whole frames373
373
374
Cause found: the 2D preview wrapped its clock on the source clip duration, while the export holds `ceil(duration × fps)` frames. As a result, the last frame of the loop was shown for only `duration − (frames−1)/fps` instead of a full `1/fps`. For example, at 4 fps a clip of 1.1 s showed its fifth frame for only 0.1 s. Fix: playback loops over exactly `frames / fps` seconds, so every frame, including the last, is shown for an equal `1/fps`. A regression test covers a non-whole duration.374
Cause found: the 2D preview wrapped its clock on the source clip duration, while the export holds `ceil(duration × fps)` frames. As a result, the last frame of the loop was shown for only `duration − (frames−1)/fps` instead of a full `1/fps`. For example, at 4 fps a clip of 1.1 s showed its fifth frame for only 0.1 s. Fix: playback loops over exactly `frames / fps` seconds, so every frame, including the last, is shown for an equal `1/fps`. A regression test covers a non-whole duration.375
376
## Decision 2026-11-07 (Tim t963u/t964u): narrow fixed depth range per body; light hold-button fix377
378
- **Depth range:** the exported depth no longer uses the global near 0.05 / far 40, where a body filled only about 1.3% of the 16-bit range. Each sex gets a **fixed, narrow depth interval around the orbit pivot**, derived deterministically from its fixed framing: `near = camera_distance − R`, `far = camera_distance + R`, where R is a half-depth derived from the framing height (default R = framing height × 0.5, at least 0.5 m). For the default 2.6 m framing, that is roughly 8.7 m to 11.3 m. All clips, frames, views and the equipment of that sex share exactly the same interval, so depth compositing stays consistent. Geometry outside the interval is clamped and reported as a diagnostic, never silently rescaled per frame. The encoding stays `distance = near + (gray/65535)·(far−near)`. near/far per sex are stored in `render.json`, the export contract and the **`.ppda` metadata** (`depth_near`, `depth_far`, `depth_encoding`), so a renderer can convert depth back to distance. Exports that use the old global range are recognized as such through their contract and are not mixed with exports that use the new range.379
- **Light hold buttons:** holding Azimut ± / Elevatie ± in the 2D previewer stops after about 1 second. The likely cause is egui's click-sense, which stops reporting a press as `is_pointer_button_down_on` once it lasts longer than a click. Fix: drive holds from the raw pointer state (primary button down, press started on the button, pointer still over the button), so a hold lasts as long as it is held. Release, losing focus or the pointer leaving the window still stop it. Add a test that a hold of several seconds keeps rotating.