cozyclay 2.1.1 → 3.0.1
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 +88 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +43 -116
- package/bin/agent/agent-runner.mjs +14 -15
- 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/session-store.mjs +2 -2
- package/bin/agent/studio-context-budget.mjs +93 -0
- 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 +3 -3
- 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-BWCqdgWA.js +1 -0
- package/dist/assets/app-DfTCxaKk.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-BxKXh07s.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
- package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
- package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-D78eiKTa.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +3 -3
- 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 +151 -2625
- package/src/agent-progress.js +80 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +12 -2
- 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 +10 -8
- 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 +214 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +55 -13
- 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 +53 -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 +47 -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 +60 -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 +42 -413
- 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 +79 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +113 -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 +197 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +177 -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 +144 -0
- package/src/motion3/compiler/validate-parts.js +118 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +74 -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 +177 -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 +204 -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/people.js +82 -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 +125 -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 +195 -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 +44 -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/people-checks.js +37 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +228 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +129 -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 +113 -0
- package/src/motion3/schema/types.js +149 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/settle.js +136 -0
- package/src/motion3/skills/basic.js +83 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/flip.js +200 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/impact.js +109 -0
- package/src/motion3/skills/index.js +85 -0
- package/src/motion3/skills/info.js +80 -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/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/qa-label.js +25 -0
- 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 +9 -51
- 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/TopBar.jsx +5 -84
- package/src/shell/ViewportToolbar.jsx +10 -70
- 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/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 +16 -14
- package/src/studio-agent-commands.js +19 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +47 -77
- package/src/studio-app-binding.js +27 -47
- 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 +15 -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 +109 -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/knip-baseline.json +0 -179
- package/tools/loc-baseline.json +31 -81
- 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 -125
- package/bin/agent/motion-runtime.mjs +0 -76
- package/dist/ardy/cskel27-rest.json +0 -557
- package/dist/assets/analytics-C9pMpW7s.js +0 -1
- package/dist/assets/app-B_2XB9rw.css +0 -1
- package/dist/assets/app-DAuvKPP8.js +0 -4920
- package/dist/assets/config-Bx7pYsD9.js +0 -1
- package/dist/assets/config-DeoFTYzb.css +0 -1
- package/dist/assets/demo-CvKuBgy5.js +0 -1
- package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
- package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
- package/dist/assets/ticket-BPk2Ni95.js +0 -1
- package/dist/assets/workflow-jJRBR94Z.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 -182
- 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,339 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Provision the best-supported Kimodo runtime for the host this script runs on.
|
|
3
|
-
# Run directly on the host, or through setup-local.mjs (which pipes it over ssh).
|
|
4
|
-
#
|
|
5
|
-
# The installer is a router: it detects OS / architecture / RAM / CUDA and
|
|
6
|
-
# installs one of four backends, best first:
|
|
7
|
-
#
|
|
8
|
-
# kimodo-mlx macOS arm64 with > 32 GB RAM — MLX/Metal port with the
|
|
9
|
-
# 15 GB LLM2Vec encoder resident in unified memory
|
|
10
|
-
# (measured 0.93 s warm E2E vs 37 s kimodo.cpp Metal on an
|
|
11
|
-
# M4 Max 64 GB; see NomaDamas/kimodo-mlx README benchmarks).
|
|
12
|
-
# kimodo.cpp-metal macOS arm64 with <= 32 GB RAM — GGML build streaming
|
|
13
|
-
# transformer layers from disk; residency is the wrong
|
|
14
|
-
# trade when the encoder cannot stay in memory.
|
|
15
|
-
# nvidia-cuda Linux with a working NVIDIA GPU — the upstream PyTorch
|
|
16
|
-
# Kimodo stack (nv-tlabs/kimodo), fully CUDA accelerated.
|
|
17
|
-
# kimodo.cpp-cpu any other Unix — GGML CPU build, Vulkan when available.
|
|
18
|
-
#
|
|
19
|
-
# Detection can be overridden for tests and dry-runs:
|
|
20
|
-
# CCLAY_KIMODO_DETECT_OS, CCLAY_KIMODO_DETECT_ARCH,
|
|
21
|
-
# CCLAY_KIMODO_DETECT_RAM_GB, CCLAY_KIMODO_DETECT_CUDA (0|1)
|
|
22
|
-
# The route itself is overridden with --backend or CCLAY_KIMODO_BACKEND.
|
|
23
|
-
set -euo pipefail
|
|
24
|
-
|
|
25
|
-
KIMODO_DIR="${CCLAY_KIMODO_REMOTE_DIR:-$HOME/.cozyclay/kimodo}"
|
|
26
|
-
VENV_DIR="${CCLAY_KIMODO_VENV_DIR:-$HOME/.cozyclay/kimodo-venv}"
|
|
27
|
-
MLX_DIR="${CCLAY_KIMODO_MLX_DIR:-$HOME/.cozyclay/kimodo-mlx}"
|
|
28
|
-
MLX_VENV_DIR="${CCLAY_KIMODO_MLX_VENV_DIR:-$HOME/.cozyclay/kimodo-mlx-venv}"
|
|
29
|
-
CPP_DIR="${CCLAY_KIMODO_CPP_DIR:-$HOME/.cozyclay/kimodo.cpp}"
|
|
30
|
-
CPP_VENV_DIR="${CCLAY_KIMODO_CPP_VENV_DIR:-$HOME/.cozyclay/kimodo-cpp-venv}"
|
|
31
|
-
# kimodo.cpp ref the Metal patch in NomaDamas/kimodo-mlx is known to apply to.
|
|
32
|
-
CPP_METAL_REF="${CCLAY_KIMODO_CPP_METAL_REF:-568b0253}"
|
|
33
|
-
MLX_MIN_RAM_GB="${CCLAY_KIMODO_MLX_MIN_RAM_GB:-32}"
|
|
34
|
-
CPP_VULKAN="${CCLAY_KIMODO_CPP_VULKAN:-auto}"
|
|
35
|
-
MODEL="${CCLAY_KIMODO_MODEL:-Kimodo-SOMA-RP-v1.1}"
|
|
36
|
-
BACKEND="${CCLAY_KIMODO_BACKEND:-auto}"
|
|
37
|
-
DRY_RUN=0
|
|
38
|
-
|
|
39
|
-
usage() {
|
|
40
|
-
cat <<'EOF'
|
|
41
|
-
Usage: setup-on-box.sh [--backend NAME] [--kimodo-dir DIR] [--venv DIR]
|
|
42
|
-
[--model NAME] [--dry-run]
|
|
43
|
-
|
|
44
|
-
Detects the host and installs the best-supported Kimodo backend:
|
|
45
|
-
kimodo-mlx, kimodo.cpp-metal, nvidia-cuda, or kimodo.cpp-cpu.
|
|
46
|
-
--backend (or CCLAY_KIMODO_BACKEND) forces a route; --dry-run prints the
|
|
47
|
-
detected route and every command without changing the host.
|
|
48
|
-
HF_TOKEN may be present in the environment for Hugging Face access; it is never
|
|
49
|
-
printed by this script.
|
|
50
|
-
EOF
|
|
51
|
-
}
|
|
52
|
-
log() { printf 'setup-kimodo: %s\n' "$*"; }
|
|
53
|
-
die() { printf 'setup-kimodo: error: %s\n' "$*" >&2; exit 1; }
|
|
54
|
-
run() {
|
|
55
|
-
if [ "$DRY_RUN" -eq 1 ]; then printf '+ '; printf '%q ' "$@"; printf '\n'; return 0; fi
|
|
56
|
-
"$@"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
while [ "$#" -gt 0 ]; do
|
|
60
|
-
case "$1" in
|
|
61
|
-
--backend) [ "$#" -ge 2 ] || die "--backend needs a value"; BACKEND="$2"; shift 2 ;;
|
|
62
|
-
--kimodo-dir) [ "$#" -ge 2 ] || die "--kimodo-dir needs a value"; KIMODO_DIR="$2"; shift 2 ;;
|
|
63
|
-
--venv) [ "$#" -ge 2 ] || die "--venv needs a value"; VENV_DIR="$2"; shift 2 ;;
|
|
64
|
-
--model) [ "$#" -ge 2 ] || die "--model needs a value"; MODEL="$2"; shift 2 ;;
|
|
65
|
-
--dry-run) DRY_RUN=1; shift ;;
|
|
66
|
-
--help|-h) usage; exit 0 ;;
|
|
67
|
-
*) die "unknown option: $1" ;;
|
|
68
|
-
esac
|
|
69
|
-
done
|
|
70
|
-
|
|
71
|
-
# --- host detection -------------------------------------------------------
|
|
72
|
-
|
|
73
|
-
detect_os() {
|
|
74
|
-
if [ -n "${CCLAY_KIMODO_DETECT_OS:-}" ]; then printf '%s' "$CCLAY_KIMODO_DETECT_OS"; else uname -s; fi
|
|
75
|
-
}
|
|
76
|
-
detect_arch() {
|
|
77
|
-
if [ -n "${CCLAY_KIMODO_DETECT_ARCH:-}" ]; then printf '%s' "$CCLAY_KIMODO_DETECT_ARCH"; else uname -m; fi
|
|
78
|
-
}
|
|
79
|
-
detect_ram_gb() {
|
|
80
|
-
if [ -n "${CCLAY_KIMODO_DETECT_RAM_GB:-}" ]; then printf '%s' "$CCLAY_KIMODO_DETECT_RAM_GB"; return; fi
|
|
81
|
-
local bytes=""
|
|
82
|
-
case "$(detect_os)" in
|
|
83
|
-
Darwin) bytes=$(sysctl -n hw.memsize 2>/dev/null || true) ;;
|
|
84
|
-
Linux) bytes=$(awk '/^MemTotal:/ {print $2 * 1024}' /proc/meminfo 2>/dev/null || true) ;;
|
|
85
|
-
esac
|
|
86
|
-
[ -n "$bytes" ] || { printf '0'; return; }
|
|
87
|
-
printf '%s' $(( bytes / 1073741824 ))
|
|
88
|
-
}
|
|
89
|
-
detect_cuda() {
|
|
90
|
-
if [ -n "${CCLAY_KIMODO_DETECT_CUDA:-}" ]; then printf '%s' "$CCLAY_KIMODO_DETECT_CUDA"; return; fi
|
|
91
|
-
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then printf '1'; else printf '0'; fi
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
route_backend() {
|
|
95
|
-
case "$BACKEND" in
|
|
96
|
-
auto) ;;
|
|
97
|
-
kimodo-mlx|kimodo.cpp-metal|nvidia-cuda|kimodo.cpp-cpu) printf '%s' "$BACKEND"; return ;;
|
|
98
|
-
*) die "unknown backend: $BACKEND (expected kimodo-mlx, kimodo.cpp-metal, nvidia-cuda, kimodo.cpp-cpu, or auto)" ;;
|
|
99
|
-
esac
|
|
100
|
-
local os arch ram cuda
|
|
101
|
-
os=$(detect_os); arch=$(detect_arch); ram=$(detect_ram_gb); cuda=$(detect_cuda)
|
|
102
|
-
case "$os" in
|
|
103
|
-
Darwin)
|
|
104
|
-
case "$arch" in
|
|
105
|
-
arm64)
|
|
106
|
-
# > 32 GB keeps the 15 GB encoder resident; at or below it, stream.
|
|
107
|
-
if [ "$ram" -gt "$MLX_MIN_RAM_GB" ]; then printf 'kimodo-mlx'; else printf 'kimodo.cpp-metal'; fi
|
|
108
|
-
;;
|
|
109
|
-
*) printf 'kimodo.cpp-cpu' ;;
|
|
110
|
-
esac
|
|
111
|
-
;;
|
|
112
|
-
Linux)
|
|
113
|
-
if [ "$cuda" = "1" ]; then printf 'nvidia-cuda'; else printf 'kimodo.cpp-cpu'; fi
|
|
114
|
-
;;
|
|
115
|
-
*) die "unsupported OS: $os (use --backend to force a route, or run inside WSL on Windows)" ;;
|
|
116
|
-
esac
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
OS=$(detect_os); ARCH=$(detect_arch); RAM_GB=$(detect_ram_gb); CUDA=$(detect_cuda)
|
|
120
|
-
BACKEND=$(route_backend)
|
|
121
|
-
|
|
122
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
123
|
-
log "dry run; no files, packages, or models will be changed"
|
|
124
|
-
fi
|
|
125
|
-
log "detected: os=$OS arch=$ARCH ram=${RAM_GB}GB cuda=$CUDA"
|
|
126
|
-
log "backend=$BACKEND"
|
|
127
|
-
|
|
128
|
-
# --- backends ---------------------------------------------------------------
|
|
129
|
-
|
|
130
|
-
install_nvidia_cuda() {
|
|
131
|
-
if [ "$DRY_RUN" -ne 1 ]; then
|
|
132
|
-
command -v git >/dev/null 2>&1 || die "git is required"
|
|
133
|
-
command -v python3 >/dev/null 2>&1 || die "python3 is required"
|
|
134
|
-
command -v nvidia-smi >/dev/null 2>&1 || die "an NVIDIA CUDA host is required (nvidia-smi not found)"
|
|
135
|
-
nvidia-smi >/dev/null 2>&1 || die "nvidia-smi cannot access the GPU"
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
if [ ! -e "$KIMODO_DIR/.git" ]; then
|
|
139
|
-
mkdir -p "$(dirname "$KIMODO_DIR")"
|
|
140
|
-
run git clone --depth 1 https://github.com/nv-tlabs/kimodo.git "$KIMODO_DIR"
|
|
141
|
-
else
|
|
142
|
-
log "Kimodo checkout already exists at $KIMODO_DIR"
|
|
143
|
-
fi
|
|
144
|
-
|
|
145
|
-
if [ ! -x "$VENV_DIR/bin/python" ]; then
|
|
146
|
-
run python3 -m venv "$VENV_DIR"
|
|
147
|
-
else
|
|
148
|
-
log "Python environment already exists at $VENV_DIR"
|
|
149
|
-
fi
|
|
150
|
-
|
|
151
|
-
PY="$VENV_DIR/bin/python"
|
|
152
|
-
run "$PY" -m pip install --upgrade pip
|
|
153
|
-
run "$PY" -m pip install torch
|
|
154
|
-
run "$PY" -m pip install -e "$KIMODO_DIR" llm2vec
|
|
155
|
-
|
|
156
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
157
|
-
log "would prefetch model $MODEL and LLM2Vec encoder assets"
|
|
158
|
-
else
|
|
159
|
-
"$PY" - "$MODEL" <<'PY'
|
|
160
|
-
import sys
|
|
161
|
-
from huggingface_hub import snapshot_download
|
|
162
|
-
model = sys.argv[1]
|
|
163
|
-
snapshot_download(repo_id=f"nvidia/{model}")
|
|
164
|
-
snapshot_download(repo_id="meta-llama/Meta-Llama-3-8B-Instruct")
|
|
165
|
-
snapshot_download(repo_id="McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp")
|
|
166
|
-
snapshot_download(repo_id="McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp-supervised")
|
|
167
|
-
print("model and encoder assets ready")
|
|
168
|
-
PY
|
|
169
|
-
fi
|
|
170
|
-
|
|
171
|
-
if [ "$VENV_DIR" != "$KIMODO_DIR/.venv" ]; then
|
|
172
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
173
|
-
log "would link $KIMODO_DIR/.venv -> $VENV_DIR"
|
|
174
|
-
else
|
|
175
|
-
ln -sfn "$VENV_DIR" "$KIMODO_DIR/.venv"
|
|
176
|
-
fi
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
log "export CCLAY_MOTION_BACKEND=kimodo"
|
|
180
|
-
log "export CCLAY_KIMODO_HOST=<this host>"
|
|
181
|
-
log "export CCLAY_KIMODO_REPO=$KIMODO_DIR (venv available at $KIMODO_DIR/.venv)"
|
|
182
|
-
log "Kimodo model: $MODEL"
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
install_kimodo_mlx() {
|
|
186
|
-
if [ "$DRY_RUN" -ne 1 ]; then
|
|
187
|
-
command -v git >/dev/null 2>&1 || die "git is required"
|
|
188
|
-
command -v python3 >/dev/null 2>&1 || die "python3 is required"
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
if [ ! -e "$MLX_DIR/.git" ]; then
|
|
192
|
-
mkdir -p "$(dirname "$MLX_DIR")"
|
|
193
|
-
run git clone --depth 1 https://github.com/NomaDamas/kimodo-mlx.git "$MLX_DIR"
|
|
194
|
-
else
|
|
195
|
-
log "kimodo-mlx checkout already exists at $MLX_DIR"
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
if [ ! -x "$MLX_VENV_DIR/bin/python" ]; then
|
|
199
|
-
if command -v uv >/dev/null 2>&1; then
|
|
200
|
-
run uv venv --python 3.12 "$MLX_VENV_DIR"
|
|
201
|
-
else
|
|
202
|
-
run python3 -m venv "$MLX_VENV_DIR"
|
|
203
|
-
fi
|
|
204
|
-
else
|
|
205
|
-
log "Python environment already exists at $MLX_VENV_DIR"
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
PY="$MLX_VENV_DIR/bin/python"
|
|
209
|
-
HF="$MLX_VENV_DIR/bin/hf"
|
|
210
|
-
run "$PY" -m pip install --upgrade pip
|
|
211
|
-
run "$PY" -m pip install -e "$MLX_DIR" huggingface_hub
|
|
212
|
-
|
|
213
|
-
run "$HF" download "nvidia/$MODEL" --local-dir "$MLX_DIR/models/$(printf '%s' "$MODEL" | sed 's/^Kimodo-/nvidia-/' | tr 'A-Z' 'a-z')"
|
|
214
|
-
run "$HF" download LocalAI-io/Llama-3-Kimodo-GGML --local-dir "$MLX_DIR/models/llm2vec-text-bundle"
|
|
215
|
-
|
|
216
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
217
|
-
log "would run: $PY -m kimodo_mlx diagnose (expect mlx-metal)"
|
|
218
|
-
log "would verify: $PY -m kimodo_mlx --help"
|
|
219
|
-
else
|
|
220
|
-
"$PY" -m kimodo_mlx diagnose || die "kimodo-mlx diagnose failed; see $MLX_DIR/README.md"
|
|
221
|
-
"$PY" -m kimodo_mlx --help >/dev/null || die "kimodo-mlx CLI verification failed; see $MLX_DIR/README.md"
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
|
-
log "kimodo-mlx ready: $PY -m kimodo_mlx generate --prompt \"walk forward\" --frames 30 --steps 10"
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
install_kimodo_cpp() {
|
|
228
|
-
local accel="$1" # metal | cpu
|
|
229
|
-
if [ "$DRY_RUN" -ne 1 ]; then
|
|
230
|
-
command -v git >/dev/null 2>&1 || die "git is required"
|
|
231
|
-
command -v cmake >/dev/null 2>&1 || die "cmake is required (CMake 3.25+)"
|
|
232
|
-
command -v python3 >/dev/null 2>&1 || die "python3 is required"
|
|
233
|
-
fi
|
|
234
|
-
|
|
235
|
-
if [ ! -e "$CPP_DIR/.git" ]; then
|
|
236
|
-
mkdir -p "$(dirname "$CPP_DIR")"
|
|
237
|
-
run git clone --depth 1 https://github.com/localai-org/kimodo.cpp.git "$CPP_DIR"
|
|
238
|
-
else
|
|
239
|
-
log "kimodo.cpp checkout already exists at $CPP_DIR"
|
|
240
|
-
fi
|
|
241
|
-
run git -C "$CPP_DIR" submodule update --init --recursive
|
|
242
|
-
|
|
243
|
-
local build_dir="$CPP_DIR/build-$accel"
|
|
244
|
-
if [ "$accel" = "metal" ]; then
|
|
245
|
-
# The GGML Metal wiring lives in a patch maintained with the kimodo-mlx
|
|
246
|
-
# port; apply it onto the ref it was written against.
|
|
247
|
-
if [ ! -e "$MLX_DIR/.git" ]; then
|
|
248
|
-
mkdir -p "$(dirname "$MLX_DIR")"
|
|
249
|
-
run git clone --depth 1 https://github.com/NomaDamas/kimodo-mlx.git "$MLX_DIR"
|
|
250
|
-
fi
|
|
251
|
-
run git -C "$CPP_DIR" fetch --depth 1 origin "$CPP_METAL_REF"
|
|
252
|
-
run git -C "$CPP_DIR" checkout FETCH_HEAD
|
|
253
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
254
|
-
printf '+ '; printf '%q ' git -C "$CPP_DIR" apply "$MLX_DIR/patches/0001-kimodo-ggml-metal.patch"; printf '\n'
|
|
255
|
-
else
|
|
256
|
-
if git -C "$CPP_DIR" apply --check "$MLX_DIR/patches/0001-kimodo-ggml-metal.patch" 2>/dev/null; then
|
|
257
|
-
git -C "$CPP_DIR" apply "$MLX_DIR/patches/0001-kimodo-ggml-metal.patch"
|
|
258
|
-
elif git -C "$CPP_DIR" apply --check -R "$MLX_DIR/patches/0001-kimodo-ggml-metal.patch" 2>/dev/null; then
|
|
259
|
-
log "Metal patch already applied; continuing"
|
|
260
|
-
else
|
|
261
|
-
die "Metal patch cannot be applied cleanly; see $CPP_DIR and $MLX_DIR/patches/0001-kimodo-ggml-metal.patch"
|
|
262
|
-
fi
|
|
263
|
-
fi
|
|
264
|
-
run cmake -S "$CPP_DIR" -B "$build_dir" \
|
|
265
|
-
-DKIMODO_ENABLE_VULKAN=OFF -DKIMODO_ENABLE_METAL=ON -DKIMODO_BUILD_TESTS=OFF
|
|
266
|
-
else
|
|
267
|
-
local vulkan="$CPP_VULKAN"
|
|
268
|
-
if [ "$vulkan" = "auto" ]; then
|
|
269
|
-
if pkg-config --exists vulkan 2>/dev/null || [ -f /usr/include/vulkan/vulkan.h ]; then
|
|
270
|
-
vulkan=ON
|
|
271
|
-
else
|
|
272
|
-
vulkan=OFF
|
|
273
|
-
fi
|
|
274
|
-
fi
|
|
275
|
-
log "kimodo.cpp CPU build: vulkan=$vulkan"
|
|
276
|
-
run cmake -S "$CPP_DIR" -B "$build_dir" \
|
|
277
|
-
-DKIMODO_ENABLE_VULKAN="$vulkan" -DKIMODO_BUILD_TESTS=OFF
|
|
278
|
-
fi
|
|
279
|
-
run cmake --build "$build_dir" --parallel
|
|
280
|
-
|
|
281
|
-
local binary="$build_dir/kmd-generate"
|
|
282
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
283
|
-
log "would verify executable $binary"
|
|
284
|
-
else
|
|
285
|
-
[ -x "$binary" ] || die "kimodo.cpp build did not produce executable: $binary"
|
|
286
|
-
log "verified kimodo.cpp executable: $binary"
|
|
287
|
-
fi
|
|
288
|
-
|
|
289
|
-
if [ "$accel" = "metal" ] && [ "$DRY_RUN" -ne 1 ]; then
|
|
290
|
-
local metal_enabled=0
|
|
291
|
-
if [ -f "$build_dir/CMakeCache.txt" ] && grep -Eq '^KIMODO_ENABLE_METAL(:BOOL)?=ON$' "$build_dir/CMakeCache.txt"; then
|
|
292
|
-
metal_enabled=1
|
|
293
|
-
else
|
|
294
|
-
while IFS= read -r -d '' binary; do
|
|
295
|
-
if command -v nm >/dev/null 2>&1 && nm "$binary" 2>/dev/null | grep -Eiq 'metal|ggml_metal'; then
|
|
296
|
-
metal_enabled=1
|
|
297
|
-
break
|
|
298
|
-
fi
|
|
299
|
-
done < <(find "$build_dir" -type f -perm -111 -print0 2>/dev/null)
|
|
300
|
-
fi
|
|
301
|
-
[ "$metal_enabled" -eq 1 ] || die "Metal build verification failed; KIMODO_ENABLE_METAL is not enabled"
|
|
302
|
-
log "verified Metal build: KIMODO_ENABLE_METAL=ON"
|
|
303
|
-
fi
|
|
304
|
-
|
|
305
|
-
# GGUF weights come from the LocalAI-io org through the upstream script,
|
|
306
|
-
# which needs the hf CLI; keep it in a small dedicated venv.
|
|
307
|
-
if [ ! -x "$CPP_VENV_DIR/bin/hf" ]; then
|
|
308
|
-
run python3 -m venv "$CPP_VENV_DIR"
|
|
309
|
-
run "$CPP_VENV_DIR/bin/python" -m pip install --upgrade pip huggingface_hub
|
|
310
|
-
fi
|
|
311
|
-
local cpp_model
|
|
312
|
-
cpp_model=$(printf '%s' "$MODEL" | sed 's/^Kimodo-//' | tr 'A-Z' 'a-z')
|
|
313
|
-
run env "PATH=$CPP_VENV_DIR/bin:$PATH" bash "$CPP_DIR/scripts/download_gguf_weights.sh" \
|
|
314
|
-
--output "$CPP_DIR" --model "$cpp_model"
|
|
315
|
-
|
|
316
|
-
log "kimodo.cpp ($accel) ready: build at $build_dir, GGUF weights under $CPP_DIR"
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
case "$BACKEND" in
|
|
320
|
-
nvidia-cuda) install_nvidia_cuda ;;
|
|
321
|
-
kimodo-mlx) install_kimodo_mlx ;;
|
|
322
|
-
kimodo.cpp-metal) install_kimodo_cpp metal ;;
|
|
323
|
-
kimodo.cpp-cpu) install_kimodo_cpp cpu ;;
|
|
324
|
-
esac
|
|
325
|
-
|
|
326
|
-
# Tell the Studio runner exactly which installed route to use.
|
|
327
|
-
if [ "$DRY_RUN" -eq 1 ]; then
|
|
328
|
-
log "would write $HOME/.cozyclay/kimodo-backend.json"
|
|
329
|
-
else
|
|
330
|
-
mkdir -p "$HOME/.cozyclay"
|
|
331
|
-
if [ "$BACKEND" = "kimodo-mlx" ]; then
|
|
332
|
-
printf '{"backend":"%s","model":"%s","motion":"%s/models/nvidia-soma-rp-v1.1","text":"%s/models/llm2vec-text-bundle"}\n' "$BACKEND" "$MODEL" "$MLX_DIR" "$MLX_DIR" > "$HOME/.cozyclay/kimodo-backend.json"
|
|
333
|
-
elif [ "$BACKEND" = "kimodo.cpp-metal" ] || [ "$BACKEND" = "kimodo.cpp-cpu" ]; then
|
|
334
|
-
printf '{"backend":"%s","model":"%s","motion":"%s/models/kimodo-%s-f32.gguf","text":"%s/generated/llm2vec-text-bundle"}\n' "$BACKEND" "$MODEL" "$CPP_DIR" "$(printf '%s' "$MODEL" | sed 's/^Kimodo-//' | tr 'A-Z' 'a-z')" "$CPP_DIR" > "$HOME/.cozyclay/kimodo-backend.json"
|
|
335
|
-
else
|
|
336
|
-
printf '{"backend":"%s","model":"%s"}\n' "$BACKEND" "$MODEL" > "$HOME/.cozyclay/kimodo-backend.json"
|
|
337
|
-
fi
|
|
338
|
-
fi
|
|
339
|
-
log "ready"
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* soma77-to-cskel27.mjs — Kimodo's somaskel77 motion npz → the exact motion
|
|
3
|
-
* arrays the cclay npz encoder consumes ({ frames, fps, rotMats, rootPos,
|
|
4
|
-
* posedJoints }), i.e. the same shape tools/ardy/bvh-cskel27.mjs produces.
|
|
5
|
-
*
|
|
6
|
-
* WHY GLOBAL ROTATIONS. cskel27 and somaskel77 do not share a spine
|
|
7
|
-
* segmentation: cskel27 runs Hips→Spine→Spine1→Spine2→Spine3 (four segments
|
|
8
|
-
* before the shoulder carrier) where somaskel77 runs Hips→Spine1→Spine2→Chest
|
|
9
|
-
* (three), and somaskel77 splits the neck in two (Neck1→Neck2) where cskel27
|
|
10
|
-
* has one. Re-deriving each cskel27 LOCAL from a per-joint global — exactly
|
|
11
|
-
* the rule tools/ardy/bvh-cskel27.mjs states for the Mixamo case — makes that
|
|
12
|
-
* mismatch a non-issue in both directions:
|
|
13
|
-
*
|
|
14
|
-
* - a source segment cskel27 lacks (Neck2) is absorbed into the child's
|
|
15
|
-
* local, because local = parentGlobalᵀ · global composes whatever sits
|
|
16
|
-
* between the two mapped joints. No rotation is lost.
|
|
17
|
-
* - a cskel27 joint the source lacks (Spine2, the Hand ends) borrows its
|
|
18
|
-
* nearest mapped ancestor's global, so its local comes out identity —
|
|
19
|
-
* the same "not authored" rule poseToCskel27 and bvhToCskel27Motion use.
|
|
20
|
-
*
|
|
21
|
-
* Both skeletons rest in the same convention (Y-up, metres, standard T-pose:
|
|
22
|
-
* Kimodo writes its NPZ against the canonical SOMA T-pose, and CSKEL27_NEUTRAL
|
|
23
|
-
* is the cskel27 T-pose), so a somaskel77 global IS the cskel27 global for the
|
|
24
|
-
* matching joint and no basis change is needed.
|
|
25
|
-
*
|
|
26
|
-
* POSITIONS ARE RE-GROWN, never copied: the take has to move CozyClay's body,
|
|
27
|
-
* not drag Kimodo's per-model bone lengths into the scene. FK runs over the
|
|
28
|
-
* canonical cskel27 skeleton and the root trajectory is scaled by the
|
|
29
|
-
* leg-length ratio so stride length survives the reproportioning, then
|
|
30
|
-
* floor-shifted so the clip's lowest foot sample touches Y=0.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import { CSKEL27_JOINTS, CSKEL27_PARENTS } from "../../src/ardy/cskel27.js";
|
|
34
|
-
import { deriveBoneOffsets, forwardKinematics, matMul, matTranspose } from "../../src/ardy/convert.js";
|
|
35
|
-
import { canonicalCskel27Reference } from "../../src/ardy/to-cskel27.js";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* somaskel77 joint order, transcribed from the upstream skeleton definition
|
|
39
|
-
* (`SOMASkeleton77.bone_order_names_with_parents` in ardy/skeleton/definitions.py,
|
|
40
|
-
* identical in the Kimodo tree). Index here == joint index in the Kimodo npz
|
|
41
|
-
* arrays. The standard-T-pose BVH in the Kimodo assets carries an extra `Root`
|
|
42
|
-
* node ABOVE Hips that is a BVH-file artifact only — it is not part of the
|
|
43
|
-
* joint arrays, so this list starts at Hips and is 77 long.
|
|
44
|
-
*/
|
|
45
|
-
export const SOMA77_JOINTS = [
|
|
46
|
-
"Hips", "Spine1", "Spine2", "Chest", "Neck1", "Neck2", "Head", "HeadEnd",
|
|
47
|
-
"Jaw", "LeftEye", "RightEye",
|
|
48
|
-
"LeftShoulder", "LeftArm", "LeftForeArm", "LeftHand",
|
|
49
|
-
"LeftHandThumb1", "LeftHandThumb2", "LeftHandThumb3", "LeftHandThumbEnd",
|
|
50
|
-
"LeftHandIndex1", "LeftHandIndex2", "LeftHandIndex3", "LeftHandIndex4", "LeftHandIndexEnd",
|
|
51
|
-
"LeftHandMiddle1", "LeftHandMiddle2", "LeftHandMiddle3", "LeftHandMiddle4", "LeftHandMiddleEnd",
|
|
52
|
-
"LeftHandRing1", "LeftHandRing2", "LeftHandRing3", "LeftHandRing4", "LeftHandRingEnd",
|
|
53
|
-
"LeftHandPinky1", "LeftHandPinky2", "LeftHandPinky3", "LeftHandPinky4", "LeftHandPinkyEnd",
|
|
54
|
-
"RightShoulder", "RightArm", "RightForeArm", "RightHand",
|
|
55
|
-
"RightHandThumb1", "RightHandThumb2", "RightHandThumb3", "RightHandThumbEnd",
|
|
56
|
-
"RightHandIndex1", "RightHandIndex2", "RightHandIndex3", "RightHandIndex4", "RightHandIndexEnd",
|
|
57
|
-
"RightHandMiddle1", "RightHandMiddle2", "RightHandMiddle3", "RightHandMiddle4", "RightHandMiddleEnd",
|
|
58
|
-
"RightHandRing1", "RightHandRing2", "RightHandRing3", "RightHandRing4", "RightHandRingEnd",
|
|
59
|
-
"RightHandPinky1", "RightHandPinky2", "RightHandPinky3", "RightHandPinky4", "RightHandPinkyEnd",
|
|
60
|
-
"LeftLeg", "LeftShin", "LeftFoot", "LeftToeBase", "LeftToeEnd",
|
|
61
|
-
"RightLeg", "RightShin", "RightFoot", "RightToeBase", "RightToeEnd",
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* cskel27 joint name → the somaskel77 joint whose GLOBAL rotation drives it,
|
|
66
|
-
* or null for "this joint is not authored by the source".
|
|
67
|
-
*
|
|
68
|
-
* The two anchors that fix the torso alignment are structural, not cosmetic:
|
|
69
|
-
* Hips is the root in both, and cskel27's Spine3 carries the shoulders and the
|
|
70
|
-
* neck exactly as somaskel77's Chest does — so Spine3↔Chest is forced. That
|
|
71
|
-
* leaves three cskel27 links (Spine, Spine1, Spine2) spanning the two
|
|
72
|
-
* somaskel77 links (Spine1, Spine2) between those anchors, so exactly one
|
|
73
|
-
* cskel27 spine joint must go unauthored. Spine2 is the one chosen: mapping
|
|
74
|
-
* from the bottom up keeps the lower spine — where the large trunk rotation
|
|
75
|
-
* lives — driven by real data, and pushes the identity link to the top of the
|
|
76
|
-
* chain where the residual Spine2→Chest rotation is absorbed into Spine3's
|
|
77
|
-
* local anyway.
|
|
78
|
-
*
|
|
79
|
-
* NOTE ON THE LEGS: the names shift by one between the two skeletons.
|
|
80
|
-
* somaskel77's LeftLeg is the THIGH (cskel27's LeftUpLeg) and its LeftShin is
|
|
81
|
-
* the shank (cskel27's LeftLeg). Mapping these by identical name would silently
|
|
82
|
-
* put the knee rotation on the hip.
|
|
83
|
-
*
|
|
84
|
-
* The hand ends stay unauthored, matching bvhToCskel27Motion: somaskel77's
|
|
85
|
-
* nearest equivalents are finger roots, and borrowing one would splay the hand.
|
|
86
|
-
*/
|
|
87
|
-
export const CSKEL27_FROM_SOMA77 = {
|
|
88
|
-
Hips: "Hips",
|
|
89
|
-
Spine: "Spine1",
|
|
90
|
-
Spine1: "Spine2",
|
|
91
|
-
Spine2: null,
|
|
92
|
-
Spine3: "Chest",
|
|
93
|
-
Neck: "Neck1",
|
|
94
|
-
Head: "Head",
|
|
95
|
-
|
|
96
|
-
RightShoulder: "RightShoulder",
|
|
97
|
-
RightArm: "RightArm",
|
|
98
|
-
RightForeArm: "RightForeArm",
|
|
99
|
-
RightHand: "RightHand",
|
|
100
|
-
RightHandEnd: null,
|
|
101
|
-
RightHandThumb1: "RightHandThumb1",
|
|
102
|
-
|
|
103
|
-
LeftShoulder: "LeftShoulder",
|
|
104
|
-
LeftArm: "LeftArm",
|
|
105
|
-
LeftForeArm: "LeftForeArm",
|
|
106
|
-
LeftHand: "LeftHand",
|
|
107
|
-
LeftHandEnd: null,
|
|
108
|
-
LeftHandThumb1: "LeftHandThumb1",
|
|
109
|
-
|
|
110
|
-
RightUpLeg: "RightLeg",
|
|
111
|
-
RightLeg: "RightShin",
|
|
112
|
-
RightFoot: "RightFoot",
|
|
113
|
-
RightToeBase: "RightToeBase",
|
|
114
|
-
|
|
115
|
-
LeftUpLeg: "LeftLeg",
|
|
116
|
-
LeftLeg: "LeftShin",
|
|
117
|
-
LeftFoot: "LeftFoot",
|
|
118
|
-
LeftToeBase: "LeftToeBase",
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const IDENTITY = [
|
|
122
|
-
[1, 0, 0],
|
|
123
|
-
[0, 1, 0],
|
|
124
|
-
[0, 0, 1],
|
|
125
|
-
];
|
|
126
|
-
|
|
127
|
-
/** cskel27 joints whose Y decides where the floor is. */
|
|
128
|
-
const GROUND_JOINTS = ["LeftFoot", "LeftToeBase", "RightFoot", "RightToeBase"];
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Per cskel27 joint, the somaskel77 index whose global rotation it takes.
|
|
132
|
-
* An unmapped joint walks up the cskel27 parent chain to the nearest mapped
|
|
133
|
-
* ancestor, which is what makes its local come out identity.
|
|
134
|
-
*/
|
|
135
|
-
export function resolveSourceIndices(jointNames = SOMA77_JOINTS) {
|
|
136
|
-
const sourceIndex = new Map(jointNames.map((name, index) => [name, index]));
|
|
137
|
-
const missing = Object.values(CSKEL27_FROM_SOMA77).filter(
|
|
138
|
-
(name) => name !== null && !sourceIndex.has(name)
|
|
139
|
-
);
|
|
140
|
-
if (missing.length) {
|
|
141
|
-
throw new Error(`soma77ToCskel27Motion: source skeleton is missing ${missing.join(", ")}`);
|
|
142
|
-
}
|
|
143
|
-
const resolved = new Array(CSKEL27_JOINTS.length);
|
|
144
|
-
for (let index = 0; index < CSKEL27_JOINTS.length; index += 1) {
|
|
145
|
-
let cursor = index;
|
|
146
|
-
let source = CSKEL27_FROM_SOMA77[CSKEL27_JOINTS[cursor]];
|
|
147
|
-
while (source == null) {
|
|
148
|
-
cursor = CSKEL27_PARENTS[cursor];
|
|
149
|
-
if (cursor === null) {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`soma77ToCskel27Motion: ${CSKEL27_JOINTS[index]} has no mapped ancestor`
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
source = CSKEL27_FROM_SOMA77[CSKEL27_JOINTS[cursor]];
|
|
155
|
-
}
|
|
156
|
-
resolved[index] = sourceIndex.get(source);
|
|
157
|
-
}
|
|
158
|
-
return resolved;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function readMat(flat, base) {
|
|
162
|
-
return [
|
|
163
|
-
[flat[base], flat[base + 1], flat[base + 2]],
|
|
164
|
-
[flat[base + 3], flat[base + 4], flat[base + 5]],
|
|
165
|
-
[flat[base + 6], flat[base + 7], flat[base + 8]],
|
|
166
|
-
];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function chainLength(positions, indexByName, names) {
|
|
170
|
-
let total = 0;
|
|
171
|
-
for (let step = 1; step < names.length; step += 1) {
|
|
172
|
-
const a = positions[indexByName.get(names[step - 1])];
|
|
173
|
-
const b = positions[indexByName.get(names[step])];
|
|
174
|
-
total += Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
175
|
-
}
|
|
176
|
-
return total;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* @param {object} input
|
|
181
|
-
* @param {number} input.frames
|
|
182
|
-
* @param {number} input.fps
|
|
183
|
-
* @param {Float32Array} input.globalRotMats Kimodo `global_rot_mats`, frames*J*9
|
|
184
|
-
* @param {Float32Array} input.posedJoints Kimodo `posed_joints`, frames*J*3
|
|
185
|
-
* @param {string[]} [input.jointNames] source joint order (default somaskel77)
|
|
186
|
-
* @returns {{frames:number, fps:number, rotMats:Float32Array, rootPos:Float32Array, posedJoints:Float32Array}}
|
|
187
|
-
*/
|
|
188
|
-
export function soma77ToCskel27Motion({ frames, fps, globalRotMats, posedJoints, jointNames = SOMA77_JOINTS }) {
|
|
189
|
-
if (!Number.isInteger(frames) || frames < 1) {
|
|
190
|
-
throw new Error("soma77ToCskel27Motion: frames must be a positive integer");
|
|
191
|
-
}
|
|
192
|
-
if (!Number.isInteger(fps) || fps < 1) {
|
|
193
|
-
throw new Error("soma77ToCskel27Motion: fps must be a positive integer");
|
|
194
|
-
}
|
|
195
|
-
const jointCount = jointNames.length;
|
|
196
|
-
if (globalRotMats.length !== frames * jointCount * 9) {
|
|
197
|
-
throw new Error(
|
|
198
|
-
`soma77ToCskel27Motion: globalRotMats must be ${frames * jointCount * 9} long, got ${globalRotMats.length}`
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
if (posedJoints.length !== frames * jointCount * 3) {
|
|
202
|
-
throw new Error(
|
|
203
|
-
`soma77ToCskel27Motion: posedJoints must be ${frames * jointCount * 3} long, got ${posedJoints.length}`
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const sources = resolveSourceIndices(jointNames);
|
|
208
|
-
const indexByName = new Map(jointNames.map((name, index) => [name, index]));
|
|
209
|
-
|
|
210
|
-
// Canonical cskel27 proportions. The reference rests with identity locals,
|
|
211
|
-
// so these offsets are the neutral skeleton's own bone vectors.
|
|
212
|
-
const reference = canonicalCskel27Reference();
|
|
213
|
-
const boneOffsets = deriveBoneOffsets(reference.posed_joints, reference.local_rot_mats);
|
|
214
|
-
|
|
215
|
-
// Leg-length ratio, measured on the source's own first frame against the
|
|
216
|
-
// canonical body, so a stride generated for Kimodo's proportions covers the
|
|
217
|
-
// same fraction of a step on CozyClay's.
|
|
218
|
-
const firstFrame = [];
|
|
219
|
-
for (let joint = 0; joint < jointCount; joint += 1) {
|
|
220
|
-
const base = joint * 3;
|
|
221
|
-
firstFrame.push([posedJoints[base], posedJoints[base + 1], posedJoints[base + 2]]);
|
|
222
|
-
}
|
|
223
|
-
const sourceLeg = chainLength(firstFrame, indexByName, ["LeftLeg", "LeftShin", "LeftFoot"]);
|
|
224
|
-
const canonicalIndex = new Map(CSKEL27_JOINTS.map((name, index) => [name, index]));
|
|
225
|
-
const canonicalLeg = chainLength(reference.posed_joints, canonicalIndex, [
|
|
226
|
-
"LeftUpLeg",
|
|
227
|
-
"LeftLeg",
|
|
228
|
-
"LeftFoot",
|
|
229
|
-
]);
|
|
230
|
-
if (!(sourceLeg > 0)) {
|
|
231
|
-
throw new Error("soma77ToCskel27Motion: source leg length measured as zero");
|
|
232
|
-
}
|
|
233
|
-
const rootScale = canonicalLeg / sourceLeg;
|
|
234
|
-
|
|
235
|
-
const rotMats = new Float32Array(frames * 27 * 9);
|
|
236
|
-
const rootPos = new Float32Array(frames * 3);
|
|
237
|
-
const outPosed = new Float32Array(frames * 27 * 3);
|
|
238
|
-
|
|
239
|
-
const hipsSource = indexByName.get("Hips");
|
|
240
|
-
let floorY = Infinity;
|
|
241
|
-
|
|
242
|
-
for (let frame = 0; frame < frames; frame += 1) {
|
|
243
|
-
const rotBase = frame * jointCount * 9;
|
|
244
|
-
const globals = new Array(27);
|
|
245
|
-
for (let joint = 0; joint < 27; joint += 1) {
|
|
246
|
-
globals[joint] = readMat(globalRotMats, rotBase + sources[joint] * 9);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const locals = new Array(27);
|
|
250
|
-
for (let joint = 0; joint < 27; joint += 1) {
|
|
251
|
-
const parent = CSKEL27_PARENTS[joint];
|
|
252
|
-
locals[joint] =
|
|
253
|
-
parent === null ? globals[joint].map((row) => row.slice()) : matMul(matTranspose(globals[parent]), globals[joint]);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const posBase = frame * jointCount * 3 + hipsSource * 3;
|
|
257
|
-
const root = [
|
|
258
|
-
posedJoints[posBase] * rootScale,
|
|
259
|
-
posedJoints[posBase + 1] * rootScale,
|
|
260
|
-
posedJoints[posBase + 2] * rootScale,
|
|
261
|
-
];
|
|
262
|
-
const positions = forwardKinematics(locals, boneOffsets, root);
|
|
263
|
-
|
|
264
|
-
for (const name of GROUND_JOINTS) {
|
|
265
|
-
const y = positions[canonicalIndex.get(name)][1];
|
|
266
|
-
if (y < floorY) floorY = y;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const outRotBase = frame * 27 * 9;
|
|
270
|
-
for (let joint = 0; joint < 27; joint += 1) {
|
|
271
|
-
const m = locals[joint];
|
|
272
|
-
for (let row = 0; row < 3; row += 1) {
|
|
273
|
-
for (let col = 0; col < 3; col += 1) {
|
|
274
|
-
rotMats[outRotBase + joint * 3 * 3 + row * 3 + col] = m[row][col];
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
rootPos[frame * 3] = root[0];
|
|
279
|
-
rootPos[frame * 3 + 1] = root[1];
|
|
280
|
-
rootPos[frame * 3 + 2] = root[2];
|
|
281
|
-
const outPosBase = frame * 27 * 3;
|
|
282
|
-
for (let joint = 0; joint < 27; joint += 1) {
|
|
283
|
-
outPosed[outPosBase + joint * 3] = positions[joint][0];
|
|
284
|
-
outPosed[outPosBase + joint * 3 + 1] = positions[joint][1];
|
|
285
|
-
outPosed[outPosBase + joint * 3 + 2] = positions[joint][2];
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// One rigid floor shift for the whole clip: per-frame grounding would
|
|
290
|
-
// flatten the arc of a jump, which is exactly the motion this pipeline
|
|
291
|
-
// exists to stage.
|
|
292
|
-
if (Number.isFinite(floorY) && floorY !== 0) {
|
|
293
|
-
for (let frame = 0; frame < frames; frame += 1) {
|
|
294
|
-
rootPos[frame * 3 + 1] -= floorY;
|
|
295
|
-
const outPosBase = frame * 27 * 3;
|
|
296
|
-
for (let joint = 0; joint < 27; joint += 1) {
|
|
297
|
-
outPosed[outPosBase + joint * 3 + 1] -= floorY;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return { frames, fps, rotMats, rootPos, posedJoints: outPosed };
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
export { IDENTITY as CSKEL27_IDENTITY };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Ground truth from MorphGS's own Animation.step: writes rot_params.npy + pred_joints.npy exactly like src/render.py:606-618.
|
|
2
|
-
# usage: python gen_truth.py <MorphGS-root> <mesh.obj> <rig.txt> <outdir>
|
|
3
|
-
import sys, os
|
|
4
|
-
morphgs_root, mesh_path, rig_path, out = sys.argv[1:5]
|
|
5
|
-
sys.path.insert(0, os.path.join(morphgs_root, "src"))
|
|
6
|
-
import numpy as np, torch, trimesh
|
|
7
|
-
from model.RigModel import Rig
|
|
8
|
-
from model.AnimationField import Animation, get_embedder
|
|
9
|
-
|
|
10
|
-
os.makedirs(out, exist_ok=True)
|
|
11
|
-
mesh = trimesh.load_mesh(mesh_path, process=False, maintain_order=True)
|
|
12
|
-
rig = Rig(mesh, rig_path, smooth_w=0, device="cpu", skinning_method="lbs")
|
|
13
|
-
N = rig.joints_name; J = len(N); ix = N.index
|
|
14
|
-
# Emulate MorphGS morphology (ParametricModel.get_joints_pos): legs +8%, arms -5%, same bone directions.
|
|
15
|
-
scale = {n: 1.08 for n in N if "Leg" in n or "Foot" in n or "Toe" in n}
|
|
16
|
-
scale.update({n: 0.95 for n in N if "Arm" in n or "Hand" in n})
|
|
17
|
-
joints = rig.joints_pos.clone()
|
|
18
|
-
for p, c in rig.bones: # bones are BFS-ordered from the root, parents first
|
|
19
|
-
joints[c] = joints[p] + (rig.joints_pos[c] - rig.joints_pos[p]) * scale.get(N[c], 1.0)
|
|
20
|
-
# Animation.__init__ hard-codes a CUDA deform net (AnimationField.py:83); step() with explicit rot_params never uses it.
|
|
21
|
-
anim = Animation.__new__(Animation)
|
|
22
|
-
anim.skinning_method, anim.embed_time_fn, anim.joint_num = "lbs", get_embedder(6, 1)[0], J
|
|
23
|
-
fixed = rig.fixed_joint_indices
|
|
24
|
-
torch.manual_seed(0)
|
|
25
|
-
frames = []
|
|
26
|
-
f1 = torch.zeros(J, 3) # the lead's spec
|
|
27
|
-
f1[ix("LeftForeArm")] = torch.tensor([0, 0, np.pi / 2]); f1[ix("RightLeg")] = torch.tensor([np.pi / 3, 0, 0])
|
|
28
|
-
f1[ix("Hips")] = torch.tensor([0, np.pi / 6, 0])
|
|
29
|
-
frames += [(torch.zeros(J, 3), torch.zeros(3)), (f1, torch.tensor([0.3, 0.0, 0.2]))]
|
|
30
|
-
for _ in range(4): # random full-body poses, every joint (fixed ones included -- step() must zero them)
|
|
31
|
-
frames.append((torch.randn(J, 3) * 0.5, torch.randn(3) * 0.3))
|
|
32
|
-
rps, pj = [], []
|
|
33
|
-
for i, (rp, gt) in enumerate(frames):
|
|
34
|
-
d = anim.step(rig.vertices, joints, rig.skinning_weights, rig, torch.tensor([i / len(frames)]),
|
|
35
|
-
rot_params=rp.clone(), global_translation=gt, fixed_joints=fixed)
|
|
36
|
-
rps.append(d["rot_params"].numpy()); pj.append(d["joints_warped"].numpy())
|
|
37
|
-
np.save(f"{out}/rot_params.npy", np.stack(rps).astype(np.float32))
|
|
38
|
-
np.save(f"{out}/pred_joints.npy", np.stack(pj).astype(np.float32))
|
|
39
|
-
print(f"frames={len(frames)} J={J} fixed={[N[i] for i in fixed]} -> {out}")
|