feat(player): swap normal↔attack model by combat state (FLO-481)#124
Merged
Conversation
Mount the strike-pose twin (korovany_hero_player-attack.glb, FLO-480) alongside the neutral survivor GLB and toggle which renders by melee state — default while idle, attack pose while a swing is in flight (windup/active/recovery). Gives the player two clearly distinct combat states in every melee scene. - survivorAvatar: mountSurvivorAvatar/wireSurvivorAvatar take an optional attack URL; both GLBs load in parallel, are faceted+matted, and parented under the capsule at the same foot offset. Drop-in twin (shared bbox) needs no scale/position correction; static swap, no animation playback (FLO-440 pattern). Attack fetch failure degrades gracefully to default-only. - CharacterController: registerCombatVisual + edge-fire the swap from setAttackPhase on the idle↔swing transition (flips twice per swing, not per frame). - Wired in forest, human-lands, mountains, empire (every scene with melee); controller-playground (no combat) stays default-only. - Tests: model swap by combat state + controller edge-firing. - Docs: public/models/README + docs/guide/assets.md two-state player section. Co-Authored-By: Wayland <wayland@agents.flopbut.local> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Plan step 2 of FLO-474: the player now has two clearly distinct visual states driven by combat. Alongside the neutral survivor GLB we mount the strike-pose twin
korovany_hero_player-attack.glb(FLO-480, drop-in twin: same bbox/scale/identity) and toggle which renders by melee state — default while idle, attack pose while a swing is in flight (windup/active/recovery).How
survivorAvatar.ts—mountSurvivorAvatar/wireSurvivorAvatartake an optional attack URL. Both GLBs load in parallel, are faceted + matted, and parented under the capsule at the same foot offset. Shared bbox ⇒ no scale/position correction; static swap, no animation playback (FLO-440 swap-by-URL pattern). Attack-fetch failure degrades gracefully to default-only (player visual never drops).CharacterController— newregisterCombatVisual(swap);setAttackPhaseedge-fires the swap on the idle↔swing transition (flips twice per swing, not every frame). The default root stays the animator's node so bob/lean/lunge keep playing between swings.forest,human-lands,mountains,empire(every scene with melee).controller-playground(no combat) stays default-only.Tests
survivorAvatar.test.ts— attack twin mounts hidden + faceted; swap toggles default↔attack visibility; mount path loads both GLBs and registers the swap.characterController.test.ts— edge-firing (exactly[true,false]across a full swing; no fire while idle).Docs
public/models/README.md— two-state player wiring (FLO-481).docs/guide/assets.md— combat-state swap section + attack-pose table row; cleared stale "pending engine-wiring".Verification
npm run lint✅ cleannpm test✅ 952 passed (106 files)npm run build✅ built🤖 Generated with Claude Code