- GDScript 89.1%
- Nix 8.1%
- Shell 2.8%
|
All checks were successful
/ check (push) Successful in 1m30s
Daniel: "when 'clap-grabbing' a setting slider, we seem to be resorting to wrist position again?" It was — `grab.gd` took its midpoint from the wrists, so grabbing a slider snapped the marker back onto the joint after every other pointer in the game had just agreed the hand is further along the forearm, and the drag was then measured from somewhere the player was not looking. These are two questions and only one was being asked. SEPARATION decides whether this is a clap, and every threshold in grab.gd was tuned against wrist distance on real footage — moving both endpoints outward along the forearms would rescale all of them for no benefit. POSITION is where the player is pointing, which the rest of the game answers with the middle of the hand. So the pair carries both: wrists for the gesture, centres for the marker and the drag origin. Absent centres fall back to the wrists, so nothing changes for a caller that does not have them. This is the same split I made when the pointer moved into the hand and then only did half of — the commit then said `_hand_pairs` was left alone deliberately because the clap is judged by the size of the gap rather than where the gap is. True, and it silently answered the OTHER question with the wrist too. # Testing `_the_grab_marker_sits_in_the_hands_but_the_clap_is_judged_on_wrists` puts the hand centres straight DOWN from the wrists — a large offset that leaves wrist separation untouched — so the two questions can be told apart. It asserts the same wrists engage either way, the marker moves to the hands, the fallback still works, and that the two positions differ at all, without which the test would prove nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtnYWFX9eMBH7oK3gmcMMs |
||
|---|---|---|
| .forgejo/workflows | ||
| doc | ||
| issues | ||
| nix | ||
| project | ||
| steam | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| README.md | ||
| THIRD-PARTY.md | ||
deck-slice — Fruit Punch Party
The repository and package are deck-slice; the game is called Fruit Punch
Party. The product name lives in one constant (TITLE in
project/title_screen.gd) and the repo name is a separate, coordinated change
because it is a flake input URL elsewhere.
A game where your hands are boxing gloves. Fruit is flung up from the bottom of the screen; you punch it, and it bursts in the direction your fist was going. Up to six players at once, each with their own colour and score. Godot 4, GDScript, CC0 art.
2.5D: lit, tumbling 3D fruit that burst into splatter when hit, over a
game whose logic is strictly 2D. An orthographic camera maps one world unit to
one screen pixel, so the letterbox mapping that gameplay depends on is
untouched. --flat reverts to the original drawn shapes and is kept working.
Anti-aliasing, glow and ambient occlusion are settings on a Graphics page,
each with a measured frame-time cost and pixel-diff in
doc/deck-slice.md.
Shadows are deliberately absent rather than off-by-default: nothing in the scene
could receive one.
It opens on a title screen that says whether the camera is working, and on a first run explains the gestures nobody can guess before letting you press Play.
It opens on a title screen that says whether the camera is working, and on a first run explains the gestures nobody can guess before letting you press Play.
It is the first real consumer of deck-pose, the markerless body-tracking daemon, and exists as much to prove that daemon's socket protocol is usable as to be a game.
Licence
GPL-3.0-or-later — see LICENSE.
Bundled art and audio are Kenney's, under CC0; the Godot engine is MIT; the
model weights and several dependencies are Apache-2.0. Those keep their own
terms, and a binary distribution must carry
THIRD-PARTY.md alongside LICENSE.
GPLv3 rather than GPLv2 is a requirement rather than a preference: Apache-2.0 is compatible with the former and not the latter, and both the model weights and much of the Rust dependency tree are Apache-2.0.
Read this first
doc/deck-slice.md— how to run it, every tunable flag, the framing model, and what the tests do and deliberately do not cover.- deck-pose's
doc/protocol.md— the wire format this game consumes. Read it before touchingproject/pose_client.gdorproject/video_client.gd.
Running it
Two processes. The daemon owns the camera; the game reads its socket. Order does not matter — the game polls for the socket and reconnects on its own.
nix run .#deck-pose -- --headless # terminal 1
nix run .#deck-slice # terminal 2
Both default to $XDG_RUNTIME_DIR/deck-pose.sock, so the common case needs no
arguments. On the steamdeck host the daemon is socket-activated by the NixOS
module and deck-slice-launch starts the socket for you.
Settings, without a terminal
Every tunable is reachable with your hands: hold a hand in the top-left corner
box for ~1.5s (or press Esc) to open the settings screen, then hold over a
button until the ring around your hand fills. Bring both hands together to
grab the highlighted row and slide it — steppers for nudging, clap-to-grab
for sweeping.
Controller, keyboard and mouse are first-class too, not a camera-absent fallback: d-pad/arrows to move, right stick to slide, A/Enter to press, B/Esc to close, mouse wheel to adjust.
Precedence is default < environment < flags < saved settings — the in-game
screen wins, because a value you changed with your hands should stick.
--reset-settings is the way back if a saved value makes the game unplayable.
See doc/deck-slice.md.
Outputs
| output | what |
|---|---|
packages.<system>.deck-slice |
the game + deck-slice-launch + a .desktop entry (also .default) |
packages.<system>.deck-pose |
re-exported from the input, so nix run .#deck-pose works |
overlays.default |
adds pkgs.deck-slice |
checks.<system> |
package (build + seven test suites), protocol-drift |
The protocol-drift check
checks.protocol-drift is why deck-pose is a flake input rather than a link
in a document. It reads the message types and event kinds the pinned daemon
can emit, straight out of its source, and fails if the game names none of them.
Before the split, a daemon change that added or renamed an event showed up in
the same diff as the game consuming it. It no longer does, and the failure mode
is silent: the game's match stops matching and the feature quietly does
nothing. Nothing errors, nothing logs.
Naming a kind is a low bar on purpose — it proves someone looked at it, not
that the handling is right. project/main.gd lists the kinds this game ignores
and why.
Building and testing
nix build
nix flake check
The framing, view-mapping, blade-geometry, dwell-timing, clap-gesture,
settings-rules and settings-screen tests run inside the build (pure arithmetic — no
camera, no socket, no clock). project/tests/render_test.gd reads back real
pixels and is deliberately not in the build: Godot's headless renderer
produces none, so it needs Xvfb and software Mesa. nix develop provides them;
see the header of that file.