Balatro Feel (SimVX port)
SimVX port of mixandjam/balatro-feel, André Cardoso's Unity study of what makes Balatro's card hand feel so good. Seven procedurally drawn cards fan across the table; each lifts and tilts toward the cursor on hover, punches when selected, and swaps slots with its neighbours while dragged. Playing a hand pulses the selected cards left to right before clearing them.
There is no scoring and no deck: the whole point is the feel.
Licensing: clean re-implementation under MIT, with every card face, suit pip, and drop
shadow generated at runtime as a NumPy array. No upstream art, audio, or code is
redistributed. See ATTRIBUTION.md and LICENSE.
Run
# from the repo root
uv run python examples/ports/balatro_feel/main.py # interactive
uv run python examples/ports/balatro_feel/main.py --test # headless capture (3 frames)
uv run python examples/ports/balatro_feel/harness.py # scripted-input capture (7 stages)
uv run simvx export web examples/ports/balatro_feel/main.py \
-o /tmp/balatro_feel.html
Controls
Every action has an on-screen button, so mouse or touch alone is enough; the keys are shortcuts for the same verbs.
| Input | Action |
|---|---|
| Hover | Lift, scale-up, parallax tilt toward the cursor |
| Click | Toggle selection (selected cards rest higher) |
| Drag | Card follows the cursor; crossing a neighbour swaps their slots |
| Play hand / Space | Pulse the selected cards left to right, then deselect |
| Discard / Delete | Remove the hovered card, or every selected card |
| Clear / right-click | Deselect all |
| New hand | Re-deal the seven cards |
| Menu / Esc | Back to the menu (Esc quits from the menu) |
What it demonstrates
- Signals as the seam between logic and juice.
Cardowns the interaction state and emits a signal per change;CardVisualconnects to those signals in its constructor and answers each one with a spring, a punch, or a scale. Neither node calls the other. - Coroutines for animation. Each punch is a damped-sine coroutine started on the event and finishing on its own, with no tween graph or update-flag bookkeeping.
- InputMap actions polled from
on_update, so one code path serves the window, a touch screen, and the scripted harness. - Procedural textures.
nodes/card_textures.pyrasterises each face into an RGBAuint8array (rounded corners, freetype rank glyphs, vector suit pips, soft drop shadow) and hands it straight toSprite2D. No asset files ship with the port. z_indexdraw order, so a hovered, selected, or dragged card lifts above its neighbours while resting cards keep slot order.- Resize-aware layout. The hand centre and every text box are recomputed from the
tree's
screen_resizedsignal; the controls strip is anchored, so the port follows a desktop window resize and the responsive web canvas alike.
Layout
balatro_feel/
├── main.py # entry, InputMap actions, menu + table screens, controls strip
├── harness.py # scripted input via InputSimulator + staged screenshots
├── nodes/
│ ├── card.py # Card (state + signals) and CardVisual (spring-follow juice)
│ ├── card_textures.py # procedural card faces, suit pips, drop shadow
│ └── hand_holder.py # fan layout, slot swapping, input dispatch, hand verbs
├── screenshots/ # idle + harness captures
├── ATTRIBUTION.md
└── LICENSE
License
MIT (matches upstream).