Skip to content

feat: validate wearable armature bone names against dcl avatar skeleton#3429

Merged
juanmahidalgo merged 3 commits into
masterfrom
feat/wearable-armature-name-validation
Jun 30, 2026
Merged

feat: validate wearable armature bone names against dcl avatar skeleton#3429
juanmahidalgo merged 3 commits into
masterfrom
feat/wearable-armature-name-validation

Conversation

@juanmahidalgo

Copy link
Copy Markdown
Contributor

Why

Analysis of 4,340 real wearable submissions shows rigging issues are a top curation-feedback reason (12.7% of collections). The Builder already validates bone influences (>4/vertex), leaf bones, and non-deform bones for wearables — but it did not validate that a wearable's armature bone names match the Decentraland avatar skeleton. A wearable skinned to a non-DCL or misnamed skeleton passes import and then breaks in-world / fails curation. (validateArmatureNaming existed but was wired only into emote validation.)

Changes

  • Add validateArmatureBoneNames (in src/lib/glbValidation/wearableValidators.ts): collects skinned-mesh joint names and reports a WARNING when the skeleton looks wrong — required core avatar bones are missing, or joints reference unknown/misnamed bones. Spring bones (names containing springbone) are allowed extras and ignored. Wearables with no skinned meshes (rigid accessories) are skipped.
  • Add validateNoUnriggedVertices: flags skinned-mesh vertices whose total skin weight is effectively zero (not bound to any bone), which won't follow the avatar's movement.
  • Wire both validators into validateWearableGLTF in src/lib/glbValidation/index.ts.
  • Add the canonical 62-bone DCL avatar skeleton (AVATAR_BONE_NAMES / AVATAR_BONE_NAME_SET) and a required core-bone subset (AVATAR_CORE_BONE_NAMES) to src/lib/glbValidation/constants.ts. No existing source of truth for this list was found in the repo or @dcl/schemas.
  • Add armature_bone_names and unrigged_vertices message keys to en.json, es.json, and zh.json.
  • Add focused unit tests covering: correct full skeleton (no issue), spring-bone extras ignored, missing core bones (warning), unknown/misnamed bones (warning), unknown-only branch, no-skinned-mesh skip, and unrigged-vertex detection.

Severity is WARNING (non-blocking), consistent with the other non-fatal wearable checks, since valid edge cases exist.

Test plan

  • prettier check passes
  • lint (eslint) passes
  • build passes
  • testglbValidation suite green (126 tests)

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
builder Ready Ready Preview, Comment Jun 30, 2026 8:00am

Request Review

@coveralls

coveralls commented Jun 25, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 28429301540

Coverage increased (+0.2%) to 52.401%

Details

  • Coverage increased (+0.2%) from the base build.
  • Patch coverage: 50 of 50 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 12718
Covered Lines: 7278
Line Coverage: 57.23%
Relevant Branches: 5566
Covered Branches: 2303
Branch Coverage: 41.38%
Branches in Coverage %: Yes
Coverage Strength: 34.48 hits per line

💛 - Coveralls

@juanmahidalgo juanmahidalgo marked this pull request as ready for review June 25, 2026 18:39

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved — Solid new validators with good test coverage

Overview

Adds two wearable validators: validateArmatureBoneNames (checks skinned-mesh joints match the DCL avatar skeleton) and validateNoUnriggedVertices (flags zero-weight vertices). Both emit WARNINGs (non-blocking), consistent with the existing validator pattern. i18n added for en/es/zh.

Findings

[P2] Bone count comment says 62 — verify it's accurate
src/lib/glbValidation/constants.ts — The JSDoc claims "62 bones." By my count: 6 (spine/head) + 8 (arm chains) + 40 (fingers: 5×4×2) + 8 (leg chains) = 62. ✅ Checks out, but the count is non-obvious because of the programmatic handFingerBones() expansion — consider adding a brief breakdown in the comment so future maintainers don't have to re-derive it.

[P2] Avatar_Spine1/Avatar_Spine2 and shoulders omitted from AVATAR_CORE_BONE_NAMES
src/lib/glbValidation/constants.ts — The core subset (16 bones) omits Spine1, Spine2, LeftShoulder, and RightShoulder. If this is intentional (allowing simpler partial skeletons for accessories), a brief comment explaining the rationale would help. If not, they should be added.

[P2] No multi-mesh aggregation test
src/lib/glbValidation/wearableValidators.spec.tsvalidateArmatureBoneNames collects joints across all SkinnedMesh nodes into one Set, but every test uses a single mesh. Consider adding a test with two meshes whose combined bone sets pass/fail the core check.

[P2] No test for the (+N more) truncation branch
The formatting code truncates bone lists to 5 items. A test with a fully foreign skeleton (>5 unknown bones) would exercise this path.

[P2] Armature root node could be flagged as "unknown"
src/lib/glbValidation/wearableValidators.ts — If a GLB exporter includes the armature root in skeleton.bones, it would be reported as unknown since AVATAR_BONE_NAMES doesn't include 'Armature'. Consider adding it to the allowlist alongside the spring bone exception.

[P2] Case-sensitive matching with no near-miss hint
Bone matching is case-sensitive (correct), but spring bone filtering is case-insensitive. A bone named avatar_hips (wrong case) gets reported as "unknown" with no hint about casing. A case-insensitive near-miss suggestion would help creators using non-standard DCC tools.

CI Status

All checks passing (audit ✅, test ✅, Vercel ✅).

Verdict

No P0 or P1 issues. The validators are well-structured, follow existing patterns, and have solid test coverage. The P2 items are minor improvements that can be addressed in follow-ups.


Reviewed by Jarvis 🤖 · Requested by Juan Manuel Hidalgo via Slack

@juanmahidalgo juanmahidalgo merged commit c0af0fa into master Jun 30, 2026
7 checks passed
@juanmahidalgo juanmahidalgo deleted the feat/wearable-armature-name-validation branch June 30, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants