The first-person head-shrink (SkeletonModifier3D) left the camera looking at
the inside of the neck/torso/hair. Replaced it: the owner's model now renders
shadows-only in first person (clean FPS view, still fully animated and visible
to others and in shadows).
Added a third-person toggle (V / toggle_camera_view) so you can actually see
your own animated model — the easiest way to verify a new skin's animations:
- over-the-shoulder SpringArm3D camera (wall-collision aware) on the local
player; press V to swap, press again to return
- firing still uses the first-person camera, so aim is unchanged
- reveals the owner's model via set_owner_visible() on both SkinnedPlayerModel
and HumanoidModel; hides the first-person weapon viewmodel while in TP
- death forces first person so the toggle can't fight the death cam
Smoke test extended to cover the toggle (camera boom created, becomes current,
round-trips) — 28/28 checks pass for both color and GLB skins.
Co-Authored-By: Claude Fable 5 <[email protected]>
Character pipeline (tools/):
- sketchfab_import.py: search/download via Sketchfab Download API with
license/attribution tracking (SKETCHFAB_API_TOKEN)
- autorig.py: headless Blender auto-rig — fits a Mixamo-named skeleton
to unrigged humanoids, binds automatic weights
- merge_animations.py: merges the shared Mixamo-skeleton animation
library onto any rigged character, strips root motion, canonical names
- pipeline.py: one command chains download -> rig -> animate -> register
In-game skin system:
- SkinManager autoload reads skins.json (auto-written by the pipeline)
- SkinnedPlayerModel rewritten: canonical clips with fallback chains,
blend times, speed-scaled locomotion, weapon bone attachment
- First-person: full animated body for the owner, head hidden via
SkeletonModifier3D; third-person: full model for other players
- Skin selector in main menu; skin id synced in multiplayer
- Fixed GLBLoader crash (GLTFDocument.get_animation_count doesn't exist)
Multiplayer sync overhaul:
- Movement is now client-authoritative: the owning peer simulates
locally (no input round-trip), server keeps health/kills/death
- Remote players interpolate synced_position/velocity with
extrapolation and snap-on-teleport
- Knockback/impulses routed to the simulating peer
Audio:
- AudioManager autoload: SFX/Weapons/Footsteps/UI/Music buses, pooled
3D players, variation + pitch randomization, auto-registration from
assets/sounds
Docs: 3D_ASSET_PIPELINE.md rewritten end-to-end, new ASSET_SOURCES.md
(non-procedural animation/map/sound sources) and SOUND_DESIGN.md.
Verified with debug/spawn_smoke_test.gd (headless: 24/24 checks pass).
Co-Authored-By: Claude Fable 5 <[email protected]>
The Miku model T-posed because the previous _update_skin() used
set_bone_pose(i, get_bone_pose(i)) which is a no-op when the pose
is unchanged. Replace with skeleton.notification(NOTIFICATION_UPDATE_SKELETON)
to force the Skeleton3D to recompute bone transforms and notify the
MeshInstance to update vertex buffers.
Also fix scale: the GLB is ~1.2m tall (not 1.6m as documented), so
set scale_factor=1.25 to fit the 1.8m player capsule, and add
position_y_offset=-0.2 to align the model's feet with the player origin.
Co-Authored-By: Hermes Agent <[email protected]>
The skinned player model was loading miku_rigged_final.glb which only
contained a single "Idle" animation (1 track, near-rest pose). This caused
"animation 'Jump/Walk/Run' not found" spam and a T-pose appearance.
Switch to miku_rigged_animated.glb which has all 7 animations
(Crouch, Death, Idle, Idle2, Jump, Run, Walk).
Additional fixes:
- Fix scaling: the GLB is already in meters (~1.6m tall), not cm.
Removed the unconditional 0.01 cm->m conversion that was shrinking
the character to 1/100th size.
- Fix bone track paths: use "MikuRig/Skeleton3D:" prefix matching the
actual scene tree structure (AnimationPlayer is sibling of MikuRig).
- Add _ensure_locomotion_animations() to create Walk/Run/Jump/Idle
procedurally if the GLB is missing them.
- Eliminate per-frame "not found" log spam with rate-limited warnings.
- Update level_runtime.gd and test_level_builder.gd to use animated GLB.
Closes #3d-player-model animation pipeline
The Blender GLTF exporter was stripping animation tracks (only 1 of 51
channels survived export). Now SkinnedPlayerModel detects this at
runtime and creates a proper Idle animation programmatically using Godot's
Animation API with 5 bone tracks (Spine, Arms, Neck, Hips).
Also switched model_path back to miku_rigged_final.glb since the
re-export wasn't adding usable animations.
Godot headless/CLI can't import GLB files — the GLTF loader only works
in the editor GUI. Switched SkinnedPlayerModel to use GLTFDocument.append_from_buffer()
which parses GLB data from raw bytes at runtime.
Verified: GLB parses successfully, generates scene with MikuRig skeleton,
AnimationPlayer, and 7 animations (Crouch, Death, Idle, Idle_001, Jump, Run, Walk).
Also added characters/glb_loader.gd as a reusable utility for loading
any GLB file at runtime.
- Add miku_rigged_animated.glb (3.27MB) with 18-bone skeleton and 6 animations
(Idle, Walk, Run, Jump, Crouch, Death) via Blender auto-rig script
- Add tools/rig_and_animate.py: reusable Blender script for rigging any humanoid
mesh with Mixamo-compatible bone naming
- Update SkinnedPlayerModel: scale_factor, first-person mode, animation state
matching (Idle/Walk/Run/Jump/Crouch/Death)
- Update level_runtime.gd: use skinned model for local player, procedural
humanoid for remote players
- Update skin_manager.gd and test_level_builder.gd to use animated model
- Fix Godot 4.2.1 'is not Type' syntax in 5 weapon files
- Add editor/import_miku_to_tscn.gd for editor-based GLB import
Third-person camera:
- Camera offset now follows player's forward direction using basis.z
- Smoothly orbits behind player when they turn
- Looks at player's head area (y+1.5)
SkinnedPlayerModel:
- Creates AnimationPlayer programmatically if GLB doesn't have one
- Copies animations from armature's animation_data to the player
- Handles both direct actions and NLA tracks
- More detailed debug output for scene tree and animation state
SkinnedPlayerModel:
- Added _print_tree debug to see GLB scene structure at runtime
- Auto-play Idle animation on load
- Added periodic debug output for animation state
- Only change animation when target differs from current
Third-person camera:
- F1 toggles between FPS and third-person view
- Third-person camera positioned behind/above player
- Smooth follow with lerp
- Camera tracks player position each frame
- Fixed Blender export: remove FBX armature modifier before scaling,
then transform_apply(scale=True) before creating new armature
- Model now exports at correct 1.8 unit height (verified in Blender)
- SkinnedPlayerModel now polls MovementStateMachine in _process
to drive animations based on movement state
- Player 1 gets Miku at origin, others get procedural humanoid at y=-0.9
Pipeline:
1. Downloaded TDA-style Miku model from Sketchfab (19MB FBX, 38K verts)
2. Imported to Blender, scaled to Godot humanoid proportions (1.8u tall)
3. Created clean 17-bone humanoid armature (Hips/Spine/Chest/Head/Arms/Legs)
4. Auto-weight-painted mesh to armature
5. Added Idle (breath bounce) and Run (cycle) animations
6. Exported as GLB with embedded animations (3MB)
New:
- SkinnedPlayerModel class: loads GLB with own armature+animations
- Player 1 spawns with Miku model, others get procedural humanoid
- Completely separate from procedural model system
Files:
- assets/characters/skins/miku_rigged_final.glb (3MB, 48K verts, 17 bones, 2 anims)
- characters/skinned_player_model.gd
- Removed old procedural GLB attempts
Skin System:
- PlayerSkin resource class (model_path, color_tint, etc.)
- SkinManager with default skins: Default, Red Team, Forest, Miku
- HumanoidModel.apply_skin() supports both GLB model replacement
and procedural color tinting
- Procedural meshes auto-hide when GLB model is loaded
Miku Skin:
- 43-part procedural model generated in Blender (headless)
- Twin tails, headphones, thigh-high socks, idol outfit
- Teal/cyan color scheme with red accents
- Exported to assets/characters/skins/miku.glb
- Applied to player 1 in test level builder
Pipeline:
- Blender 5.0.1 + MCP addon installed
- Bridge script for socket-based Blender control
- docs/3D_ASSET_PIPELINE.md documents full workflow
Problems fixed:
- Player spawn moved from inside central platform to open area (z=20)
- Removed broken internal stairs inside tower (disconnected ramps)
- Removed corner towers, walkways, stepping stones, wall-run corridor,
wall-climb surfaces, grapple anchors — all were overlapping or unreachable
- Reduced arena from 96x96 to 80x80 for tighter gameplay
- Crates properly spaced (1.5u apart), no overlaps or intersections
- Reduced from 6 spawns to 4 (corners only), each with 2 L-shaped cover
walls and clear exit routes — no more 3-wall traps
- Spawn alcoves use 2 walls max with open diagonal exits
- Dummies placed in open areas away from geometry:
TargetDummy at (0,-25), KillableDummy at (25,0),
WalkingDummy patrols z=-30 from x=-20 to 20
- Central platform simplified: 16x16 base (2u) + 8x8 upper (4u)
- 4 cardinal ramps properly connect ground to platform edge
- Cover walls placed in open lanes, not blocking movement
- Barrels placed along outer walls, not in pathways
- Fix tab character in _build_elevated_walkways() call (line 63)
- Fix untyped 'pos' variable in grapple pillar loop (line 376)
- Remove fog_sky_affinity (Godot 4.3+ only property)
- Replace preload() with load() for runtime script loading
- Replace 'is DoubleBarrelShotgun' type check with duck-typing
- Fix 'is not OfflineMultiplayerPeer' syntax in grenade spawn
- Replace absf() with abs() in state_machine, state_air, state_ground
- Update test_level.tscn to remove stale UID reference
All fixes verified: PARSE OK and scene runs without script errors
on Godot 4.2.1 headless.
96x96 arena with multi-level layout, grapple points, wall-run/climb
surfaces, 6 team spawns with anti-camping cover, and varied movement
challenges.
Map Features:
- Central multi-level structure: 20x20 platform (3u), 10x10 tower (6u),
14x14 top platform (9u) with crown cover walls and internal stairs
- 4 corner towers (5u high) with railings and top platforms
- 4 elevated mid-side walkways (3u) with railings connecting center to edges
- 8 ramps: cardinal to central, diagonal to corners, to walkways
- Quarter-pipe curve (8 segments) near NE corner
- 4 parkour stepping stone chains (NW, NE, SW, SE quadrants)
- Wall-run corridor (N side) with parallel walls, obstacles, and floor gap
- Wall-run surfaces on all 4 outer wall sections
- Wall-climb surfaces around central tower and mid-map (warm color)
- 4 grapple anchor pillars (15u tall) with visible tops at cardinal points
- Cover system: low walls, crate clusters, corridor walls, structural pillars
- Speed corridor with side rails, speed bumps, and floor markings
- 6 spawn alcoves (3 red: NW/SW/West, 3 blue: NE/SE/East) with cover walls
- Anti-spawn-camping: each alcove has 2+ exits and blocking walls
- Floor accent tiles in central area
- Atmospheric sky with procedural sky material and fog
- Directional sun + fill light + center omni + 6 spawn accent lights
- Decorative: barrels, hazard stripes, accent beams, spawn area lights
- Full multiplayer spawning, weapon system, HUD, entities preserved
- All movement states: ground, air, wall_run, wall_climb, wall_cling,
slide, dash, grapple
Parse verified clean with Godot 4.2.1 headless.