Commit Graph
9 Commits
Author SHA1 Message Date
Nicholas ButzkeandClaude Fable 5 648872a16d feat: ad-graphic layer — generated posters, billboards and sign columns
The city's flat color sign panels are now real graphic designs, closing
the street-level "graphic density" that anime cities live on:

- tools/generate_ads.py: procedural ad library (24 textures) — bold
  two-tone layouts (diagonal splits, bands, circles, stripes) with
  fake-glyph text blocks that read as kanji/kana from gameplay distance,
  inked borders, seeded palette system
- Every building gets 1-3 street-level posters plastered on its facade
- Vertical sign columns render a stacked-glyph column texture
- Rooftop billboards, tower crown boards (both faces) and the central
  4-face screen tower all show distinct ad graphics
- Posters under the viaduct arches on every pier
- All panels lit (albedo + emission of the same texture) so they glow
  as signage without blooming out

Verified via street capture (glyph posters, pharmacy-cross signs, ad
boards visible down the avenue); movement 11/11, smoke 0 failures,
acoustics ALL PASSED.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-19 02:44:55 -04:00
Nicholas ButzkeandClaude Fable 5 a9b0775de3 feat: real gunshots, localized 3D audio, seamless music, better animations
Audio:
- All ballistic weapons now fire real firearm recordings (The Free Firearm
  Sound Library, CC0): AK-47 uses actual AK-47 shots, M4=AR-15, MP7=PPSh,
  AWP=Mosin Nagant, DMR=Savage 10, shotgun=Mossberg/Nova, nailgun=Ruger .22,
  rocket/mortar layered with real booms. Plasma keeps its energy sound.
- Reload is real lever-action foley instead of interface clicks
- Projectile flight loops localized: unit_size 50->6, max_db 6->0,
  max_distance 45 — no more mortar/rocket drone in every player's ear;
  loops also got proper loop_end (was a zero-length loop)
- Flight loops lowpassed into soft whooshes instead of sci-fi engine drones
- Menu music converted to OGG with native full-track looping (47s seamless,
  replaces the broken manual WAV loop points)

Animations (movement-shooter pass):
- Rebaked miku.glb with 4 new clips from the CC0 library: Grapple (swim
  reach — reads as a swing), PistolIdle (armed idle with weapon up),
  PistolShoot, PistolReload
- Armed idle: standing with a weapon now uses PistolIdle instead of
  arms-at-sides
- Slide pose overhaul: legs kick out front (lead/trail thighs, knees
  straighten) — feet-first slide instead of "sitting in a crouch"
- Wall run: forward drive pitch + inner arm reaches out to the wall
- Per-transition blend times: dash/hit/jump cut fast (0.05-0.08s),
  locomotion cross-fades smoothly (0.2-0.25s); CrouchWalk speed-scales

Fixes:
- Third-person camera no longer renders the first-person viewmodel layer
  (the gun/arms floated in front of the third-person view)

Verified: 11/11 movement tests, smoke test 0 failures (17 clips resolved),
third-person run screenshot shows grounded animated model, no floating gun.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-17 21:49:10 -04:00
Nicholas ButzkeandClaude Fable 5 9939e7e524 fix: correct rig deformation — arms no longer cross body, feet no longer stretch to center
The model animated but deformed wrong: arms crossed the torso and foot heels
stretched to the model's center-bottom. Two root causes, both fixed:

1. Pose mismatch. Sketchfab models are modelled in an A-pose (arms angled
   down) but the Quaternius library rests in a T-pose. Binding the A-pose mesh
   to T-pose arm bones misweighted the arms, and the library clips (which
   rotate arms ~70° down from the T rest) then shoved the already-drooped arms
   across the body.
   Fix: autorig.fit_arms_to_mesh() reorients each arm bone chain along the
   model's real arm direction; merge_animations retargets every clip from the
   library's T-pose rest onto the fitted rest via world-space constraint bake
   (Copy Rotation/Location + nla.bake), so world motion is reproduced
   regardless of the rest difference.

2. Feet-to-center stretch. The library's deform-flagged `root` bone runs up
   the body centre-line; nearest-bone weighting assigned inner-foot/heel verts
   to it, stretching them to center when animated.
   Fix: exclude root/control/mechanism bones from weighting (_NON_DEFORM_HINTS).

Also upgraded nearest-bone weighting from rigid (1 bone/vert) to a smooth
inverse-distance blend across the nearest 4 bones, so joints deform cleanly.
Bone-heat still fails on Miku's joined hair/clothing mesh, so this is the
primary path.

Verified by rendering Idle/Walk/Run poses (Blender): natural stance, arms at
sides swinging correctly, feet planted, proper running stride. Smoke test
still 30/30.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-06 19:38:59 -04:00
Nicholas ButzkeandClaude Fable 5 22cb0a58b7 fix: T-posing skinned models — autorig produced an orphan skin with no weights
The model animated its skeleton but rendered a permanent T-pose: the mesh
wasn't skin-bound. Root cause was in autorig's binding, introduced while
chasing an earlier "skins:0" export:

- The earlier "skins:0" was actually caused by bone-heat weighting failing
  (0 weighted verts → empty skin gets dropped), NOT by the Armature modifier.
- The "fix" then stripped the Armature modifier and used parent_type=ARMATURE.
  That makes the glTF exporter emit a skin OBJECT but with no node.skin
  reference and no per-vertex JOINTS/WEIGHTS — an orphan skin. The mesh then
  renders its bind pose (T-pose) forever while the skeleton animates unseen.

Fix: keep the standard ARMATURE_AUTO result (Armature modifier + vertex
groups). With the nearest-bone fallback ensuring real weights, the exporter
now writes a COMPLETE skin (verified: meshnode.skin=0, JOINTS/WEIGHTS present).

Also:
- skinned_player_model: _ensure_meshes_bound() re-binds any skinned mesh whose
  skeleton NodePath doesn't resolve at load — graceful degradation instead of
  a silent T-pose for imperfect GLBs.
- smoke test now asserts the spawned player's mesh is bound to its skeleton,
  so this class of bug fails the test instead of shipping. 30/30 pass.
- regenerated miku_test.glb with the corrected pipeline.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-06 18:11:26 -04:00
Nicholas ButzkeandClaude Fable 5 64bbbf93c6 fix: make the character pipeline work end-to-end in Blender 5.1 + bundle CC0 animation library
Verified the full chain on a real Sketchfab model (Miku UID -> rigged ->
13 clips -> loads and animates in-engine, 24/24 smoke checks pass).

Fixes found while running it for real:
- sketchfab_import: read .sketchfab_token as UTF-16/BOM too (PowerShell's
  `echo >` writes UTF-16LE, which crashed the UTF-8 reader)
- autorig: rig to the animation library's OWN skeleton when _library.glb
  is present (zero retargeting); robust binding — fall back to rigid
  nearest-bone weights when Blender bone-heat fails on complex meshes
  (Miku's joined hair/clothing gave 0 weighted verts); export as
  parent_type=ARMATURE with no modifier (Blender 5.x only emits a glTF
  skin in that exact form — a lingering Armature modifier gave skins:0);
  export_apply=False (applying modifiers baked away the skin); flatten
  the Sketchfab empty hierarchy before binding
- merge_animations: support a single multi-clip library GLB via
  LIBRARY_CLIP_MAP; version-safe fcurve access for Blender 4.4+/5.x
  slotted actions (Action.fcurves was removed)

Assets/tooling:
- bundle assets/characters/animations/_library.glb — CC0 Quaternius
  Universal Animation Library (13 game clips), + .gdignore so Godot
  skips the pipeline-input folder
- requirements.txt (stdlib-only; documents Blender-python separation)
- pipeline docs updated for the bundled library + swap instructions

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-06 12:42:31 -04:00
Nicholas ButzkeandClaude Fable 5 d05477c135 feat: Sketchfab-to-game character pipeline, FP/TP animated views, client-auth netcode, audio system
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]>
2026-07-06 02:28:58 -04:00
Hermes 39063bfe9e fix: create proper Idle animation in Godot when GLB export loses tracks
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.
2026-06-23 18:55:12 -04:00
Hermes a83fa41b19 fix: use original rigged skeleton for animations, add 6 new animations
The twintails were moving as arms because the auto-rig script treated the
combined mesh as one piece. Now using the original miku_rigged_final.glb
skeleton (which has correct skin weights from the model creator) and
adding 6 new animations (Idle, Walk, Run, Jump, Crouch, Death) on top
of the existing skeleton.

- tools/add_animations.py: adds animations to an existing rigged GLB
- tools/rig_and_animate.py: updated to separate mesh into loose parts
  before rigging (for future use with other models)
- miku_rigged_animated.glb: now 7 animations with correct skin weights
2026-06-23 00:33:40 -04:00
Hermes 0672bebe7b feat: add rigged+animated Miku player model with auto-rig pipeline
- 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
2026-06-23 00:19:52 -04:00