Commit Graph

790 Commits

Author SHA1 Message Date
clement 67f347e705 feat(iphone): emit skeleton topology on connect 2026-06-30 21:58:35 +02:00
clement 6f941c52cb feat(wire): topology payload + tag 2026-06-30 21:49:37 +02:00
clement b2dab64aae fix(iphone): sendable hand buffer handoff 2026-06-30 21:47:29 +02:00
clement bb90820988 docs(iphone): phase 1 faithful skeleton plan 2026-06-30 21:45:31 +02:00
clement 5adb8abdc8 docs(iphone): SOTA 2026 refonte design spec 2026-06-30 21:33:45 +02:00
L'électron rare 40c21a246c perf(iphone): drop face vision + RealityKit view
CI build oscope-of / build-check (push) Has been cancelled
ARKit-only-body mode no longer consumes face: the Mac dropped face
entirely (face=0, /pose/mouth gone), so VNDetectFaceLandmarksRequest
and the .face USB frames were pure wasted per-frame compute. Drop the
face request and its send.

The on-device ARView (RealityKit) rendered a black background behind
the SwiftUI skeleton overlay -- it never showed the camera -- so it
only spun up the RealityKit AR render pipeline (the engine:rematerial
console spam) to draw black. Remove the ARView; the screen stays
black + skeleton overlay, identical UX, minus the GPU/thermal cost.

Video (HEVC) and hands are kept: the Mac uses the iPhone video as the
visualizer backdrop and Vision hands drive pinch/fist gestures.
2026-06-30 20:31:10 +02:00
L'électron rare 2b7b4a81c6 docs(data-only-viz): arkit body source mode
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 20:14:17 +02:00
L'électron rare ef99c32cac fix(iphone): explicit SIMD2<Float> for skeleton2D
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 19:42:22 +02:00
L'électron rare 27d5ce9d98 feat(iphone): send 2D projected skeleton
Add camera: ARCamera param to publishUSB and thread frame.camera
through from the session delegate. After the existing .skeleton
send, project all 91 joints to viewport 2D, normalize to [0,1],
and send as Skeleton2DPayload / FrameTag.skeleton2D (tag 6).
2026-06-30 19:41:02 +02:00
L'électron rare 33de64f599 chore(launcher): drop arkit_fuse, arkit is source 2026-06-30 19:32:04 +02:00
L'électron rare 5a9a6338a0 feat(pose): arkit body, skip mediapipe pose+face
Under --iphone-usb, skip all three MediaPipe detectors
(pose, face, hand) and rebuild the MP-33 body from
state.persons_arkit_{2d,joints} via new arkit_body_2d /
arkit_body_3d builders. Add head anchor (ARKIT_HEAD_IDX=51,
needs live verify) as MP33 slot 0. Webcam path unchanged.
2026-06-30 19:29:20 +02:00
L'électron rare c49de5c500 feat(pose): decode iphone 2D skeleton
Add TAG_SKELETON2D=6, SKEL2D_BYTES=819, decode_skeleton2D() to
iphone_usb_bridge.py; handler in IphoneUSBSource writing
persons_arkit_2d / persons_arkit_2d_t to state; new state fields
in State dataclass. TDD: test_arkit_body.py (round-trip + wrong
length → None). Import check verified.
2026-06-30 19:19:54 +02:00
L'électron rare 660d493ad6 feat(wire): skeleton2D frame payload
Add FrameTag.skeleton2D (raw 6) and Skeleton2DPayload for
2D-projected ARKit joints: 91×SIMD2<Float> + 91 valid bytes,
big-endian wire format mirroring SkeletonPayload style.

Note: raw value is 6 (not 5 as drafted) because face=5 is taken.
2026-06-30 19:15:16 +02:00
L'électron rare bd9f9fca29 docs: arkit-only body position plan 2026-06-30 18:47:10 +02:00
L'électron rare 7037ebcd82 docs: arkit-only body position spec 2026-06-30 18:43:20 +02:00
L'électron rare 02f7ad42b2 feat(pose): all-fingers-curled fist metric 2026-06-30 18:22:38 +02:00
L'électron rare 16cd6a3655 fix(pose): pinch closest-finger-wins + margin
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 18:06:34 +02:00
L'électron rare 4c0794a3db fix(pose): iphone-only hands, cut mac mediapipe
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 17:32:55 +02:00
L'électron rare 9111da4a5c feat(control): fist sensitivity + indicators
CI build oscope-of / build-check (push) Has been cancelled
Add matFistThresh state (default 0.15) with localStorage persistence.
Wire a "Sensibilite poing" slider in Reglages, synced via fisthresh.
Add two fist indicator rows in #morceau-fists driven by fistprogress.
2026-06-30 16:54:54 +02:00
L'électron rare 65c06ed4c6 feat(presets): emit default fist threshold
Context: Task 1 wired fistThresh into the SC matrix engine (default
0.15); the generator was not yet emitting this field, so every
.matrix was missing it and the engine fell back to its hardcoded
default.

Approach: TDD — added a failing check to test_global_actions.py,
then edited to_sc so pinchHoldMs ends with a comma and fistThresh
0.15 follows as the last field before the closing paren.
Regenerated 84 presets twice for determinism.

Changes:
- generate_presets.py: pinchHoldMs now ends with comma; fistThresh
  0.15 emitted as the final key in every preset's SC Event literal
- test_global_actions.py: EXPECT_FTH block checks to_sc output and
  all 84 on-disk .matrix files
- *.matrix (84 files): regenerated with fistThresh field

Impact: all four gates green (GLOBALACT-PY, test_sections,
test_families, GLOBALACT SC); fistThresh is now a first-class
preset field readable at load time by ~matLoadFile.
2026-06-30 16:50:02 +02:00
L'électron rare 24078111b4 feat(matrix): fist-held gestures (reload/next)
Held closed-fist (low openness, hysteresis+presence guard) per hand
fires an action after ~matPinchHoldMs: left hand reloads the current
preset, right hand advances to the next. Progress emitted on
/matrix/fistprogress.

- ~matFistEdge edge detector (engage/release/absent + hysteresis)
- ~matFistTick fires once past hold threshold (guarded by ~matFistFired)
- ~matFistReloadCurrent and ~matNextPreset wired to hand 0/1
- /matrix/fisthresh[/get] OSCdefs + ~matFistThreshPush
- fistThresh saved and restored per .matrix file
- 30 Hz poller now calls ~matFistTick alongside ~matPinchTick
- Harness group Q: A-Q all green
2026-06-30 16:42:58 +02:00
L'électron rare 4cfd2f0a98 docs(matrix): fist-held gestures plan 2026-06-30 16:39:02 +02:00
L'électron rare f9f62e2951 docs(matrix): fist-held gestures spec 2026-06-30 16:36:34 +02:00
L'électron rare 38dca5642e feat(control): pinch hold, progress, 2-col menu
CI build oscope-of / build-check (push) Has been cancelled
- matPinchHoldMs state (default 300ms) + setPinchHoldMs + persistence
- .morceau-slots column-first grid (MG left, MD right, 4 rows)
- per-slot .morceau-slot-fill progress bar (/matrix/pinchprogress)
- hold slider in Réglages wired to /matrix/pinchhold (50-2000ms)
2026-06-30 16:08:47 +02:00
L'électron rare 2ced4e728f feat(presets): emit default pinch hold ms
Add top-level 'pinchHoldMs': 300 to every generated .matrix so the SC
engine (Task 2) reads it instead of its hardcoded default.

- generate_presets.py: globalSettings ends with ',' and
  'pinchHoldMs': 300 is the last field before the closing ')'
- test_global_actions.py: EXPECT_PHMS check added (TDD red then green)
- 84 .matrix files regenerated (28 morceaux x intro/live/outro)
2026-06-30 16:01:59 +02:00
L'électron rare 0daa6d6bcd feat(matrix): pinch hold-to-fire + progress 2026-06-30 15:53:59 +02:00
L'électron rare b3ec348378 feat(pose): pinch engage/release edges + launcher
PinchDetector now emits state=1 on engage and state=0 on release
(and on hand-disappear). send_pinch appends the state as the 4th
OSC arg so SC can distinguish hold from lift. Launcher switches
from FINGER_PIANO to PINCH_ENABLE to gate only the pinch detector.
2026-06-30 15:46:13 +02:00
L'électron rare 2902f5c7cd docs(matrix): pinch refinements plan 2026-06-30 15:43:24 +02:00
L'électron rare 4bccbc1580 feat(pose): decouple pinch from air-piano gate 2026-06-30 15:40:33 +02:00
L'électron rare 50386efe8f docs(matrix): pinch refinements spec 2026-06-30 15:39:28 +02:00
L'électron rare d31c6c52d0 feat(launcher): enable pinch detection for matrix
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 15:10:35 +02:00
L'électron rare 65fe76d5f0 feat(control): 8 pinch slots panel + tempo 2026-06-30 15:07:06 +02:00
L'électron rare 140953f3cb feat(control): 8 pinch slots + trim settings state 2026-06-30 15:02:11 +02:00
L'électron rare 9590615069 feat(presets): 8 pinch actions, trim settings
Expand globalActions from 4 to 8 slots:
[\fill, \drop, \breakdown, \evolve,
 \muteDrums, \muteMelo, \washReverb, \next]

Drop openThresh/closeThresh from globalSettings (now
engine-side constants via Task 1). Regenerate all 84
.matrix files deterministically.

All gates: GLOBALACT-PY PASS, TEST PASS x2, GLOBALACT PASS
2026-06-30 14:56:50 +02:00
L'électron rare cc485003f6 feat(matrix): pinch-triggered global actions
Replace open/close hand detection with 8 pinch slots (hand*4+finger-1).
Global actions array grows from 4 to 8 entries (L/R x index..ring).
Remove ~matHandFlip, ~matHandState, openThresh/closeThresh entirely.
2026-06-30 14:49:49 +02:00
L'électron rare 2994778b02 docs(matrix): pinch-trigger global actions plan 2026-06-30 14:42:26 +02:00
L'électron rare e04fb88e42 docs(matrix): pinch-trigger global actions spec 2026-06-30 14:35:04 +02:00
L'électron rare afc220f83f feat(matrix): matrix bpm tempo route 2026-06-30 14:29:23 +02:00
L'électron rare d4306f6252 docs(matrix): global actions phase 3 plan 2026-06-30 14:27:13 +02:00
L'électron rare 9dbf0bcbc9 feat(control): extended global action choices
CI build oscope-of / build-check (push) Has been cancelled
2026-06-30 14:08:23 +02:00
L'électron rare 0bd8e46dd7 feat(matrix): mute groups, time-warp, wash, next 2026-06-30 14:00:09 +02:00
L'électron rare d483a29d3d feat(control): reglages group in morceau panel
Add the Reglages group to the morceau panel: two threshold sliders
(open/close, the close one being the user-requested "sensibilite"),
a transient-duration slider (1-8 bars), and a breakdown kept-voices
checkbox grid covering all MATRIX_VOICES.

Wired over /matrix/globalsettings with inbound sync and onOpen
get-request. Imports consolidated into a single coherent block;
no duplicate identifiers. DOM container added to index.html;
styles appended to control.css.
2026-06-30 13:45:17 +02:00
L'électron rare 64348aa90d feat(control): global settings state + persistence 2026-06-30 13:40:19 +02:00
L'électron rare 8bead14e23 feat(presets): emit default global settings
Context: Phase 2 Task 1 made the SC engine load a globalSettings Event
from .matrix files (openThresh/closeThresh/transientBars/breakdownKeep)
and default it when absent. Generator was not yet writing the field.

Approach: append globalSettings after globalActions in to_sc() return
string; extend test_global_actions.py with EXPECT_SET check against
both the to_sc sample and all 84 .matrix files on disk.

Changes:
- generate_presets.py: to_sc now ends with globalActions (comma) then
  globalSettings Event with default values matching SC defaults
- test_global_actions.py: add EXPECT_SET literal + two check() calls
- *.matrix (84 files): each preset now carries the globalSettings field

Impact: every preset ships with openThresh/closeThresh/transientBars/
breakdownKeep defaults; SC engine reads them on load; no more implicit
fallback needed at runtime for any preset in the library.
2026-06-30 13:36:00 +02:00
L'électron rare 9f53f27317 feat(matrix): editable global action settings
Replace four hard-coded constants (~matTransientBars,
~matBreakdownKeep, ~matOpenThresh, ~matCloseThresh) with
~matGlobalSettings Event (openThresh, closeThresh,
transientBars, breakdownKeep). All three consumers
(~matHandFlip, ~matSetTransient, ~matFireGlobal) now
read from settings. Add ~matGlobalSettingsPush + OSCdefs
/matrix/globalsettings[/get]. Save/restore in .matrix.
Harness A-K green.
2026-06-30 13:27:51 +02:00
L'électron rare 1d6f65bbb2 docs(matrix): global actions phase 2 plan 2026-06-30 13:20:41 +02:00
L'électron rare cadbced958 fix(matrix): no baseGrid leak in evolve one-shot
CI build oscope-of / build-check (push) Has been cancelled
When the evolve toggle is OFF, ~matRelanceEvolve now snapshots
~matBaseGrid, mutates once, then restores it to nil. When ON it
keeps the persistent base and re-mutates from it. Fixes stale-
snapshot corruption across preset loads. Case I added to harness.
2026-06-30 12:19:14 +02:00
L'électron rare 8ed0365309 feat(control): morceau panel with action slots
Add bottom-of-matrix panel with 4 gesture-slot dropdowns wired
over OSC (/matrix/globalaction). State lives in matrix-state.js;
syncs on connect and on incoming OSC echo.
2026-06-30 12:00:55 +02:00
L'électron rare 69176fb94d feat(control): global action state + persistence 2026-06-30 11:56:06 +02:00
L'électron rare 50e9e79a22 feat(presets): emit default global actions mapping
Context: SC engine (Task 2) loads 'globalActions' from .matrix files
and defaults to [\fill, \drop, \evolve, \breakdown] when absent.
Generated presets did not write this field, causing implicit reliance
on the engine default.

Approach: extend to_sc() return string to include the globalActions
key so every preset explicitly carries the default mapping
(LH-open=fill, LH-closed=drop, RH-open=evolve, RH-closed=breakdown).

Changes:
- generate_presets.py: add 'globalActions' line in to_sc() return
- test_global_actions.py: new Python test verifying to_sc() output
  and all 84 on-disk .matrix files carry the field
- 84 .matrix files: regenerated with globalActions field present

Impact: presets are self-documenting; SC engine reads the explicit
value rather than applying a silent default.
2026-06-30 11:50:51 +02:00