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,354 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import pytest
|
|
5
|
-
import torch
|
|
6
|
-
|
|
7
|
-
import scene
|
|
8
|
-
from scene import SceneError
|
|
9
|
-
|
|
10
|
-
SCENE_JSON = { # evidence/exp3/gt/bump/scene.json as written by tools/gt-render/scene-box.mjs
|
|
11
|
-
"kind": "cube",
|
|
12
|
-
"placement": {"x": -0.46474942564964294, "z": 4.095341396331787, "rot": 0, "sx": 1.5, "sy": 1.5, "sz": 0.4},
|
|
13
|
-
"centre": [-0.46474942564964294, 0.75, 4.095341396331787],
|
|
14
|
-
"halfExtents": [0.75, 0.75, 0.2],
|
|
15
|
-
"yawDeg": 0,
|
|
16
|
-
"min": [-1.214749425649643, 0, 3.895341396331787],
|
|
17
|
-
"max": [0.28525057435035706, 1.5, 4.2953413963317875],
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def boxes_of(records, frames=1, dtype=torch.float64):
|
|
22
|
-
return scene.box_tensors(scene.parse_scene(records), frames, dtype=dtype)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def pts(*xyz):
|
|
26
|
-
return torch.tensor(np.array([xyz], dtype=np.float64)) # (T=1, N, 3)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def ry(yaw): # three.js rotation about +Y (tools/gt-render/scene-box.mjs boxCorners)
|
|
30
|
-
c, s = math.cos(yaw), math.sin(yaw)
|
|
31
|
-
return np.array([[c, 0, s], [0, 1, 0], [-s, 0, c]])
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def reference_sdf(p, center, half, yaw):
|
|
35
|
-
local = ry(yaw).T @ (np.asarray(p) - center)
|
|
36
|
-
q = np.abs(local) - half
|
|
37
|
-
if np.all(q <= 0):
|
|
38
|
-
return float(q.max())
|
|
39
|
-
return float(np.linalg.norm(local - np.clip(local, -half, half)))
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# --- parsing ---------------------------------------------------------------
|
|
43
|
-
|
|
44
|
-
def test_parses_bench_scene_json_min_max():
|
|
45
|
-
[box] = scene.parse_scene({"min": [0, 0, 0], "max": [2, 1, 4]})
|
|
46
|
-
np.testing.assert_allclose(box.center, [1, 0.5, 2])
|
|
47
|
-
np.testing.assert_allclose(box.half_extents, [1, 0.5, 2])
|
|
48
|
-
assert box.yaw == 0 and box.per_frame_center is None
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_parses_real_scene_json_and_boxes_list():
|
|
52
|
-
[box] = scene.parse_scene(SCENE_JSON)
|
|
53
|
-
np.testing.assert_allclose(box.center, SCENE_JSON["centre"])
|
|
54
|
-
np.testing.assert_allclose(box.half_extents, SCENE_JSON["halfExtents"])
|
|
55
|
-
two = scene.parse_scene({"boxes": [{"min": SCENE_JSON["min"], "max": SCENE_JSON["max"]}, {"center": [0, 1, 0], "halfExtents": [1, 1, 1], "yawDeg": 90}]})
|
|
56
|
-
assert len(two) == 2 and two[1].yaw == pytest.approx(math.pi / 2)
|
|
57
|
-
assert scene.parse_scene(None) == []
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def test_parses_shot_context_obb_with_per_frame():
|
|
61
|
-
[box] = scene.parse_scene([{"center": [0, 0.5, 0], "halfExtents": [0.5, 0.5, 0.5], "yaw": 0.3,
|
|
62
|
-
"perFrame": [[0, 0.5, 0], {"center": [1, 0.5, 0], "yaw": 0.6}, {"centre": [2, 0.5, 0]}]}])
|
|
63
|
-
t = scene.box_tensors([box], 3, dtype=torch.float64)
|
|
64
|
-
np.testing.assert_allclose(t.centers[0, :, 0].numpy(), [0, 1, 2])
|
|
65
|
-
np.testing.assert_allclose(t.yaw[0].numpy(), [0.3, 0.6, 0.3])
|
|
66
|
-
with pytest.raises(SceneError) as err:
|
|
67
|
-
scene.box_tensors([box], 4)
|
|
68
|
-
assert err.value.code == "box-frames-mismatch"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@pytest.mark.parametrize("record", [
|
|
72
|
-
{"min": [0, 0, 0], "max": [0, 0, 0]},
|
|
73
|
-
{"min": [0, 0, 0], "max": [1, 0, 1]},
|
|
74
|
-
{"min": [1, 0, 0], "max": [0, 1, 1]},
|
|
75
|
-
{"center": [0, 0, 0], "halfExtents": [0.5, 0, 0.5]},
|
|
76
|
-
])
|
|
77
|
-
def test_zero_or_negative_size_is_degenerate_box(record):
|
|
78
|
-
with pytest.raises(SceneError) as err:
|
|
79
|
-
scene.parse_scene(record)
|
|
80
|
-
assert err.value.code == "degenerate-box"
|
|
81
|
-
assert str(err.value).startswith("degenerate-box")
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@pytest.mark.parametrize("record", [
|
|
85
|
-
{"min": [0, float("nan"), 0], "max": [1, 1, 1]},
|
|
86
|
-
{"center": [0, 0, 0], "halfExtents": [0.5, float("inf"), 0.5]},
|
|
87
|
-
{"center": [0, 0, 0], "halfExtents": [0.5, 0.5, 0.5], "yaw": float("nan")},
|
|
88
|
-
{"center": [0, 0, 0], "halfExtents": [0.5, 0.5, 0.5], "perFrame": [[0, float("nan"), 0]]},
|
|
89
|
-
{"center": [0, 0, 0]},
|
|
90
|
-
{"min": [0, 0], "max": [1, 1]},
|
|
91
|
-
"box",
|
|
92
|
-
])
|
|
93
|
-
def test_malformed_box_is_rejected(record):
|
|
94
|
-
with pytest.raises(SceneError) as err:
|
|
95
|
-
scene.parse_scene(record)
|
|
96
|
-
assert err.value.code == "bad-box"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
# --- signed distance ---------------------------------------------------------
|
|
100
|
-
|
|
101
|
-
def test_sdf_unit_box_sign_and_magnitude():
|
|
102
|
-
boxes = boxes_of({"min": [-0.5, -0.5, -0.5], "max": [0.5, 0.5, 0.5]})
|
|
103
|
-
sd = scene.box_sdf(pts([0, 0, 0], [0.4, 0, 0], [0.5, 0, 0], [1, 0, 0], [1, 1, 0], [1, 1, 1], [0, -2, 0]), boxes)[0, :, 0]
|
|
104
|
-
expected = [-0.5, -0.1, 0.0, 0.5, math.sqrt(0.5), math.sqrt(0.75), 1.5]
|
|
105
|
-
np.testing.assert_allclose(sd.numpy(), expected, atol=1e-12)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def test_sdf_rotated_and_translated_box():
|
|
109
|
-
center, half, yaw = np.array([2.0, 0.75, -3.0]), np.array([1.0, 0.75, 0.2]), math.radians(90)
|
|
110
|
-
boxes = boxes_of({"center": center.tolist(), "halfExtents": half.tolist(), "yawDeg": 90})
|
|
111
|
-
# Rotated 90 deg the long (x) side lies along world z: 0.9 m along z is inside, 0.5 m along x is outside.
|
|
112
|
-
sd = scene.box_sdf(pts(center + [0, 0, 0.9], center + [0.5, 0, 0], center), boxes)[0, :, 0].numpy()
|
|
113
|
-
np.testing.assert_allclose(sd, [-0.1, 0.3, -0.2], atol=1e-12)
|
|
114
|
-
corners = [center + ry(yaw) @ (half * [sx, sy, sz]) for sx in (-1, 1) for sy in (-1, 1) for sz in (-1, 1)]
|
|
115
|
-
np.testing.assert_allclose(scene.box_sdf(pts(*corners), boxes)[0, :, 0].numpy(), 0, atol=1e-12)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def test_sdf_matches_reference_on_random_points():
|
|
119
|
-
rng = np.random.default_rng(8)
|
|
120
|
-
center, half, yaw = np.array([-0.46, 0.75, 4.1]), np.array([0.75, 0.75, 0.2]), 0.7
|
|
121
|
-
boxes = boxes_of({"center": center.tolist(), "halfExtents": half.tolist(), "yaw": yaw})
|
|
122
|
-
points = center + rng.uniform(-1.5, 1.5, size=(500, 3))
|
|
123
|
-
sd = scene.box_sdf(torch.tensor(points[None]), boxes)[0, :, 0].numpy()
|
|
124
|
-
ref = np.array([reference_sdf(p, center, half, yaw) for p in points])
|
|
125
|
-
np.testing.assert_allclose(sd, ref, atol=1e-10)
|
|
126
|
-
assert (sd < 0).any() and (sd > 0).any()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def test_sdf_follows_per_frame_box():
|
|
130
|
-
boxes = boxes_of({"center": [0, 0.5, 0], "halfExtents": [0.5, 0.5, 0.5], "perFrame": [[0, 0.5, 0], [3, 0.5, 0]]}, frames=2)
|
|
131
|
-
sd = scene.box_sdf(torch.tensor([[[0, 0.5, 0]], [[0, 0.5, 0]]], dtype=torch.float64), boxes)[:, 0, 0]
|
|
132
|
-
np.testing.assert_allclose(sd.numpy(), [-0.5, 2.5])
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def test_penetration_loss_values_and_finite_gradients():
|
|
136
|
-
boxes = boxes_of({"min": [-0.5, 0, -0.5], "max": [0.5, 1, 0.5]})
|
|
137
|
-
# inside, on a face, on an edge, on a corner, at the box centre, outside, below the floor
|
|
138
|
-
points = pts([0.4, 0.5, 0], [0.5, 0.5, 0], [0.5, 1, 0], [0.5, 1, 0.5], [0, 0.5, 0], [2, 0.5, 0], [3, -0.02, 0]).requires_grad_(True)
|
|
139
|
-
loss = scene.penetration_loss(points, boxes)
|
|
140
|
-
assert loss["box"].item() == pytest.approx(0.1 ** 2 + 0.5 ** 2)
|
|
141
|
-
assert loss["floor"].item() == pytest.approx(0.02 ** 2)
|
|
142
|
-
(loss["box"] + loss["floor"]).backward()
|
|
143
|
-
grad = points.grad[0]
|
|
144
|
-
assert torch.isfinite(grad).all()
|
|
145
|
-
assert grad[0, 0] < 0 # descending pushes the penetrating point out through the +x face
|
|
146
|
-
assert grad[6, 1] < 0 # and the sunken point up through the floor
|
|
147
|
-
assert torch.all(grad[5] == 0)
|
|
148
|
-
sd_points = pts([0.5, 1, 0.5], [2, 3, 4]).requires_grad_(True)
|
|
149
|
-
scene.box_sdf(sd_points, boxes).sum().backward()
|
|
150
|
-
assert torch.isfinite(sd_points.grad).all()
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def test_penetration_stats_and_empty_scene():
|
|
154
|
-
boxes = boxes_of({"min": [-0.5, 0, -0.5], "max": [0.5, 1, 0.5]}, frames=3)
|
|
155
|
-
points = torch.tensor([[[2, 0.5, 0]], [[0.45, 0.5, 0]], [[2, -0.01, 0]]], dtype=torch.float64)
|
|
156
|
-
stats = scene.penetration_stats(points, boxes)
|
|
157
|
-
assert stats["maxBoxCm"] == pytest.approx(5.0)
|
|
158
|
-
assert stats["maxFloorCm"] == pytest.approx(1.0)
|
|
159
|
-
assert stats["frames"] == [1, 2]
|
|
160
|
-
empty = scene.box_tensors([], 3, dtype=torch.float64)
|
|
161
|
-
assert scene.penetration_loss(points, empty)["box"].item() == 0
|
|
162
|
-
assert scene.penetration_stats(points, empty)["maxBoxCm"] == 0
|
|
163
|
-
assert not scene.ray_occlusion(points, [0, 1, 5], empty).any()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# --- stance HMM and skate ------------------------------------------------------
|
|
167
|
-
|
|
168
|
-
def synthetic_walk(frames=150, fps=30.0, period=1.0, duty=0.6, stride=1.2, seed=0, ground=None):
|
|
169
|
-
"""Ankle+toe of two feet, (T, 2, 2, 3), and the true stance (T, 2)."""
|
|
170
|
-
rng = np.random.default_rng(seed)
|
|
171
|
-
feet, stance = np.zeros((frames, 2, 2, 3)), np.zeros((frames, 2), dtype=bool)
|
|
172
|
-
for f, (phase, x_side) in enumerate(((0.0, 0.1), (0.5, -0.1))):
|
|
173
|
-
for t in range(frames):
|
|
174
|
-
cycle = t / fps / period + phase
|
|
175
|
-
k, u = math.floor(cycle), cycle - math.floor(cycle)
|
|
176
|
-
if u < duty:
|
|
177
|
-
s, lift = 0.0, 0.0
|
|
178
|
-
stance[t, f] = True
|
|
179
|
-
else:
|
|
180
|
-
w = (u - duty) / (1 - duty)
|
|
181
|
-
s, lift = (1 - math.cos(math.pi * w)) / 2, math.sin(math.pi * w)
|
|
182
|
-
z = (k + s) * stride + phase * stride
|
|
183
|
-
base = 0.0 if ground is None else ground(z)
|
|
184
|
-
feet[t, f, 0] = [x_side, base + 0.08 + 0.12 * lift, z]
|
|
185
|
-
feet[t, f, 1] = [x_side, base + 0.02 + 0.10 * lift, z + 0.15]
|
|
186
|
-
return feet + rng.normal(0, 0.004, feet.shape), stance, fps
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def test_stance_hmm_recovers_walk():
|
|
190
|
-
feet, truth, fps = synthetic_walk()
|
|
191
|
-
got = scene.stance_hmm(torch.tensor(feet), fps)
|
|
192
|
-
assert got.shape == truth.shape
|
|
193
|
-
agreement = (got == truth).mean(axis=0)
|
|
194
|
-
assert np.all(agreement >= 0.9), agreement
|
|
195
|
-
# every true stance run is found and no spurious one-frame toggles appear
|
|
196
|
-
for f in range(2):
|
|
197
|
-
runs = np.flatnonzero(np.diff(got[:, f].astype(int)) != 0)
|
|
198
|
-
assert len(runs) <= len(np.flatnonzero(np.diff(truth[:, f].astype(int)) != 0)) + 1
|
|
199
|
-
explicit = scene.stance_hmm(feet, fps, contact_height=[[0.08, 0.02], [0.08, 0.02]])
|
|
200
|
-
assert np.all((explicit == truth).mean(axis=0) >= 0.9)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def test_stance_hmm_uses_box_top_as_support():
|
|
204
|
-
top = 0.4
|
|
205
|
-
boxes = boxes_of({"min": [-1, 0, 2.0], "max": [1, top, 20]})
|
|
206
|
-
feet, truth, fps = synthetic_walk(ground=lambda z: top if z >= 2.0 else 0.0)
|
|
207
|
-
ref = [[0.08, 0.02], [0.08, 0.02]]
|
|
208
|
-
with_box = scene.stance_hmm(feet, fps, boxes, contact_height=ref)
|
|
209
|
-
assert np.all((with_box == truth).mean(axis=0) >= 0.9)
|
|
210
|
-
on_box = feet[:, :, 0, 2] > 2.2
|
|
211
|
-
floor_only = scene.stance_hmm(feet, fps, contact_height=ref)
|
|
212
|
-
assert not floor_only[on_box & truth].any() # without the box a planted foot on it looks airborne
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def test_support_height_floor_box_top_and_step_tolerance():
|
|
216
|
-
boxes = boxes_of({"center": [0, 0.2, 0], "halfExtents": [0.5, 0.2, 0.5], "yawDeg": 45})
|
|
217
|
-
# beside the box, on its top, 5 cm sunk into its top, deep inside it, inside the unrotated
|
|
218
|
-
# footprint's corner but outside the 45-degree footprint
|
|
219
|
-
points = pts([2, 0.1, 0], [0, 0.45, 0], [0.1, 0.35, 0], [0, 0.1, 0], [0.45, 0.45, 0.45])
|
|
220
|
-
np.testing.assert_allclose(scene.support_height(points, boxes)[0].numpy(), [0, 0.4, 0.4, 0, 0])
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def test_stance_hmm_rejects_nan():
|
|
224
|
-
feet, _, fps = synthetic_walk(frames=10)
|
|
225
|
-
feet[4, 0, 0, 1] = np.nan
|
|
226
|
-
with pytest.raises(SceneError) as err:
|
|
227
|
-
scene.stance_hmm(feet, fps)
|
|
228
|
-
assert err.value.code == "non-finite"
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def test_skate_loss_only_on_stance_frames_and_differentiable():
|
|
232
|
-
fps = 30.0
|
|
233
|
-
joints = torch.zeros(4, 27, 3, dtype=torch.float64)
|
|
234
|
-
joints[:, 25, 0] = torch.tensor([0.0, 0.01, 0.02, 0.5]) # left ankle slides 1 cm/frame, then jumps
|
|
235
|
-
joints[:, 21, 1] = torch.tensor([0.0, 0.5, 1.0, 1.5]) # right ankle moves vertically only
|
|
236
|
-
joints.requires_grad_(True)
|
|
237
|
-
stance = np.array([[1, 1], [1, 1], [1, 1], [0, 1]], dtype=bool)
|
|
238
|
-
loss = scene.skate_loss(scene.foot_points(joints), stance, fps)
|
|
239
|
-
assert loss.item() == pytest.approx(2 * (0.01 * fps) ** 2)
|
|
240
|
-
loss.backward()
|
|
241
|
-
assert torch.isfinite(joints.grad).all()
|
|
242
|
-
assert joints.grad[3, 25, 0] == 0
|
|
243
|
-
assert scene.skate_loss(scene.foot_points(joints), np.zeros((4, 2), dtype=bool), fps).item() == 0
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
# --- occlusion -------------------------------------------------------------------
|
|
247
|
-
|
|
248
|
-
def test_camera_center_from_world_to_camera():
|
|
249
|
-
yaw = 0.5235987755982988
|
|
250
|
-
r = ry(yaw).T * np.array([[1], [-1], [-1]]) # OpenCV y down, z forward from a three.js camera
|
|
251
|
-
position = np.array([1.72, 1.13, 7.13])
|
|
252
|
-
w2c = np.eye(4)
|
|
253
|
-
w2c[:3, :3], w2c[:3, 3] = r, -r @ position
|
|
254
|
-
np.testing.assert_allclose(scene.camera_center({"worldToCamera": w2c.tolist()}), position, atol=1e-12)
|
|
255
|
-
with pytest.raises(SceneError):
|
|
256
|
-
scene.camera_center(np.full((4, 4), np.nan))
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
def test_ray_occlusion_behind_vs_in_front():
|
|
260
|
-
cam = [0, 1, 5]
|
|
261
|
-
boxes = boxes_of({"min": [-0.5, 0.5, -0.5], "max": [0.5, 1.5, 0.5]})
|
|
262
|
-
points = pts([0, 1, -2], [0, 1, 2], [2, 1, -2], [0, 1, 0], [0, 1, 0.5], [0, 2, -2])
|
|
263
|
-
np.testing.assert_array_equal(scene.ray_occlusion(points, cam, boxes)[0].numpy(), [True, False, False, True, False, False])
|
|
264
|
-
# a box behind the camera hides nothing in front of it
|
|
265
|
-
behind_camera = boxes_of({"min": [-0.5, 0.5, 7], "max": [0.5, 1.5, 8]})
|
|
266
|
-
assert not scene.ray_occlusion(points, cam, behind_camera).any()
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
def test_ray_occlusion_rotated_and_moving_box():
|
|
270
|
-
cam = [0, 1, 5]
|
|
271
|
-
# thin wall rotated 90 deg: its long side spans world z, so it only blocks lines of sight near x=0
|
|
272
|
-
wall = {"center": [0, 1, 0], "halfExtents": [1.0, 0.5, 0.05], "yawDeg": 90}
|
|
273
|
-
points = pts([0, 1, -2], [0.3, 1, -2])
|
|
274
|
-
np.testing.assert_array_equal(scene.ray_occlusion(points, cam, boxes_of(wall))[0].numpy(), [True, False])
|
|
275
|
-
np.testing.assert_array_equal(scene.ray_occlusion(points, cam, boxes_of({**wall, "yawDeg": 0}))[0].numpy(), [True, True])
|
|
276
|
-
moving = boxes_of({"center": [0, 1, 0], "halfExtents": [0.5, 0.5, 0.5], "perFrame": [[0, 1, 0], [3, 1, 0]]}, frames=2)
|
|
277
|
-
behind = torch.tensor([[[0, 1, -2]], [[0, 1, -2]]], dtype=torch.float64)
|
|
278
|
-
np.testing.assert_array_equal(scene.ray_occlusion(behind, cam, moving)[:, 0].numpy(), [True, False])
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
# --- device / dtype boundaries ----------------------------------------------------
|
|
282
|
-
|
|
283
|
-
def test_float32_points_with_float64_boxes():
|
|
284
|
-
boxes = boxes_of({"min": [-0.5, 0, -0.5], "max": [0.5, 1, 0.5]}) # float64
|
|
285
|
-
points = pts([0.4, 0.5, 0], [0, 0.5, -2]).float().requires_grad_(True)
|
|
286
|
-
sd = scene.box_sdf(points, boxes)
|
|
287
|
-
assert sd.dtype == torch.float32
|
|
288
|
-
scene.penetration_loss(points, boxes)["box"].backward()
|
|
289
|
-
assert torch.isfinite(points.grad).all()
|
|
290
|
-
assert scene.support_height(points, boxes).dtype == torch.float32
|
|
291
|
-
np.testing.assert_array_equal(scene.ray_occlusion(points, torch.tensor([0.0, 0.5, 5]), boxes)[0].numpy(), [True, True])
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
needs_cuda = pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA-origin inputs need a CUDA device")
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
def cuda_boxes(boxes):
|
|
298
|
-
return scene.SceneBoxes(*(v.cuda() for v in boxes))
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
@needs_cuda
|
|
302
|
-
def test_cuda_stance_hmm_matches_cpu_with_and_without_boxes():
|
|
303
|
-
feet, truth, fps = synthetic_walk(seed=0)
|
|
304
|
-
cpu = scene.stance_hmm(feet, fps)
|
|
305
|
-
gpu_feet = torch.tensor(feet, device="cuda")
|
|
306
|
-
np.testing.assert_array_equal(scene.stance_hmm(gpu_feet, fps), cpu)
|
|
307
|
-
np.testing.assert_array_equal(scene.stance_hmm(gpu_feet.float(), fps), scene.stance_hmm(torch.tensor(feet).float(), fps))
|
|
308
|
-
top = 0.4
|
|
309
|
-
boxes = boxes_of({"min": [-1, 0, 2.0], "max": [1, top, 20]})
|
|
310
|
-
step, step_truth, _ = synthetic_walk(ground=lambda z: top if z >= 2.0 else 0.0)
|
|
311
|
-
ref = [[0.08, 0.02], [0.08, 0.02]]
|
|
312
|
-
cpu_box = scene.stance_hmm(step, fps, boxes, contact_height=ref)
|
|
313
|
-
gpu_step = torch.tensor(step, device="cuda")
|
|
314
|
-
for support in (boxes, cuda_boxes(boxes)):
|
|
315
|
-
for height in (ref, torch.tensor(ref, device="cuda")):
|
|
316
|
-
got = scene.stance_hmm(gpu_step, fps, support, contact_height=height)
|
|
317
|
-
np.testing.assert_array_equal(got, cpu_box)
|
|
318
|
-
assert np.all((cpu_box == step_truth).mean(axis=0) >= 0.9)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
@needs_cuda
|
|
322
|
-
def test_cuda_points_with_cpu_or_cuda_boxes():
|
|
323
|
-
cam = [0, 1, 5]
|
|
324
|
-
boxes = boxes_of({"center": [0, 1, 0], "halfExtents": [0.5, 0.5, 0.5], "yawDeg": 30, "perFrame": [[0, 1, 0], [3, 1, 0]]}, frames=2)
|
|
325
|
-
cpu_points = torch.tensor([[[0, 1, -2], [0.3, 1, 0.2], [2, -0.01, 0]], [[0, 1, -2], [0.3, 1, 0.2], [2, 0.5, 0]]], dtype=torch.float64)
|
|
326
|
-
cpu_sd = scene.box_sdf(cpu_points, boxes)
|
|
327
|
-
cpu_occ = scene.ray_occlusion(cpu_points, cam, boxes)
|
|
328
|
-
cpu_support = scene.support_height(cpu_points, boxes)
|
|
329
|
-
cpu_stats = scene.penetration_stats(cpu_points, boxes)
|
|
330
|
-
for support in (boxes, cuda_boxes(boxes)):
|
|
331
|
-
points = cpu_points.cuda().requires_grad_(True)
|
|
332
|
-
sd = scene.box_sdf(points, support)
|
|
333
|
-
assert sd.device.type == "cuda"
|
|
334
|
-
torch.testing.assert_close(sd.cpu(), cpu_sd)
|
|
335
|
-
loss = scene.penetration_loss(points, support)
|
|
336
|
-
(loss["box"] + loss["floor"]).backward()
|
|
337
|
-
assert points.grad.device.type == "cuda" and torch.isfinite(points.grad).all() and points.grad.abs().sum() > 0
|
|
338
|
-
for camera in (cam, torch.tensor(cam, dtype=torch.float64, device="cuda")):
|
|
339
|
-
occ = scene.ray_occlusion(points.detach(), camera, support)
|
|
340
|
-
assert occ.device.type == "cuda"
|
|
341
|
-
torch.testing.assert_close(occ.cpu(), cpu_occ)
|
|
342
|
-
height = scene.support_height(points.detach(), support)
|
|
343
|
-
assert height.device.type == "cuda"
|
|
344
|
-
torch.testing.assert_close(height.cpu(), cpu_support)
|
|
345
|
-
stats = scene.penetration_stats(points.detach(), support)
|
|
346
|
-
assert stats["frames"] == cpu_stats["frames"] == [0]
|
|
347
|
-
assert stats["maxBoxCm"] == pytest.approx(cpu_stats["maxBoxCm"]) and cpu_stats["maxBoxCm"] > 0
|
|
348
|
-
assert stats["maxFloorCm"] == pytest.approx(cpu_stats["maxFloorCm"]) == pytest.approx(1.0)
|
|
349
|
-
joints = torch.zeros(3, 27, 3, device="cuda", requires_grad=True)
|
|
350
|
-
scene.skate_loss(scene.foot_points(joints), np.ones((3, 2), dtype=bool), 30.0).backward()
|
|
351
|
-
assert joints.grad.device.type == "cuda"
|
|
352
|
-
w2c = torch.eye(4, dtype=torch.float64, device="cuda")
|
|
353
|
-
w2c[:3, 3] = torch.tensor([1.0, 2, 3])
|
|
354
|
-
np.testing.assert_allclose(scene.camera_center(w2c), [-1, -2, -3])
|