- GDScript 87.6%
- Nix 9.2%
- Shell 3.2%
|
All checks were successful
/ check (push) Successful in 12s
`_on_setting_changed` carries a decision AGAINST a confirmation step — "a dwell UI is slow enough already" — and the play-area guard is exactly such a step. Left alone, the two read as a contradiction, and the reader who finds the comment first has no way to tell which one is current. The objection is about cost, and it is right: confirming every setting doubles the length of every adjustment and buys nothing for values that are one press from being changed back. What it does not cover is the one class where a bad value removes the ability to undo itself, which is the mapping. The asymmetry is not that the mapping matters more — it is that every other setting leaves the way back intact. So both comments now say so, from their own side. No behaviour changes: the guard was already scoped to `play_reach` and already ran on close rather than per press. This records WHY that scope is the whole argument rather than an implementation detail somebody may later widen "for consistency". 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.