Extends the earlier Xbox-only ability glyphs into full brand-aware
controller support, following standard practice (position-based
button mapping, safe defaults for unrecognised pads, no per-device
special-casing):
- Controls detects PlayStation pads (DualShock/DualSense) from
Input.get_joy_name() via a name-substring heuristic, checking for
"xbox" first so a Bluetooth-connected Xbox pad (reports as "Xbox
Wireless Controller") can't be misread as PlayStation through the
generic "wireless controller" hint. Unrecognised/generic pads read
as Xbox-style, matching the browser's Standard Gamepad Mapping.
- Ability-bar keycaps and the options menu now show ✕/○/□/△ for a
detected PlayStation pad instead of A/B/X/Y — no index remapping
needed, since PlayStation's face buttons sit in the exact same
four positions as Xbox's.
- The options menu's Controls section gains a gamepad rebind button
next to each ability's keyboard one (movement stays on the D-pad/
stick, not individually remapped, matching convention). Clicking it
captures the next joypad button press, mirroring the existing
keyboard-rebind flow exactly (Esc cancels either). Gamepad rebinds
persist to controls.cfg alongside keyboard ones and survive a
reload.
- Added a player-facing "Controller Vibration" toggle (Settings...
Gameplay section) — Controls.vibrate() now checks it alongside the
existing DP debug flag, so either can silence rumble.
Verified headlessly end-to-end: default bindings show correct
brand-agnostic glyphs (kick=X, dash=A, ...), rebinding kick to a
different button through the real options-menu flow changes only
that action's glyph, leaves its keyboard binding and other abilities'
gamepad bindings untouched, and survives a reload from disk. Sanity-
checked the PlayStation name heuristic against realistic controller
name strings from Xbox, PlayStation (Windows/macOS/Bluetooth
variants), and other brands.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MXBNaEBmrYDSMcv4NgUWtV
Move every script and scene into role-based directories (actors/, systems/, ui/,
levels/, props/) and all raw art under art/ (grouped by role, snake_case,
Extract-Textures GLBs), dropping Blender version-suffix noise. Filenames are
snake_case (PascalCase reserved for class_name) to avoid case-insensitive
filesystem aliasing on the web/macOS targets. Routes the bull's hits through the
typed DamageEvent pipeline and wires the bull's abilities to the Fx library.
Updates CLAUDE.md's folder-layout overview to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCyaJPTHCH9EDthpf4A5Sj