cozyclay 2.1.1 → 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 +60 -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 +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-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-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
- package/dist/assets/{landing-ChUvB_zL.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/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 +150 -2624
- 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 +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 +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/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 +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 +12 -14
- package/src/studio-agent-commands.js +19 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +41 -71
- package/src/studio-app-binding.js +25 -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/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 +8 -124
- 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,561 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
-
# SPDX-FileCopyrightText: CozyClay contributors
|
|
3
|
-
#
|
|
4
|
-
# cclay-owned script. Source of truth lives in the CozyClay repo at
|
|
5
|
-
# tools/ardy/cclay_constrained_generate.py. The local runner executes it in
|
|
6
|
-
# place; a box deployment may copy it to ~/ardy/scripts/. Do not edit a
|
|
7
|
-
# deployed copy.
|
|
8
|
-
"""One-shot constrained text-to-motion generation for the cclay ARDY pipeline.
|
|
9
|
-
|
|
10
|
-
One full ``model(...)`` sampling call over the whole clip, optionally
|
|
11
|
-
conditioned on:
|
|
12
|
-
|
|
13
|
-
* ``--pose-from <npz> <src-frame> <dst-frame>`` (repeatable): pins the FULL
|
|
14
|
-
* BODY pose stored in an ARDY motion npz (``local_rot_mats`` +
|
|
15
|
-
* ``posed_joints``) onto a clip frame — joint positions, authored joint
|
|
16
|
-
* rotations, root X/Y/Z and heading. CozyClay pose npz files carry an
|
|
17
|
-
* explicit rotation-index mask; ordinary motion npz files constrain all
|
|
18
|
-
* rotations.
|
|
19
|
-
* ``--root-2d FRAME X Z HEADING`` (repeatable): sparse root waypoints on the
|
|
20
|
-
X/Z ground plane via ``Root2DConstraintSet`` (HEADING in radians or the
|
|
21
|
-
literal ``none``), the same contract as cclay_sequence_generate.py.
|
|
22
|
-
|
|
23
|
-
With no constraints at all this is plain text-to-motion (the local twin of
|
|
24
|
-
``scripts/generate.py``); a ``--base`` flag is accepted for grammar
|
|
25
|
-
compatibility with the remote script but ignored — constraint conditioning
|
|
26
|
-
here needs no unconstrained first pass.
|
|
27
|
-
|
|
28
|
-
The last stdout line is a single JSON object whose ``target_space`` field
|
|
29
|
-
marks it as a constrained-generation report (bridge.mjs keys on that):
|
|
30
|
-
{"target_space": "skeleton_joint_center", "frames": int, "fps": int,
|
|
31
|
-
"model": str,
|
|
32
|
-
"poses": [{"dst_frame", "root_error_m", "shape_mean_error_m",
|
|
33
|
-
"shape_max_error_m"}],
|
|
34
|
-
"waypoints": [{"frame", "requested_xz", "achieved_xz",
|
|
35
|
-
"achieved_error_m", "heading_rad"}]}
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
import argparse
|
|
39
|
-
import json
|
|
40
|
-
import os
|
|
41
|
-
|
|
42
|
-
import numpy as np
|
|
43
|
-
import torch
|
|
44
|
-
|
|
45
|
-
from ardy.model import DEFAULT_MODEL, load_model
|
|
46
|
-
from ardy.constraints import FullBodyConstraintSet
|
|
47
|
-
from ardy.model.loading import get_env_var
|
|
48
|
-
from ardy.model.registry import resolve_model_name
|
|
49
|
-
from ardy.motion_rep.tools import length_to_mask
|
|
50
|
-
from ardy.postprocess import post_process_motion
|
|
51
|
-
from ardy.skeleton import SOMASkeleton30
|
|
52
|
-
from ardy.tools import seed_everything, to_numpy
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def parse_args(argv=None):
|
|
56
|
-
parser = argparse.ArgumentParser(
|
|
57
|
-
description="One-shot constrained text-to-motion generation (cclay)"
|
|
58
|
-
)
|
|
59
|
-
parser.add_argument("--prompt", type=str, required=True, help="Text prompt.")
|
|
60
|
-
parser.add_argument("--duration", type=float, required=True, help="Clip length in seconds.")
|
|
61
|
-
parser.add_argument(
|
|
62
|
-
"--output",
|
|
63
|
-
type=str,
|
|
64
|
-
required=True,
|
|
65
|
-
help="Output npz path (.npz appended when missing; parent dirs created).",
|
|
66
|
-
)
|
|
67
|
-
parser.add_argument(
|
|
68
|
-
"--pose-from",
|
|
69
|
-
dest="pose_from",
|
|
70
|
-
action="append",
|
|
71
|
-
nargs=3,
|
|
72
|
-
metavar=("NPZ", "SRC_FRAME", "DST_FRAME"),
|
|
73
|
-
help="Repeatable: pin the full-body pose NPZ[SRC_FRAME] at clip frame DST_FRAME.",
|
|
74
|
-
)
|
|
75
|
-
parser.add_argument(
|
|
76
|
-
"--root-2d",
|
|
77
|
-
dest="root_2d",
|
|
78
|
-
action="append",
|
|
79
|
-
nargs=4,
|
|
80
|
-
metavar=("FRAME", "X", "Z", "HEADING"),
|
|
81
|
-
help="Repeatable: pin the root's ground position (meters) at a clip frame; HEADING radians or 'none'.",
|
|
82
|
-
)
|
|
83
|
-
parser.add_argument(
|
|
84
|
-
"--base",
|
|
85
|
-
type=str,
|
|
86
|
-
default=None,
|
|
87
|
-
help="Accepted for remote-grammar compatibility; unused locally.",
|
|
88
|
-
)
|
|
89
|
-
parser.add_argument("--seed", type=int, default=None, help="Seed for reproducible results.")
|
|
90
|
-
parser.add_argument(
|
|
91
|
-
"--model",
|
|
92
|
-
type=str,
|
|
93
|
-
default=DEFAULT_MODEL,
|
|
94
|
-
help="Model nickname or full folder name (default: %(default)s).",
|
|
95
|
-
)
|
|
96
|
-
parser.add_argument(
|
|
97
|
-
"--diffusion_steps",
|
|
98
|
-
type=int,
|
|
99
|
-
default=None,
|
|
100
|
-
help="Denoising steps, at most the model's num_base_steps (the default).",
|
|
101
|
-
)
|
|
102
|
-
parser.add_argument(
|
|
103
|
-
"--cfg_weight",
|
|
104
|
-
type=float,
|
|
105
|
-
nargs="+",
|
|
106
|
-
default=[2.0, 2.0],
|
|
107
|
-
help="CFG scale(s): one float (text) or two floats (text, constraint).",
|
|
108
|
-
)
|
|
109
|
-
parser.add_argument(
|
|
110
|
-
"--no-postprocess",
|
|
111
|
-
action="store_true",
|
|
112
|
-
help="Don't apply motion post-processing (foot-skate reduction).",
|
|
113
|
-
)
|
|
114
|
-
parser.add_argument(
|
|
115
|
-
"--history_frames",
|
|
116
|
-
type=int,
|
|
117
|
-
default=None,
|
|
118
|
-
help=(
|
|
119
|
-
"History crop budget per autoregressive step (multiple of the model's "
|
|
120
|
-
"token size). Default: the longest history fitting the trained 10 s "
|
|
121
|
-
"window together with the generation horizon."
|
|
122
|
-
),
|
|
123
|
-
)
|
|
124
|
-
parser.add_argument(
|
|
125
|
-
"--root-margin",
|
|
126
|
-
type=float,
|
|
127
|
-
default=None,
|
|
128
|
-
help="Root position correction margin for post-processing (default: ARDY's 0.04 m). Larger = looser pin grip, less foot skate.",
|
|
129
|
-
)
|
|
130
|
-
parser.add_argument(
|
|
131
|
-
"--contact-threshold",
|
|
132
|
-
type=float,
|
|
133
|
-
default=None,
|
|
134
|
-
help="Foot contact detection threshold for post-processing (default: ARDY's 0.5).",
|
|
135
|
-
)
|
|
136
|
-
parser.add_argument(
|
|
137
|
-
"--checkpoints_dir",
|
|
138
|
-
type=str,
|
|
139
|
-
default=None,
|
|
140
|
-
help="Local dir holding released model folders (falls back to CHECKPOINTS_DIR env).",
|
|
141
|
-
)
|
|
142
|
-
return parser.parse_args(argv)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def cclay_pick_device():
|
|
146
|
-
"""cuda > mps > cpu, overridable with CCLAY_ARDY_DEVICE (cpu|mps|cuda[:N]).
|
|
147
|
-
|
|
148
|
-
The env override is how the local runner forces CPU (--cpu) without
|
|
149
|
-
relying on CUDA_VISIBLE_DEVICES, which cannot hide an Apple GPU.
|
|
150
|
-
"""
|
|
151
|
-
forced = os.environ.get("CCLAY_ARDY_DEVICE", "").strip().lower()
|
|
152
|
-
if forced:
|
|
153
|
-
return forced
|
|
154
|
-
if torch.cuda.is_available():
|
|
155
|
-
return "cuda:0"
|
|
156
|
-
mps_backend = getattr(torch.backends, "mps", None)
|
|
157
|
-
if mps_backend is not None and mps_backend.is_available():
|
|
158
|
-
return "mps"
|
|
159
|
-
return "cpu"
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def cclay_mps_compat(device):
|
|
163
|
-
"""Downcast float64 buffers to float32 at registration when running on MPS.
|
|
164
|
-
|
|
165
|
-
The MPS backend has no float64. ARDY's skeleton loads neutral_joints from
|
|
166
|
-
a float64 pickle and registers it as a buffer, which makes Ardy.__init__'s
|
|
167
|
-
.to("mps") fail; float32 is plenty for joint positions in meters. No-op on
|
|
168
|
-
cuda/cpu so remote-box behavior is untouched.
|
|
169
|
-
"""
|
|
170
|
-
if not str(device).startswith("mps"):
|
|
171
|
-
return
|
|
172
|
-
original = torch.nn.Module.register_buffer
|
|
173
|
-
if getattr(original, "_cclay_f32", False):
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
def register_buffer_f32(self, name, tensor, persistent=True):
|
|
177
|
-
if tensor is not None and getattr(tensor, "dtype", None) == torch.float64:
|
|
178
|
-
tensor = tensor.float()
|
|
179
|
-
return original(self, name, tensor, persistent)
|
|
180
|
-
|
|
181
|
-
register_buffer_f32._cclay_f32 = True
|
|
182
|
-
torch.nn.Module.register_buffer = register_buffer_f32
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def cclay_progress(iterable):
|
|
186
|
-
"""Print one line per sampling step so the bridge can stream progress.
|
|
187
|
-
|
|
188
|
-
The model calls this where it would call tqdm; every line lands in the
|
|
189
|
-
UI as a status event, which is the only liveness signal the operator has
|
|
190
|
-
during a minutes-long generation.
|
|
191
|
-
"""
|
|
192
|
-
total = len(iterable) if hasattr(iterable, "__len__") else None
|
|
193
|
-
for index, item in enumerate(iterable):
|
|
194
|
-
if total:
|
|
195
|
-
print(f"sampling step {index + 1}/{total}", flush=True)
|
|
196
|
-
else:
|
|
197
|
-
print(f"sampling step {index + 1}", flush=True)
|
|
198
|
-
yield item
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def _default_history_frames(fps: float, gen_horizon_len: int, num_frames_per_token: int) -> int:
|
|
202
|
-
"""Longest history that, with the generation horizon, fits the trained 10 s window."""
|
|
203
|
-
max_window_len = (int(10 * fps) // num_frames_per_token) * num_frames_per_token
|
|
204
|
-
return ((max_window_len - gen_horizon_len) // num_frames_per_token) * num_frames_per_token
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def _single_file_path(path: str, ext: str) -> str:
|
|
208
|
-
if not path.endswith(ext):
|
|
209
|
-
path = path.rstrip(os.sep) + ext
|
|
210
|
-
parent = os.path.dirname(path)
|
|
211
|
-
if parent:
|
|
212
|
-
os.makedirs(parent, exist_ok=True)
|
|
213
|
-
return path
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def save_motion_npz(path: str, motion_dict: dict, fps: float, text: str) -> None:
|
|
217
|
-
arrays = {k: np.asarray(v) for k, v in motion_dict.items()}
|
|
218
|
-
arrays["fps"] = np.asarray(fps)
|
|
219
|
-
arrays["text"] = np.asarray(text)
|
|
220
|
-
np.savez(path, **arrays)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def parse_root_waypoints(raw_waypoints, num_frames: int) -> list:
|
|
224
|
-
"""Same contract as cclay_sequence_generate.py, frames in clip-local range."""
|
|
225
|
-
if not raw_waypoints:
|
|
226
|
-
return []
|
|
227
|
-
waypoints = []
|
|
228
|
-
seen = set()
|
|
229
|
-
for raw_frame, raw_x, raw_z, raw_heading in raw_waypoints:
|
|
230
|
-
try:
|
|
231
|
-
frame = int(raw_frame)
|
|
232
|
-
except ValueError:
|
|
233
|
-
raise ValueError(f"--root-2d frame must be an integer, got {raw_frame!r}.")
|
|
234
|
-
if not 0 <= frame < num_frames:
|
|
235
|
-
raise ValueError(f"--root-2d frame {frame} is outside the clip (0..{num_frames - 1}).")
|
|
236
|
-
if frame in seen:
|
|
237
|
-
raise ValueError(f"duplicate --root-2d for frame {frame}; one waypoint per frame.")
|
|
238
|
-
seen.add(frame)
|
|
239
|
-
try:
|
|
240
|
-
x, z = float(raw_x), float(raw_z)
|
|
241
|
-
except ValueError:
|
|
242
|
-
raise ValueError(f"--root-2d X Z must be numbers, got {(raw_x, raw_z)!r}.")
|
|
243
|
-
if str(raw_heading).lower() == "none":
|
|
244
|
-
heading = None
|
|
245
|
-
else:
|
|
246
|
-
try:
|
|
247
|
-
heading = float(raw_heading)
|
|
248
|
-
except ValueError:
|
|
249
|
-
raise ValueError(f"--root-2d HEADING must be a number or 'none', got {raw_heading!r}.")
|
|
250
|
-
waypoints.append({"frame": frame, "xz": [x, z], "heading": heading})
|
|
251
|
-
waypoints.sort(key=lambda entry: entry["frame"])
|
|
252
|
-
if len({entry["heading"] is None for entry in waypoints}) > 1:
|
|
253
|
-
raise ValueError(
|
|
254
|
-
"--root-2d heading must be given for every waypoint or for none of them; "
|
|
255
|
-
"ARDY conditions the whole waypoint set on one heading tensor."
|
|
256
|
-
)
|
|
257
|
-
return waypoints
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def load_pose(path, skeleton, device):
|
|
261
|
-
"""Pose npz -> local rotations, positions, and rotation constraint indices.
|
|
262
|
-
|
|
263
|
-
The npz stores per-joint LOCAL rotations; FullBodyConstraintSet wants
|
|
264
|
-
GLOBAL rotations and posed positions, so the caller runs skeleton.fk on
|
|
265
|
-
the selected frame — the same expansion cclay_motion_edit.py uses.
|
|
266
|
-
"""
|
|
267
|
-
with np.load(path, allow_pickle=False) as data:
|
|
268
|
-
local = torch.from_numpy(np.asarray(data["local_rot_mats"])).float().to(device)
|
|
269
|
-
posed = torch.from_numpy(np.asarray(data["posed_joints"])).float().to(device)
|
|
270
|
-
if "rotation_constraint_indices" in data:
|
|
271
|
-
rotation_indices = torch.from_numpy(
|
|
272
|
-
np.asarray(data["rotation_constraint_indices"], dtype=np.int64)
|
|
273
|
-
)
|
|
274
|
-
else:
|
|
275
|
-
rotation_indices = torch.arange(local.shape[1], dtype=torch.long)
|
|
276
|
-
return local, posed, rotation_indices
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
class CclayFullBodyConstraintSet(FullBodyConstraintSet):
|
|
280
|
-
"""Upstream full-body positions plus explicit global-rotation observations.
|
|
281
|
-
|
|
282
|
-
ARDY's FullBodyConstraintSet accepts rotations but deliberately omits them
|
|
283
|
-
from update_constraints. CozyClay poses need shoulder, elbow and wrist
|
|
284
|
-
orientation as well as joint centers, so this subclass fills the motion
|
|
285
|
-
representation's supported global_joints_rots channel for authored joints.
|
|
286
|
-
"""
|
|
287
|
-
|
|
288
|
-
name = "cclay-fullbody-position-rotation"
|
|
289
|
-
|
|
290
|
-
def __init__(self, *args, rotation_indices, **kwargs):
|
|
291
|
-
super().__init__(*args, **kwargs)
|
|
292
|
-
self.rotation_indices = rotation_indices.long().cpu()
|
|
293
|
-
|
|
294
|
-
def update_constraints(self, data_dict, index_dict):
|
|
295
|
-
super().update_constraints(data_dict, index_dict)
|
|
296
|
-
indices = torch.cartesian_prod(self.frame_indices.cpu(), self.rotation_indices)
|
|
297
|
-
device_indices = self.rotation_indices.to(self.global_joints_rots.device)
|
|
298
|
-
data_dict["global_joints_rots"].append(
|
|
299
|
-
self.global_joints_rots[:, device_indices].reshape(-1, 3, 3)
|
|
300
|
-
)
|
|
301
|
-
index_dict["global_joints_rots"].append(indices)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
def measure_waypoints(waypoints: list, generated_joints, skeleton) -> list:
|
|
305
|
-
report = []
|
|
306
|
-
root_index = skeleton.root_idx
|
|
307
|
-
for entry in waypoints:
|
|
308
|
-
root = np.asarray(generated_joints[entry["frame"], root_index], dtype=np.float64)
|
|
309
|
-
achieved = [float(root[0]), float(root[2])]
|
|
310
|
-
error = float(np.linalg.norm(np.asarray(achieved) - np.asarray(entry["xz"])))
|
|
311
|
-
report.append(
|
|
312
|
-
{
|
|
313
|
-
"frame": entry["frame"],
|
|
314
|
-
"requested_xz": [round(value, 4) for value in entry["xz"]],
|
|
315
|
-
"achieved_xz": [round(value, 4) for value in achieved],
|
|
316
|
-
"achieved_error_m": round(error, 4),
|
|
317
|
-
"heading_rad": entry["heading"],
|
|
318
|
-
}
|
|
319
|
-
)
|
|
320
|
-
return report
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
def main(argv=None, preloaded_model=None):
|
|
324
|
-
args = parse_args(argv)
|
|
325
|
-
device = cclay_pick_device()
|
|
326
|
-
cclay_mps_compat(device)
|
|
327
|
-
print(f"Using device: {device}")
|
|
328
|
-
|
|
329
|
-
prompt = args.prompt.strip()
|
|
330
|
-
if not prompt:
|
|
331
|
-
raise ValueError("--prompt must be non-empty.")
|
|
332
|
-
if args.duration <= 0:
|
|
333
|
-
raise ValueError(f"--duration must be > 0 seconds, got {args.duration}.")
|
|
334
|
-
|
|
335
|
-
if len(args.cfg_weight) == 1:
|
|
336
|
-
cfg_weight = float(args.cfg_weight[0])
|
|
337
|
-
elif len(args.cfg_weight) == 2:
|
|
338
|
-
cfg_weight = (float(args.cfg_weight[0]), float(args.cfg_weight[1]))
|
|
339
|
-
else:
|
|
340
|
-
raise ValueError("--cfg_weight expects one float (text) or two floats (text, constraint).")
|
|
341
|
-
|
|
342
|
-
checkpoints_dir = args.checkpoints_dir or get_env_var("CHECKPOINTS_DIR")
|
|
343
|
-
resolved_model = resolve_model_name(args.model, checkpoints_dir=checkpoints_dir)
|
|
344
|
-
model = (
|
|
345
|
-
preloaded_model
|
|
346
|
-
if preloaded_model is not None
|
|
347
|
-
else load_model(resolved_model, device=device, checkpoints_dir=checkpoints_dir)
|
|
348
|
-
)
|
|
349
|
-
model.eval()
|
|
350
|
-
skeleton = model.skeleton
|
|
351
|
-
fps = model.motion_rep.fps
|
|
352
|
-
patch = model.num_frames_per_token
|
|
353
|
-
|
|
354
|
-
num_frames = int(args.duration * fps)
|
|
355
|
-
if num_frames < 3:
|
|
356
|
-
raise ValueError(f"--duration {args.duration}s yields {num_frames} frames; the minimum is 3.")
|
|
357
|
-
|
|
358
|
-
num_base_steps = int(model.diffusion.num_base_steps)
|
|
359
|
-
diffusion_steps = args.diffusion_steps if args.diffusion_steps is not None else num_base_steps
|
|
360
|
-
if not 1 <= diffusion_steps <= num_base_steps:
|
|
361
|
-
raise ValueError(
|
|
362
|
-
f"--diffusion_steps must be between 1 and {num_base_steps}; got {diffusion_steps}."
|
|
363
|
-
)
|
|
364
|
-
if args.history_frames is not None:
|
|
365
|
-
if args.history_frames < patch or args.history_frames % patch != 0:
|
|
366
|
-
raise ValueError(
|
|
367
|
-
f"--history_frames must be a positive multiple of {patch} (this model's token size)."
|
|
368
|
-
)
|
|
369
|
-
history_frames = args.history_frames
|
|
370
|
-
else:
|
|
371
|
-
history_frames = _default_history_frames(fps, model.gen_horizon_len, patch)
|
|
372
|
-
|
|
373
|
-
# --- constraints --------------------------------------------------------
|
|
374
|
-
constraint_lst = []
|
|
375
|
-
pose_targets = [] # for the report: (dst_frame, requested positions [J,3])
|
|
376
|
-
for npz_path, raw_src, raw_dst in args.pose_from or []:
|
|
377
|
-
try:
|
|
378
|
-
src_frame, dst_frame = int(raw_src), int(raw_dst)
|
|
379
|
-
except ValueError:
|
|
380
|
-
raise ValueError(f"--pose-from frames must be integers, got {(raw_src, raw_dst)!r}.")
|
|
381
|
-
if not 0 <= dst_frame < num_frames:
|
|
382
|
-
raise ValueError(f"--pose-from dst-frame {dst_frame} is outside the clip (0..{num_frames - 1}).")
|
|
383
|
-
local, posed, rotation_indices = load_pose(npz_path, skeleton, device)
|
|
384
|
-
if not 0 <= src_frame < local.shape[0]:
|
|
385
|
-
raise ValueError(
|
|
386
|
-
f"--pose-from src-frame {src_frame} is outside {npz_path} (0..{local.shape[0] - 1})."
|
|
387
|
-
)
|
|
388
|
-
root = posed[src_frame : src_frame + 1, skeleton.root_idx]
|
|
389
|
-
rotations, positions, _ = skeleton.fk(local[src_frame : src_frame + 1], root)
|
|
390
|
-
constraint_lst.append(
|
|
391
|
-
CclayFullBodyConstraintSet(
|
|
392
|
-
skeleton,
|
|
393
|
-
torch.tensor([dst_frame]),
|
|
394
|
-
positions,
|
|
395
|
-
rotations,
|
|
396
|
-
rotation_indices=rotation_indices,
|
|
397
|
-
)
|
|
398
|
-
)
|
|
399
|
-
pose_targets.append((dst_frame, positions[0].cpu().numpy()))
|
|
400
|
-
print(f"FullBodyConstraintSet: {npz_path}[{src_frame}] pinned at clip frame {dst_frame}")
|
|
401
|
-
|
|
402
|
-
waypoints = parse_root_waypoints(args.root_2d or [], num_frames)
|
|
403
|
-
if waypoints:
|
|
404
|
-
from ardy.constraints import Root2DConstraintSet
|
|
405
|
-
|
|
406
|
-
headings = [entry["heading"] for entry in waypoints]
|
|
407
|
-
constraint_lst.append(
|
|
408
|
-
Root2DConstraintSet(
|
|
409
|
-
skeleton,
|
|
410
|
-
frame_indices=torch.tensor([entry["frame"] for entry in waypoints]),
|
|
411
|
-
root_2d=torch.tensor(
|
|
412
|
-
[entry["xz"] for entry in waypoints], device=device, dtype=torch.float32
|
|
413
|
-
),
|
|
414
|
-
global_root_heading=(
|
|
415
|
-
None
|
|
416
|
-
if headings[0] is None
|
|
417
|
-
else torch.tensor(headings, device=device, dtype=torch.float32)
|
|
418
|
-
),
|
|
419
|
-
)
|
|
420
|
-
)
|
|
421
|
-
print(f"Root2DConstraintSet on clip frames {[entry['frame'] for entry in waypoints]}")
|
|
422
|
-
|
|
423
|
-
observed_motion = None
|
|
424
|
-
motion_mask = None
|
|
425
|
-
lengths = torch.tensor([num_frames], device=device)
|
|
426
|
-
if constraint_lst:
|
|
427
|
-
observed_motion, motion_mask = model.motion_rep.create_conditions_from_constraints_batched(
|
|
428
|
-
constraint_lst,
|
|
429
|
-
lengths,
|
|
430
|
-
to_normalize=True,
|
|
431
|
-
device=device,
|
|
432
|
-
)
|
|
433
|
-
|
|
434
|
-
# --- sampling -----------------------------------------------------------
|
|
435
|
-
if args.seed is not None:
|
|
436
|
-
seed_everything(args.seed)
|
|
437
|
-
print(f"Generating {num_frames} frames ({num_frames / fps:.2f}s at {fps} fps)")
|
|
438
|
-
with torch.no_grad():
|
|
439
|
-
motion = model(
|
|
440
|
-
[prompt],
|
|
441
|
-
num_frames,
|
|
442
|
-
num_denoising_steps=diffusion_steps,
|
|
443
|
-
pad_mask=length_to_mask(lengths),
|
|
444
|
-
first_heading_angle=torch.zeros(1, device=device),
|
|
445
|
-
motion_mask=motion_mask,
|
|
446
|
-
observed_motion=observed_motion,
|
|
447
|
-
cfg_weight=cfg_weight,
|
|
448
|
-
progress_bar=cclay_progress,
|
|
449
|
-
crop_history_length=history_frames,
|
|
450
|
-
)
|
|
451
|
-
output = model.motion_rep.inverse(motion, is_normalized=True)
|
|
452
|
-
|
|
453
|
-
postprocess_kwargs = {}
|
|
454
|
-
use_postprocess = "g1" not in resolved_model.lower() and not args.no_postprocess
|
|
455
|
-
if use_postprocess:
|
|
456
|
-
if args.root_margin is not None:
|
|
457
|
-
postprocess_kwargs["root_margin"] = args.root_margin
|
|
458
|
-
if args.contact_threshold is not None:
|
|
459
|
-
postprocess_kwargs["contact_threshold"] = args.contact_threshold
|
|
460
|
-
corrected = post_process_motion(
|
|
461
|
-
output["local_rot_mats"],
|
|
462
|
-
output["root_positions"],
|
|
463
|
-
output["foot_contacts"],
|
|
464
|
-
skeleton,
|
|
465
|
-
constraint_lst=constraint_lst if constraint_lst else None,
|
|
466
|
-
**postprocess_kwargs,
|
|
467
|
-
)
|
|
468
|
-
output.update(corrected)
|
|
469
|
-
|
|
470
|
-
if isinstance(skeleton, SOMASkeleton30):
|
|
471
|
-
output = skeleton.output_to_SOMASkeleton77(output)
|
|
472
|
-
|
|
473
|
-
output = to_numpy(output)
|
|
474
|
-
motion_dict = {
|
|
475
|
-
k: (v[0] if hasattr(v, "shape") and len(v.shape) > 0 and v.shape[0] == 1 else v)
|
|
476
|
-
for k, v in output.items()
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
npz_path = _single_file_path(args.output, ".npz")
|
|
480
|
-
print(f"Saving the npz output to {npz_path}")
|
|
481
|
-
save_motion_npz(npz_path, motion_dict, fps, prompt)
|
|
482
|
-
|
|
483
|
-
# --- report (last stdout line, keyed on target_space by bridge.mjs) ------
|
|
484
|
-
generated_joints = np.asarray(motion_dict["posed_joints"])
|
|
485
|
-
root_index = skeleton.root_idx
|
|
486
|
-
pose_reports = []
|
|
487
|
-
|
|
488
|
-
# Quality metrics alongside the pose/waypoint accuracy: the operator can
|
|
489
|
-
# judge a path by them, not just trust it. Continuity is the largest
|
|
490
|
-
# one-frame root jump (chained seams show up here); surface contact
|
|
491
|
-
# verifies that stance frames keep the foot planted instead of skating.
|
|
492
|
-
def motion_continuity(root_positions):
|
|
493
|
-
if len(root_positions) < 2:
|
|
494
|
-
return None
|
|
495
|
-
deltas = np.linalg.norm(np.diff(root_positions[:, [0, 2]], axis=0), axis=1)
|
|
496
|
-
worst = int(deltas.argmax()) + 1 if len(deltas) else 0
|
|
497
|
-
return {
|
|
498
|
-
"mean_jump_m": round(float(deltas.mean()), 6),
|
|
499
|
-
"max_jump_m": round(float(deltas.max()), 6),
|
|
500
|
-
"max_jump_frame": worst,
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
def surface_contact_verified(contacts, posed, foot_indices):
|
|
504
|
-
if contacts is None or not len(foot_indices):
|
|
505
|
-
return None
|
|
506
|
-
contacts_arr = np.asarray(contacts)
|
|
507
|
-
if contacts_arr.ndim == 3:
|
|
508
|
-
contacts_arr = contacts_arr[0]
|
|
509
|
-
checked = 0
|
|
510
|
-
held = 0
|
|
511
|
-
for contact_idx, joint_idx in enumerate(foot_indices[: contacts_arr.shape[1]]):
|
|
512
|
-
ys = posed[:, joint_idx, 1]
|
|
513
|
-
for frame in range(1, len(posed)):
|
|
514
|
-
if contacts_arr[frame, contact_idx] > 0.5 and contacts_arr[frame - 1, contact_idx] > 0.5:
|
|
515
|
-
checked += 1
|
|
516
|
-
if abs(ys[frame] - ys[frame - 1]) < 0.02:
|
|
517
|
-
held += 1
|
|
518
|
-
return checked == 0 or (held / checked) >= 0.8
|
|
519
|
-
|
|
520
|
-
root_positions = np.asarray(motion_dict["root_positions"])
|
|
521
|
-
foot_indices = [idx for idx, name in enumerate(skeleton.bone_order_names) if "foot" in name.lower() or "toe" in name.lower()]
|
|
522
|
-
continuity = motion_continuity(root_positions)
|
|
523
|
-
contact_verified = surface_contact_verified(
|
|
524
|
-
motion_dict.get("foot_contacts"), generated_joints, foot_indices
|
|
525
|
-
)
|
|
526
|
-
for dst_frame, requested in pose_targets:
|
|
527
|
-
achieved = generated_joints[dst_frame]
|
|
528
|
-
root_error = float(np.linalg.norm(achieved[root_index] - requested[root_index]))
|
|
529
|
-
# Shape error compares body proportions with both roots removed, so a
|
|
530
|
-
# root miss is not double-counted against every joint.
|
|
531
|
-
requested_centered = requested - requested[root_index]
|
|
532
|
-
achieved_centered = achieved - achieved[root_index]
|
|
533
|
-
joint_errors = np.linalg.norm(achieved_centered - requested_centered, axis=-1)
|
|
534
|
-
pose_reports.append(
|
|
535
|
-
{
|
|
536
|
-
"dst_frame": dst_frame,
|
|
537
|
-
"root_error_m": round(root_error, 4),
|
|
538
|
-
"shape_mean_error_m": round(float(joint_errors.mean()), 4),
|
|
539
|
-
"shape_max_error_m": round(float(joint_errors.max()), 4),
|
|
540
|
-
}
|
|
541
|
-
)
|
|
542
|
-
|
|
543
|
-
report = {
|
|
544
|
-
"target_space": "skeleton_joint_center",
|
|
545
|
-
"frames": int(generated_joints.shape[0]),
|
|
546
|
-
"fps": int(fps),
|
|
547
|
-
"model": resolved_model,
|
|
548
|
-
"surface_contact_verified": contact_verified,
|
|
549
|
-
"continuity": continuity,
|
|
550
|
-
"postprocess": {
|
|
551
|
-
"contact_threshold": postprocess_kwargs.get("contact_threshold", 0.5) if use_postprocess else None,
|
|
552
|
-
"root_margin": postprocess_kwargs.get("root_margin", 0.04) if use_postprocess else None,
|
|
553
|
-
},
|
|
554
|
-
"poses": pose_reports,
|
|
555
|
-
"waypoints": measure_waypoints(waypoints, generated_joints, skeleton),
|
|
556
|
-
}
|
|
557
|
-
print(json.dumps(report))
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if __name__ == "__main__":
|
|
561
|
-
main()
|