Commit Graph

22 Commits

Author SHA1 Message Date
L'électron rare 1c07211dd8 feat(viz): perf-safe keys, frozen pinch tuning
CI build oscope-of / build-check (push) Has been cancelled
Live session outcomes: (1) pinch thresholds validated for inner
fingers frozen as defaults (ratio_on 0.50, margin 0.05, ext_min 1);
(2) panel frames + X/Y gauges now permanent (no early-return when
nothing is detected); (3) wxcvbn source-bundle shortcuts gated off by
default (VIZ_SOURCE_KEYS=1 re-enables) — a stray key mid-performance
switched the audio scene.
2026-07-02 16:44:28 +02:00
L'électron rare 6fe98c6b00 feat(viz): continuous frame quality intensity
CI build oscope-of / build-check (push) Has been cancelled
Add gesture_quality() pure helper (hand_display.py) that maps a slot's
plausibility, facing, and proximity to a score in [0,1]. Renderer uses
it to modulate panel frame brightness (0.25+0.75*q) and stroke count
(1..3 passes at q≥0, ≥0.5, ≥0.85 / status==3). Status still drives
hue (pid 7/8/9). New gesture_slot_quality field in State written
alongside gesture_slot_status each tick.

Add gauge_segments() for X/Y position gauges around each panel: a
horizontal rail below and a vertical rail on the outer side, each with
a bold two-tick notch at the hand's normalised cx/cy (mirror-aware for
X). Dim rails (conf 0.25) when slot absent. Renderer reads hand_feats
L/R directly from state.

11 new tests (6 gesture_quality + 5 gauge_segments); suite 430 passed.
2026-07-02 16:34:08 +02:00
L'électron rare 32a722e281 feat(viz): gesture status panel indicators
CI build oscope-of / build-check (push) Has been cancelled
Add gesture_slot_status [0..3] to State (absent/detected/armed/engaged).
PinchDetector.engaged_slots() exposes per-slot pinch state. Publisher
writes status after each tick via _update_gesture_slot_status().
Renderer draws panel frame always: dim (pid7 conf=0.3) when absent,
normal (pid7) detected, pid8 armed, pid9 double-stroke engaged.
2026-07-02 15:16:14 +02:00
L'électron rare ef1d557eff feat(viz): rotate iphone 2d points, hide fingers
CI build oscope-of / build-check (push) Has been cancelled
Portrait mode validated live: VIDEO_ROTATE now also rotates the
iPhone 2D landmarks (skeleton2D + Vision hands) at the decode layer so
overlays/panels/gestures stay aligned with the rotated video. ARKit
per-finger joints are masked from the wireframe (unreliable 2D, seen
as false hands); the display shows the filtered Vision hands instead.
2026-07-02 14:36:57 +02:00
L'électron rare b85a9c93a9 fix(viz): no body mesh when arkit is the source
CI build oscope-of / build-check (push) Has been cancelled
The body-mesh triangles (solid cyan blob reported live) were the one
surface no filter covered: under iphone-usb persons_body is the ARKit
conversion with c=1.0, so garbage/stale joints painted full triangles.
Skip BODY_TRIANGLES whenever the ARKit topology is present (webcam
MediaPipe path unchanged); the body stays the freshness-gated ARKit
wireframe.
2026-07-02 14:26:03 +02:00
L'électron rare 0126fc97a8 fix(viz): wire arkit-full + osc port via config
renderer.py: read ARKIT_FULL_SKELETON via VizConfig at
initWithState_ instead of module-level os.environ; store as
self._arkit_full, use getattr fallback for __new__ test bypass.

main.py: pass cfg.iphone_osc_port to IphoneOSCListener
instead of hardcoded 57128; log actual port.

hand_slots.py: import _finite/_coord/_clamp from hand_features
at module level (acyclic: hand_features imports hand_slots only
lazily inside step()); delete the duplicate copies.
2026-07-02 14:23:47 +02:00
L'électron rare 4e33a03e1b feat(viz): persistence grace frames 2026-07-02 11:46:01 +02:00
L'électron rare e7ce016688 feat(viz): central VizConfig from env
Add data_only_viz/config.py: frozen dataclass VizConfig with typed
fields for all 56 env reads in data_only_viz. from_env() reads
os.environ at call time — no module-level singleton, test-compat.

Migrate action_head_pub._init_finger_piano and renderer.initWithState_
to consume VizConfig. Keep renderer.py ARKIT_FULL module-level (test
uses MetalRenderer.__new__ without calling initWithState_).

HAND_SWAP_LR default changed False (was True): Vision chirality
validated correct live 2026-07-02; swap knob now defaults off.
2026-07-02 11:21:55 +02:00
L'électron rare 32cdfa0d3e fix(pose): swap chirality only, default on
CI build oscope-of / build-check (push) Has been cancelled
User-confirmed live: ARBodyTracker Vision chirality arrives inverted
vs the mirrored view. HAND_SWAP_LR now inverts the chirality mapping
inside route_hands (cx fallback untouched, it is already screen
relative) and defaults to 1. Also: HandPersistenceGate greedy-match
limitation documented + malformed-entry guard (review follow-ups).
2026-07-02 11:00:25 +02:00
L'électron rare 366d916e9d refactor(pose): detectors consume routed slots
Convert all four consumers to accept pre-routed [L|None, R|None]:
- finger_strike: remove order_hands_by_cx + _slot_hands; step()
  iterates enumerate(slotted), None slot resets state / synthesizes
  release edges in-place.
- hand_features: step(hands, chirality=None) delegates to route_hands;
  speed buffer indexed by slot, not cx order.
- action_head_pub: _pick_hands returns chirality; _emit_fingers/
  _emit_pinch call route_hands with HAND_SWAP_LR/HAND_NEAR_MIN;
  _emit_hands plumbs chirality to HandFeatureExtractor.
- renderer: panels block replaced with route_hands call; persistence
  gate + hand_plausible mask applied before routing so a ghost hand
  cannot steal a slot; HAND_SWAP_LR read at init.
Test updates: [hand, None] slot lists in test_finger_strike;
_hand() fixture in test_action_head_finger_emit gains realistic size
so near_min=0.10 gate passes.
2026-07-02 10:55:32 +02:00
L'électron rare 5bfc63f86d feat(viz): hand persistence gate + conf knobs
HandPersistenceGate (min_frames=3, radius=0.15) suppresses ghost
hands that flash for fewer than min_frames consecutive frames.
Gate is called once per frame in the renderer on persons_hands;
result filters both the video overlay loop and the side panels.

hand_plausible now rejects wrists outside [-0.1, 1.1] (out-of-frame
ghost anchor check).  panel_segments gains a conf_min param.

Env knobs read at renderer init (single parse, no per-frame cost):
  HAND_CONF_MIN (default 0.45, raised from 0.3)
  HAND_PERSIST_FRAMES (default 3)
  ARKIT_BONE_MAX (default 0.5, passed to arkit_segments)

New tests: 12 gate tests + 4 wrist-bounds tests.
2026-07-02 10:27:58 +02:00
L'électron rare 48b04084fa fix(viz): gate arkit overlay on 2d freshness
persons_arkit_2d_t was written by IphoneUSBSource but never
read. A USB drop left the frozen skeleton on screen indefinitely.

- Add arkit_2d_fresh(ts_by_pid, now, max_age=1.0) pure helper
  in hand_display.py (8 TDD tests, all green)
- renderer._update_skeleton: use_arkit now requires at least one
  pid younger than 1 s (replaces bool check)
- Per-pid freshness gate in draw loop skips stale pids
2026-07-02 10:13:05 +02:00
L'électron rare 0a2865e136 feat(viz): left/right hand front-view panels
CI build oscope-of / build-check (push) Has been cancelled
Add panel_rect/panel_segments/panel_frame helpers to hand_display.py
(PANEL_SIDE=0.30, PANEL_MARGIN=0.02, PANEL_INNER=0.10). Segments use
uniform pixel-space scale so the hand aspect ratio is preserved
regardless of view aspect. mirror=True flips X within the panel.

In renderer._update_skeleton add push_panel (no mirror flip) and a
panels block before the segs==0 epilogue: routes persons_hands to
left/right panel via chirality list when aligned, screen-cx fallback
otherwise. Draws frame (pid 7) + wireframe (pid 5 left / 6 right).
Runs on every path including use_arkit. Guards: _mp_bones None, empty
hands, misaligned chirality, height==0.

26 tests pass (10 new for panel helpers).
2026-07-02 09:56:08 +02:00
L'électron rare ef719e76f3 feat(viz): filter hand overlay artifacts
Add hand_display.py with hand_plausible / segment_ok / hand_size pure
helpers; wire into both skeleton hands loops (plausibility gate +
per-segment confidence+spike filter + real min(A.c,B.c) push); remove
filled mesh triangles for hands from _update_mesh (HAND_TRIANGLES block
deleted).
2026-07-02 09:42:51 +02:00
clement 24ce960992 fix(iphone): mirror skeleton overlay to video 2026-06-30 22:40:31 +02:00
clement 08b7c72e49 feat(iphone): render full arkit body skeleton 2026-06-30 22:14:35 +02:00
L'électron rare 886b90b84d feat(viz): pack hand features into uniforms
UNIFORM_FLOATS 20→24 (96 bytes, 16-byte aligned). Added hand_height,
hand_openness, hand_speed, hand_dist at slots 19-22 derived from
state.hand_feats. state.py gets hand_feats field; action_head_pub
writes it after each HandFeatureExtractor.step(). Existing 14 uniforms
and wrist xy (15-18) unchanged.
2026-06-26 10:19:10 +02:00
L'électron rare 934bf99ba7 chore(viz): address final review nits
- renderer: replace magic literal 10 with 2 * SKEL_VERT_FLOATS (x2)
- renderer: remove dead MESH_MAX_TRIS outer guard; add per-person break
  after body/face/hand loops when MESH_MAX_VERTS reached
- test: modernize __builtins__ pattern to use builtins module directly
2026-05-13 12:43:27 +02:00
L'électron rare 498ca2be70 fix(renderer): cap mesh writes at MESH_MAX_VERTS 2026-05-13 12:23:38 +02:00
L'électron rare d033282aa3 perf(renderer): preallocate mesh cpu buffer 2026-05-13 12:19:07 +02:00
L'électron rare 20acbeb704 perf(renderer): preallocate skeleton cpu buffer
Replace per-frame floats list + struct.pack in _update_skeleton
with a preallocated numpy.float32 staging buffer (_skel_cpu_buf),
eliminating the dynamic allocation on every draw call (~60/s).
2026-05-13 11:58:32 +02:00
L'électron rare 0497a8951a feat(viz): python+metal data-only visualizer
New standalone visualizer: OSC listener, pose bridge,
Apple Vision / CoreML / YOLO pose backends, Euro filter,
fine analysis, mesh topology, holistic renderer.
Metal shader (scene.metal) for GPU-accelerated drawing.
2026-05-13 09:34:01 +02:00