fix(deck-slice): make the cut threshold body-relative and forgiving #910

Closed
lytedev wants to merge 2 commits from deck-slice-cut into deck-slice-framing
Owner

Fixes the unforgiving cut threshold Daniel hit playing #909: "feels much less responsive than it did before and 'fast enough to count as a cut' seems to be a bit unforgiving with the lerping at play so sometimes I move fast but still not enough for the game?"

Stacked on #909. Base is deck-slice-framing.

Root cause — more specific than "it was never retuned"

The unit has now been wrong twice, which is the argument for the third one.

  1. Pixels/second demanded a faster physical swing on a larger window.
  2. Play-rect widths/second fixed that but still moved whenever the framing did — and it moved badly. Letterboxing corrected the vertical axis from stretched-to-window-height back to its true 16:9 proportion, which roughly halved the measured speed of a vertical swing while the threshold stayed put. That is the concrete mechanism behind "I move fast but still not enough".
  3. Body heights (shoulder-to-hip) per second is the invariant that actually holds.

Body-relative — yes, and here is why

You asked me to decide and say why. Body-relative, definitely. A swing is a physical motion of a physical arm; measuring it against the player's own apparent size makes it independent of the window, the letterbox, the capture resolution, and how far from the camera they stand. The old scheme was silently distance-dependent — someone further from the camera faced a higher effective threshold. It is also the unit the daemon's gesture thresholds already use, so the two now agree instead of each having a private idea of "fast", and it should not need retuning the next time the framing changes.

Retuned down, with numbers rather than vibes

Default is now 0.8 body-heights/sec, against measurements:

  • a deliberate swing: 7–10 body-heights/sec
  • the daemon's swipe gesture threshold: 1.5
  • the old effective threshold at mid distance: ~3.0 — i.e. sitting in the middle of the range of real swings, which is exactly why it felt unforgiving

0.8 is roughly a quarter of the old value and well under any deliberate motion. Biased forgiving as you asked: a missed slice is far more frustrating than an accidental one, and the only cost of generosity here is the occasional unintended bomb.

--cut-speed flag

Exposed for the same reason as the One Euro parameters — tuned by feel, so a rebuild per attempt makes tuning impractical.

No config file, deliberately: the game has no config mechanism today, there is exactly one tunable, and live tuning is what a flag is for. Say the word if you want one anyway and I will add it.

Diagnostics — so this stops being unfalsifiable

DECK_SLICE_DEBUG=1 now reports peak observed hand speed against the current threshold, and logs any swing that passed through a target while judged too slow — which is precisely the number the threshold should sit below:

deck-slice: 145 fps, peak hand 10.57 body-heights/sec (cut >= 0.80)
deck-slice: MISS at 0.62 body-heights/sec (threshold 0.80)

Second cause checked — it was not rendering

You asked me to confirm the framing work did not slow the game down. Measured over identical 1200-frame runs against the same synthetic stream:

build fps
pre-framing (#908) 129
with framing (#909) 128

Within noise. "Less responsive" was the threshold, not a render regression — the self-view, vignette and edge glows cost nothing measurable.

Stack rebased onto the fixed #907

You were right that #908/#909 were branched from #907 before the flock fix, so they carried the original publisher. Rebased with --ignore-immutable (change IDs preserved, no divergence); all three game branches now have it:

deck-slice           flock fix present: YES
deck-slice-framing   flock fix present: YES
deck-slice-cut       flock fix present: YES

Untested

  • Not played by a person. The units are validated against a synthetic swing of known speed and the maths is sound, but whether 0.8 feels right is exactly the judgement that was wrong last time. The flag exists so Daniel can settle it in one run rather than waiting on me.
  • The MISS diagnostic has only fired against synthetic motion.
Fixes the unforgiving cut threshold Daniel hit playing #909: *"feels much less responsive than it did before and 'fast enough to count as a cut' seems to be a bit unforgiving with the lerping at play so sometimes I move fast but still not enough for the game?"* **Stacked on #909.** Base is `deck-slice-framing`. ## Root cause — more specific than "it was never retuned" The unit has now been wrong twice, which is the argument for the third one. 1. **Pixels/second** demanded a faster physical swing on a larger window. 2. **Play-rect widths/second** fixed that but still moved whenever the framing did — and it moved *badly*. Letterboxing corrected the vertical axis from stretched-to-window-height back to its true 16:9 proportion, which roughly **halved the measured speed of a vertical swing** while the threshold stayed put. That is the concrete mechanism behind "I move fast but still not enough". 3. **Body heights (shoulder-to-hip) per second** is the invariant that actually holds. ## Body-relative — yes, and here is why You asked me to decide and say why. **Body-relative, definitely.** A swing is a physical motion of a physical arm; measuring it against the player's own apparent size makes it independent of the window, the letterbox, the capture resolution, *and* how far from the camera they stand. The old scheme was silently distance-dependent — someone further from the camera faced a higher effective threshold. It is also the unit the daemon's gesture thresholds already use, so the two now agree instead of each having a private idea of "fast", and it should not need retuning the next time the framing changes. ## Retuned down, with numbers rather than vibes Default is now **0.8 body-heights/sec**, against measurements: - a deliberate swing: **7–10 body-heights/sec** - the daemon's `swipe` gesture threshold: 1.5 - the **old** effective threshold at mid distance: ~3.0 — i.e. sitting in the middle of the range of real swings, which is exactly why it felt unforgiving 0.8 is roughly a quarter of the old value and well under any deliberate motion. Biased forgiving as you asked: a missed slice is far more frustrating than an accidental one, and the only cost of generosity here is the occasional unintended bomb. ## `--cut-speed` flag Exposed for the same reason as the One Euro parameters — tuned by feel, so a rebuild per attempt makes tuning impractical. **No config file, deliberately:** the game has no config mechanism today, there is exactly one tunable, and live tuning is what a flag is for. Say the word if you want one anyway and I will add it. ## Diagnostics — so this stops being unfalsifiable `DECK_SLICE_DEBUG=1` now reports peak observed hand speed against the current threshold, and logs any swing that passed **through** a target while judged too slow — which is precisely the number the threshold should sit below: ``` deck-slice: 145 fps, peak hand 10.57 body-heights/sec (cut >= 0.80) deck-slice: MISS at 0.62 body-heights/sec (threshold 0.80) ``` ## Second cause checked — it was not rendering You asked me to confirm the framing work did not slow the game down. Measured over identical 1200-frame runs against the same synthetic stream: | build | fps | | --- | --- | | pre-framing (#908) | 129 | | with framing (#909) | 128 | Within noise. **"Less responsive" was the threshold, not a render regression** — the self-view, vignette and edge glows cost nothing measurable. ## Stack rebased onto the fixed #907 You were right that #908/#909 were branched from #907 *before* the flock fix, so they carried the original publisher. Rebased with `--ignore-immutable` (change IDs preserved, no divergence); all three game branches now have it: ``` deck-slice flock fix present: YES deck-slice-framing flock fix present: YES deck-slice-cut flock fix present: YES ``` ## Untested - **Not played by a person.** The units are validated against a synthetic swing of known speed and the maths is sound, but whether 0.8 *feels* right is exactly the judgement that was wrong last time. The flag exists so Daniel can settle it in one run rather than waiting on me. - The `MISS` diagnostic has only fired against synthetic motion.
fix(deck-slice): make the cut threshold body-relative and forgiving
Some checks failed
/ check-format (push) Has been cancelled
/ build (push) Has been cancelled
692d9aad74
Daniel, playing #909: "feels much less responsive than it did before and `fast
enough to count as a cut` seems to be a bit unforgiving ... sometimes I move
fast but still not enough for the game?"

The unit has now been wrong twice, which is the argument for the third one.

Pixels/second demanded a faster physical swing on a larger window.
Play-rect widths/second fixed that but still moved whenever the framing did —
and it moved badly. Letterboxing corrected the vertical axis from
stretched-to-window-height back to its true 16:9 proportion, which roughly
HALVED the measured speed of a vertical swing while the threshold stayed put.
That is the specific mechanism behind the report.

Body heights (shoulder-to-hip) per second is the invariant that holds. A swing
is a physical motion of a physical arm, so measuring it against the player`s
own apparent size makes it independent of the window, the letterbox, the
capture resolution, and how far from the camera they stand. It is also the unit
the daemon`s gesture thresholds already use, so the two now agree instead of
each having their own idea of "fast".

Retuned down and biased forgiving: 0.8, against a measured 7-10
body-heights/sec for a deliberate swing and the daemon`s 1.5 for a `swipe`.
Roughly a quarter of the old effective threshold at mid distance. A missed
slice is far more frustrating than an accidental one and the only cost of
generosity here is the occasional unintended bomb.

`--cut-speed` exposes it, for the same reason the One Euro parameters are
flags: tuned by feel, so a rebuild per attempt makes tuning impractical. No
config file — one tunable, and live tuning is what a flag is for.

Diagnostics, so this stops being unfalsifiable: DECK_SLICE_DEBUG=1 now reports
peak observed hand speed against the current threshold, and logs any swing that
passed THROUGH a target while judged too slow, with its speed — which is
exactly the number the threshold should sit below.

It also reports the game`s own frame rate, which answers the other half of the
report: 1200-frame runs measure 129fps before the framing work and 128fps
after, so "less responsive" was the threshold and not a render regression.
lytedev force-pushed deck-slice-cut from 692d9aad74
Some checks failed
/ check-format (push) Has been cancelled
/ build (push) Has been cancelled
to 78c0c116ca
Some checks failed
/ check-format (push) Has been cancelled
/ build (push) Has been cancelled
2026-08-03 11:01:58 -05:00
Compare
docs(deck-pose): record the real-camera measurements
All checks were successful
/ check-format (push) Successful in 11s
/ build (push) Successful in 6m30s
1ea0cc719a
The cut threshold and the framing had only ever been exercised against a
synthetic stream or a 16:9 viewport. Both have now run against the real camera:

* Peak hand speed with a real person reaches ~14 body-heights/second, against
  a 0.8 threshold and with no near-miss events logged — so the retune is
  forgiving by more than an order of magnitude rather than by estimate.
* The letterbox ran with an actively non-16:9 window
  (1280x1413 -> play rect 0,346 1280x720), which is the first time the
  runtime path has been exercised outside a viewport where it does nothing.

Also documents how to read the publish telemetry, since the two numbers only
mean anything as a pair.
Author
Owner

Superseded by #915, which consolidates the whole markerless-pose-input program into a single WIP branch against main. Every commit from this PR is preserved there — nothing was squashed, so the root-cause writeups in the commit messages are intact. Closing here; review happens on #915.

Superseded by #915, which consolidates the whole markerless-pose-input program into a single WIP branch against `main`. Every commit from this PR is preserved there — nothing was squashed, so the root-cause writeups in the commit messages are intact. Closing here; review happens on #915.
lytedev closed this pull request 2026-08-03 11:30:25 -05:00
All checks were successful
/ check-format (push) Successful in 11s
/ build (push) Successful in 6m30s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lytedev/nix!910
No description provided.