[BUG] Casino: MiuTang (鄧妙婷) dealer bow is wrong — head rises, dress lifts/swings #2

Open
opened 2026-11-10 06:37:55 +08:00 by admin · 3 comments
Owner

Service / Project

casino (Node: pve01, LXC 19019 / casino-lxc)
Public: https://casino.theforwardway.com

Description

During dealer handover, 鄧妙婷 / MiuTang's bow animation is incorrect. The model is now rigged with 4 bones (Hips/Spine/Spine1/Head) and feet stay planted, but the live bow still fails: the head moves up instead of down, and dress/leg-adjacent meshes lift and swing in Z. Project test tests/test_miutang_bow_fix.mjs FAILS: "Head must move down at least 10 units" (actual Δy ≈ +37.4). Live top-down camera can show legs behind the table, but the bow peak was not captured in screenshots; code-level FAIL stands.

Earlier unrigged-fallback root cause (04:12) is superseded — current path is spine bones (hasSpine=true); preferred remaining fix is bone-axis / bind-pose correction (or invert Spine rotX sign and re-weight dress/leg verts onto Hips only).

Steps to Reproduce

  1. Open https://casino.theforwardway.com/#bac-1
  2. Wait for 3D dealer (李雅姿) to appear
  3. Click 「🔄 換官交更」 until 鄧妙婷 / MiuTang is the incoming or outgoing dealer
  4. Drag the camera down for a top-down view (or side view) during the mutual ~70° bow
  5. Optionally run: node tests/test_miutang_bow_fix.mjs

Expected Behavior

Head/torso bend forward and down; feet and lower body stay planted; dress does not lift/swing backward (same contract as Grace Lee / Asian male spine bows).

Actual Behavior

Head sample Δy ≈ +37.4 (UP); dress AABB minY lifts ~+10.8 and maxZ ~+12.3; test_miutang_bow_fix.mjs fails. Feet Object_4 minY planted.

Error Logs / Evidence

  • Retest: /workspace/casino-qa/casino-retest-20261110-0531.txt §7
  • Earlier filing: /workspace/casino-qa/casino-defect-miutang-bow-20261110-0412.txt (root cause outdated; repro still valid)
  • src/main.js applyDealerWaistBow (~4280–4358); public/models/MiuTang.glb (4 joints, animations:[])
  • Quantitative peak bowAngle=1.2217: Spine.rotX=1.10, Spine1.rotX=0.15; Head rest y=11.248 → bow y=48.647
  • Fix guidance: invert Spine rotX / correct bind-pose bone axes; re-weight dress verts to Hips; re-run test_miutang_bow_fix.mjs + top-down handover capture

Reported automatically by Grok QA Agent (Lumi).

### Service / Project **casino** (Node: `pve01`, LXC `19019` / casino-lxc) Public: https://casino.theforwardway.com ### Description During dealer handover, 鄧妙婷 / MiuTang's bow animation is incorrect. The model is now rigged with 4 bones (Hips/Spine/Spine1/Head) and feet stay planted, but the live bow still fails: the head moves **up** instead of down, and dress/leg-adjacent meshes lift and swing in Z. Project test `tests/test_miutang_bow_fix.mjs` FAILS: "Head must move down at least 10 units" (actual Δy ≈ +37.4). Live top-down camera can show legs behind the table, but the bow peak was not captured in screenshots; code-level FAIL stands. Earlier unrigged-fallback root cause (04:12) is **superseded** — current path is spine bones (`hasSpine=true`); preferred remaining fix is bone-axis / bind-pose correction (or invert Spine rotX sign and re-weight dress/leg verts onto Hips only). ### Steps to Reproduce 1. Open https://casino.theforwardway.com/#bac-1 2. Wait for 3D dealer (李雅姿) to appear 3. Click 「🔄 換官交更」 until 鄧妙婷 / MiuTang is the incoming or outgoing dealer 4. Drag the camera **down** for a top-down view (or side view) during the mutual ~70° bow 5. Optionally run: `node tests/test_miutang_bow_fix.mjs` ### Expected Behavior Head/torso bend forward and down; feet and lower body stay planted; dress does not lift/swing backward (same contract as Grace Lee / Asian male spine bows). ### Actual Behavior Head sample Δy ≈ +37.4 (UP); dress AABB minY lifts ~+10.8 and maxZ ~+12.3; `test_miutang_bow_fix.mjs` fails. Feet Object_4 minY planted. ### Error Logs / Evidence - Retest: `/workspace/casino-qa/casino-retest-20261110-0531.txt` §7 - Earlier filing: `/workspace/casino-qa/casino-defect-miutang-bow-20261110-0412.txt` (root cause outdated; repro still valid) - `src/main.js` `applyDealerWaistBow` (~4280–4358); `public/models/MiuTang.glb` (4 joints, animations:[]) - Quantitative peak bowAngle=1.2217: Spine.rotX=1.10, Spine1.rotX=0.15; Head rest y=11.248 → bow y=48.647 - Fix guidance: invert Spine rotX / correct bind-pose bone axes; re-weight dress verts to Hips; re-run `test_miutang_bow_fix.mjs` + top-down handover capture --- *Reported automatically by **Grok QA Agent** (Lumi).*
admin added the
bug
qa/grok
pve01
labels 2026-11-10 06:37:55 +08:00
Author
Owner

Update from Patrick (06:41 HKT, Nov 10): in the latest casino build MiuTang (鄧妙婷) does not bow at all during the handover. The banner still announces the 70° bow, but the model never performs it. This explains why the 06:02-06:28 HKT screen captures never caught a bow peak from any camera angle. Expected: a correct 70° waist bow with legs and feet planted. Actual: no bow animation plays.


Reported automatically by Grok QA Agent (Lumi).

Update from Patrick (06:41 HKT, Nov 10): in the latest casino build MiuTang (鄧妙婷) does not bow at all during the handover. The banner still announces the 70° bow, but the model never performs it. This explains why the 06:02-06:28 HKT screen captures never caught a bow peak from any camera angle. Expected: a correct 70° waist bow with legs and feet planted. Actual: no bow animation plays. --- *Reported automatically by **Grok QA Agent** (Lumi).*
Author
Owner

QA follow-up (2026-11-10 06:45 HKT) — “fails to bow at all” on the latest build

Patrick reported at 06:41 HKT that 鄧妙婷 / MiuTang no longer bows. Read-only retest of the 06:19 tree vs the 05:30 build, plus a headless three.js r160 GLTFLoader sim of applyDealerWaistBow at peak (1.2217 rad). Full write-up: casino-defect-miutang-nobow-20261110-0641.txt.

Deployed site matches the 06:19 build

  • https://casino.theforwardway.com/ → assets/index-DrR0rZdu.js (sha256 960685cb…, Last-Modified 2026-11-09 22:19:39 GMT = 06:19:39 HKT)
  • /models/MiuTang.glb sha256 2dfe3f9b…, 3,365,592 bytes, Last-Modified 2026-11-09 21:51:36 GMT = 05:51:36 HKT
  • Both match /home/iiaiiappa/PatProject/casino exactly. The 05:30 bundle was index-CJXh54Ih.js; the 05:30 GLB was the same size but a different hash (6b083119…).

What is not broken

Bone names are still Hips / Spine / Spine1 / Head (no mixamorig: prefix). hasSpine=true. Bow amplitude is not 0 (Spine.rotX=1.10, Spine1.rotX=0.15). No clip to miss (animations: []; bow is procedural). Skin is bound to the correct 4-bone skeleton (bindOk=true). applyDealerWaistBow at src/main.js:4293-4374 is unchanged from 05:30 and still takes the rigged path, so the unrigged fallback is not used.

Root cause

The attempted “plant the dress / legs” fix overshot.

public/models/MiuTang.glb was replaced at 05:51 HKT. Object_2, Object_4 and Object_6 (body / dress / skirt) are now 100% weighted to Hips. The same assignment is applied again at runtime in loadDealerModel (src/main.js:4270-4282, present in index-DrR0rZdu.js, absent from the 05:30 bundle). The comment says “for Miu Tang” but the code is not gated on modelPath. Source of the baked weights: scratch/reweight_miutang.py:50-53 (mtime 05:50 HKT):

# Lower body, dress, skirt: 100% Hips (strictly stationary, no lift, no swing)
if mesh.name in ['Object_4', 'Object_2', 'Object_6']:
    for i in range(len(mesh.data.vertices)):
        vg_hips.add([i], 1.0, 'REPLACE')

Those meshes are not lower-body only. Object_2 has 413/665 vertices above the Spine pivot (Y=38), up to Y≈57.7 (chest / shoulders, just below the Head bone at Y=58). Object_4 has 309 vertices above Y=38. applyDealerWaistBow never rotates Hips, so the visible waist, chest and dress stay still.

Object_3 / Object_5 (face / head) still have the 05:30 Spine1/Head weights and still bow.

Headless sim (peak bow, updateMatrixWorld at rest)

Vertex 05:30 model 05:51 / deployed model
Object_4 idx 1177, Y=50 (chest) Δy=-6.24, Δz=+10.92 Δ=0
Object_2 idx 90, Y=54 (upper dress/torso) Δy=-7.93, Δz=+15.32 Δ=0
Object_2 idx 490, Y=30 (hem) Δ=0 Δ=0
Object_5 idx 1530, top of head Δy=-20.60, Δz=+28.65 same (head still bows; ≈0.50 m down, 0.69 m forward at 1.68 m scale)

From the seated table camera this reads as “she failed to bow”: the torso and dress stay ramrod straight, and the head shears off an unmoving neck (and may dip behind the table rail).

Note on tests/test_miutang_bow_fix.mjs

Still fails at line 117 (“Head must move down at least 10 units”) on both the 05:30 and 05:51 models. That is a test artifact: rest is sampled with applyBoneTransform before updateMatrixWorld, so rest head Y comes out as 11.248 instead of 69.248, and the test sees Δy=+37.4. With matrices updated at rest, Δy=-20.60 and the assertion would pass on both models. The test also does not assert that a chest vertex moves, so it cannot catch this regression.

Suggested fix (not applied; QA is read-only)

  1. Model: keep Y≤38 at 100% Hips (feet / hem planted). Re-introduce a height blend on Object_2/4/6 for Y>38 (Hips→Spine in (38,48], Spine→Spine1 in (48,58]), using world Y (the shipped rig is Y-up). Do not bind an entire mesh that reaches Y=57 to Hips.
  2. Code: remove or narrow main.js:4270-4282. As written it will stomp a correct blend, and it is not limited to MiuTang. If a runtime guard is kept, only rewrite vertices with model-space Y≤38, and only when modelPath includes MiuTang.
  3. Test: call updateMatrixWorld(true) before rest samples; add an assertion that an Object_4/Object_2 vertex near Y=50–54 moves forward (Δz>8) and down (Δy<-4) at peak, while a Y≤30 hem/foot vertex stays at delta 0.

This does not close #2. The original dress-swing issue is still worth fixing, but the 05:51 weights + the new runtime override are why the waist bow is gone on the live 06:19 build.

## QA follow-up (2026-11-10 06:45 HKT) — “fails to bow at all” on the latest build Patrick reported at 06:41 HKT that 鄧妙婷 / MiuTang no longer bows. Read-only retest of the 06:19 tree vs the 05:30 build, plus a headless three.js r160 GLTFLoader sim of `applyDealerWaistBow` at peak (1.2217 rad). Full write-up: `casino-defect-miutang-nobow-20261110-0641.txt`. ### Deployed site matches the 06:19 build - `https://casino.theforwardway.com/` → `assets/index-DrR0rZdu.js` (sha256 `960685cb…`, Last-Modified 2026-11-09 22:19:39 GMT = **06:19:39 HKT**) - `/models/MiuTang.glb` sha256 `2dfe3f9b…`, 3,365,592 bytes, Last-Modified 2026-11-09 21:51:36 GMT = **05:51:36 HKT** - Both match `/home/iiaiiappa/PatProject/casino` exactly. The 05:30 bundle was `index-CJXh54Ih.js`; the 05:30 GLB was the same size but a different hash (`6b083119…`). ### What is *not* broken Bone names are still `Hips / Spine / Spine1 / Head` (no `mixamorig:` prefix). `hasSpine=true`. Bow amplitude is not 0 (`Spine.rotX=1.10`, `Spine1.rotX=0.15`). No clip to miss (`animations: []`; bow is procedural). Skin is bound to the correct 4-bone skeleton (`bindOk=true`). `applyDealerWaistBow` at `src/main.js:4293-4374` is unchanged from 05:30 and still takes the rigged path, so the unrigged fallback is not used. ### Root cause The attempted “plant the dress / legs” fix overshot. `public/models/MiuTang.glb` was replaced at 05:51 HKT. `Object_2`, `Object_4` and `Object_6` (body / dress / skirt) are now **100% weighted to Hips**. The same assignment is applied again at runtime in `loadDealerModel` (`src/main.js:4270-4282`, present in `index-DrR0rZdu.js`, absent from the 05:30 bundle). The comment says “for Miu Tang” but the code is not gated on `modelPath`. Source of the baked weights: `scratch/reweight_miutang.py:50-53` (mtime 05:50 HKT): ```python # Lower body, dress, skirt: 100% Hips (strictly stationary, no lift, no swing) if mesh.name in ['Object_4', 'Object_2', 'Object_6']: for i in range(len(mesh.data.vertices)): vg_hips.add([i], 1.0, 'REPLACE') ``` Those meshes are not lower-body only. `Object_2` has **413/665 vertices above the Spine pivot (Y=38)**, up to Y≈57.7 (chest / shoulders, just below the Head bone at Y=58). `Object_4` has 309 vertices above Y=38. `applyDealerWaistBow` never rotates Hips, so the visible waist, chest and dress stay still. `Object_3` / `Object_5` (face / head) still have the 05:30 Spine1/Head weights and still bow. ### Headless sim (peak bow, `updateMatrixWorld` at rest) | Vertex | 05:30 model | 05:51 / deployed model | |---|---|---| | Object_4 idx 1177, Y=50 (chest) | Δy=-6.24, Δz=+10.92 | **Δ=0** | | Object_2 idx 90, Y=54 (upper dress/torso) | Δy=-7.93, Δz=+15.32 | **Δ=0** | | Object_2 idx 490, Y=30 (hem) | Δ=0 | Δ=0 | | Object_5 idx 1530, top of head | Δy=-20.60, Δz=+28.65 | same (head still bows; ≈0.50 m down, 0.69 m forward at 1.68 m scale) | From the seated table camera this reads as “she failed to bow”: the torso and dress stay ramrod straight, and the head shears off an unmoving neck (and may dip behind the table rail). ### Note on `tests/test_miutang_bow_fix.mjs` Still fails at line 117 (“Head must move down at least 10 units”) on **both** the 05:30 and 05:51 models. That is a test artifact: rest is sampled with `applyBoneTransform` *before* `updateMatrixWorld`, so rest head Y comes out as 11.248 instead of 69.248, and the test sees Δy=+37.4. With matrices updated at rest, Δy=-20.60 and the assertion would pass on both models. The test also does not assert that a chest vertex moves, so it cannot catch this regression. ### Suggested fix (not applied; QA is read-only) 1. **Model:** keep Y≤38 at 100% Hips (feet / hem planted). Re-introduce a height blend on Object_2/4/6 for Y>38 (Hips→Spine in (38,48], Spine→Spine1 in (48,58]), using world **Y** (the shipped rig is Y-up). Do not bind an entire mesh that reaches Y=57 to Hips. 2. **Code:** remove or narrow `main.js:4270-4282`. As written it will stomp a correct blend, and it is not limited to MiuTang. If a runtime guard is kept, only rewrite vertices with model-space Y≤38, and only when `modelPath` includes `MiuTang`. 3. **Test:** call `updateMatrixWorld(true)` before rest samples; add an assertion that an Object_4/Object_2 vertex near Y=50–54 moves forward (Δz>8) and down (Δy<-4) at peak, while a Y≤30 hem/foot vertex stays at delta 0. This does not close #2. The original dress-swing issue is still worth fixing, but the 05:51 weights + the new runtime override are why the waist bow is gone on the live 06:19 build.
Author
Owner

Root cause update (latest build, MiuTang does not bow at all)

The banner and the 2.8s–5.5s handover timer still run. applyDealerWaistBow in src/main.js:4293 finds the new Spine / Spine1 bones (hasSpine=true) and rotates them on +X. That path is correct, and the axis/sign on this Y-up rig would dip the head down and forward. The unrigged fallback is therefore skipped. Idle/mixer do not overwrite the bow (animate() is gated on !isHandoverActive).

The visible bow is missing because the torso cannot deform:

  1. Model — public/models/MiuTang.glb (05:51 HKT, also in dist/, md5 7f94ab2c…) was re-exported by scratch/reweight_miutang.py. It has a valid 4-bone skin (Hips/Spine/Spine1/Head, JOINTS_0/WEIGHTS_0, IBMs OK), but the script binds every vertex of Object_2, Object_4 and Object_6 to Hips, not just the legs. Those meshes include the chest and upper dress (Object_2 has 287 verts in Y 48–58; Object_4 has 309 verts above the waist at Y=38). Only the small neck piece (Object_3) and head/hair (Object_5) follow Spine/Head, so the head dives into a rigid standing bodice. From the table camera there is no waist bow to screenshot.

  2. Code — loadDealerModel at src/main.js:4247–4259 re-forces the same 100% Hips lock on Object_2/Object_4/Object_6 at runtime, which would undo a correct re-skin.

  3. False-green test — tests/test_miutang_bow_fix.mjs now passes (exit 0, read-only run). It only checks that the feet/dress hem stay still and that the head moves down. It never samples a torso vertex above the waist.

Fix

  • Model: Re-weight Object_2/Object_4/Object_6 by height (Y≤38 Hips; 38–48 blend Hips/Spine; 48–58 Spine/Spine1; then Head). Keep feet and dress hem on Hips.
  • Code: Remove or narrow the runtime lock at main.js:4247–4259 so it cannot wipe those torso weights. Do not flip the Spine +X sign on this rig.
  • Test: Fail the case unless an Object_2/Object_4 vertex with bind-pose Y>48 also moves down and forward.

Full write-up: /workspace/casino-qa/casino-defect-miutang-nobow-20261110.txt


Reported automatically by Grok QA Agent (Lumi).

### Root cause update (latest build, MiuTang does not bow at all) The banner and the 2.8s–5.5s handover timer still run. `applyDealerWaistBow` in `src/main.js:4293` finds the new `Spine` / `Spine1` bones (`hasSpine=true`) and rotates them on +X. That path is correct, and the axis/sign on this Y-up rig would dip the head down and forward. The unrigged fallback is therefore skipped. Idle/mixer do not overwrite the bow (`animate()` is gated on `!isHandoverActive`). The visible bow is missing because the torso cannot deform: 1. **Model** — `public/models/MiuTang.glb` (05:51 HKT, also in `dist/`, md5 `7f94ab2c…`) was re-exported by `scratch/reweight_miutang.py`. It has a valid 4-bone skin (Hips/Spine/Spine1/Head, JOINTS_0/WEIGHTS_0, IBMs OK), but the script binds **every** vertex of `Object_2`, `Object_4` and `Object_6` to **Hips**, not just the legs. Those meshes include the chest and upper dress (`Object_2` has 287 verts in Y 48–58; `Object_4` has 309 verts above the waist at Y=38). Only the small neck piece (`Object_3`) and head/hair (`Object_5`) follow Spine/Head, so the head dives into a rigid standing bodice. From the table camera there is no waist bow to screenshot. 2. **Code** — `loadDealerModel` at `src/main.js:4247–4259` re-forces the same 100% Hips lock on `Object_2`/`Object_4`/`Object_6` at runtime, which would undo a correct re-skin. 3. **False-green test** — `tests/test_miutang_bow_fix.mjs` now passes (exit 0, read-only run). It only checks that the feet/dress hem stay still and that the *head* moves down. It never samples a torso vertex above the waist. ### Fix - **Model:** Re-weight `Object_2`/`Object_4`/`Object_6` by height (Y≤38 Hips; 38–48 blend Hips/Spine; 48–58 Spine/Spine1; then Head). Keep feet and dress hem on Hips. - **Code:** Remove or narrow the runtime lock at `main.js:4247–4259` so it cannot wipe those torso weights. Do not flip the Spine +X sign on this rig. - **Test:** Fail the case unless an `Object_2`/`Object_4` vertex with bind-pose Y>48 also moves down and forward. Full write-up: `/workspace/casino-qa/casino-defect-miutang-nobow-20261110.txt` --- *Reported automatically by **Grok QA Agent** (Lumi).*
Sign in to join this conversation.
No description provided.