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,304 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
-
# SPDX-FileCopyrightText: CozyClay contributors
|
|
4
|
-
#
|
|
5
|
-
# cclay-owned script. Source of truth lives in the CozyClay repo at
|
|
6
|
-
# tools/ardy/cclay_worker.py.
|
|
7
|
-
"""Persistent local generation worker for the CozyClay ARDY bridge.
|
|
8
|
-
|
|
9
|
-
Loading the motion model and compiling its GPU kernels costs minutes on MPS,
|
|
10
|
-
while the sampling itself takes seconds. Spawning a fresh python per request
|
|
11
|
-
(the remote-box contract run-local.mjs mirrors) pays that cost every time, so
|
|
12
|
-
this worker pays it ONCE: it loads the model, runs a tiny no-text warmup to
|
|
13
|
-
force kernel compilation, and then serves generation jobs from the warm
|
|
14
|
-
process. run-local.mjs prefers the worker and silently falls back to a direct
|
|
15
|
-
spawn when it is not running, so the worker is an accelerator, never a
|
|
16
|
-
dependency.
|
|
17
|
-
|
|
18
|
-
Protocol (loopback TCP, one connection per job, one job at a time):
|
|
19
|
-
|
|
20
|
-
client -> worker one JSON line
|
|
21
|
-
{"mode": "ping"}
|
|
22
|
-
{"mode": "single"|"sequence"|"edit", "argv": [...]}
|
|
23
|
-
worker -> client the generator's stdout lines, verbatim, then
|
|
24
|
-
"worker: pong" (ping) or "worker: exit <code>"
|
|
25
|
-
|
|
26
|
-
`argv` is exactly the CLI argument vector of the corresponding
|
|
27
|
-
cclay_*_generate/edit script; the worker calls that script's main() in
|
|
28
|
-
process with the cached model injected, so worker and direct-spawn runs share
|
|
29
|
-
one code path and cannot drift.
|
|
30
|
-
|
|
31
|
-
env:
|
|
32
|
-
CCLAY_ARDY_WORKER_PORT listen port (default 9552, loopback only)
|
|
33
|
-
CHECKPOINTS_DIR / TEXT_ENCODER_URL / TEXT_ENCODERS_DIR as usual
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
import importlib
|
|
37
|
-
import json
|
|
38
|
-
import os
|
|
39
|
-
import socket
|
|
40
|
-
import sys
|
|
41
|
-
import traceback
|
|
42
|
-
|
|
43
|
-
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
44
|
-
sys.path.insert(0, HERE)
|
|
45
|
-
|
|
46
|
-
MODULES = {
|
|
47
|
-
"single": "cclay_constrained_generate",
|
|
48
|
-
"sequence": "cclay_sequence_generate",
|
|
49
|
-
"edit": "cclay_motion_edit",
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class _Tee:
|
|
54
|
-
"""Mirror generator stdout to the job's socket AND the worker console.
|
|
55
|
-
|
|
56
|
-
A vanished client must not kill the job: the generation keeps running,
|
|
57
|
-
the npz still lands on disk, and only the socket copy is dropped.
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
def __init__(self, sock_file):
|
|
61
|
-
self._sock_file = sock_file
|
|
62
|
-
|
|
63
|
-
def write(self, data):
|
|
64
|
-
sys.__stdout__.write(data)
|
|
65
|
-
try:
|
|
66
|
-
self._sock_file.write(data)
|
|
67
|
-
self._sock_file.flush()
|
|
68
|
-
except OSError:
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
def flush(self):
|
|
72
|
-
sys.__stdout__.flush()
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def requested_model_name(mode, argv, resolve_model_name, default_model, checkpoints_dir):
|
|
76
|
-
"""The model a job's argv asks for (edit has no --model flag)."""
|
|
77
|
-
name = default_model
|
|
78
|
-
if mode != "edit":
|
|
79
|
-
for index, arg in enumerate(argv):
|
|
80
|
-
if arg == "--model" and index + 1 < len(argv):
|
|
81
|
-
name = argv[index + 1]
|
|
82
|
-
return resolve_model_name(name, checkpoints_dir=checkpoints_dir)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def fix_text_encoder_device(model, device):
|
|
86
|
-
"""Move an in-process LLM2Vec encoder onto the generation device, fast.
|
|
87
|
-
|
|
88
|
-
ARDY's load_text_encoder ends with `.to(device or "cuda"/"cpu")`, so on a
|
|
89
|
-
Mac the fallback encoder lands on CPU even when TEXT_ENCODER_DEVICE says
|
|
90
|
-
mps. On MPS the dtype matters as much as the device: bf16 matmuls are
|
|
91
|
-
emulated (a single prompt costs ~30-50 s) while fp16 is native, so fp16
|
|
92
|
-
is tried first and a canary encode guards against fp16 overflow — NaNs
|
|
93
|
-
demote back to bf16. Only the real in-process encoder has a `.model`;
|
|
94
|
-
the API client stub is left alone.
|
|
95
|
-
"""
|
|
96
|
-
encoder = getattr(model, "text_encoder", None)
|
|
97
|
-
if encoder is None or not hasattr(encoder, "model") or device == "cpu":
|
|
98
|
-
return
|
|
99
|
-
import torch
|
|
100
|
-
|
|
101
|
-
for dtype in (torch.float16, torch.bfloat16):
|
|
102
|
-
try:
|
|
103
|
-
encoder.to(device=device, dtype=dtype)
|
|
104
|
-
canary, _ = encoder(["a person walks forward"])
|
|
105
|
-
if bool(torch.isfinite(canary.float()).all()):
|
|
106
|
-
print(f"worker: text encoder on {device} as {dtype}", flush=True)
|
|
107
|
-
return
|
|
108
|
-
print(f"worker: text encoder {dtype} produced non-finite values; trying next dtype", flush=True)
|
|
109
|
-
except Exception as exc:
|
|
110
|
-
print(f"worker: text encoder {dtype} on {device} failed ({exc}); trying next dtype", flush=True)
|
|
111
|
-
try: # both GPU dtypes failed: back to the slow-but-correct CPU encoder
|
|
112
|
-
encoder.to(device="cpu", dtype=torch.bfloat16)
|
|
113
|
-
print("worker: text encoder stays on cpu", flush=True)
|
|
114
|
-
except Exception as exc:
|
|
115
|
-
print(f"worker: text encoder left as loaded ({exc})", flush=True)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class _CachingEncoder:
|
|
119
|
-
"""Per-prompt embedding cache in front of the in-process encoder.
|
|
120
|
-
|
|
121
|
-
Authoring iterates on ONE prompt (new seed, new pose pin, new waypoints),
|
|
122
|
-
so most requests re-encode text the worker has already seen. Embeddings
|
|
123
|
-
are deterministic per (model, dtype) — exactly the cache key's tag — and
|
|
124
|
-
a few KB each, so they live in memory and under ~/.cozyclay/embed-cache
|
|
125
|
-
across worker restarts. Misses are timed on the console; hits are free.
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
def __init__(self, inner, cache_dir, tag):
|
|
129
|
-
import os
|
|
130
|
-
|
|
131
|
-
self._inner = inner
|
|
132
|
-
self._dir = cache_dir
|
|
133
|
-
self._tag = tag
|
|
134
|
-
self._mem = {}
|
|
135
|
-
os.makedirs(cache_dir, exist_ok=True)
|
|
136
|
-
|
|
137
|
-
def _key(self, text):
|
|
138
|
-
import hashlib
|
|
139
|
-
|
|
140
|
-
return hashlib.sha256(f"{self._tag}\x00{text}".encode("utf-8")).hexdigest()
|
|
141
|
-
|
|
142
|
-
def _encode_one(self, text):
|
|
143
|
-
import os
|
|
144
|
-
import time
|
|
145
|
-
|
|
146
|
-
import numpy as np
|
|
147
|
-
|
|
148
|
-
key = self._key(text)
|
|
149
|
-
if key in self._mem:
|
|
150
|
-
return self._mem[key]
|
|
151
|
-
path = os.path.join(self._dir, f"{key}.npy")
|
|
152
|
-
if os.path.isfile(path):
|
|
153
|
-
try:
|
|
154
|
-
embedding = np.load(path)
|
|
155
|
-
self._mem[key] = embedding
|
|
156
|
-
return embedding
|
|
157
|
-
except Exception:
|
|
158
|
-
pass # unreadable cache entry: re-encode below
|
|
159
|
-
started = time.time()
|
|
160
|
-
tensor, _ = self._inner([text])
|
|
161
|
-
embedding = tensor[0].detach().float().cpu().numpy()
|
|
162
|
-
print(f"worker: text encode took {time.time() - started:.1f}s (cache miss)", flush=True)
|
|
163
|
-
self._mem[key] = embedding
|
|
164
|
-
try:
|
|
165
|
-
np.save(path, embedding)
|
|
166
|
-
except Exception:
|
|
167
|
-
pass # cache write failure must never fail the job
|
|
168
|
-
return embedding
|
|
169
|
-
|
|
170
|
-
def __call__(self, texts):
|
|
171
|
-
import numpy as np
|
|
172
|
-
import torch
|
|
173
|
-
|
|
174
|
-
is_string = isinstance(texts, str)
|
|
175
|
-
text_list = [texts] if is_string else list(texts)
|
|
176
|
-
stacked = np.stack([self._encode_one(text) for text in text_list])
|
|
177
|
-
device = getattr(self._inner, "_device", "cpu")
|
|
178
|
-
encoded = torch.from_numpy(stacked).to(device)
|
|
179
|
-
lengths = [1] * len(text_list)
|
|
180
|
-
if is_string:
|
|
181
|
-
return encoded[0], 1
|
|
182
|
-
return encoded, lengths
|
|
183
|
-
|
|
184
|
-
def __getattr__(self, name):
|
|
185
|
-
return getattr(self._inner, name)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def warmup(model, device):
|
|
189
|
-
"""One throwaway sampling call so kernel compilation happens off the clock.
|
|
190
|
-
|
|
191
|
-
Zero text features skip the text encoder entirely — the warmup must not
|
|
192
|
-
drag the 16 GB Llama encoder into RAM just to compile Metal shaders.
|
|
193
|
-
"""
|
|
194
|
-
import torch
|
|
195
|
-
from ardy.motion_rep.tools import length_to_mask
|
|
196
|
-
|
|
197
|
-
try:
|
|
198
|
-
frames = int(model.gen_horizon_len)
|
|
199
|
-
lengths = torch.tensor([frames], device=device)
|
|
200
|
-
with torch.no_grad():
|
|
201
|
-
model(
|
|
202
|
-
[""],
|
|
203
|
-
frames,
|
|
204
|
-
num_denoising_steps=1,
|
|
205
|
-
pad_mask=length_to_mask(lengths),
|
|
206
|
-
first_heading_angle=torch.zeros(1, device=device),
|
|
207
|
-
motion_mask=None,
|
|
208
|
-
observed_motion=None,
|
|
209
|
-
cfg_weight=2.0,
|
|
210
|
-
text_feat=torch.zeros(1, 1, 4096, device=device),
|
|
211
|
-
text_pad_mask=torch.ones(1, 1, device=device, dtype=torch.bool),
|
|
212
|
-
progress_bar=lambda iterable: iterable,
|
|
213
|
-
)
|
|
214
|
-
print("worker: warmup complete", flush=True)
|
|
215
|
-
except Exception as exc: # non-fatal: first real job just pays the compile
|
|
216
|
-
print(f"worker: warmup skipped ({exc})", flush=True)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def main():
|
|
220
|
-
port = int(os.environ.get("CCLAY_ARDY_WORKER_PORT", "9552"))
|
|
221
|
-
|
|
222
|
-
single = importlib.import_module(MODULES["single"])
|
|
223
|
-
device = single.cclay_pick_device()
|
|
224
|
-
single.cclay_mps_compat(device)
|
|
225
|
-
|
|
226
|
-
from ardy.model import DEFAULT_MODEL, load_model
|
|
227
|
-
from ardy.model.loading import get_env_var
|
|
228
|
-
from ardy.model.registry import resolve_model_name
|
|
229
|
-
|
|
230
|
-
checkpoints_dir = get_env_var("CHECKPOINTS_DIR", None)
|
|
231
|
-
cached_name = resolve_model_name(DEFAULT_MODEL, checkpoints_dir=checkpoints_dir)
|
|
232
|
-
print(f"worker: loading {cached_name} on {device} ...", flush=True)
|
|
233
|
-
cached_model = load_model(cached_name, device=device, checkpoints_dir=checkpoints_dir)
|
|
234
|
-
cached_model.eval()
|
|
235
|
-
fix_text_encoder_device(cached_model, device)
|
|
236
|
-
encoder = getattr(cached_model, "text_encoder", None)
|
|
237
|
-
if encoder is not None and hasattr(encoder, "model"):
|
|
238
|
-
try:
|
|
239
|
-
param = next(encoder.model.parameters())
|
|
240
|
-
tag = f"llm2vec:{param.dtype}:{param.device.type}"
|
|
241
|
-
except Exception:
|
|
242
|
-
tag = "llm2vec:unknown"
|
|
243
|
-
cache_dir = os.path.join(os.path.expanduser("~"), ".cozyclay", "embed-cache")
|
|
244
|
-
cached_model.text_encoder = _CachingEncoder(encoder, cache_dir, tag)
|
|
245
|
-
print(f"worker: embedding cache at {cache_dir} ({tag})", flush=True)
|
|
246
|
-
warmup(cached_model, device)
|
|
247
|
-
|
|
248
|
-
server = socket.create_server(("127.0.0.1", port))
|
|
249
|
-
print(f"worker: ready on 127.0.0.1:{port} (model {cached_name}, device {device})", flush=True)
|
|
250
|
-
|
|
251
|
-
while True:
|
|
252
|
-
conn, _ = server.accept()
|
|
253
|
-
with conn:
|
|
254
|
-
rfile = conn.makefile("r", encoding="utf-8")
|
|
255
|
-
wfile = conn.makefile("w", encoding="utf-8")
|
|
256
|
-
try:
|
|
257
|
-
job = json.loads(rfile.readline())
|
|
258
|
-
except (ValueError, OSError):
|
|
259
|
-
continue
|
|
260
|
-
mode = job.get("mode") if isinstance(job, dict) else None
|
|
261
|
-
if mode == "ping":
|
|
262
|
-
try:
|
|
263
|
-
wfile.write("worker: pong\n")
|
|
264
|
-
wfile.flush()
|
|
265
|
-
except OSError:
|
|
266
|
-
pass
|
|
267
|
-
continue
|
|
268
|
-
argv = job.get("argv") if isinstance(job, dict) else None
|
|
269
|
-
if mode not in MODULES or not isinstance(argv, list) or not all(isinstance(a, str) for a in argv):
|
|
270
|
-
try:
|
|
271
|
-
wfile.write("worker: exit 2\n")
|
|
272
|
-
wfile.flush()
|
|
273
|
-
except OSError:
|
|
274
|
-
pass
|
|
275
|
-
continue
|
|
276
|
-
|
|
277
|
-
module = importlib.import_module(MODULES[mode])
|
|
278
|
-
code = 0
|
|
279
|
-
old_stdout = sys.stdout
|
|
280
|
-
sys.stdout = _Tee(wfile)
|
|
281
|
-
try:
|
|
282
|
-
wanted = requested_model_name(mode, argv, resolve_model_name, DEFAULT_MODEL, checkpoints_dir)
|
|
283
|
-
if wanted != cached_name:
|
|
284
|
-
print(f"worker: switching model {cached_name} -> {wanted}", flush=True)
|
|
285
|
-
cached_model = load_model(wanted, device=device, checkpoints_dir=checkpoints_dir)
|
|
286
|
-
cached_model.eval()
|
|
287
|
-
cached_name = wanted
|
|
288
|
-
module.main(argv, preloaded_model=cached_model)
|
|
289
|
-
except SystemExit as exit_exc:
|
|
290
|
-
code = exit_exc.code if isinstance(exit_exc.code, int) else 1
|
|
291
|
-
except Exception:
|
|
292
|
-
traceback.print_exc(file=sys.stdout)
|
|
293
|
-
code = 1
|
|
294
|
-
finally:
|
|
295
|
-
sys.stdout = old_stdout
|
|
296
|
-
try:
|
|
297
|
-
wfile.write(f"worker: exit {code}\n")
|
|
298
|
-
wfile.flush()
|
|
299
|
-
except OSError:
|
|
300
|
-
pass
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if __name__ == "__main__":
|
|
304
|
-
main()
|
package/tools/ardy/dump-npz.py
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Dump one frame of an ARDY motion npz as a JSON document on stdout.
|
|
3
|
-
|
|
4
|
-
Runs under the ARDY box python (``~/ardy/.venv/bin/python``); it needs numpy
|
|
5
|
-
but no torch. Usage::
|
|
6
|
-
|
|
7
|
-
python dump-npz.py <motion.npz> <frame>
|
|
8
|
-
|
|
9
|
-
Emitted document (schema "ardy.frame.v1"):
|
|
10
|
-
|
|
11
|
-
{
|
|
12
|
-
"schema": "ardy.frame.v1",
|
|
13
|
-
"source_npz": "<basename of the npz>",
|
|
14
|
-
"frame": <requested frame index>,
|
|
15
|
-
"frames_total": <frame count of the motion>,
|
|
16
|
-
"members": {"<member name>": {"shape": [...], "dtype": "..."}, ...},
|
|
17
|
-
"local_rot_mats": [ 27 x [[3],[3],[3]] row-major ],
|
|
18
|
-
"posed_joints": [ 27 x [x, y, z] ]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
Member names and axis order match the ARDY archives exactly as consumed by
|
|
22
|
-
CozyClay (blender-addon/cclay): ``local_rot_mats[frame, joint]`` is the
|
|
23
|
-
per-joint LOCAL rotation matrix in cskel27 order (Hips = joint 0), and
|
|
24
|
-
``posed_joints[frame, joint]`` the joint center position. ``foot_contacts``
|
|
25
|
-
is optional and reported only when present. ``members`` lists every array in
|
|
26
|
-
the archive (sorted), including carried members like ``fps``, so a consumer
|
|
27
|
-
can see the exact contents without re-opening the npz.
|
|
28
|
-
|
|
29
|
-
Before emitting, every one of the 27 rotation matrices of the requested frame
|
|
30
|
-
is checked for finite entries, orthonormal rows/columns, and determinant +1,
|
|
31
|
-
with the same tolerance CozyClay's motion_retarget uses
|
|
32
|
-
(ROTATION_MATRIX_TOLERANCE = 1e-3 on squared norms, pairwise dots, and
|
|
33
|
-
determinant). On the first violation the matrix index and the failing
|
|
34
|
-
quantity are printed to stderr, the exit status is 1, and NO JSON is emitted:
|
|
35
|
-
a garbage rotation must not silently reach a downstream consumer.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
import json
|
|
39
|
-
import math
|
|
40
|
-
import sys
|
|
41
|
-
|
|
42
|
-
import numpy as np
|
|
43
|
-
|
|
44
|
-
SCHEMA = "ardy.frame.v1"
|
|
45
|
-
JOINTS = 27
|
|
46
|
-
# Mirror of CozyClay motion_retarget.ROTATION_MATRIX_TOLERANCE: applies to
|
|
47
|
-
# squared row/column norms, pairwise dot products, and determinant, in
|
|
48
|
-
# float64. float32 ARDY serialization noise stays far below 1e-3.
|
|
49
|
-
TOLERANCE = 1e-3
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def _fail(message):
|
|
53
|
-
"""Report a fatal error on stderr and exit 1 without emitting JSON."""
|
|
54
|
-
print(f"dump-npz: {message}", file=sys.stderr)
|
|
55
|
-
sys.exit(1)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def _check_rotation(matrix, frame, joint):
|
|
59
|
-
"""Return a list of violation strings for one 3x3 matrix, or [] if clean."""
|
|
60
|
-
violations = []
|
|
61
|
-
rows = [[float(matrix[i][j]) for j in range(3)] for i in range(3)]
|
|
62
|
-
columns = [[rows[i][j] for i in range(3)] for j in range(3)]
|
|
63
|
-
prefix = f"frame {frame} joint {joint}"
|
|
64
|
-
for label, vectors in (("row", rows), ("column", columns)):
|
|
65
|
-
for index, vector in enumerate(vectors):
|
|
66
|
-
squared_norm = sum(c * c for c in vector)
|
|
67
|
-
if not math.isfinite(squared_norm):
|
|
68
|
-
violations.append(
|
|
69
|
-
f"{prefix} {label} {index} has non-finite entries"
|
|
70
|
-
)
|
|
71
|
-
elif abs(squared_norm - 1.0) > TOLERANCE:
|
|
72
|
-
violations.append(
|
|
73
|
-
f"{prefix} {label} {index} squared norm {squared_norm:.6f} "
|
|
74
|
-
f"differs from 1.0 by more than {TOLERANCE}"
|
|
75
|
-
)
|
|
76
|
-
for first, second in ((0, 1), (0, 2), (1, 2)):
|
|
77
|
-
dot = sum(
|
|
78
|
-
vectors[first][i] * vectors[second][i] for i in range(3)
|
|
79
|
-
)
|
|
80
|
-
if not math.isfinite(dot):
|
|
81
|
-
violations.append(
|
|
82
|
-
f"{prefix} {label} {first}/{second} dot is non-finite"
|
|
83
|
-
)
|
|
84
|
-
elif abs(dot) > TOLERANCE:
|
|
85
|
-
violations.append(
|
|
86
|
-
f"{prefix} {label} {first}/{second} dot {dot:.6f} "
|
|
87
|
-
f"exceeds {TOLERANCE} in magnitude"
|
|
88
|
-
)
|
|
89
|
-
determinant = (
|
|
90
|
-
rows[0][0] * (rows[1][1] * rows[2][2] - rows[1][2] * rows[2][1])
|
|
91
|
-
- rows[0][1] * (rows[1][0] * rows[2][2] - rows[1][2] * rows[2][0])
|
|
92
|
-
+ rows[0][2] * (rows[1][0] * rows[2][1] - rows[1][1] * rows[2][0])
|
|
93
|
-
)
|
|
94
|
-
if not math.isfinite(determinant):
|
|
95
|
-
violations.append(f"{prefix} determinant is non-finite")
|
|
96
|
-
elif abs(determinant - 1.0) > TOLERANCE:
|
|
97
|
-
violations.append(
|
|
98
|
-
f"{prefix} determinant {determinant:.6f} differs from 1.0 "
|
|
99
|
-
f"by more than {TOLERANCE}"
|
|
100
|
-
)
|
|
101
|
-
return violations
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def main(argv):
|
|
105
|
-
if len(argv) != 3:
|
|
106
|
-
_fail(f"usage: {argv[0]} <motion.npz> <frame>")
|
|
107
|
-
npz_path, frame_text = argv[1], argv[2]
|
|
108
|
-
try:
|
|
109
|
-
frame = int(frame_text)
|
|
110
|
-
except ValueError:
|
|
111
|
-
_fail(f"frame must be an integer, got {frame_text!r}")
|
|
112
|
-
if frame < 0:
|
|
113
|
-
_fail(f"frame must be >= 0, got {frame}")
|
|
114
|
-
|
|
115
|
-
try:
|
|
116
|
-
data = np.load(npz_path, allow_pickle=False)
|
|
117
|
-
except Exception as exc:
|
|
118
|
-
_fail(f"cannot load {npz_path}: {exc}")
|
|
119
|
-
|
|
120
|
-
try:
|
|
121
|
-
if "local_rot_mats" not in data.files:
|
|
122
|
-
_fail(f"{npz_path} has no 'local_rot_mats' member")
|
|
123
|
-
if "posed_joints" not in data.files:
|
|
124
|
-
_fail(f"{npz_path} has no 'posed_joints' member")
|
|
125
|
-
rotations = data["local_rot_mats"]
|
|
126
|
-
joints = data["posed_joints"]
|
|
127
|
-
if rotations.shape[1:] != (JOINTS, 3, 3):
|
|
128
|
-
_fail(
|
|
129
|
-
f"local_rot_mats must have shape (F, {JOINTS}, 3, 3), "
|
|
130
|
-
f"got {rotations.shape}"
|
|
131
|
-
)
|
|
132
|
-
if joints.shape[1:] != (JOINTS, 3):
|
|
133
|
-
_fail(
|
|
134
|
-
f"posed_joints must have shape (F, {JOINTS}, 3), "
|
|
135
|
-
f"got {joints.shape}"
|
|
136
|
-
)
|
|
137
|
-
if joints.shape[0] != rotations.shape[0]:
|
|
138
|
-
_fail(
|
|
139
|
-
"local_rot_mats and posed_joints frame counts differ "
|
|
140
|
-
f"({rotations.shape[0]} vs {joints.shape[0]})"
|
|
141
|
-
)
|
|
142
|
-
frames_total = int(rotations.shape[0])
|
|
143
|
-
if frames_total < 1:
|
|
144
|
-
_fail(f"motion has no frames ({frames_total})")
|
|
145
|
-
if frame >= frames_total:
|
|
146
|
-
_fail(
|
|
147
|
-
f"frame {frame} out of range: motion has {frames_total} frames"
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
# Validate every rotation matrix of the requested frame BEFORE any
|
|
151
|
-
# JSON is written; a violation aborts with a stderr report and a
|
|
152
|
-
# non-zero exit status instead of emitting garbage.
|
|
153
|
-
violations = []
|
|
154
|
-
for joint in range(JOINTS):
|
|
155
|
-
violations.extend(_check_rotation(rotations[frame][joint], frame, joint))
|
|
156
|
-
for joint in range(JOINTS):
|
|
157
|
-
for axis in range(3):
|
|
158
|
-
if not math.isfinite(float(joints[frame][joint][axis])):
|
|
159
|
-
violations.append(
|
|
160
|
-
f"frame {frame} joint {joint} axis {axis} "
|
|
161
|
-
"position is not finite"
|
|
162
|
-
)
|
|
163
|
-
if violations:
|
|
164
|
-
for violation in violations[:20]:
|
|
165
|
-
print(f"dump-npz: VIOLATION {violation}", file=sys.stderr)
|
|
166
|
-
if len(violations) > 20:
|
|
167
|
-
print(
|
|
168
|
-
f"dump-npz: ... and {len(violations) - 20} more",
|
|
169
|
-
file=sys.stderr,
|
|
170
|
-
)
|
|
171
|
-
_fail(
|
|
172
|
-
f"refusing to emit {npz_path} frame {frame}: "
|
|
173
|
-
f"{len(violations)} rotation/position check(s) failed"
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
members = {}
|
|
177
|
-
for name in sorted(data.files):
|
|
178
|
-
member = data[name]
|
|
179
|
-
members[name] = {
|
|
180
|
-
"shape": [int(size) for size in member.shape],
|
|
181
|
-
"dtype": str(member.dtype),
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
document = {
|
|
185
|
-
"schema": SCHEMA,
|
|
186
|
-
"source_npz": npz_path.rsplit("/", 1)[-1],
|
|
187
|
-
"frame": frame,
|
|
188
|
-
"frames_total": frames_total,
|
|
189
|
-
"members": members,
|
|
190
|
-
"local_rot_mats": [
|
|
191
|
-
[[float(value) for value in row] for row in rotations[frame][joint]]
|
|
192
|
-
for joint in range(JOINTS)
|
|
193
|
-
],
|
|
194
|
-
"posed_joints": [
|
|
195
|
-
[float(value) for value in joints[frame][joint]]
|
|
196
|
-
for joint in range(JOINTS)
|
|
197
|
-
],
|
|
198
|
-
}
|
|
199
|
-
print(json.dumps(document, indent=2))
|
|
200
|
-
finally:
|
|
201
|
-
data.close()
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if __name__ == "__main__":
|
|
205
|
-
main(sys.argv)
|