cozyclay 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +40 -113
- package/bin/agent/agent-runner.mjs +9 -10
- package/bin/agent/cliproxy-provider.mjs +135 -0
- package/bin/agent/credential-store.mjs +30 -7
- package/bin/agent/pi-tools.mjs +4 -1
- package/bin/agent/provider-keys.mjs +32 -0
- package/bin/agent/provider-login.mjs +110 -0
- package/bin/agent/provider-routes.mjs +99 -0
- package/bin/agent/providers.mjs +19 -97
- package/bin/agent/script-tool.mjs +17 -4
- package/bin/agent/studio-motion-reference.mjs +23 -0
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-rebase-text.mjs +32 -0
- package/bin/agent/studio-rebase.mjs +26 -39
- package/bin/agent/studio-tools.mjs +9 -28
- package/bin/agent/tool-arguments.mjs +49 -0
- package/bin/agent/turn-frames.mjs +66 -0
- package/bin/codex-auth.mjs +9 -2
- package/bin/cozyclay.mjs +10 -116
- package/bin/live/cli.mjs +22 -6
- package/bin/mcp-runtime.mjs +2 -12
- package/bin/package-signature.mjs +0 -4
- package/dist/app/index.html +7 -6
- package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
- package/dist/assets/analytics-C9sUnndd.js +1 -0
- package/dist/assets/app-CCh--1Hc.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
- package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
- package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-C4yKH1p4.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +3 -3
- package/dist/llms.txt +14 -0
- package/dist/sw.js +3 -6
- package/dist/workflow/index.html +5 -4
- package/mcp/LIVE-PROTOCOL.md +7 -47
- package/mcp/README.md +16 -26
- package/mcp/live-hub.mjs +6 -10
- package/mcp/package.json +1 -3
- package/mcp/tool-handlers.mjs +4 -168
- package/package.json +3 -22
- package/src/App.jsx +174 -2639
- package/src/agent-progress.js +79 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +5 -0
- package/src/app-stage.jsx +2 -34
- package/src/asset-pane.jsx +6 -5
- package/src/camera-block.js +21 -0
- package/src/camera-direction.js +120 -0
- package/src/character-kind.js +3 -9
- package/src/command-bus.js +8 -6
- package/src/commands/cast.js +5 -34
- package/src/commands/elements/character.js +1 -1
- package/src/commands/elements/motion.js +1 -6
- package/src/commands/elements/object.js +6 -2
- package/src/commands/elements/shot.js +4 -1
- package/src/commands/elements.js +38 -14
- package/src/commands/index.js +3 -1
- package/src/commands/kits.js +37 -0
- package/src/commands/motion-timing.js +57 -0
- package/src/commands/motion.js +9 -152
- package/src/commands/motion3-compile.js +65 -0
- package/src/commands/motion3.js +207 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +49 -11
- package/src/commands/stage.js +14 -1
- package/src/commands/view.js +4 -1
- package/src/document-mirrors.js +42 -0
- package/src/document-store.js +4 -0
- package/src/domains/cast.js +19 -194
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion/take-source.js +51 -0
- package/src/domains/motion.js +60 -1838
- package/src/domains/scenes.js +12 -55
- package/src/domains/shots.js +2 -2
- package/src/domains/stage.js +4 -2
- package/src/draft-ghost.js +46 -0
- package/src/draft-ghost.jsx +129 -0
- package/src/dualview.jsx +4 -3
- package/src/effects/EffectsLayer.jsx +112 -0
- package/src/effects/effect-meshes.js +232 -0
- package/src/effects/effect-record.js +103 -0
- package/src/effects/emitter.js +59 -0
- package/src/effects/simulate.js +261 -0
- package/src/effects/state.js +59 -0
- package/src/execution-telemetry.js +2 -3
- package/src/first-success-guide.jsx +5 -5
- package/src/ghost-set.js +257 -0
- package/src/held-object-edit.jsx +113 -0
- package/src/held-object-pose.js +175 -0
- package/src/hierarchy-model.js +1 -1
- package/src/hierarchy-panel.jsx +1 -1
- package/src/imported-mesh.jsx +103 -0
- package/src/kits/held.js +84 -0
- package/src/kits/index.js +70 -0
- package/src/kits/smoking.js +57 -0
- package/src/light-blockers.js +93 -0
- package/src/motion/beat-board-model.js +84 -0
- package/src/motion/beat-board.css +124 -0
- package/src/motion/beat-board.jsx +59 -0
- package/src/motion/center-of-mass.js +66 -0
- package/src/motion/fix-collisions.js +850 -0
- package/src/motion/physics-review.js +118 -0
- package/src/{ardy → motion}/physics-support.js +1 -76
- package/src/motion/rig-snapshot.js +22 -0
- package/src/motion/take-segments.jsx +140 -0
- package/src/{ardy → motion}/timeline-coordinates.js +0 -21
- package/src/{ardy → motion}/timeline.css +1 -2
- package/src/{ardy → motion}/timeline.jsx +48 -419
- package/src/motion/waypoints.js +76 -0
- package/src/motion3/beats.js +83 -0
- package/src/motion3/body.js +158 -0
- package/src/motion3/bones.js +47 -0
- package/src/motion3/carried.js +47 -0
- package/src/motion3/compile-job.js +75 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +105 -0
- package/src/motion3/compiler/arm-orient.js +128 -0
- package/src/motion3/compiler/channels.js +125 -0
- package/src/motion3/compiler/compile.js +205 -0
- package/src/motion3/compiler/gait-rhythm.js +97 -0
- package/src/motion3/compiler/grip.js +171 -0
- package/src/motion3/compiler/head-steady.js +48 -0
- package/src/motion3/compiler/hold.js +134 -0
- package/src/motion3/compiler/idle.js +113 -0
- package/src/motion3/compiler/limbs.js +170 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +162 -0
- package/src/motion3/compiler/quat.js +49 -0
- package/src/motion3/compiler/skeleton.js +74 -0
- package/src/motion3/compiler/validate-common.js +32 -0
- package/src/motion3/compiler/validate-goals.js +118 -0
- package/src/motion3/compiler/validate-objects.js +143 -0
- package/src/motion3/compiler/validate-parts.js +116 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +73 -0
- package/src/motion3/compiler/walk-pelvis.js +275 -0
- package/src/motion3/compiler/walk.js +207 -0
- package/src/motion3/compiler/wrist-clamp.js +32 -0
- package/src/motion3/delta.js +47 -0
- package/src/motion3/describe.js +174 -0
- package/src/motion3/docs.js +27 -0
- package/src/motion3/edit-carry.js +21 -0
- package/src/motion3/fix/ease.js +16 -0
- package/src/motion3/fix/ground.js +37 -0
- package/src/motion3/fix/index.js +52 -0
- package/src/motion3/fix/push.js +71 -0
- package/src/motion3/fix/reach.js +46 -0
- package/src/motion3/fix/retime.js +79 -0
- package/src/motion3/fix/self.js +211 -0
- package/src/motion3/fix/slide.js +70 -0
- package/src/motion3/fix/turn.js +51 -0
- package/src/motion3/follow.js +39 -0
- package/src/motion3/free-motion.js +173 -0
- package/src/motion3/grip-choice.js +130 -0
- package/src/motion3/hold-plan.js +157 -0
- package/src/motion3/json-patch.js +77 -0
- package/src/motion3/key-aim.js +105 -0
- package/src/motion3/key-edit.js +82 -0
- package/src/motion3/lenient.js +127 -0
- package/src/motion3/object-keys.js +236 -0
- package/src/motion3/object-pose.js +182 -0
- package/src/motion3/object-tracks.js +12 -0
- package/src/motion3/pipeline.js +102 -0
- package/src/motion3/playback.js +51 -0
- package/src/motion3/probes.js +91 -0
- package/src/motion3/qa/body-checks.js +34 -0
- package/src/motion3/qa/check-names.js +14 -0
- package/src/motion3/qa/checks.js +121 -0
- package/src/motion3/qa/contact-checks.js +51 -0
- package/src/motion3/qa/explain.js +80 -0
- package/src/motion3/qa/fmt.js +5 -0
- package/src/motion3/qa/foot-checks.js +72 -0
- package/src/motion3/qa/geometry.js +77 -0
- package/src/motion3/qa/goals.js +191 -0
- package/src/motion3/qa/ground.js +60 -0
- package/src/motion3/qa/hints-contact.js +179 -0
- package/src/motion3/qa/hints-goal.js +160 -0
- package/src/motion3/qa/hints-knee.js +24 -0
- package/src/motion3/qa/hints-motion.js +209 -0
- package/src/motion3/qa/hints-object.js +91 -0
- package/src/motion3/qa/index.js +42 -0
- package/src/motion3/qa/key-checks.js +82 -0
- package/src/motion3/qa/near.js +96 -0
- package/src/motion3/qa/object-checks.js +135 -0
- package/src/motion3/qa/patch.js +161 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +218 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +120 -0
- package/src/motion3/repair-tune.js +121 -0
- package/src/motion3/repair.js +83 -0
- package/src/motion3/report.js +67 -0
- package/src/motion3/rigs/index.js +14 -0
- package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/x-bot-tpose.json +1 -0
- package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/y-bot-tpose.json +1 -0
- package/src/motion3/scene.js +60 -0
- package/src/motion3/schema/brief.js +89 -0
- package/src/motion3/schema/fields.js +44 -0
- package/src/motion3/schema/spec-examples.js +46 -0
- package/src/motion3/schema/topics.js +111 -0
- package/src/motion3/schema/types.js +147 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/skills/basic.js +82 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/index.js +83 -0
- package/src/motion3/skills/info.js +65 -0
- package/src/motion3/skills/smoke-kit.js +109 -0
- package/src/motion3/skills/smoke.js +160 -0
- package/src/motion3/spec-store.js +59 -0
- package/src/motion3/take-edit.js +155 -0
- package/src/motion3/take.js +63 -0
- package/src/motion3/timeline.js +127 -0
- package/src/motion3/views.js +121 -0
- package/src/motion3/walk-plan.js +119 -0
- package/src/object-catalog.jsx +7 -1
- package/src/object-colors.js +98 -0
- package/src/object-gizmo-parts.js +115 -0
- package/src/object-gizmo.jsx +37 -122
- package/src/object-glow.js +139 -0
- package/src/object-hidden.js +33 -0
- package/src/object-look.js +196 -0
- package/src/object-size.js +10 -0
- package/src/object-travel.js +71 -6
- package/src/panels/CameraPanel.jsx +7 -7
- package/src/panels/HdrEnvironmentControls.jsx +59 -0
- package/src/panels/LightPanel.jsx +25 -4
- package/src/panels/ObjectLookPanel.jsx +88 -0
- package/src/panels/PoseImagePanel.jsx +1 -1
- package/src/panels/PosePanel.jsx +2 -17
- package/src/panels/RigControlPanel.jsx +5 -53
- package/src/panels/SubjectBox.jsx +4 -1
- package/src/panels/details.css +14 -0
- package/src/posestudio.jsx +4 -27
- package/src/project-browser.jsx +3 -4
- package/src/project-resources.js +18 -31
- package/src/project.js +13 -104
- package/src/props.jsx +25 -280
- package/src/rail-dot-drag.js +23 -0
- package/src/render-passes.js +10 -0
- package/src/resource-status.jsx +1 -0
- package/src/result-modal.jsx +4 -19
- package/src/room.jsx +20 -12
- package/src/scene-assets.js +8 -6
- package/src/scene-light-place.js +72 -0
- package/src/scene-lights.jsx +148 -0
- package/src/scene-objects.js +31 -139
- package/src/scenes.js +15 -105
- package/src/semantic-edit.js +2 -5
- package/src/set-pieces.jsx +183 -0
- package/src/settings-menu.jsx +3 -11
- package/src/shell/BottomDock.jsx +11 -53
- package/src/shell/CompositionGuideButton.jsx +20 -0
- package/src/shell/DetailsSlot.jsx +16 -200
- package/src/shell/GhostsMenuGroup.jsx +74 -0
- package/src/shell/LibrarySlot.jsx +1 -3
- package/src/shell/MenuBar.jsx +3 -3
- package/src/shell/PreferencesDialog.jsx +15 -264
- package/src/shell/PreferencesSlot.jsx +2 -8
- package/src/shell/ShotPreviewHeader.jsx +17 -0
- package/src/shell/TopBar.jsx +5 -83
- package/src/shell/ViewportToolbar.jsx +23 -93
- package/src/shell/agent-glass.css +19 -6
- package/src/shell/details-selection.js +42 -0
- package/src/shell/ghosts-menu.css +22 -0
- package/src/shell/glass-regions.css +29 -3
- package/src/shell/preferences.css +6 -1
- package/src/shell/viewport.css +12 -0
- package/src/shot-authoring.js +4 -7
- package/src/soft-shadows.js +37 -0
- package/src/stage-attach-frames.js +12 -12
- package/src/stage-canvas-rigs.jsx +3 -3
- package/src/stage-capture.jsx +42 -8
- package/src/stage-characters.jsx +22 -216
- package/src/stage-editor-gizmos.jsx +6 -6
- package/src/stage-environment.js +93 -0
- package/src/stage-hdr-builtins.js +107 -0
- package/src/stage-hdr-image.js +116 -0
- package/src/stage-hdr-library.js +70 -0
- package/src/stage-hdr-map.js +94 -0
- package/src/stage-hdr.js +130 -0
- package/src/stage-lighting.js +149 -0
- package/src/stage-occlusion.js +210 -0
- package/src/stage-sky.jsx +159 -0
- package/src/stage-startup-defaults.js +5 -9
- package/src/studio-actions.js +12 -14
- package/src/studio-agent-commands.js +46 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +46 -73
- package/src/studio-app-binding.js +29 -45
- package/src/studio-asset-list.js +17 -0
- package/src/studio-contact-sheet.js +37 -5
- package/src/studio-elements.js +27 -7
- package/src/studio-entity-bounds.js +18 -0
- package/src/studio-error-codes.js +8 -0
- package/src/studio-export-framing.js +152 -0
- package/src/studio-lighting-check.js +103 -0
- package/src/studio-motion-visual.js +150 -0
- package/src/studio-schema-errors.js +80 -0
- package/src/studio-support-gap.js +74 -0
- package/src/styles.css +1 -19
- package/src/timeline-defaults.js +5 -0
- package/src/timeline-extent.js +8 -20
- package/src/tutorial-walk.js +17 -0
- package/src/ui-scrub.js +1 -1
- package/src/use-shot-camera-tracks.js +12 -0
- package/src/view-ghosts.js +97 -0
- package/src/view-ghosts.jsx +49 -0
- package/src/workflow/AgentPanel.jsx +47 -166
- package/src/workflow/AgentProgressCard.jsx +107 -0
- package/src/workflow/AgentReplyText.jsx +37 -0
- package/src/workflow/AgentTurnSteps.jsx +84 -0
- package/src/workflow/LoginPanel.jsx +140 -0
- package/src/workflow/WorkflowBuilder.jsx +7 -23
- package/src/workflow/agent-client.js +54 -51
- package/src/workflow/agent-panel.css +71 -1
- package/src/workflow/agent-progress-card.css +167 -0
- package/src/workflow/agent-progress-view.js +47 -0
- package/src/workflow/agent-turn-steps.css +113 -0
- package/src/workflow/agent-turn.js +191 -0
- package/src/workflow/login-client.js +34 -0
- package/src/workflow/motion-input.js +18 -31
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/reply-markdown.js +69 -0
- package/src/workflow/scene-asset-sync.js +8 -8
- package/tools/agent-session-stats.mjs +61 -0
- package/tools/dev-full.mjs +5 -56
- package/tools/eslint-baseline.json +12 -13
- package/tools/headless-studio.mjs +85 -0
- package/tools/knip-baseline.json +0 -179
- package/tools/loc-baseline.json +33 -83
- package/tools/motion3/extract-body.mjs +103 -0
- package/tools/motion3/extract-rig.mjs +85 -0
- package/tools/process-supervisor.mjs +0 -88
- package/tools/run-tests.mjs +9 -124
- package/bin/agent/motion-runtime.mjs +0 -76
- package/dist/ardy/cskel27-rest.json +0 -557
- package/dist/assets/analytics-B41FmPYI.js +0 -1
- package/dist/assets/app-Do-Og5Pu.css +0 -1
- package/dist/assets/app-DwP-tl2x.js +0 -4920
- package/dist/assets/config-Bx7pYsD9.js +0 -1
- package/dist/assets/config-DeoFTYzb.css +0 -1
- package/dist/assets/demo-Dt0qZfS7.js +0 -1
- package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
- package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
- package/dist/assets/ticket-jqMhqL88.js +0 -1
- package/dist/assets/workflow-Br-K7Srs.js +0 -179
- package/dist/demo/walk-then-stop.npz +0 -0
- package/mcp/ardy-prompts.mjs +0 -218
- package/src/ardy/auto-fix-panel.css +0 -108
- package/src/ardy/auto-physics.js +0 -1194
- package/src/ardy/client.js +0 -153
- package/src/ardy/convert.js +0 -313
- package/src/ardy/cskel27-neutral.js +0 -39
- package/src/ardy/cskel27.js +0 -77
- package/src/ardy/export.js +0 -165
- package/src/ardy/fix-collisions.js +0 -2257
- package/src/ardy/foot-lock.js +0 -230
- package/src/ardy/motion-calibration.js +0 -118
- package/src/ardy/motion-edit.js +0 -213
- package/src/ardy/motion-url.js +0 -55
- package/src/ardy/mp4-duration.js +0 -102
- package/src/ardy/npz.js +0 -595
- package/src/ardy/physics-panel.css +0 -21
- package/src/ardy/physics-panel.jsx +0 -89
- package/src/ardy/physics-refine.js +0 -111
- package/src/ardy/physics-review.js +0 -567
- package/src/ardy/physics-temporal.js +0 -54
- package/src/ardy/platform-fit-panel.css +0 -64
- package/src/ardy/platform-fit-panel.jsx +0 -41
- package/src/ardy/platform-fit.js +0 -326
- package/src/ardy/playback.js +0 -711
- package/src/ardy/pose-pin.js +0 -97
- package/src/ardy/prompt-clips.js +0 -30
- package/src/ardy/retime.js +0 -211
- package/src/ardy/root-drop.js +0 -369
- package/src/ardy/timeline-resize.js +0 -13
- package/src/ardy/to-cskel27.js +0 -225
- package/src/ardy/trim.js +0 -33
- package/src/ardy/waypoints.js +0 -369
- package/src/ardy-bridge-contract.js +0 -281
- package/src/domains/motion/motion-video-capture.js +0 -664
- package/src/i2v-motion-client.js +0 -77
- package/src/i2v-motion-studio.jsx +0 -180
- package/src/line-edit.js +0 -1348
- package/src/motion/generation.js +0 -105
- package/src/motion-readiness-ui.jsx +0 -67
- package/src/motion-readiness.js +0 -40
- package/src/motion-resources.js +0 -177
- package/src/motion-store.js +0 -65
- package/src/motion-trail.js +0 -601
- package/src/multimodel-ingest.js +0 -394
- package/src/panels/PromptBlocksPanel.jsx +0 -444
- package/src/panels/VideoCapturePanel.jsx +0 -181
- package/src/pose-extract/browser.js +0 -42
- package/src/pose-extract/detector.js +0 -100
- package/src/pose-extract/fit.js +0 -227
- package/src/pose-extract/image-frame.js +0 -51
- package/src/pose-extract/index.js +0 -58
- package/src/pose-extract/keyframes.js +0 -74
- package/src/pose-extract/landmarks.js +0 -162
- package/src/pose-extract/mirror.js +0 -153
- package/src/pose-extract/take.js +0 -131
- package/src/pose-extract/video-frames.js +0 -91
- package/src/take-recipe.js +0 -165
- package/src/trail-key-conflicts.js +0 -39
- package/src/trail-pick.js +0 -59
- package/src/use-i2v-capture-modal.js +0 -15
- package/tools/ardy/BRIDGE.md +0 -37
- package/tools/ardy/GVHMR-NPZ.md +0 -68
- package/tools/ardy/README.md +0 -124
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/ardy/artifacts.mjs +0 -34
- package/tools/ardy/bridge.mjs +0 -1732
- package/tools/ardy/bvh-cskel27.mjs +0 -1265
- package/tools/ardy/cclay_constrained_generate.py +0 -561
- package/tools/ardy/cclay_gvhmr_worker.py +0 -264
- package/tools/ardy/cclay_motion_edit.py +0 -510
- package/tools/ardy/cclay_sequence_generate.py +0 -705
- package/tools/ardy/cclay_worker.py +0 -304
- package/tools/ardy/dump-npz.py +0 -205
- package/tools/ardy/extract-rest.mjs +0 -299
- package/tools/ardy/extract.mjs +0 -507
- package/tools/ardy/footage.mjs +0 -467
- package/tools/ardy/gvhmr-floor.mjs +0 -102
- package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
- package/tools/ardy/gvhmr_fastpath.py +0 -168
- package/tools/ardy/gvhmr_trajectory.py +0 -240
- package/tools/ardy/merge-text-encoder.py +0 -160
- package/tools/ardy/mocap-metrics.mjs +0 -200
- package/tools/ardy/mocap-quality-gate.mjs +0 -110
- package/tools/ardy/motion-stabilize.mjs +0 -348
- package/tools/ardy/npz.mjs +0 -414
- package/tools/ardy/pose-to-npz.mjs +0 -106
- package/tools/ardy/prompt-limits.mjs +0 -5
- package/tools/ardy/run-edit-on-box.sh +0 -73
- package/tools/ardy/run-local.mjs +0 -233
- package/tools/ardy/run-on-box.sh +0 -593
- package/tools/ardy/run-sequence-on-box.sh +0 -177
- package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
- package/tools/ardy/runners/index.mjs +0 -18
- package/tools/ardy/runners/local.mjs +0 -455
- package/tools/ardy/runners/proc.mjs +0 -125
- package/tools/ardy/runners/remote.mjs +0 -252
- package/tools/ardy/setup-local.mjs +0 -189
- package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
- package/tools/ardy/setup-text-encoder.py +0 -306
- package/tools/ardy/smpl-cskel27.mjs +0 -178
- package/tools/ardy/visual-qa.mjs +0 -196
- package/tools/ardy/vq-car.mjs +0 -52
- package/tools/bench/EXP3.md +0 -61
- package/tools/bench/cclay_bench_extract_incam.py +0 -125
- package/tools/bench/cclay_bench_extract_obs.py +0 -204
- package/tools/bench/cclay_bench_runner.py +0 -42
- package/tools/bench/cube-contact.mjs +0 -162
- package/tools/bench/exp3.mjs +0 -152
- package/tools/bench/extract-bench-lib.mjs +0 -216
- package/tools/bench/extract-bench.mjs +0 -302
- package/tools/bench/fal-generate.mjs +0 -88
- package/tools/bench/fit/README.md +0 -189
- package/tools/bench/fit/camera.mjs +0 -59
- package/tools/bench/fit/contact.mjs +0 -419
- package/tools/bench/fit/footlock.mjs +0 -234
- package/tools/bench/fit/motion.mjs +0 -85
- package/tools/bench/fit/pin.mjs +0 -27
- package/tools/bench/fit/remote.mjs +0 -105
- package/tools/bench/fit-bench.mjs +0 -126
- package/tools/bench/fit-sanity.mjs +0 -45
- package/tools/bench/metrics.mjs +0 -313
- package/tools/bench/obs/depth.mjs +0 -258
- package/tools/bench/obs/extrinsics.mjs +0 -175
- package/tools/bench/obs/fit_mannequin_betas.py +0 -340
- package/tools/bench/obs/ground.mjs +0 -294
- package/tools/bench/obs/heading.mjs +0 -151
- package/tools/bench/obs/ladder.mjs +0 -555
- package/tools/bench/obs/mannequin-betas.json +0 -124
- package/tools/bench/obs/remote.mjs +0 -83
- package/tools/bench/obs/rest_joints.py +0 -52
- package/tools/bench/obs/ybot-targets.mjs +0 -49
- package/tools/bench/obs-bench.mjs +0 -520
- package/tools/bench/score.mjs +0 -343
- package/tools/bench/summarize.mjs +0 -86
- package/tools/demo-worker/README.md +0 -137
- package/tools/demo-worker/api-client.mjs +0 -233
- package/tools/demo-worker/generate.mjs +0 -301
- package/tools/demo-worker/index.mjs +0 -466
- package/tools/demo-worker/sign-core.mjs +0 -112
- package/tools/demo-worker/sign.mjs +0 -161
- package/tools/gt-render/browser.mjs +0 -159
- package/tools/gt-render/camera-math.mjs +0 -276
- package/tools/gt-render/page.mjs +0 -267
- package/tools/gt-render/render.mjs +0 -514
- package/tools/gt-render/scene-box.mjs +0 -31
- package/tools/gt-render/take-transform.mjs +0 -87
- package/tools/kimodo/compare-seam.mjs +0 -108
- package/tools/kimodo/constraints.mjs +0 -244
- package/tools/kimodo/edit.mjs +0 -259
- package/tools/kimodo/effector-constraints.mjs +0 -200
- package/tools/kimodo/generate.mjs +0 -646
- package/tools/kimodo/local-output.mjs +0 -265
- package/tools/kimodo/measure-pose.mjs +0 -65
- package/tools/kimodo/measure-preserve.mjs +0 -899
- package/tools/kimodo/measure-waypoints.mjs +0 -55
- package/tools/kimodo/mlx-generate.py +0 -111
- package/tools/kimodo/pose-constraints.mjs +0 -248
- package/tools/kimodo/preserve-mask.mjs +0 -543
- package/tools/kimodo/read-npz.mjs +0 -189
- package/tools/kimodo/run-edit-on-box.mjs +0 -155
- package/tools/kimodo/run-sequence-on-box.mjs +0 -178
- package/tools/kimodo/runner.mjs +0 -284
- package/tools/kimodo/seam-batch.mjs +0 -77
- package/tools/kimodo/setup-local.mjs +0 -30
- package/tools/kimodo/setup-on-box.sh +0 -339
- package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
- package/tools/morphgs/assets/gen_truth.py +0 -39
- package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
- package/tools/morphgs/assets/playback-check.mjs +0 -30
- package/tools/morphgs/demo-gate.sh +0 -26
- package/tools/morphgs/fbx2morphgs.mjs +0 -68
- package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
- package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
- package/tools/morphgs/setup-on-cluster.sh +0 -126
- package/tools/projflow/driver.py +0 -1069
- package/tools/projflow/generate.mjs +0 -805
- package/tools/projflow/hml22-to-cskel27.mjs +0 -735
- package/tools/projflow/line-edit-job.mjs +0 -547
- package/tools/projflow/replay.mjs +0 -452
- package/tools/projflow/runner.mjs +0 -269
- package/tools/projflow/service.mjs +0 -742
- package/tools/track/DESIGN.md +0 -513
- package/tools/track/backfill-provenance.mjs +0 -116
- package/tools/track/budget.mjs +0 -8
- package/tools/track/check-rig.mjs +0 -209
- package/tools/track/diagnostics.schema.json +0 -60
- package/tools/track/export-rig.mjs +0 -256
- package/tools/track/fallback.mjs +0 -7
- package/tools/track/fk-parity-fixture.mjs +0 -161
- package/tools/track/gate.mjs +0 -349
- package/tools/track/masks.mjs +0 -318
- package/tools/track/metrics.mjs +0 -201
- package/tools/track/publish-obs.mjs +0 -108
- package/tools/track/py/check_env.py +0 -61
- package/tools/track/py/eval_lr.py +0 -229
- package/tools/track/py/lr_viterbi.py +0 -294
- package/tools/track/py/masks.py +0 -405
- package/tools/track/py/objective.py +0 -382
- package/tools/track/py/rig.py +0 -508
- package/tools/track/py/scene.py +0 -326
- package/tools/track/py/test_joint_indices.py +0 -123
- package/tools/track/py/test_lr_viterbi.py +0 -195
- package/tools/track/py/test_masks.py +0 -229
- package/tools/track/py/test_rig.py +0 -288
- package/tools/track/py/test_scene.py +0 -354
- package/tools/track/py/test_track.py +0 -328
- package/tools/track/py/track.py +0 -411
- package/tools/track/remote.mjs +0 -140
- package/tools/track/rig-dump.mjs +0 -227
- package/tools/track/run-box-tests.mjs +0 -14
- package/tools/track/run-box.mjs +0 -168
- package/tools/track/setup-box.sh +0 -59
- package/tools/track/study-2d.mjs +0 -728
- /package/src/{ardy → motion}/collision-blockers.js +0 -0
- /package/src/{ardy → motion}/ground.js +0 -0
- /package/src/{ardy → motion}/ik-drag.js +0 -0
- /package/src/{ardy → motion}/ik-key-json.js +0 -0
- /package/src/{ardy → motion}/ik.js +0 -0
- /package/src/{ardy → motion}/physics-surface.js +0 -0
- /package/src/{ardy → motion}/playback-clock.js +0 -0
- /package/src/{ardy → motion}/range-pin.js +0 -0
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
const IDENTITY_3 = [
|
|
2
|
-
1, 0, 0,
|
|
3
|
-
0, 1, 0,
|
|
4
|
-
0, 0, 1,
|
|
5
|
-
];
|
|
6
|
-
|
|
7
|
-
function flat3(m) {
|
|
8
|
-
return Array.isArray(m[0]) ? m.flat() : m;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function rows3(m) {
|
|
12
|
-
return [m.slice(0, 3), m.slice(3, 6), m.slice(6, 9)];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function mat3Vec(m, v) {
|
|
16
|
-
return [
|
|
17
|
-
m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
|
|
18
|
-
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
|
|
19
|
-
m[6] * v[0] + m[7] * v[1] + m[8] * v[2],
|
|
20
|
-
];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function mat3Mul(a, b) {
|
|
24
|
-
return [
|
|
25
|
-
a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
|
|
26
|
-
a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
|
|
27
|
-
a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
|
|
28
|
-
a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
|
|
29
|
-
a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
|
|
30
|
-
a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
|
|
31
|
-
a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
|
|
32
|
-
a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
|
|
33
|
-
a[6] * b[2] + a[7] * b[5] + a[8] * b[8],
|
|
34
|
-
];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function transpose3(m) {
|
|
38
|
-
return [m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8]];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function add3(a, b) {
|
|
42
|
-
return a.map((x, i) => x + b[i]);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function scale3(m, s) {
|
|
46
|
-
return m.map((x) => x * s);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function skew(v) {
|
|
50
|
-
return [
|
|
51
|
-
0, -v[2], v[1],
|
|
52
|
-
v[2], 0, -v[0],
|
|
53
|
-
-v[1], v[0], 0,
|
|
54
|
-
];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function axisAngleToMatrix(axisAngle) {
|
|
58
|
-
const theta = Math.hypot(...axisAngle);
|
|
59
|
-
const W = skew(axisAngle);
|
|
60
|
-
const W2 = mat3Mul(W, W);
|
|
61
|
-
let a;
|
|
62
|
-
let b;
|
|
63
|
-
if (theta < 1e-8) {
|
|
64
|
-
const theta2 = theta * theta;
|
|
65
|
-
a = 1 - theta2 / 6 + theta2 * theta2 / 120;
|
|
66
|
-
b = 0.5 - theta2 / 24 + theta2 * theta2 / 720;
|
|
67
|
-
} else {
|
|
68
|
-
a = Math.sin(theta) / theta;
|
|
69
|
-
b = (1 - Math.cos(theta)) / (theta * theta);
|
|
70
|
-
}
|
|
71
|
-
return add3(add3(IDENTITY_3, scale3(W, a)), scale3(W2, b));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function matrixToAxisAngle(m) {
|
|
75
|
-
const trace = m[0] + m[4] + m[8];
|
|
76
|
-
const qw = Math.sqrt(Math.max(0, 1 + trace)) / 2;
|
|
77
|
-
let qx;
|
|
78
|
-
let qy;
|
|
79
|
-
let qz;
|
|
80
|
-
if (qw > 1e-6) {
|
|
81
|
-
const scale = 1 / (4 * qw);
|
|
82
|
-
qx = (m[7] - m[5]) * scale;
|
|
83
|
-
qy = (m[2] - m[6]) * scale;
|
|
84
|
-
qz = (m[3] - m[1]) * scale;
|
|
85
|
-
} else if (m[0] >= m[4] && m[0] >= m[8]) {
|
|
86
|
-
qx = Math.sqrt(Math.max(0, 1 + m[0] - m[4] - m[8])) / 2;
|
|
87
|
-
const scale = qx > 1e-8 ? 1 / (4 * qx) : 0;
|
|
88
|
-
qy = (m[1] + m[3]) * scale;
|
|
89
|
-
qz = (m[2] + m[6]) * scale;
|
|
90
|
-
} else if (m[4] >= m[8]) {
|
|
91
|
-
qy = Math.sqrt(Math.max(0, 1 - m[0] + m[4] - m[8])) / 2;
|
|
92
|
-
const scale = qy > 1e-8 ? 1 / (4 * qy) : 0;
|
|
93
|
-
qx = (m[1] + m[3]) * scale;
|
|
94
|
-
qz = (m[5] + m[7]) * scale;
|
|
95
|
-
} else {
|
|
96
|
-
qz = Math.sqrt(Math.max(0, 1 - m[0] - m[4] + m[8])) / 2;
|
|
97
|
-
const scale = qz > 1e-8 ? 1 / (4 * qz) : 0;
|
|
98
|
-
qx = (m[2] + m[6]) * scale;
|
|
99
|
-
qy = (m[5] + m[7]) * scale;
|
|
100
|
-
}
|
|
101
|
-
const qNorm = Math.hypot(qw, qx, qy, qz);
|
|
102
|
-
if (!(qNorm > 0)) return [0, 0, 0];
|
|
103
|
-
const q = [qw / qNorm, qx / qNorm, qy / qNorm, qz / qNorm];
|
|
104
|
-
if (q[0] < 0) q.forEach((_, i) => { q[i] = -q[i]; });
|
|
105
|
-
const angle = 2 * Math.atan2(Math.hypot(q[1], q[2], q[3]), q[0]);
|
|
106
|
-
if (angle < 1e-12) return [0, 0, 0];
|
|
107
|
-
const scale = angle / Math.hypot(q[1], q[2], q[3]);
|
|
108
|
-
return [q[1] * scale, q[2] * scale, q[3] * scale];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function rigidWorldToCamera(camera) {
|
|
112
|
-
const matrix = camera?.worldToCamera;
|
|
113
|
-
if (!Array.isArray(matrix) || matrix.length !== 4 || !matrix.every((row) => Array.isArray(row) && row.length === 4 && row.every(Number.isFinite))) {
|
|
114
|
-
throw new Error("camera.json needs a finite 4x4 worldToCamera matrix");
|
|
115
|
-
}
|
|
116
|
-
if (matrix[3][0] !== 0 || matrix[3][1] !== 0 || matrix[3][2] !== 0 || matrix[3][3] !== 1) {
|
|
117
|
-
throw new Error("camera.json worldToCamera must be an affine 4x4 matrix");
|
|
118
|
-
}
|
|
119
|
-
return matrix;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function cameraFromJson(camera) {
|
|
123
|
-
const matrix = rigidWorldToCamera(camera);
|
|
124
|
-
const R_w2c = [
|
|
125
|
-
matrix[0][0], matrix[0][1], matrix[0][2],
|
|
126
|
-
matrix[1][0], matrix[1][1], matrix[1][2],
|
|
127
|
-
matrix[2][0], matrix[2][1], matrix[2][2],
|
|
128
|
-
];
|
|
129
|
-
const t_w2c = [matrix[0][3], matrix[1][3], matrix[2][3]];
|
|
130
|
-
const R_c2w = transpose3(R_w2c);
|
|
131
|
-
const t_c2w = scale3(mat3Vec(R_c2w, t_w2c), -1);
|
|
132
|
-
const K = camera.K?.map((row) => row.slice()) ?? [
|
|
133
|
-
[camera.fx, 0, camera.cx],
|
|
134
|
-
[0, camera.fy, camera.cy],
|
|
135
|
-
[0, 0, 1],
|
|
136
|
-
];
|
|
137
|
-
if (!Array.isArray(K) || K.length !== 3 || !K.every((row) => Array.isArray(row) && row.length === 3 && row.every(Number.isFinite))) {
|
|
138
|
-
throw new Error("camera.json needs a finite 3x3 K matrix");
|
|
139
|
-
}
|
|
140
|
-
return { K, R_c2w: rows3(R_c2w), t_c2w, R_w2c: rows3(R_w2c), t_w2c };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function camToWorldPoint(p, cam) {
|
|
144
|
-
return add3(mat3Vec(flat3(cam.R_c2w), p), cam.t_c2w);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function worldToCameraPoint(p, cam) {
|
|
148
|
-
return add3(mat3Vec(flat3(cam.R_w2c), p), cam.t_w2c);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function camToWorldOrient(axisAngleCam, cam) {
|
|
152
|
-
return matrixToAxisAngle(mat3Mul(flat3(cam.R_c2w), axisAngleToMatrix(axisAngleCam)));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function worldToCamOrient(axisAngleWorld, cam) {
|
|
156
|
-
return matrixToAxisAngle(mat3Mul(flat3(cam.R_w2c), axisAngleToMatrix(axisAngleWorld)));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function worldToPixel(p, cam) {
|
|
160
|
-
const [x, y, depth] = worldToCameraPoint(p, cam);
|
|
161
|
-
return [cam.K[0][0] * x / depth + cam.K[0][2], cam.K[1][1] * y / depth + cam.K[1][2], depth];
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function pixelRay(u, v, cam) {
|
|
165
|
-
const rayCamera = [
|
|
166
|
-
(u - cam.K[0][2]) / cam.K[0][0],
|
|
167
|
-
(v - cam.K[1][2]) / cam.K[1][1],
|
|
168
|
-
1,
|
|
169
|
-
];
|
|
170
|
-
const direction = mat3Vec(flat3(cam.R_c2w), rayCamera);
|
|
171
|
-
const length = Math.hypot(...direction);
|
|
172
|
-
return { origin: cam.t_c2w.slice(), direction: direction.map((x) => x / length) };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export { axisAngleToMatrix, matrixToAxisAngle };
|
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Fit the ten SuperMotion SMPL-X shape coefficients to the y-bot rest rig.
|
|
3
|
-
|
|
4
|
-
The production playback path does not deform cskel27 to every authored rig
|
|
5
|
-
bone. It measures the rig's leg height, divides by the canonical cskel27 toe
|
|
6
|
-
height, and applies that one factor to the neutral cskel27 offsets. This
|
|
7
|
-
script uses those same scaled neutral offsets as the shape targets. The
|
|
8
|
-
public cskel27-rest.json supplies the bind-joint inventory/rest contract; its
|
|
9
|
-
entries are rotations, while the neutral positions used by playback are the
|
|
10
|
-
canonical CSKEL27_NEUTRAL coordinates below.
|
|
11
|
-
|
|
12
|
-
Run this from the GVHMR checkout (or pass --gvhmr-root):
|
|
13
|
-
CUDA_VISIBLE_DEVICES="" .venv/bin/python /path/to/fit_mannequin_betas.py --device cpu --output /tmp/cclay-betas-out.json
|
|
14
|
-
|
|
15
|
-
The generated JSON is intentionally independent of a video or ground-truth
|
|
16
|
-
motion. Only the neutral rig measurements and the SMPL-X body model are used.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
import argparse
|
|
22
|
-
import json
|
|
23
|
-
import os
|
|
24
|
-
import sys
|
|
25
|
-
from pathlib import Path
|
|
26
|
-
|
|
27
|
-
import torch
|
|
28
|
-
|
|
29
|
-
# cskel27-neutral.js, copied as numerical data so this runner has no JS
|
|
30
|
-
# runtime dependency on the GPU box. Coordinates are metres, hips-origin,
|
|
31
|
-
# exactly as used by src/ardy/playback.js.
|
|
32
|
-
CSKEL27_NEUTRAL = torch.tensor([
|
|
33
|
-
[0.0, 0.0, 0.0],
|
|
34
|
-
[0.0, 0.0709891, -0.0473261],
|
|
35
|
-
[0.0, 0.1642033, -0.0637623],
|
|
36
|
-
[0.0, 0.2584953, -0.0720118],
|
|
37
|
-
[0.0, 0.3531475, -0.0720119],
|
|
38
|
-
[0.0, 0.6016096, -0.0365176],
|
|
39
|
-
[0.0, 0.7297793, -0.0139179],
|
|
40
|
-
[-0.0319949, 0.5259196, -0.0186873],
|
|
41
|
-
[-0.1909029, 0.5259195, -0.0186873],
|
|
42
|
-
[-0.4863389, 0.5259194, -0.0186873],
|
|
43
|
-
[-0.7189909, 0.5259193, -0.0186873],
|
|
44
|
-
[-0.7886024, 0.5259193, -0.0186873],
|
|
45
|
-
[-0.7468355, 0.5073563, 0.0277204],
|
|
46
|
-
[0.0319949, 0.5259196, -0.0186873],
|
|
47
|
-
[0.1909029, 0.5259196, -0.0186873],
|
|
48
|
-
[0.4863389, 0.5259196, -0.0186873],
|
|
49
|
-
[0.7189909, 0.5259196, -0.0186873],
|
|
50
|
-
[0.7886024, 0.5259196, -0.0186873],
|
|
51
|
-
[0.7468355, 0.5073565, 0.0277204],
|
|
52
|
-
[-0.0949182, -0.0277289, 0.0],
|
|
53
|
-
[-0.0949182, -0.4398469, 0.0],
|
|
54
|
-
[-0.0949182, -0.8959379, 0.0],
|
|
55
|
-
[-0.0949182, -0.9544128, 0.1606583],
|
|
56
|
-
[0.0949182, -0.0277289, 0.0],
|
|
57
|
-
[0.0949182, -0.4398469, 0.0],
|
|
58
|
-
[0.0949182, -0.8959379, 0.0],
|
|
59
|
-
[0.0949182, -0.9544128, 0.1606583],
|
|
60
|
-
], dtype=torch.float32)
|
|
61
|
-
|
|
62
|
-
# The values are measured from public/models/y-bot-tpose.fbx in armature
|
|
63
|
-
# metres: hips y 0.9979193878, lowest toe y 0.0328365048. The playback
|
|
64
|
-
# code uses the same lowest-toe convention and canonical height 0.9544128.
|
|
65
|
-
YBOT_LEG_HEIGHT_M = 0.9650828829792554
|
|
66
|
-
CANONICAL_LEG_HEIGHT_M = 0.9544128
|
|
67
|
-
|
|
68
|
-
# SMPL-24 regressed-joint indices, matching the OBS contract and
|
|
69
|
-
# tools/ardy/smpl-cskel27.mjs.
|
|
70
|
-
SEGMENTS = {
|
|
71
|
-
"thigh_left": ((23, 24), (1, 4)),
|
|
72
|
-
"thigh_right": ((19, 20), (2, 5)),
|
|
73
|
-
"shin_left": ((24, 25), (4, 7)),
|
|
74
|
-
"shin_right": ((20, 21), (5, 8)),
|
|
75
|
-
"foot_left": ((25, 26), (7, 10)),
|
|
76
|
-
"foot_right": ((21, 22), (8, 11)),
|
|
77
|
-
"pelvis_width": ((23, 19), (1, 2)),
|
|
78
|
-
"spine_length": ((0, 4), (0, 9)),
|
|
79
|
-
# Playback's Shoulder/Arm scale spans cskel Spine3 -> Arm, because the
|
|
80
|
-
# rig's collar and upper-arm chain are authored as one visible shoulder
|
|
81
|
-
# reach. The corresponding SMPL source is spine3 -> shoulder.
|
|
82
|
-
"upper_arm_left": ((4, 14), (9, 16)),
|
|
83
|
-
"upper_arm_right": ((4, 8), (9, 17)),
|
|
84
|
-
"forearm_left": ((14, 15), (16, 18)),
|
|
85
|
-
"forearm_right": ((8, 9), (17, 19)),
|
|
86
|
-
"shoulder_width": ((14, 8), (16, 17)),
|
|
87
|
-
"total_height": (None, None),
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def parse_args() -> argparse.Namespace:
|
|
92
|
-
parser = argparse.ArgumentParser(description=__doc__)
|
|
93
|
-
parser.add_argument("--output", required=True, type=Path)
|
|
94
|
-
parser.add_argument("--gvhmr-root", type=Path, default=Path.cwd())
|
|
95
|
-
parser.add_argument("--device", choices=("cpu",), default="cpu")
|
|
96
|
-
parser.add_argument("--adam-steps", type=int, default=5000)
|
|
97
|
-
parser.add_argument("--adam-lr", type=float, default=0.005)
|
|
98
|
-
parser.add_argument("--beta-limit", type=float, default=3.0)
|
|
99
|
-
parser.add_argument("--smooth-max-weight", type=float, default=0.0)
|
|
100
|
-
parser.add_argument("--smooth-max-temperature", type=float, default=0.002)
|
|
101
|
-
parser.add_argument("--minimax-steps", type=int, default=350)
|
|
102
|
-
parser.add_argument("--prior", type=float, default=1e-5)
|
|
103
|
-
# Segment lengths of the rendered rig (tools/bench/obs/ybot-targets.mjs).
|
|
104
|
-
# Segments absent from the file are left out of the fit.
|
|
105
|
-
parser.add_argument("--targets-json", type=Path)
|
|
106
|
-
return parser.parse_args()
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def load_model(root: Path, device: torch.device):
|
|
110
|
-
root = root.resolve()
|
|
111
|
-
if str(root) not in sys.path:
|
|
112
|
-
sys.path.insert(0, str(root))
|
|
113
|
-
os.chdir(root)
|
|
114
|
-
from cclay_gvhmr_extract import make_smplx # pylint: disable=import-outside-toplevel
|
|
115
|
-
|
|
116
|
-
model = make_smplx("supermotion").to(device).eval()
|
|
117
|
-
sparse = torch.load(root / "hmr4d/utils/body_model/smplx2smpl_sparse.pt", map_location=device).to(device)
|
|
118
|
-
regressor = torch.load(root / "hmr4d/utils/body_model/smpl_neutral_J_regressor.pt", map_location=device).to(device)
|
|
119
|
-
return model, sparse, regressor
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def length(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
|
|
123
|
-
return torch.linalg.vector_norm(a - b)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def targets(device: torch.device) -> tuple[dict[str, float], float]:
|
|
127
|
-
neutral = CSKEL27_NEUTRAL.to(device)
|
|
128
|
-
scale = YBOT_LEG_HEIGHT_M / CANONICAL_LEG_HEIGHT_M
|
|
129
|
-
values: dict[str, float] = {}
|
|
130
|
-
for name, spec in SEGMENTS.items():
|
|
131
|
-
if name == "total_height":
|
|
132
|
-
values[name] = float((neutral[:, 1].max() - neutral[:, 1].min()) * scale)
|
|
133
|
-
continue
|
|
134
|
-
cskel_pair, _ = spec
|
|
135
|
-
values[name] = float(length(neutral[cskel_pair[0]], neutral[cskel_pair[1]]) * scale)
|
|
136
|
-
return values, scale
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def rest_joints(model, sparse, regressor, betas: torch.Tensor) -> torch.Tensor:
|
|
140
|
-
output = model(
|
|
141
|
-
**{
|
|
142
|
-
"betas": betas,
|
|
143
|
-
"body_pose": torch.zeros((1, 63), device=betas.device),
|
|
144
|
-
"global_orient": torch.zeros((1, 3), device=betas.device),
|
|
145
|
-
"transl": torch.zeros((1, 3), device=betas.device),
|
|
146
|
-
}
|
|
147
|
-
)
|
|
148
|
-
smpl_vertices = torch.stack([torch.matmul(sparse, vertices) for vertices in output.vertices])
|
|
149
|
-
return torch.einsum("jv,tvc->tjc", regressor, smpl_vertices)[0]
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def measured_lengths(joints: torch.Tensor) -> dict[str, torch.Tensor]:
|
|
153
|
-
result: dict[str, torch.Tensor] = {}
|
|
154
|
-
for name, spec in SEGMENTS.items():
|
|
155
|
-
if name == "total_height":
|
|
156
|
-
result[name] = joints[:, 1].max() - joints[:, 1].min()
|
|
157
|
-
continue
|
|
158
|
-
_, smpl_pair = spec
|
|
159
|
-
result[name] = length(joints[smpl_pair[0]], joints[smpl_pair[1]])
|
|
160
|
-
return result
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def fit(args: argparse.Namespace) -> dict:
|
|
164
|
-
if args.device != "cpu":
|
|
165
|
-
raise RuntimeError("mannequin beta fitting is CPU-only")
|
|
166
|
-
device = torch.device("cpu")
|
|
167
|
-
model, sparse, regressor = load_model(args.gvhmr_root, device)
|
|
168
|
-
target, playback_scale = targets(device)
|
|
169
|
-
target_source = "cskel27 neutral offsets scaled by playback leg-height rule"
|
|
170
|
-
if args.targets_json is not None:
|
|
171
|
-
global SEGMENTS # pylint: disable=global-statement
|
|
172
|
-
rig = json.loads(args.targets_json.read_text(encoding="utf-8"))
|
|
173
|
-
target = {name: float(value) for name, value in rig["targets"].items() if name in SEGMENTS}
|
|
174
|
-
SEGMENTS = {name: spec for name, spec in SEGMENTS.items() if name in target}
|
|
175
|
-
target_source = f"rendered rig rest pose ({rig.get('model', args.targets_json.name)}), segments: {', '.join(SEGMENTS)}"
|
|
176
|
-
target_tensor = torch.tensor([target[name] for name in SEGMENTS], device=device)
|
|
177
|
-
|
|
178
|
-
if args.beta_limit <= 0:
|
|
179
|
-
raise ValueError("--beta-limit must be positive")
|
|
180
|
-
betas = torch.zeros((1, 10), device=device, requires_grad=True)
|
|
181
|
-
if args.adam_lr <= 0 or args.smooth_max_weight < 0 or args.smooth_max_temperature <= 0:
|
|
182
|
-
raise ValueError("optimizer parameters must be positive")
|
|
183
|
-
optimizer = torch.optim.Adam([betas], lr=args.adam_lr)
|
|
184
|
-
for _ in range(args.adam_steps):
|
|
185
|
-
fitted = measured_lengths(rest_joints(model, sparse, regressor, betas))
|
|
186
|
-
fitted_tensor = torch.stack([fitted[name] for name in SEGMENTS])
|
|
187
|
-
residual = fitted_tensor - target_tensor
|
|
188
|
-
smooth_max = args.smooth_max_temperature * torch.logsumexp(
|
|
189
|
-
torch.abs(residual) / args.smooth_max_temperature, dim=0
|
|
190
|
-
)
|
|
191
|
-
loss = (
|
|
192
|
-
torch.sum(residual**2)
|
|
193
|
-
+ args.smooth_max_weight * smooth_max
|
|
194
|
-
+ args.prior * torch.sum(betas**2)
|
|
195
|
-
)
|
|
196
|
-
optimizer.zero_grad()
|
|
197
|
-
loss.backward()
|
|
198
|
-
optimizer.step()
|
|
199
|
-
with torch.no_grad():
|
|
200
|
-
betas.clamp_(-args.beta_limit, args.beta_limit)
|
|
201
|
-
# Refine the projected-Adam point with a CPU-only minimax solve. SLSQP's
|
|
202
|
-
# explicit bounds are the hard box constraint; t bounds every signed
|
|
203
|
-
# residual, while the small quadratic term keeps the requested L2 prior.
|
|
204
|
-
from scipy.optimize import minimize # pylint: disable=import-outside-toplevel
|
|
205
|
-
import numpy as np # pylint: disable=import-outside-toplevel
|
|
206
|
-
|
|
207
|
-
def residual_and_jacobian(beta_values):
|
|
208
|
-
beta_tensor = torch.tensor(beta_values, dtype=torch.float32, device=device, requires_grad=True).reshape(10)
|
|
209
|
-
|
|
210
|
-
def values(value):
|
|
211
|
-
measured = measured_lengths(rest_joints(model, sparse, regressor, value[None]))
|
|
212
|
-
return torch.stack([measured[name] for name in SEGMENTS])
|
|
213
|
-
|
|
214
|
-
residual = values(beta_tensor) - target_tensor
|
|
215
|
-
jacobian = torch.autograd.functional.jacobian(values, beta_tensor)
|
|
216
|
-
return residual.detach().numpy(), jacobian.detach().numpy()
|
|
217
|
-
|
|
218
|
-
def minimax_objective(variables):
|
|
219
|
-
residual, jacobian = residual_and_jacobian(variables[:10])
|
|
220
|
-
beta_values = variables[:10]
|
|
221
|
-
value = variables[10] + 1e-3 * (
|
|
222
|
-
float((residual * residual).sum()) + args.prior * float((beta_values * beta_values).sum())
|
|
223
|
-
)
|
|
224
|
-
gradient = np.zeros(11, dtype=float)
|
|
225
|
-
gradient[:10] = 1e-3 * (2 * jacobian.T @ residual + 2 * args.prior * beta_values)
|
|
226
|
-
gradient[10] = 1.0
|
|
227
|
-
return value, gradient
|
|
228
|
-
|
|
229
|
-
def minimax_constraints(variables):
|
|
230
|
-
residual, _ = residual_and_jacobian(variables[:10])
|
|
231
|
-
return np.concatenate((variables[10] - residual, variables[10] + residual))
|
|
232
|
-
|
|
233
|
-
start_beta = betas.detach().cpu().numpy().astype(float).reshape(10)
|
|
234
|
-
seeds = [start_beta]
|
|
235
|
-
active_face_seed = start_beta.copy()
|
|
236
|
-
active_face_seed[6:10] = [-args.beta_limit, -args.beta_limit, args.beta_limit, args.beta_limit]
|
|
237
|
-
seeds.append(active_face_seed)
|
|
238
|
-
seeds.append(np.array([
|
|
239
|
-
2.50849517, 0.85280948, 0.30636654, 1.80294858, 1.24747668,
|
|
240
|
-
0.64413053, -args.beta_limit, -args.beta_limit, args.beta_limit, args.beta_limit,
|
|
241
|
-
], dtype=float))
|
|
242
|
-
best_candidate = betas.detach().clone()
|
|
243
|
-
best_residual = torch.max(torch.abs(torch.stack([
|
|
244
|
-
measured_lengths(rest_joints(model, sparse, regressor, best_candidate))[name] - target[name]
|
|
245
|
-
for name in SEGMENTS
|
|
246
|
-
])))
|
|
247
|
-
result = None
|
|
248
|
-
for seed_beta in seeds:
|
|
249
|
-
seed_residual, _ = residual_and_jacobian(seed_beta)
|
|
250
|
-
start = np.r_[seed_beta, max(abs(seed_residual))]
|
|
251
|
-
trial = minimize(
|
|
252
|
-
lambda variables: minimax_objective(variables)[0],
|
|
253
|
-
start,
|
|
254
|
-
jac=lambda variables: minimax_objective(variables)[1],
|
|
255
|
-
constraints={"type": "ineq", "fun": minimax_constraints},
|
|
256
|
-
bounds=[(-args.beta_limit, args.beta_limit)] * 10 + [(0.0, 1.0)],
|
|
257
|
-
method="SLSQP",
|
|
258
|
-
options={"maxiter": args.minimax_steps, "ftol": 1e-10},
|
|
259
|
-
)
|
|
260
|
-
candidate = torch.tensor(trial.x[:10], dtype=torch.float32, device=device)
|
|
261
|
-
with torch.no_grad():
|
|
262
|
-
candidate.clamp_(-args.beta_limit, args.beta_limit)
|
|
263
|
-
candidate_residual = torch.stack([
|
|
264
|
-
measured_lengths(rest_joints(model, sparse, regressor, candidate.reshape(1, 10)))[name] - target[name]
|
|
265
|
-
for name in SEGMENTS
|
|
266
|
-
])
|
|
267
|
-
candidate_max = torch.max(torch.abs(candidate_residual))
|
|
268
|
-
if torch.isfinite(candidate).all() and candidate_max < best_residual:
|
|
269
|
-
best_candidate = candidate.clone()
|
|
270
|
-
best_residual = candidate_max
|
|
271
|
-
result = trial
|
|
272
|
-
|
|
273
|
-
with torch.no_grad():
|
|
274
|
-
betas = best_candidate.reshape(1, 10)
|
|
275
|
-
fitted = measured_lengths(rest_joints(model, sparse, regressor, betas))
|
|
276
|
-
|
|
277
|
-
beta_values = betas.detach().cpu().reshape(-1).tolist()
|
|
278
|
-
rows = {}
|
|
279
|
-
residuals = []
|
|
280
|
-
for name in SEGMENTS:
|
|
281
|
-
target_m = target[name]
|
|
282
|
-
fitted_m = float(fitted[name].detach().cpu())
|
|
283
|
-
residual_m = fitted_m - target_m
|
|
284
|
-
residuals.append(residual_m)
|
|
285
|
-
rows[name] = {
|
|
286
|
-
"target_m": target_m,
|
|
287
|
-
"fitted_m": fitted_m,
|
|
288
|
-
"residual_m": residual_m,
|
|
289
|
-
"abs_residual_m": abs(residual_m),
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
"schema": "obs.mannequin-betas.v1",
|
|
294
|
-
"method": {
|
|
295
|
-
"model": "smpl-x supermotion neutral",
|
|
296
|
-
"optimizer": "projected Adam warm start + bounded SLSQP minimax",
|
|
297
|
-
"adam_steps": args.adam_steps,
|
|
298
|
-
"adam_lr": args.adam_lr,
|
|
299
|
-
"minimax_steps": args.minimax_steps,
|
|
300
|
-
"minimax_starts": 3,
|
|
301
|
-
"minimax_success": bool(result.success) if result is not None else False,
|
|
302
|
-
"minimax_status": int(result.status) if result is not None else -1,
|
|
303
|
-
"beta_limit": args.beta_limit,
|
|
304
|
-
"smooth_max_weight": args.smooth_max_weight,
|
|
305
|
-
"smooth_max_temperature": args.smooth_max_temperature,
|
|
306
|
-
"l2_prior": args.prior,
|
|
307
|
-
"device": str(device),
|
|
308
|
-
"source": target_source,
|
|
309
|
-
},
|
|
310
|
-
"betas": beta_values,
|
|
311
|
-
"target_geometry": {
|
|
312
|
-
"ybot_leg_height_m": YBOT_LEG_HEIGHT_M,
|
|
313
|
-
"canonical_cskel27_leg_height_m": CANONICAL_LEG_HEIGHT_M,
|
|
314
|
-
"playback_scale": playback_scale,
|
|
315
|
-
"rest_contract": "public/ardy/cskel27-rest.json",
|
|
316
|
-
},
|
|
317
|
-
"residuals": rows,
|
|
318
|
-
"summary": {
|
|
319
|
-
"segment_count": len(rows),
|
|
320
|
-
"max_abs_beta": max(abs(value) for value in beta_values),
|
|
321
|
-
"max_abs_residual_m": max(abs(value) for value in residuals),
|
|
322
|
-
"rms_residual_m": (sum(value * value for value in residuals) / len(residuals)) ** 0.5,
|
|
323
|
-
"max_bone_length_residual_m": max(abs(value) for value in residuals),
|
|
324
|
-
},
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
def main() -> None:
|
|
329
|
-
args = parse_args()
|
|
330
|
-
result = fit(args)
|
|
331
|
-
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
332
|
-
args.output.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
|
|
333
|
-
print(json.dumps(result["summary"], sort_keys=True), flush=True)
|
|
334
|
-
print("betas=" + json.dumps(result["betas"]), flush=True)
|
|
335
|
-
for name, row in result["residuals"].items():
|
|
336
|
-
print(f"{name}: target={row['target_m']:.9f} fitted={row['fitted_m']:.9f} residual={row['residual_m']:+.9f}", flush=True)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if __name__ == "__main__":
|
|
340
|
-
main()
|